📄 usb-midi.c
字号:
/* mdevs = NULL; */
goto error_end;
}
for ( i=0 ; i<devices ; i++ ) {
mdevs[i] = NULL;
}
/* obtain device name (iProduct) if not known. */
if ( ! u->deviceName ) {
u->deviceName = (char *) (mdevs + devices);
if ( ! d->have_langid && d->descriptor.iProduct) {
alt = usb_get_string(d, 0, 0, u->deviceName, 250);
if (alt < 0) {
printk(KERN_INFO "error getting string descriptor 0 (error=%d)\n", alt);
} else if (u->deviceName[0] < 4) {
printk(KERN_INFO "string descriptor 0 too short (length = %d)\n", alt);
} else {
printk(KERN_INFO "string descriptor 0 found (length = %d)\n", alt);
for(; alt >= 4; alt -= 2) {
i = u->deviceName[alt-2] | (u->deviceName[alt-1]<< 8);
printk(KERN_INFO "usb-midi: langid(%d) 0x%04x\n",
(alt-4) >> 1, i);
if ( ( ( i ^ ulangid ) & 0xff ) == 0 ) {
d->have_langid = 1;
d->string_langid = i;
printk(KERN_INFO "usb-midi: langid(match) 0x%04x\n", i);
if ( i == ulangid )
break;
}
}
}
}
u->deviceName[0] = (char) 0;
if (d->descriptor.iProduct) {
printk(KERN_INFO "usb-midi: fetchString(%d)\n", d->descriptor.iProduct);
alt = usb_string(d, d->descriptor.iProduct, u->deviceName, 255);
if( alt < 0 ) {
u->deviceName[0] = (char) 0;
}
printk(KERN_INFO "usb-midi: fetchString = %d\n", alt);
}
/* Failsafe */
if ( !u->deviceName[0] ) {
if (le16_to_cpu(d->descriptor.idVendor) == USB_VENDOR_ID_ROLAND ) {
strcpy(u->deviceName, "Unknown Roland");
} else if (le16_to_cpu(d->descriptor.idVendor) == USB_VENDOR_ID_STEINBERG ) {
strcpy(u->deviceName, "Unknown Steinberg");
} else if (le16_to_cpu(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 ) {
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,
struct usb_interface *iface, unsigned int ifnum,
struct usb_midi_state *s)
{
struct usb_host_interface *interface;
struct usb_midi_device *u;
unsigned char *buffer;
int bufSize;
int i;
int alts=-1;
int ret;
if (le16_to_cpu(d->descriptor.idVendor) != USB_VENDOR_ID_YAMAHA) {
return -EINVAL;
}
for ( i=0 ; i < iface->num_altsetting; i++ ) {
interface = iface->altsetting + i;
if ( interface->desc.bInterfaceClass != 255 ||
interface->desc.bInterfaceSubClass != 0 )
continue;
alts = interface->desc.bAlternateSetting;
}
if ( alts == -1 ) {
return -EINVAL;
}
printk(KERN_INFO "usb-midi: Found YAMAHA USB-MIDI device on dev %04x:%04x, iface %d\n",
le16_to_cpu(d->descriptor.idVendor),
le16_to_cpu(d->descriptor.idProduct), ifnum);
i = d->actconfig - d->config;
buffer = d->rawdescriptors[i];
bufSize = le16_to_cpu(d->actconfig->desc.wTotalLength);
u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 1);
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 ( le16_to_cpu(d->descriptor.idVendor) != u->idVendor ||
le16_to_cpu(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,
struct usb_interface *iface, unsigned int ifnum,
struct usb_midi_state *s)
{
struct usb_host_interface *interface;
struct usb_midi_device *u;
unsigned char *buffer;
int bufSize;
int i;
int alts=-1;
int ret;
for ( i=0 ; i < iface->num_altsetting; i++ ) {
interface = iface->altsetting + i;
if ( interface->desc.bInterfaceClass != USB_CLASS_AUDIO ||
interface->desc.bInterfaceSubClass != USB_SUBCLASS_MIDISTREAMING )
continue;
alts = interface->desc.bAlternateSetting;
}
if ( alts == -1 ) {
return -EINVAL;
}
printk(KERN_INFO "usb-midi: Found MIDISTREAMING on dev %04x:%04x, iface %d\n",
le16_to_cpu(d->descriptor.idVendor),
le16_to_cpu(d->descriptor.idProduct), ifnum);
/* 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.
*/
i = d->actconfig - d->config;
buffer = d->rawdescriptors[i];
bufSize = le16_to_cpu(d->actconfig->desc.wTotalLength);
u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 0);
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 ( le16_to_cpu(d->descriptor.idVendor) != uvendor ||
le16_to_cpu(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 = NULL; /* 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 int usb_midi_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_midi_state *s;
struct usb_device *dev = interface_to_usbdev(intf);
int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
s = (struct usb_midi_state *)kmalloc(sizeof(struct usb_midi_state), GFP_KERNEL);
if ( !s )
return -ENOMEM;
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, intf, ifnum, s ) &&
detect_vendor_specific_device( dev, ifnum, s ) &&
detect_yamaha_device( dev, intf, ifnum, s) ) {
kfree(s);
return -EIO;
}
down(&open_sem);
list_add_tail(&s->mididev, &mididevs);
up(&open_sem);
usb_set_intfdata (intf, s);
return 0;
}
static void usb_midi_disconnect(struct usb_interface *intf)
{
struct usb_midi_state *s = usb_get_intfdata (intf);
struct usb_mididev *m;
if ( !s )
return;
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;
usb_set_intfdata (intf, NULL);
list_for_each_entry(m, &s->midiDevList, 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);
}
/* we want to look at all devices by hand */
static struct usb_device_id id_table[] = {
{.driver_info = 42},
{}
};
static struct usb_driver usb_midi_driver = {
.owner = THIS_MODULE,
.name = "midi",
.probe = usb_midi_probe,
.disconnect = usb_midi_disconnect,
.id_table = id_table,
};
/* ------------------------------------------------------------------------- */
static int __init usb_midi_init(void)
{
return usb_register(&usb_midi_driver);
}
static 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 + -