IMPORTANT NOTE:

This document is outdated. I have figured out most of how the rio works but don't have time (or put in another way: have more intereting things to do) to update it. If you want to know how it works i suggest you look at the source code i have written. The information here might help you a bit but its quite incomplete.

Introduction

This section describes my findings of how data is sent to and from the RIO 500. This information has been obtained by looking at the communication between the RIO and the computer using a debugger and placing breakpoints in the windows driver to dump the content of the messages sent throught the control pipe and bulk read/write pipes. The process is rather complex to explain and maybe when i get a little more time i'll add a description so others can also do it. It basically involves using the debugger supplied in the windows DDK and another computer connected through the serial port. By adding interrupts in strategic places of the riousb.sys file the computer will fall in the debugger. From the other computer one can inspect memory, stack, and add breakpoints which will dump information when they are reached.

Overview

The RIO 500 opens 3 USB pipes: the control pipe, the bulk read and the bulk write pipe. Unfortunately it doesn't use any of the standard class specifications mentioned in the usb specs. It uses vendor specific messages which means that, if the vendor doesn't supply the specs its hard to comunicate with the device. Fortunately i've been able to look at the messages sent to the rio and i'm in the process of understanting the protocol.

If you have read the USB specs you will know that each control message is caracterized by 6 parameters: request type, request, value, index, length and data. Almost all the requests sent to the RIO have request type set to 0xC0 which means that the data transfer direction is set to Device-to-Host, the Type is set to Vendor and the Recipient is set to Device (see ths USB specs, chapter 9 for an explenation of these terms). The request byte, value and index are specific to each type of message and will be explained below. Most commands return 0x01 in the data phase indicating that the command was successfull.

request type 0xC0
request depends on msg
value depends on msg
index depends on msg
length 0x04
data depends on msg

Starting communication with the RIO

When the computer wants to communicate with the RIO it must first tell it to enter the USB Comm phase. You will notice that the RIO displays a message indicating that it is communicating with the computer. To start communication you must send a request 0x47. To end communication a request 0x48 must be sent:

Start communication
request 0x47
value 0x00
index 0x00


End communication
request 0x48
value 0x00
index 0x00

Memory usage

The Rio 500 differs significantly from its predecessor (the Rio 300) in terms of its memory map. The previous Rio had a FAT and the windows software was responsible for maintaing the FAT and deciding where information is stored. The Rio 500 works differently: the device desides were data will be stored and tells the software where in memory the last written information was stored. Memory is divided into 16Kb blocks and addresses point to the beginnig of a block. Offset 0x0 is the first 16Kb block, offset 0x1 is the second 16Kb block, etc. Normally the first 0x16 blocks are used by the Rio 500 internally. The songs, song information and folder information are stored from offset 0x17 on.

Folders and song information

As you have noticed the RIO has the posibility of creating folders and storing songs in them. The information for each folder (name of the folder, offset into memory where the content of this folder is, etc) is stored in C struct called a folder entry. Eight of this entries fit in a 16Kb block. I call this block of 8 folder the folder block. If there are more than 8 folders then there will be more than one folder block. At the moment i haven't bothered to figure out how it handles more than 8 folders so, for the time being, i'll assume there is just one folder block with the information for each of the 8 folder entries. Here's the C struct:

typedef struct
{
  WORD            offset;
  WORD            dunno1;
  WORD            fst_free_entry_off;
  WORD            dunno2;
  DWORD           dunno3;
  DWORD           dunno4;
  DWORD           time;
  rio_bitmap_data bitmap;
  BYTE            name1[362];
  BYTE            name2[128];
} folder_entry;
The relevant fields are offset which has the offset for the list of songs contained in this folder. The bitmap has the bitmap information that is displayed on the Rio (see later for more on this). The time is a unix timestamp (returned by time(NULL)). name1 and name2 have an ascii representation of the name of the folder. I don't know why but its repeated. fst_free_entry_off is the offset into the folder block of the first free folder entry. When there are no folders in the rio this is set to 0. When there is one, then it is set to 0x800, which is the offset into the folder block of the next free entry. This number is always a multiple of 0x800 which is the size of a folder entry.

The folder block is read by using the following commands:

Set read address
request 0x4e
value 0xff00
index 0x00

This command tells the RIO we want to read the folder block. This is indicated by the 0xff00. I think it returns the the number of 16Kb blocks that are used by the folder block but as i said before, since i haven't bothered with the case of more than 8 folders i'm not sure. I think i experimented a bit and saw that it returned 0 when there is no folder block (when the rio is formatted) and 1 when there are less than 8 folders. And, if i don't remember wrong, at some point i noticed it returned 2 when there were more than 8 folders but i'm not sure. Now we must read the data from the bulk pipe. This is done by sending a read command:

Transfer data to computer
request 0x45
value length_hi
index length_low

This command tells the RIO we are ready to receive a bulk transfer. At this point the RIO will begin sending length_hi * 0x10000 + length_low bytes throught the bulk pipe. To read the folder block one sets length_hi=0 and length_low=0x4000.

Once you have the folder block it can be modified. To transfer the folder list back to the RIO you should first send a write request to by issueing the command:

Set write address
request 0x4c
value 0xff00
index 0x00
then a misterious request which i'm not sure what its used for:

Unknown
request 0x4f
value 0xffff
index 0x00

followed by a write request:

Write data to RIO
request 0x46
value length_hi
index length_low

where length_hi and length_low are as in the read command (usually, for the folder block, length_hi=0 and length_low=0x4000) At this point we must write the data to the bulk write pipe and the RIO will accept it. As i said before, we do not decide where the data is being stored. After a write command we must query the Rio to tell us where it was stored. This is done by the command 0x43:

Query write address
request 0x43
value 0x00
index 0x00

This command returns the offset into memory where the last bulk transfer was written to. Once the folder block has been written we must tell the rio where the main folder block is. This is done with the command 0x56. This command is different from the rest because, during the data phase of the control message, data is sent TO the rio. 6 bytes are sent: the first two are the offset into memory where the folder block was stored. The next two i'm not sure but i set them to 0x4000 and it works fine. Its probably the size of the folder block. The last two bytes are the number of the folder we just modified (folder 0 is the first folder, etc).

Formating the RIO

To erase the content of your RIO you must send the following request:

Format RIO memory
request 0x4d
value 0x2185
index 0x00








César Miquel (miquel@df.uba.ar)