📄 usb-midi.c
字号:
printk(KERN_ERR "usbmidi: no memory for midi out-endpoint buffer\n"); kfree(ep); return NULL; } ep->urb = usb_alloc_urb(0, GFP_KERNEL); /* no ISO */ if ( !ep->urb ) { printk(KERN_ERR "usbmidi: no memory for midi out-endpoint urb\n"); kfree(ep->buf); kfree(ep); return NULL; } ep->bufSize = bufSize; /* ep->bufWrPtr = 0; */ init_waitqueue_head(&ep->wait); return ep;}static int remove_midi_out_endpoint( struct midi_out_endpoint *mout ){ usb_unlink_urb( mout->urb ); usb_free_urb( mout->urb ); kfree( mout->buf ); kfree( mout ); return 0;}/** Returns a filled usb_mididev structure, registered as a Linux MIDI device. * * Returns null if memory is not available or the device cannot be registered. * Called by allocUsbMidiDev(); * **/static struct usb_mididev *allocMidiDev( struct usb_midi_state *s, struct midi_in_endpoint *min, struct midi_out_endpoint *mout, int inCableId, int outCableId ){ struct usb_mididev *m; m = (struct usb_mididev *)kmalloc(sizeof(struct usb_mididev), GFP_KERNEL); if (!m) { printk(KERN_ERR "usbmidi: no memory for midi device\n"); return NULL; } memset(m, 0, sizeof(struct usb_mididev)); if ((m->dev_midi = register_sound_midi(&usb_midi_fops, -1)) < 0) { printk(KERN_ERR "usbmidi: cannot register midi device\n"); kfree(m); return NULL; } m->midi = s; /* m->open_mode = 0; */ if ( min ) { m->min.ep = min; m->min.ep->usbdev = s->usbdev; m->min.cableId = inCableId; } /* m->min.bufPtr = 0; */ /* m->min.bufRemains = 0; */ if ( mout ) { m->mout.ep = mout; m->mout.ep->usbdev = s->usbdev; m->mout.cableId = outCableId; } /* m->mout.bufPtr = 0; */ /* m->mout.bufRemains = 0; */ /* m->mout.isInExclusive = 0; */ /* m->mout.lastEvent = 0; */ m->singlebyte = singlebyte; return m;}static void release_midi_device( struct usb_midi_state *s ){ struct usb_mididev *m; struct midi_in_endpoint *min; struct midi_out_endpoint *mout; if ( s->count > 0 ) { up(&open_sem); return; } up( &open_sem ); wake_up( &open_wait ); while(!list_empty(&s->inEndpointList)) { min = list_entry(s->inEndpointList.next, struct midi_in_endpoint, list); list_del(&min->list); remove_midi_in_endpoint(min); } while(!list_empty(&s->outEndpointList)) { mout = list_entry(s->outEndpointList.next, struct midi_out_endpoint, list); list_del(&mout->list); remove_midi_out_endpoint(mout); } while(!list_empty(&s->midiDevList)) { m = list_entry(s->midiDevList.next, struct usb_mididev, list); list_del(&m->list); kfree(m); } kfree(s); return;}/* ------------------------------------------------------------------------- *//** Utility routine to find a descriptor in a dump of many descriptors. * Returns start of descriptor or NULL if not found. * descStart pointer to list of interfaces. * descLength length (in bytes) of dump * after (ignored if NULL) this routine returns only descriptors after "after" * dtype (mandatory) The descriptor type. * iface (ignored if -1) returns descriptor at/following given interface * altSetting (ignored if -1) returns descriptor at/following given altSetting * * * Called by parseDescriptor(), find_csinterface_descriptor(); * */static void *find_descriptor( void *descStart, unsigned int descLength, void *after, unsigned char dtype, int iface, int altSetting ){ unsigned char *p, *end, *next; int interfaceNumber = -1, altSet = -1; p = descStart; end = p + descLength; for( ; p < end; ) { if ( p[0] < 2 ) return NULL; next = p + p[0]; if ( next > end ) return NULL; if ( p[1] == USB_DT_INTERFACE ) { if ( p[0] < USB_DT_INTERFACE_SIZE ) return NULL; interfaceNumber = p[2]; altSet = p[3]; } if ( p[1] == dtype && ( !after || ( p > (unsigned char *)after) ) && ( ( iface == -1) || (iface == interfaceNumber) ) && ( (altSetting == -1) || (altSetting == altSet) )) { return p; } p = next; } return NULL;}/** Utility to find a class-specific interface descriptor. * dsubtype is a descriptor subtype * Called by parseDescriptor(); **/static void *find_csinterface_descriptor(void *descStart, unsigned int descLength, void *after, u8 dsubtype, int iface, int altSetting){ unsigned char *p; p = find_descriptor( descStart, descLength, after, USB_DT_CS_INTERFACE, iface, altSetting ); while ( p ) { if ( p[0] >= 3 && p[2] == dsubtype ) return p; p = find_descriptor( descStart, descLength, p, USB_DT_CS_INTERFACE, iface, altSetting ); } return NULL;}/** The magic of making a new usb_midi_device from config happens here. * * The caller is responsible for free-ing this return value (if not NULL). * **/static struct usb_midi_device *parse_descriptor( struct usb_device *d, unsigned char *buffer, int bufSize, unsigned int ifnum , unsigned int altSetting, int quirks){ struct usb_midi_device *u; unsigned char *p1; unsigned char *p2; unsigned char *next; int iep, oep; int length; unsigned long longBits; int pins, nbytes, offset, shift, jack;#ifdef HAVE_JACK_STRINGS /** Jacks can have associated names. **/ unsigned char jack2string[256];#endif u = NULL; /* find audiocontrol interface */ p1 = find_csinterface_descriptor( buffer, bufSize, NULL, MS_HEADER, ifnum, altSetting); if ( !p1 ) { goto error_end; } if ( p1[0] < MS_HEADER_LENGTH ) { goto error_end; } /* Assume success. Since the device corresponds to USB-MIDI spec, we assume that the rest of the USB 2.0 spec is obeyed. */ u = (struct usb_midi_device *)kmalloc( sizeof(struct usb_midi_device), GFP_KERNEL ); if ( !u ) { return NULL; } u->deviceName = NULL; u->idVendor = d->descriptor.idVendor; u->idProduct = d->descriptor.idProduct; u->interface = ifnum; u->altSetting = altSetting; u->in[0].endpoint = -1; u->in[0].cableId = -1; u->out[0].endpoint = -1; u->out[0].cableId = -1; printk(KERN_INFO "usb-midi: Found MIDIStreaming device corresponding to Release %d.%02d of spec.\n", (p1[4] >> 4) * 10 + (p1[4] & 0x0f ), (p1[3] >> 4) * 10 + (p1[3] & 0x0f ) ); length = p1[5] | (p1[6] << 8);#ifdef HAVE_JACK_STRINGS memset(jack2string, 0, sizeof(unsigned char) * 256);#endif length -= p1[0]; for (p2 = p1 + p1[0]; length > 0; p2 = next) { next = p2 + p2[0]; length -= p2[0]; if (p2[0] < 2 ) break; if (p2[1] != USB_DT_CS_INTERFACE) break; if (p2[2] == MIDI_IN_JACK && p2[0] >= 6 ) { jack = p2[4];#ifdef HAVE_JACK_STRINGS jack2string[jack] = p2[5];#endif printk(KERN_INFO "usb-midi: Found IN Jack 0x%02x %s\n", jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL" ); } else if ( p2[2] == MIDI_OUT_JACK && p2[0] >= 6) { pins = p2[5]; if ( p2[0] < (6 + 2 * pins) ) continue; jack = p2[4];#ifdef HAVE_JACK_STRINGS jack2string[jack] = p2[5 + 2 * pins];#endif printk(KERN_INFO "usb-midi: Found OUT Jack 0x%02x %s, %d pins\n", jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL", pins ); } else if ( p2[2] == ELEMENT_DESCRIPTOR && p2[0] >= 10) { pins = p2[4]; if ( p2[0] < (9 + 2 * pins ) ) continue; nbytes = p2[8 + 2 * pins ]; if ( p2[0] < (10 + 2 * pins + nbytes) ) continue; longBits = 0L; for ( offset = 0, shift = 0; offset < nbytes && offset < 8; offset ++, shift += 8) { longBits |= ((long)(p2[9 + 2 * pins + offset])) << shift; } jack = p2[3];#ifdef HAVE_JACK_STRINGS jack2string[jack] = p2[9 + 2 * pins + nbytes];#endif printk(KERN_INFO "usb-midi: Found ELEMENT 0x%02x, %d/%d pins in/out, bits: 0x%016lx\n", jack, pins, (int)(p2[5 + 2 * pins]), (long)longBits ); } else { } } iep=0; oep=0; if (quirks==0) { /* MIDISTREAM */ p2 = NULL; for (p1 = find_descriptor(buffer, bufSize, NULL, USB_DT_ENDPOINT, ifnum, altSetting ); p1; p1 = next ) { next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT, ifnum, altSetting ); p2 = find_descriptor(buffer, bufSize, p1, USB_DT_CS_ENDPOINT, ifnum, altSetting ); if ( p2 && next && ( p2 > next ) ) p2 = NULL; if ( p1[0] < 9 || !p2 || p2[0] < 4 ) continue; if ( (p1[2] & 0x80) == 0x80 ) { if ( iep < 15 ) { pins = p2[3]; /* not pins -- actually "cables" */ if ( pins > 16 ) pins = 16; u->in[iep].endpoint = p1[2]; u->in[iep].cableId = ( 1 << pins ) - 1; if ( u->in[iep].cableId ) iep ++; if ( iep < 15 ) { u->in[iep].endpoint = -1; u->in[iep].cableId = -1; } } } else { if ( oep < 15 ) { pins = p2[3]; /* not pins -- actually "cables" */ if ( pins > 16 ) pins = 16; u->out[oep].endpoint = p1[2]; u->out[oep].cableId = ( 1 << pins ) - 1; if ( u->out[oep].cableId ) oep ++; if ( oep < 15 ) { u->out[oep].endpoint = -1; u->out[oep].cableId = -1; } } } } } else if (quirks==1) { /* YAMAHA quirks */ for (p1 = find_descriptor(buffer, bufSize, NULL, USB_DT_ENDPOINT, ifnum, altSetting ); p1; p1 = next ) { next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT, ifnum, altSetting ); if ( p1[0] < 7 ) continue; if ( (p1[2] & 0x80) == 0x80 ) { if ( iep < 15 ) { pins = iep+1; if ( pins > 16 ) pins = 16; u->in[iep].endpoint = p1[2]; u->in[iep].cableId = ( 1 << pins ) - 1; if ( u->in[iep].cableId ) iep ++; if ( iep < 15 ) { u->in[iep].endpoint = -1; u->in[iep].cableId = -1; } } } else { if ( oep < 15 ) { pins = oep+1; if ( pins > 16 ) pins = 16; u->out[oep].endpoint = p1[2]; u->out[oep].cableId = ( 1 << pins ) - 1; if ( u->out[oep].cableId ) oep ++; if ( oep < 15 ) { u->out[oep].endpoint = -1; u->out[oep].cableId = -1; } } } } } if ( !iep && ! oep ) { goto error_end; } return u;error_end: kfree(u); return NULL;}/* ------------------------------------------------------------------------- *//** Returns number between 0 and 16. * **/static int on_bits( unsigned short v ){ int i; int ret=0; for ( i=0 ; i<16 ; i++ ) { if ( v & (1<<i) ) ret++; } return ret;}/** USB-device will be interrogated for altSetting. * * Returns negative on error. * Called by allocUsbMidiDev(); * **/static int get_alt_setting( struct usb_device *d, int ifnum ){ int alts, alt=0; struct usb_interface *iface; struct usb_host_interface *interface; struct usb_endpoint_descriptor *ep; int epin, epout; int i; iface = usb_ifnum_to_if( d, ifnum ); alts = iface->num_altsetting; for ( alt=0 ; alt<alts ; alt++ ) { interface = &iface->altsetting[alt]; epin = -1; epout = -1; for ( i=0 ; i<interface->desc.bNumEndpoints ; i++ ) { ep = &interface->endpoint[i].desc; if ( (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ) { continue; } if ( (ep->bEndpointAddress & USB_DIR_IN) && epin < 0 ) { epin = i; } else if ( epout < 0 ) { epout = i; } if ( epin >= 0 && epout >= 0 ) { return interface->desc.bAlternateSetting; } } } return -ENODEV;}/* ------------------------------------------------------------------------- *//** Returns 0 if successful in allocating and registering internal structures. * Returns negative on failure. * Calls allocMidiDev which additionally registers /dev/midiXX devices. * Writes messages on success to indicate which /dev/midiXX is which physical * endpoint. * **/static int alloc_usb_midi_device( struct usb_device *d, struct usb_midi_state *s, struct usb_midi_device *u ){ struct usb_mididev **mdevs=NULL; struct midi_in_endpoint *mins[15], *min; struct midi_out_endpoint *mouts[15], *mout; int inDevs=0, outDevs=0; int inEndpoints=0, outEndpoints=0; int inEndpoint, outEndpoint; int inCableId, outCableId; int i; int devices = 0; int alt = 0; /* Obtain altSetting or die.. */ alt = u->altSetting; if ( alt < 0 ) { alt = get_alt_setting( d, u->interface ); } if ( alt < 0 ) return -ENXIO; /* Configure interface */ if ( usb_set_interface( d, u->interface, alt ) < 0 ) { return -ENXIO; } for ( i = 0 ; i < 15 ; i++ ) { mins[i] = NULL; mouts[i] = NULL; } /* Begin Allocation */ while( inEndpoints < 15 && inDevs < maxdevices && u->in[inEndpoints].cableId >= 0 ) { inDevs += on_bits((unsigned short)u->in[inEndpoints].cableId); mins[inEndpoints] = alloc_midi_in_endpoint( d, u->in[inEndpoints].endpoint ); if ( mins[inEndpoints] == NULL ) goto error_end; inEndpoints++; } while( outEndpoints < 15 && outDevs < maxdevices && u->out[outEndpoints].cableId >= 0 ) { outDevs += on_bits((unsigned short)u->out[outEndpoints].cableId); mouts[outEndpoints] = alloc_midi_out_endpoint( d, u->out[outEndpoints].endpoint ); if ( mouts[outEndpoints] == NULL ) goto error_end; outEndpoints++; } devices = inDevs > outDevs ? inDevs : outDevs; devices = maxdevices > devices ? devices : maxdevices; /* obtain space for device name (iProduct) if not known. */ if ( ! u->deviceName ) { mdevs = (struct usb_mididev **) kmalloc(sizeof(struct usb_mididevs *)*devices + sizeof(char) * 256, GFP_KERNEL); } else { mdevs = (struct usb_mididev **) kmalloc(sizeof(struct usb_mididevs *)*devices, GFP_KERNEL); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -