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

📄 usbmidi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Creates an input endpoint. */static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi,					  struct snd_usb_midi_endpoint_info* ep_info,					  struct snd_usb_midi_endpoint* rep){	struct snd_usb_midi_in_endpoint* ep;	void* buffer;	unsigned int pipe;	int length;	rep->in = NULL;	ep = kzalloc(sizeof(*ep), GFP_KERNEL);	if (!ep)		return -ENOMEM;	ep->umidi = umidi;	ep->urb = usb_alloc_urb(0, GFP_KERNEL);	if (!ep->urb) {		snd_usbmidi_in_endpoint_delete(ep);		return -ENOMEM;	}	if (ep_info->in_interval)		pipe = usb_rcvintpipe(umidi->chip->dev, ep_info->in_ep);	else		pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->in_ep);	length = usb_maxpacket(umidi->chip->dev, pipe, 0);	buffer = usb_buffer_alloc(umidi->chip->dev, length, GFP_KERNEL,				  &ep->urb->transfer_dma);	if (!buffer) {		snd_usbmidi_in_endpoint_delete(ep);		return -ENOMEM;	}	if (ep_info->in_interval)		usb_fill_int_urb(ep->urb, umidi->chip->dev, pipe, buffer,				 length, snd_usbmidi_in_urb_complete, ep,				 ep_info->in_interval);	else		usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer,				  length, snd_usbmidi_in_urb_complete, ep);	ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;	rep->in = ep;	return 0;}static unsigned int snd_usbmidi_count_bits(unsigned int x){	unsigned int bits;	for (bits = 0; x; ++bits)		x &= x - 1;	return bits;}/* * Frees an output endpoint. * May be called when ep hasn't been initialized completely. */static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint* ep){	if (ep->urb) {		usb_buffer_free(ep->umidi->chip->dev, ep->max_transfer,				ep->urb->transfer_buffer,				ep->urb->transfer_dma);		usb_free_urb(ep->urb);	}	kfree(ep);}/* * Creates an output endpoint, and initializes output ports. */static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi,					   struct snd_usb_midi_endpoint_info* ep_info,			 		   struct snd_usb_midi_endpoint* rep){	struct snd_usb_midi_out_endpoint* ep;	int i;	unsigned int pipe;	void* buffer;	rep->out = NULL;	ep = kzalloc(sizeof(*ep), GFP_KERNEL);	if (!ep)		return -ENOMEM;	ep->umidi = umidi;	ep->urb = usb_alloc_urb(0, GFP_KERNEL);	if (!ep->urb) {		snd_usbmidi_out_endpoint_delete(ep);		return -ENOMEM;	}	if (ep_info->out_interval)		pipe = usb_sndintpipe(umidi->chip->dev, ep_info->out_ep);	else		pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep);	if (umidi->chip->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */		/* FIXME: we need more URBs to get reasonable bandwidth here: */		ep->max_transfer = 4;	else		ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1);	buffer = usb_buffer_alloc(umidi->chip->dev, ep->max_transfer,				  GFP_KERNEL, &ep->urb->transfer_dma);	if (!buffer) {		snd_usbmidi_out_endpoint_delete(ep);		return -ENOMEM;	}	if (ep_info->out_interval)		usb_fill_int_urb(ep->urb, umidi->chip->dev, pipe, buffer,				 ep->max_transfer, snd_usbmidi_out_urb_complete,				 ep, ep_info->out_interval);	else		usb_fill_bulk_urb(ep->urb, umidi->chip->dev,				  pipe, buffer, ep->max_transfer,				  snd_usbmidi_out_urb_complete, ep);	ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;	spin_lock_init(&ep->buffer_lock);	tasklet_init(&ep->tasklet, snd_usbmidi_out_tasklet, (unsigned long)ep);	for (i = 0; i < 0x10; ++i)		if (ep_info->out_cables & (1 << i)) {			ep->ports[i].ep = ep;			ep->ports[i].cable = i << 4;		}	if (umidi->usb_protocol_ops->init_out_endpoint)		umidi->usb_protocol_ops->init_out_endpoint(ep);	rep->out = ep;	return 0;}/* * Frees everything. */static void snd_usbmidi_free(struct snd_usb_midi* umidi){	int i;	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {		struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];		if (ep->out)			snd_usbmidi_out_endpoint_delete(ep->out);		if (ep->in)			snd_usbmidi_in_endpoint_delete(ep->in);	}	kfree(umidi);}/* * Unlinks all URBs (must be done before the usb_device is deleted). */void snd_usbmidi_disconnect(struct list_head* p){	struct snd_usb_midi* umidi;	int i;	umidi = list_entry(p, struct snd_usb_midi, list);	del_timer_sync(&umidi->error_timer);	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {		struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];		if (ep->out)			tasklet_kill(&ep->out->tasklet);		if (ep->out && ep->out->urb) {			usb_kill_urb(ep->out->urb);			if (umidi->usb_protocol_ops->finish_out_endpoint)				umidi->usb_protocol_ops->finish_out_endpoint(ep->out);		}		if (ep->in)			usb_kill_urb(ep->in->urb);	}}static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi){	struct snd_usb_midi* umidi = rmidi->private_data;	snd_usbmidi_free(umidi);}static struct snd_rawmidi_substream *snd_usbmidi_find_substream(struct snd_usb_midi* umidi,							   int stream, int number){	struct list_head* list;	list_for_each(list, &umidi->rmidi->streams[stream].substreams) {		struct snd_rawmidi_substream *substream = list_entry(list, struct snd_rawmidi_substream, list);		if (substream->number == number)			return substream;	}	return NULL;}/* * This list specifies names for ports that do not fit into the standard * "(product) MIDI (n)" schema because they aren't external MIDI ports, * such as internal control or synthesizer ports. */static struct port_info {	u32 id;	short int port;	short int voices;	const char *name;	unsigned int seq_flags;} snd_usbmidi_port_info[] = {#define PORT_INFO(vendor, product, num, name_, voices_, flags) \	{ .id = USB_ID(vendor, product), \	  .port = num, .voices = voices_, \	  .name = name_, .seq_flags = flags }#define EXTERNAL_PORT(vendor, product, num, name) \	PORT_INFO(vendor, product, num, name, 0, \		  SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \		  SNDRV_SEQ_PORT_TYPE_HARDWARE | \		  SNDRV_SEQ_PORT_TYPE_PORT)#define CONTROL_PORT(vendor, product, num, name) \	PORT_INFO(vendor, product, num, name, 0, \		  SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \		  SNDRV_SEQ_PORT_TYPE_HARDWARE)#define ROLAND_SYNTH_PORT(vendor, product, num, name, voices) \	PORT_INFO(vendor, product, num, name, voices, \		  SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \		  SNDRV_SEQ_PORT_TYPE_MIDI_GM | \		  SNDRV_SEQ_PORT_TYPE_MIDI_GM2 | \		  SNDRV_SEQ_PORT_TYPE_MIDI_GS | \		  SNDRV_SEQ_PORT_TYPE_MIDI_XG | \		  SNDRV_SEQ_PORT_TYPE_HARDWARE | \		  SNDRV_SEQ_PORT_TYPE_SYNTHESIZER)#define SOUNDCANVAS_PORT(vendor, product, num, name, voices) \	PORT_INFO(vendor, product, num, name, voices, \		  SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \		  SNDRV_SEQ_PORT_TYPE_MIDI_GM | \		  SNDRV_SEQ_PORT_TYPE_MIDI_GM2 | \		  SNDRV_SEQ_PORT_TYPE_MIDI_GS | \		  SNDRV_SEQ_PORT_TYPE_MIDI_XG | \		  SNDRV_SEQ_PORT_TYPE_MIDI_MT32 | \		  SNDRV_SEQ_PORT_TYPE_HARDWARE | \		  SNDRV_SEQ_PORT_TYPE_SYNTHESIZER)	/* Roland UA-100 */	CONTROL_PORT(0x0582, 0x0000, 2, "%s Control"),	/* Roland SC-8850 */	SOUNDCANVAS_PORT(0x0582, 0x0003, 0, "%s Part A", 128),	SOUNDCANVAS_PORT(0x0582, 0x0003, 1, "%s Part B", 128),	SOUNDCANVAS_PORT(0x0582, 0x0003, 2, "%s Part C", 128),	SOUNDCANVAS_PORT(0x0582, 0x0003, 3, "%s Part D", 128),	EXTERNAL_PORT(0x0582, 0x0003, 4, "%s MIDI 1"),	EXTERNAL_PORT(0x0582, 0x0003, 5, "%s MIDI 2"),	/* Roland U-8 */	EXTERNAL_PORT(0x0582, 0x0004, 0, "%s MIDI"),	CONTROL_PORT(0x0582, 0x0004, 1, "%s Control"),	/* Roland SC-8820 */	SOUNDCANVAS_PORT(0x0582, 0x0007, 0, "%s Part A", 64),	SOUNDCANVAS_PORT(0x0582, 0x0007, 1, "%s Part B", 64),	EXTERNAL_PORT(0x0582, 0x0007, 2, "%s MIDI"),	/* Roland SK-500 */	SOUNDCANVAS_PORT(0x0582, 0x000b, 0, "%s Part A", 64),	SOUNDCANVAS_PORT(0x0582, 0x000b, 1, "%s Part B", 64),	EXTERNAL_PORT(0x0582, 0x000b, 2, "%s MIDI"),	/* Roland SC-D70 */	SOUNDCANVAS_PORT(0x0582, 0x000c, 0, "%s Part A", 64),	SOUNDCANVAS_PORT(0x0582, 0x000c, 1, "%s Part B", 64),	EXTERNAL_PORT(0x0582, 0x000c, 2, "%s MIDI"),	/* Edirol UM-880 */	CONTROL_PORT(0x0582, 0x0014, 8, "%s Control"),	/* Edirol SD-90 */	ROLAND_SYNTH_PORT(0x0582, 0x0016, 0, "%s Part A", 128),	ROLAND_SYNTH_PORT(0x0582, 0x0016, 1, "%s Part B", 128),	EXTERNAL_PORT(0x0582, 0x0016, 2, "%s MIDI 1"),	EXTERNAL_PORT(0x0582, 0x0016, 3, "%s MIDI 2"),	/* Edirol UM-550 */	CONTROL_PORT(0x0582, 0x0023, 5, "%s Control"),	/* Edirol SD-20 */	ROLAND_SYNTH_PORT(0x0582, 0x0027, 0, "%s Part A", 64),	ROLAND_SYNTH_PORT(0x0582, 0x0027, 1, "%s Part B", 64),	EXTERNAL_PORT(0x0582, 0x0027, 2, "%s MIDI"),	/* Edirol SD-80 */	ROLAND_SYNTH_PORT(0x0582, 0x0029, 0, "%s Part A", 128),	ROLAND_SYNTH_PORT(0x0582, 0x0029, 1, "%s Part B", 128),	EXTERNAL_PORT(0x0582, 0x0029, 2, "%s MIDI 1"),	EXTERNAL_PORT(0x0582, 0x0029, 3, "%s MIDI 2"),	/* Edirol UA-700 */	EXTERNAL_PORT(0x0582, 0x002b, 0, "%s MIDI"),	CONTROL_PORT(0x0582, 0x002b, 1, "%s Control"),	/* Roland VariOS */	EXTERNAL_PORT(0x0582, 0x002f, 0, "%s MIDI"),	EXTERNAL_PORT(0x0582, 0x002f, 1, "%s External MIDI"),	EXTERNAL_PORT(0x0582, 0x002f, 2, "%s Sync"),	/* Edirol PCR */	EXTERNAL_PORT(0x0582, 0x0033, 0, "%s MIDI"),	EXTERNAL_PORT(0x0582, 0x0033, 1, "%s 1"),	EXTERNAL_PORT(0x0582, 0x0033, 2, "%s 2"),	/* BOSS GS-10 */	EXTERNAL_PORT(0x0582, 0x003b, 0, "%s MIDI"),	CONTROL_PORT(0x0582, 0x003b, 1, "%s Control"),	/* Edirol UA-1000 */	EXTERNAL_PORT(0x0582, 0x0044, 0, "%s MIDI"),	CONTROL_PORT(0x0582, 0x0044, 1, "%s Control"),	/* Edirol UR-80 */	EXTERNAL_PORT(0x0582, 0x0048, 0, "%s MIDI"),	EXTERNAL_PORT(0x0582, 0x0048, 1, "%s 1"),	EXTERNAL_PORT(0x0582, 0x0048, 2, "%s 2"),	/* Edirol PCR-A */	EXTERNAL_PORT(0x0582, 0x004d, 0, "%s MIDI"),	EXTERNAL_PORT(0x0582, 0x004d, 1, "%s 1"),	EXTERNAL_PORT(0x0582, 0x004d, 2, "%s 2"),	/* Edirol UM-3EX */	CONTROL_PORT(0x0582, 0x009a, 3, "%s Control"),	/* M-Audio MidiSport 8x8 */	CONTROL_PORT(0x0763, 0x1031, 8, "%s Control"),	CONTROL_PORT(0x0763, 0x1033, 8, "%s Control"),	/* MOTU Fastlane */	EXTERNAL_PORT(0x07fd, 0x0001, 0, "%s MIDI A"),	EXTERNAL_PORT(0x07fd, 0x0001, 1, "%s MIDI B"),	/* Emagic Unitor8/AMT8/MT4 */	EXTERNAL_PORT(0x086a, 0x0001, 8, "%s Broadcast"),	EXTERNAL_PORT(0x086a, 0x0002, 8, "%s Broadcast"),	EXTERNAL_PORT(0x086a, 0x0003, 4, "%s Broadcast"),};static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number){	int i;	for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_info); ++i) {		if (snd_usbmidi_port_info[i].id == umidi->chip->usb_id &&		    snd_usbmidi_port_info[i].port == number)			return &snd_usbmidi_port_info[i];	}	return NULL;}static void snd_usbmidi_get_port_info(struct snd_rawmidi *rmidi, int number,				      struct snd_seq_port_info *seq_port_info){	struct snd_usb_midi *umidi = rmidi->private_data;	struct port_info *port_info;	/* TODO: read port flags from descriptors */	port_info = find_port_info(umidi, number);	if (port_info) {		seq_port_info->type = port_info->seq_flags;		seq_port_info->midi_voices = port_info->voices;	}}static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi,				       int stream, int number,				       struct snd_rawmidi_substream ** rsubstream){	struct port_info *port_info;	const char *name_format;	struct snd_rawmidi_substream *substream = snd_usbmidi_find_substream(umidi, stream, number);	if (!substream) {		snd_printd(KERN_ERR "substream %d:%d not found\n", stream, number);		return;	}	/* TODO: read port name from jack descriptor */	port_info = find_port_info(umidi, number);	name_format = port_info ? port_info->name : "%s MIDI %d";	snprintf(substream->name, sizeof(substream->name),		 name_format, umidi->chip->card->shortname, number + 1);	*rsubstream = substream;}/* * Creates the endpoints and their ports. */static int snd_usbmidi_create_endpoints(struct snd_usb_midi* umidi,					struct snd_usb_midi_endpoint_info* endpoints){	int i, j, err;	int out_ports = 0, in_ports = 0;	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {		if (endpoints[i].out_cables) {			err = snd_usbmidi_out_endpoint_create(umidi, &endpoints[i],							      &umidi->endpoints[i]);			if (err < 0)				return err;		}		if (endpoints[i].in_cables) {			err = snd_usbmidi_in_endpoint_create(umidi, &endpoints[i],							     &umidi->endpoints[i]);			if (err < 0)				return err;		}		for (j = 0; j < 0x10; ++j) {			if (endpoints[i].out_cables & (1 << j)) {				snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_OUTPUT, out_ports,							   &umidi->endpoints[i].out->ports[j].substream);				++out_ports;			}			if (endpoints[i].in_cables & (1 << j)) {				snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_INPUT, in_ports,							   &umidi->endpoints[i].in->ports[j].substream);				++in_ports;			}		}	}	snd_printdd(KERN_INFO "created %d output and %d input ports\n",		    out_ports, in_ports);	return 0;}/* * Returns MIDIStreaming device capabilities. */static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,			   	   struct snd_usb_midi_endpoint_info* endpoints){	struct usb_interface* intf;	struct usb_host_interface *hostif;	struct usb_interface_descriptor* intfd;	struct usb_ms_header_descriptor* ms_header;	struct usb_host_endpoint *hostep;	struct usb_endpoint_descriptor* ep;	struct usb_ms_endpoint_descriptor* ms_ep;	int i, epidx;	intf = umidi->iface;	if (!intf)		return -ENXIO;	hostif = &intf->altsetting[0];	intfd = get_iface_desc(hostif);	ms_header = (struct usb_ms_header_descriptor*)hostif->extra;	if (hostif->extralen >= 7 &&	    ms_header->bLength >= 7 &&	    ms_header->bDescriptorType == USB_DT_CS_INTERFACE &&	    ms_header->bDescriptorSubtype == HEADER)		snd_printdd(KERN_INFO "MIDIStreaming version %02x.%02x\n",			    ms_header->bcdMSC[1], ms_header->bcdMSC[0]);	else		snd_printk(KERN_WARNING "MIDIStreaming interface descriptor not found\n");	epidx = 0;	for (i = 0; i < intfd->bNumEndpoints; ++i) {		hostep = &hostif->endpoint[i];		ep = get_ep_desc(hostep);		if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK &&

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -