Markus Rechberger / USB
 
StartSeite | MarkusRechberger/ | Neues | TestSeite | ForumSeite | Teilnehmer | Kategorien | Index | Hilfe | Einstellungen | Ändern

USB Development

general: the usb 2.0 specification allows cables up to 5 meters in length (also depends on which USB cable)

USB Specification: http://www.usb.org/developers/docs/usb_20_02212005.zip

docs about usb programming: http://www.oreilly.com/catalog/linuxdrive3/chapter/ch13.pdf

Linux URB Packet: (include/linux/usb.h)
struct urb
{
        /* private, usb core and host controller only fields in the urb */
        struct kref kref;               /* reference count of the URB */
        spinlock_t lock;                /* lock for the URB */
        void *hcpriv;                   /* private data for host controller */
        struct list_head urb_list;      /* list pointer to all active urbs */
        int bandwidth;                  /* bandwidth for INT/ISO request */
        atomic_t use_count;             /* concurrent submissions counter */
        u8 reject;                      /* submissions will fail */

        /* public, documented fields in the urb that can be used by drivers */
        struct usb_device *dev;         /* (in) pointer to associated device */
        unsigned int pipe;              /* (in) pipe information */
        int status;                     /* (return) non-ISO status */
        unsigned int transfer_flags;    /* (in) URB_SHORT_NOT_OK | ...*/
        void *transfer_buffer;          /* (in) associated data buffer */
        dma_addr_t transfer_dma;        /* (in) dma addr for transfer_buffer */
        int transfer_buffer_length;     /* (in) data buffer length */
        int actual_length;              /* (return) actual transfer length */
        unsigned char *setup_packet;    /* (in) setup packet (control only) */
        dma_addr_t setup_dma;           /* (in) dma addr for setup_packet */
        int start_frame;                /* (modify) start frame (ISO) */
        int number_of_packets;          /* (in) number of ISO packets */
        int interval;                   /* (modify) transfer interval (INT/ISO) */
        int error_count;                /* (return) number of ISO errors */
        void *context;                  /* (in) context for completion */
        usb_complete_t complete;        /* (in) completion routine */
        struct usb_iso_packet_descriptor iso_frame_desc[0];     /* (in) ISO ONLY */
};
this doc is almost only about the em2820 (terratec cinergy 250 USB TV tuner), since there's no driver available atm. I try to figure out how it works (including USB driver programming) USB Snoop:

00000017  8:30:19 PM  >>>>>>> URB 1 going down...
00000018  8:30:19 PM    Status = 00000000
00000019  8:30:19 PM  -- URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
00000020  8:30:19 PM    TransferBufferLength = 00000012
00000021  8:30:19 PM    TransferBuffer       = 842fc488
00000022  8:30:19 PM    TransferBufferMDL    = 00000000
00000023  8:30:19 PM    Index                = 00
00000024  8:30:19 PM    DescriptorType       = 01 (USB_DEVICE_DESCRIPTOR_TYPE)
00000025  8:30:19 PM    LanguageId           = 0000
00000026  8:30:19 PM
00000027  8:30:19 PM  <<<<<<< URB 1 coming back...
00000028  8:30:19 PM    Status = 00000000
00000029  8:30:19 PM  -- URB_FUNCTION_CONTROL_TRANSFER:
00000030  8:30:19 PM    PipeHandle           = 0x8459DE00
00000031  8:30:19 PM    TransferFlags        = 000000eb (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
00000032  8:30:19 PM    TransferBufferLength = 00000012
00000033  8:30:19 PM    TransferBuffer       = 842fc488
00000034  8:30:19 PM    TransferBufferMDL    = 8458fe08
00000035  8:30:19 PM
00000036  8:30:19 PM      0000: 12 01 00 02 00 00 00 40 cd 0c 36 00 00 01 02 01 # <--- chars we got from the device
00000037  8:30:19 PM      0010: 00 01  #<<<-- chars we got from the device 
00000038  8:30:19 PM    UrbLink              = 00000000
00000039  8:30:19 PM    SetupPacket          : 80 06 00 01 00 00 12 00
00000040  8:30:19 PM  UsbSnoop - IRP_MJ_INTERNAL_DEVICE_CONTROL, IOCTL_INTERNAL_USB_SUBMIT_URB
00000041  8:30:19 PM

in this case we sent 80 06 00 01 00 00 12 00 to the USB Device

the first character is a bitmap (0-7), we request 12 bytes from the device (1 byte ->256bits -> 0-FF) This request retrieves the vendor and product id of the usb device (little endian) (vendor: 0c cd: product :00 36)

0c cd -> terratec

00 36 -> cinergy 250 USB

there are a few types how to submit something to the device,

 * ISOCHRONOUS TRANSFERS (unreliable for streaming data from the device to the host / ie. audio, video
 * Bulk Transfer
 * Interrupt

usb control message specification:

Bitmap
0 Host-to-device
1 Device-to-host

0 standard
1 class
2 vendor
3 reserved

0 device
1 interface
2 endpoint
3 other
4..31 reserved

 0x40 (Bin 01000000) host to device
 0xc0 (Bin 11000000) device to host

here's a small script I wrote for converting usbsnoop requests into a sane readable format:

#!/usr/bin/perl
$urbrequest=0;

$enabled=1;
while (<>){
        if(/>>>>>/){
                if(/URB (\d{1,})/){
                        $urbrequest=sprintf("%06d",$1);
                }
                $enabled=1;
        }
        if(/<<<<</){
                if(/URB (\d{1,})/){
                        $urbrequest=sprintf("%06d",$1);
                }
                $enabled=1;

        }
        if(/ISOCH_TRANSFER/){
                $enabled=0;
        }
        if(/URB_FUNCTION_SELECT_INTERFACE/){
                $selectinterface=1;
        }
        if($enabled==1){
                if(/AlternateSetting  = 0x(\d{1,})/){
                        push(@{$urbhash{$urbrequest}{'remark'}},"Changing to Alternative Setting 0x$1\n");
                }
                if(/0000: (.*)\r/){
                        push(@{$urbhash{$urbrequest}{'in'}},$1);
                }
                if(/SetupPacket          : (.*)\r/){
                        push(@{$urbhash{$urbrequest}{'out'}},$1);
                }
        } else {
                ${$urbhash{$urbrequest}{'out'}}[0]="don't know how to handle ISOCH_TRANSFER";
                ${$urbhash{$urbrequest}{'in'}}[0]="don't know how to handle ISOCH_TRANSFER";
        }

}

foreach $indexkey (sort keys %urbhash){
        print "$indexkey:  ";
        if($urbhash{$indexkey}{'remark'}[0] ne ""){
                print $urbhash{$indexkey}{'remark'}[0];
                next;
        }
        print "OUT: ";
        foreach $outkey (@{$urbhash{$indexkey}{'out'}}){
                print "$outkey ";
                if(substr($outkey,0,1) eq "4"){
                        $outgoing=1;
                } else {
                        $outgoing=0;
                }
        }
        if($outgoing == 1){
                print ">>> ";
        } else {
                print "<<< ";
        }
        foreach $inkey (@{$urbhash{$indexkey}{'in'}}){
                print " $inkey\n";
        }
}

 <<< means received from device
 >>> value sent do device

Sample Screen: (it doesn't really handle isochronous packets)
<URB>          <request>                      <value>
1621:  OUT: c0 00 00 00 0f 00 01 00      <<<  07 
1622:  OUT: 40 00 00 00 0f 00 01 00      >>>  07 
1623:  OUT: 40 00 00 00 40 00 02 00      >>>  00 80 
1624:  OUT: 40 00 00 00 42 00 01 00      >>>  02 
1625:  OUT: c0 00 00 00 43 00 01 00      <<<  00 
1626:  OUT: 40 02 00 00 c2 00 04 00      >>>  0c f3 8e 02 
1627:  OUT: c0 00 00 00 05 00 01 00      <<<  00 
1628:  OUT: 40 02 00 00 86 00 04 00      >>>  00 d6 70 49 
1629:  OUT: c0 00 00 00 05 00 01 00      <<<  00 
1630:  OUT: c0 00 00 00 0f 00 01 00      <<<  07 
1631:  OUT: 40 00 00 00 0f 00 01 00      >>>  07 
1632:  OUT: 40 00 00 00 40 00 02 00      >>>  00 80 
1633:  OUT: 40 00 00 00 42 00 01 00      >>>  02 
1634:  OUT: c0 00 00 00 43 00 01 00      <<<  00 
1635:  OUT: 40 02 00 00 c2 00 04 00      >>>  0c f3 8e 02 
1636:  OUT: c0 00 00 00 05 00 01 00      <<<  00 
1637:  OUT: 40 02 00 00 86 00 04 00      >>>  00 d6 70 49 
1638:  OUT: c0 00 00 00 05 00 01 00      <<<  00 
1639:  OUT: 40 02 00 00 4a 00 02 00      >>>  0a 80 
1640:  OUT: c0 00 00 00 05 00 01 00      <<<  00 
1641:  OUT: 40 02 00 00 4a 00 02 00      >>>  0e 01 
1642:  OUT: c0 00 00 00 05 00 01 00      <<<  00 

pseudo code of a driver:

initiate isochronous transfer:
initiso(){
   urb->complete = URBCALLBACK!
}

URBCALLBACK!(){
   receive data frames
   submit urb again
   urb->complete = URBCALLBACK!
}


here we have a nice function of usbaudio.c from the kerneltree there's no check if the device is connected or even functual the negative thing at that point is that if you unplug an usb audio device strange things might happen like the keyboard will freeze .. I just added a few lines for testing, a better state handler will come later...

/*
 * complete callback from data urb
 */
static void snd_complete_urb(struct urb *urb, struct pt_regs *regs)
{
        snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
        snd_usb_substream_t *subs = ctx->subs;
        snd_pcm_substream_t *substream = ctx->subs->pcm_substream;
        int err = 0;
----
        if(ctx->state==SND_MISCONFIGURED){
                printk("device misconfigured\n");
                return;
        }
----
        if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) ||
            ! subs->running || /* can be stopped during retire callback */
            (err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 ||
            (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
                clear_bit(ctx->index, &subs->active_mask);
                if (err < 0) {
                        snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err);
                        snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
----
                        ctx->state |= SND_MISCONFIGURED;
----
                }
        }
}


StartSeite | MarkusRechberger/ | Neues | TestSeite | ForumSeite | Teilnehmer | Kategorien | Index | Hilfe | Einstellungen | Ändern
Text dieser Seite ändern (zuletzt geändert am 5. September 2005 0:09 (diff))
Suchbegriff: gesucht wird im Titel im Text