📄 usb-midi.c
字号:
} else if ( d->descriptor.idVendor == USB_VENDOR_ID_STEINBERG ) { strcpy(u->deviceName, "Unknown Steinberg"); } else if ( d->descriptor.idVendor == USB_VENDOR_ID_YAMAHA ) { strcpy(u->deviceName, "Unknown Yamaha"); } else { strcpy(u->deviceName, "Unknown"); } } } inEndpoint = 0; inCableId = -1; outEndpoint = 0; outCableId = -1; for ( i=0 ; i<devices ; i++ ) { for ( inCableId ++ ; inEndpoint <15 && mins[inEndpoint] && !(u->in[inEndpoint].cableId & (1<<inCableId)) ; inCableId++ ) { if ( inCableId >= 16 ) { inEndpoint ++; inCableId = 0; } } min = mins[inEndpoint]; for ( outCableId ++ ; outEndpoint <15 && mouts[outEndpoint] && !(u->out[outEndpoint].cableId & (1<<outCableId)) ; outCableId++ ) { if ( outCableId >= 16 ) { outEndpoint ++; outCableId = 0; } } mout = mouts[outEndpoint]; mdevs[i] = allocMidiDev( s, min, mout, inCableId, outCableId ); if ( mdevs[i] == NULL ) { goto error_end; } } /* Success! */ for ( i=0 ; i<devices ; i++ ) { list_add_tail( &mdevs[i]->list, &s->midiDevList ); } for ( i=0 ; i<inEndpoints ; i++ ) { list_add_tail( &mins[i]->list, &s->inEndpointList ); } for ( i=0 ; i<outEndpoints ; i++ ) { list_add_tail( &mouts[i]->list, &s->outEndpointList ); } printk(KERN_INFO "usbmidi: found [ %s ] (0x%04x:0x%04x), attached:\n", u->deviceName, u->idVendor, u->idProduct ); for ( i=0 ; i<devices ; i++ ) { int dm = (mdevs[i]->dev_midi-2)>>4; if ( mdevs[i]->mout.ep != NULL && mdevs[i]->min.ep != NULL ) { printk(KERN_INFO "usbmidi: /dev/midi%02d: in (ep:%02x cid:%2d bufsiz:%2d) out (ep:%02x cid:%2d bufsiz:%2d)\n", dm, mdevs[i]->min.ep->endpoint|USB_DIR_IN, mdevs[i]->min.cableId, mdevs[i]->min.ep->recvBufSize, mdevs[i]->mout.ep->endpoint, mdevs[i]->mout.cableId, mdevs[i]->mout.ep->bufSize); } else if ( mdevs[i]->min.ep != NULL ) { printk(KERN_INFO "usbmidi: /dev/midi%02d: in (ep:%02x cid:%2d bufsiz:%02d)\n", dm, mdevs[i]->min.ep->endpoint|USB_DIR_IN, mdevs[i]->min.cableId, mdevs[i]->min.ep->recvBufSize); } else if ( mdevs[i]->mout.ep != NULL ) { printk(KERN_INFO "usbmidi: /dev/midi%02d: out (ep:%02x cid:%2d bufsiz:%02d)\n", dm, mdevs[i]->mout.ep->endpoint, mdevs[i]->mout.cableId, mdevs[i]->mout.ep->bufSize); } } kfree(mdevs); return 0; error_end: if ( mdevs != NULL && devices > 0 ) { for ( i=0 ; i<devices ; i++ ) { if ( mdevs[i] != NULL ) { unregister_sound_midi( mdevs[i]->dev_midi ); kfree(mdevs[i]); } } kfree(mdevs); } for ( i=0 ; i<15 ; i++ ) { if ( mins[i] != NULL ) { remove_midi_in_endpoint( mins[i] ); } if ( mouts[i] != NULL ) { remove_midi_out_endpoint( mouts[i] ); } } return -ENOMEM;}/* ------------------------------------------------------------------------- *//** Attempt to scan YAMAHA's device descriptor and detect correct values of * them. * Return 0 on succes, negative on failure. * Called by usb_midi_probe(); **/static int detect_yamaha_device( struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s){ struct usb_config_descriptor *c = d->actconfig; struct usb_interface_descriptor *interface; struct usb_midi_device *u; unsigned char buf[USB_DT_CONFIG_SIZE], *buffer; int bufSize; int i; int alts=-1; int ret; if (d->descriptor.idVendor != USB_VENDOR_ID_YAMAHA) { return -EINVAL; } for ( i=0 ; i < c->interface[ifnum].num_altsetting; i++ ) { interface = c->interface[ifnum].altsetting + i; if ( interface->bInterfaceClass != 255 || interface->bInterfaceSubClass != 0 ) continue; alts = i; } if ( alts == -1 ) { return -EINVAL; } printk(KERN_INFO "usb-midi: Found YAMAHA USB-MIDI device on dev %04x:%04x, iface %d\n", d->descriptor.idVendor, d->descriptor.idProduct, ifnum); for ( i=0 ; i < d->descriptor.bNumConfigurations ; i++ ) { if ( d->config+i == c ) goto configfound; } printk(KERN_INFO "usb-midi: Config not found.\n"); return -EINVAL; configfound: /* this may not be necessary. */ if ( usb_set_configuration( d, c->bConfigurationValue ) < 0 ) { printk(KERN_INFO "usb-midi: Could not set config.\n"); return -EINVAL; } ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buf, USB_DT_CONFIG_SIZE ); if ( ret < 0 ) { printk(KERN_INFO "usb-midi: Could not get config (error=%d).\n", ret); return -EINVAL; } if ( buf[1] != USB_DT_CONFIG || buf[0] < USB_DT_CONFIG_SIZE ) { printk(KERN_INFO "usb-midi: config not as expected.\n"); return -EINVAL; } bufSize = buf[2] | buf[3]<<8; buffer = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL); if ( !buffer ) { printk(KERN_INFO "usb-midi: Could not allocate memory.\n"); return -EINVAL; } ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buffer, bufSize ); if ( ret < 0 ) { printk(KERN_INFO "usb-midi: Could not get full config (error=%d).\n", ret); kfree(buffer); return -EINVAL; } u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 1); kfree(buffer); if ( u == NULL ) { return -EINVAL; } ret = alloc_usb_midi_device( d, s, u ); kfree(u); return ret;}/** Scan table of known devices which are only partially compliant with * the MIDIStreaming specification. * Called by usb_midi_probe(); * **/static int detect_vendor_specific_device( struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s ){ struct usb_midi_device *u; int i; int ret = -ENXIO; for ( i=0; i<VENDOR_SPECIFIC_USB_MIDI_DEVICES ; i++ ) { u=&(usb_midi_devices[i]); if ( d->descriptor.idVendor != u->idVendor || d->descriptor.idProduct != u->idProduct || ifnum != u->interface ) continue; ret = alloc_usb_midi_device( d, s, u ); break; } return ret;}/** Attempt to match any config of an interface to a MIDISTREAMING interface. * Returns 0 on success, negative on failure. * Called by usb_midi_probe(); **/static int detect_midi_subclass(struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s){ struct usb_config_descriptor *c = d->actconfig; struct usb_interface_descriptor *interface; struct usb_midi_device *u; unsigned char buf[USB_DT_CONFIG_SIZE], *buffer; int bufSize; int i; int alts=-1; int ret; for ( i=0 ; i < c->interface[ifnum].num_altsetting; i++ ) { interface = c->interface[ifnum].altsetting + i; if ( interface->bInterfaceClass != USB_CLASS_AUDIO || interface->bInterfaceSubClass != USB_SUBCLASS_MIDISTREAMING ) continue; alts = i; } if ( alts == -1 ) { return -EINVAL; } printk(KERN_INFO "usb-midi: Found MIDISTREAMING on dev %04x:%04x, iface %d\n", d->descriptor.idVendor, d->descriptor.idProduct, ifnum); for ( i=0 ; i < d->descriptor.bNumConfigurations ; i++ ) { if ( d->config+i == c ) goto configfound; } printk(KERN_INFO "usb-midi: Config not found.\n"); return -EINVAL; configfound: /* this may not be necessary. */ if ( usb_set_configuration( d, c->bConfigurationValue ) < 0 ) { printk(KERN_INFO "usb-midi: Could not set config.\n"); return -EINVAL; } /* From USB Spec v2.0, Section 9.5. If the class or vendor specific descriptors use the same format as standard descriptors (e.g., start with a length byte and followed by a type byte), they must be returned interleaved with standard descriptors in the configuration information returned by a GetDescriptor(Configuration) request. In this case, the class or vendor-specific descriptors must follow a related standard descriptor they modify or extend. */ ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buf, USB_DT_CONFIG_SIZE ); if ( ret < 0 ) { printk(KERN_INFO "usb-midi: Could not get config (error=%d).\n", ret); return -EINVAL; } if ( buf[1] != USB_DT_CONFIG || buf[0] < USB_DT_CONFIG_SIZE ) { printk(KERN_INFO "usb-midi: config not as expected.\n"); return -EINVAL; } bufSize = buf[2] | buf[3]<<8; buffer = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL); if ( !buffer ) { printk(KERN_INFO "usb-midi: Could not allocate memory.\n"); return -EINVAL; } ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buffer, bufSize ); if ( ret < 0 ) { printk(KERN_INFO "usb-midi: Could not get full config (error=%d).\n", ret); kfree(buffer); return -EINVAL; } u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 0); kfree(buffer); if ( u == NULL ) { return -EINVAL; } ret = alloc_usb_midi_device( d, s, u ); kfree(u); return ret;}/** When user has requested a specific device, match it exactly. * * Uses uvendor, uproduct, uinterface, ualt, umin, umout and ucable. * Called by usb_midi_probe(); * **/static int detect_by_hand(struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s){ struct usb_midi_device u; if ( d->descriptor.idVendor != uvendor || d->descriptor.idProduct != uproduct || ifnum != uinterface ) { return -EINVAL; } if ( ualt < 0 ) { ualt = -1; } if ( umin < 0 || umin > 15 ) { umin = 0x01 | USB_DIR_IN; } if ( umout < 0 || umout > 15 ) { umout = 0x01; } if ( ucable < 0 || ucable > 15 ) { ucable = 0; } u.deviceName = 0; /* A flag for alloc_usb_midi_device to get device name from device. */ u.idVendor = uvendor; u.idProduct = uproduct; u.interface = uinterface; u.altSetting = ualt; u.in[0].endpoint = umin; u.in[0].cableId = (1<<ucable); u.out[0].endpoint = umout; u.out[0].cableId = (1<<ucable); return alloc_usb_midi_device( d, s, &u );}/* ------------------------------------------------------------------------- */static void *usb_midi_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id){ struct usb_midi_state *s; s = (struct usb_midi_state *)kmalloc(sizeof(struct usb_midi_state), GFP_KERNEL); if ( !s ) { return NULL; } memset( s, 0, sizeof(struct usb_midi_state) ); INIT_LIST_HEAD(&s->midiDevList); INIT_LIST_HEAD(&s->inEndpointList); INIT_LIST_HEAD(&s->outEndpointList); s->usbdev = dev; s->count = 0; spin_lock_init(&s->lock); if ( detect_by_hand( dev, ifnum, s ) && detect_midi_subclass( dev, ifnum, s ) && detect_vendor_specific_device( dev, ifnum, s ) && detect_yamaha_device( dev, ifnum, s) ) { kfree(s); return NULL; } down(&open_sem); list_add_tail(&s->mididev, &mididevs); up(&open_sem);#ifdef MOD_INC_EACH_PROBE MOD_INC_USE_COUNT;#endif return s;}static void usb_midi_disconnect(struct usb_device *dev, void *ptr){ struct usb_midi_state *s = (struct usb_midi_state *)ptr; struct list_head *list; struct usb_mididev *m; if ( s == (struct usb_midi_state *)-1 ) { return; } if ( !s->usbdev ) { return; } down(&open_sem); list_del(&s->mididev); INIT_LIST_HEAD(&s->mididev); s->usbdev = NULL; for ( list = s->midiDevList.next; list != &s->midiDevList; list = list->next ) { m = list_entry(list, struct usb_mididev, list); wake_up(&(m->min.ep->wait)); wake_up(&(m->mout.ep->wait)); if ( m->dev_midi >= 0 ) { unregister_sound_midi(m->dev_midi); } m->dev_midi = -1; } release_midi_device(s); wake_up(&open_wait);#ifdef MOD_INC_EACH_PROBE MOD_DEC_USE_COUNT;#endif return;}static struct usb_driver usb_midi_driver = { name: "midi", probe: usb_midi_probe, disconnect: usb_midi_disconnect, id_table: NULL, /* check all devices */ driver_list: LIST_HEAD_INIT(usb_midi_driver.driver_list)};/* ------------------------------------------------------------------------- */int __init usb_midi_init(void){ if ( usb_register(&usb_midi_driver) < 0 ) return -1; return 0;}void __exit usb_midi_exit(void){ usb_deregister(&usb_midi_driver);}module_init(usb_midi_init) ;module_exit(usb_midi_exit) ;#ifdef HAVE_ALSA_SUPPORT#define SNDRV_MAIN_OBJECT_FILE#include "../../include/driver.h"#include "../../include/control.h"#include "../../include/info.h"#include "../../include/cs46xx.h"/* ------------------------------------------------------------------------- */static int snd_usbmidi_input_close(snd_rawmidi_substream_t * substream){ return 0;}static int snd_usbmidi_input_open(snd_rawmidi_substream_t * substream ){ return 0;}static void snd_usbmidi_input_trigger(snd_rawmidi_substream_t * substream, int up){ return 0;}/* ------------------------------------------------------------------------- */static int snd_usbmidi_output_close(snd_rawmidi_substream_t * substream){ return 0;}static int snd_usbmidi_output_open(snd_rawmidi_substream_t * substream){ return 0;}static void snd_usb_midi_output_trigger(snd_rawmidi_substream_t * substream, int up){ return 0;}/* ------------------------------------------------------------------------- */static snd_rawmidi_ops_t snd_usbmidi_output ={ open: snd_usbmidi_output_open, close: snd_usbmidi_output_close, trigger: snd_usbmidi_output_trigger,};static snd_rawmidi_ops_t snd_usbmidi_input ={ open: snd_usbmidi_input_open, close: snd_usbmidi_input_close, trigger: snd_usbmidi_input_trigger,};int snd_usbmidi_midi(cs46xx_t *chip, int device, snd_rawmidi_t **rrawmidi){ snd_rawmidi_t *rmidi; int err; if (rrawmidi) *rrawmidi = NULL; if ((err = snd_rawmidi_new(chip->card, "USB-MIDI", device, 1, 1, &rmidi)) < 0) return err; strcpy(rmidi->name, "USB-MIDI"); snd_rawmidi_set_ops( rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_usbmidi_output ); snd_rawmidi_set_ops( rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_usbmidi_input ); rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = chip; chip->rmidi = rmidi; if (rrawmidi) *rrawmidi = NULL; return 0;}int snd_usbmidi_create( snd_card_t * card, struct pci_dev * pci, usbmidi_t ** rchip ){ usbmidi_t *chip; int err, idx; snd_region_t *region; static snd_device_opt_t ops = { dev_free: snd_usbmidi_dev_free, }; *rchip = NULL; chip = snd_magic_kcalloc( usbmidi_t, 0, GFP_KERNEL ); if ( chip == NULL ) return -ENOMEM;}EXPORT_SYMBOL(snd_usbmidi_create);EXPORT_SYMBOL(snd_usbmidi_midi);#endif /* HAVE_ALSA_SUPPORT */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -