⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usb-midi.c

📁 USB_MIDI_DRIVER(for linux)
💻 C
📖 第 1 页 / 共 4 页
字号:
		/* 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 + -