diff options
Diffstat (limited to 'sound/usb/midi.c')
| -rw-r--r-- | sound/usb/midi.c | 251 | 
1 files changed, 192 insertions, 59 deletions
diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 25bce7e5b1a..9da74d2e8ee 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -47,6 +47,7 @@  #include <linux/usb.h>  #include <linux/wait.h>  #include <linux/usb/audio.h> +#include <linux/module.h>  #include <sound/core.h>  #include <sound/control.h> @@ -54,6 +55,7 @@  #include <sound/asequencer.h>  #include "usbaudio.h"  #include "midi.h" +#include "power.h"  #include "helper.h"  /* @@ -114,6 +116,7 @@ struct snd_usb_midi {  	struct list_head list;  	struct timer_list error_timer;  	spinlock_t disc_lock; +	struct rw_semaphore disc_rwsem;  	struct mutex mutex;  	u32 usb_id;  	int next_midi_device; @@ -123,8 +126,9 @@ struct snd_usb_midi {  		struct snd_usb_midi_in_endpoint *in;  	} endpoints[MIDI_MAX_ENDPOINTS];  	unsigned long input_triggered; -	unsigned int opened; +	unsigned int opened[2];  	unsigned char disconnected; +	unsigned char input_running;  	struct snd_kcontrol *roland_load_ctl;  }; @@ -187,16 +191,16 @@ static int snd_usbmidi_submit_urb(struct urb* urb, gfp_t flags)  {  	int err = usb_submit_urb(urb, flags);  	if (err < 0 && err != -ENODEV) -		snd_printk(KERN_ERR "usb_submit_urb: %d\n", err); +		dev_err(&urb->dev->dev, "usb_submit_urb: %d\n", err);  	return err;  }  /*   * Error handling for URB completion functions.   */ -static int snd_usbmidi_urb_error(int status) +static int snd_usbmidi_urb_error(const struct urb *urb)  { -	switch (status) { +	switch (urb->status) {  	/* manually unlinked, or device gone */  	case -ENOENT:  	case -ECONNRESET: @@ -209,7 +213,7 @@ static int snd_usbmidi_urb_error(int status)  	case -EILSEQ:  		return -EIO;  	default: -		snd_printk(KERN_ERR "urb status %d\n", status); +		dev_err(&urb->dev->dev, "urb status %d\n", urb->status);  		return 0; /* continue */  	}  } @@ -223,7 +227,7 @@ static void snd_usbmidi_input_data(struct snd_usb_midi_in_endpoint* ep, int port  	struct usbmidi_in_port* port = &ep->ports[portidx];  	if (!port->substream) { -		snd_printd("unexpected port %d!\n", portidx); +		dev_dbg(&ep->umidi->dev->dev, "unexpected port %d!\n", portidx);  		return;  	}  	if (!test_bit(port->substream->number, &ep->umidi->input_triggered)) @@ -255,7 +259,7 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb)  		ep->umidi->usb_protocol_ops->input(ep, urb->transfer_buffer,  						   urb->actual_length);  	} else { -		int err = snd_usbmidi_urb_error(urb->status); +		int err = snd_usbmidi_urb_error(urb);  		if (err < 0) {  			if (err != -ENODEV) {  				ep->error_resubmit = 1; @@ -285,7 +289,7 @@ static void snd_usbmidi_out_urb_complete(struct urb* urb)  	}  	spin_unlock(&ep->buffer_lock);  	if (urb->status < 0) { -		int err = snd_usbmidi_urb_error(urb->status); +		int err = snd_usbmidi_urb_error(urb);  		if (err < 0) {  			if (err != -ENODEV)  				mod_timer(&ep->umidi->error_timer, @@ -815,6 +819,22 @@ static struct usb_protocol_ops snd_usbmidi_raw_ops = {  	.output = snd_usbmidi_raw_output,  }; +/* + * FTDI protocol: raw MIDI bytes, but input packets have two modem status bytes. + */ + +static void snd_usbmidi_ftdi_input(struct snd_usb_midi_in_endpoint* ep, +				   uint8_t* buffer, int buffer_length) +{ +	if (buffer_length > 2) +		snd_usbmidi_input_data(ep, 0, buffer + 2, buffer_length - 2); +} + +static struct usb_protocol_ops snd_usbmidi_ftdi_ops = { +	.input = snd_usbmidi_ftdi_input, +	.output = snd_usbmidi_raw_output, +}; +  static void snd_usbmidi_us122l_input(struct snd_usb_midi_in_endpoint *ep,  				     uint8_t *buffer, int buffer_length)  { @@ -850,8 +870,8 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep,  		return;  	} -	memset(urb->transfer_buffer + count, 0xFD, 9 - count); -	urb->transfer_buffer_length = count; +	memset(urb->transfer_buffer + count, 0xFD, ep->max_transfer - count); +	urb->transfer_buffer_length = ep->max_transfer;  }  static struct usb_protocol_ops snd_usbmidi_122l_ops = { @@ -1014,29 +1034,48 @@ static void update_roland_altsetting(struct snd_usb_midi* umidi)  	snd_usbmidi_input_start(&umidi->list);  } -static void substream_open(struct snd_rawmidi_substream *substream, int open) +static int substream_open(struct snd_rawmidi_substream *substream, int dir, +			  int open)  {  	struct snd_usb_midi* umidi = substream->rmidi->private_data;  	struct snd_kcontrol *ctl; +	down_read(&umidi->disc_rwsem); +	if (umidi->disconnected) { +		up_read(&umidi->disc_rwsem); +		return open ? -ENODEV : 0; +	} +  	mutex_lock(&umidi->mutex);  	if (open) { -		if (umidi->opened++ == 0 && umidi->roland_load_ctl) { -			ctl = umidi->roland_load_ctl; -			ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; -			snd_ctl_notify(umidi->card, +		if (!umidi->opened[0] && !umidi->opened[1]) { +			if (umidi->roland_load_ctl) { +				ctl = umidi->roland_load_ctl; +				ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; +				snd_ctl_notify(umidi->card,  				       SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); -			update_roland_altsetting(umidi); +				update_roland_altsetting(umidi); +			}  		} +		umidi->opened[dir]++; +		if (umidi->opened[1]) +			snd_usbmidi_input_start(&umidi->list);  	} else { -		if (--umidi->opened == 0 && umidi->roland_load_ctl) { -			ctl = umidi->roland_load_ctl; -			ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; -			snd_ctl_notify(umidi->card, +		umidi->opened[dir]--; +		if (!umidi->opened[1]) +			snd_usbmidi_input_stop(&umidi->list); +		if (!umidi->opened[0] && !umidi->opened[1]) { +			if (umidi->roland_load_ctl) { +				ctl = umidi->roland_load_ctl; +				ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; +				snd_ctl_notify(umidi->card,  				       SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); +			}  		}  	}  	mutex_unlock(&umidi->mutex); +	up_read(&umidi->disc_rwsem); +	return 0;  }  static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) @@ -1056,16 +1095,15 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)  		snd_BUG();  		return -ENXIO;  	} +  	substream->runtime->private_data = port;  	port->state = STATE_UNKNOWN; -	substream_open(substream, 1); -	return 0; +	return substream_open(substream, 0, 1);  }  static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)  { -	substream_open(substream, 0); -	return 0; +	return substream_open(substream, 0, 0);  }  static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, int up) @@ -1118,14 +1156,12 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream)  static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream)  { -	substream_open(substream, 1); -	return 0; +	return substream_open(substream, 1, 1);  }  static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream)  { -	substream_open(substream, 0); -	return 0; +	return substream_open(substream, 1, 0);  }  static void snd_usbmidi_input_trigger(struct snd_rawmidi_substream *substream, int up) @@ -1293,8 +1329,16 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi,  	case USB_ID(0x15ca, 0x0101): /* Textech USB Midi Cable */  	case USB_ID(0x15ca, 0x1806): /* Textech USB Midi Cable */  	case USB_ID(0x1a86, 0x752d): /* QinHeng CH345 "USB2.0-MIDI" */ +	case USB_ID(0xfc08, 0x0101): /* Unknown vendor Cable */  		ep->max_transfer = 4;  		break; +		/* +		 * Some devices only work with 9 bytes packet size: +		 */ +	case USB_ID(0x0644, 0x800E): /* Tascam US-122L */ +	case USB_ID(0x0644, 0x800F): /* Tascam US-144 */ +		ep->max_transfer = 9; +		break;  	}  	for (i = 0; i < OUTPUT_URBS; ++i) {  		buffer = usb_alloc_coherent(umidi->dev, @@ -1366,9 +1410,12 @@ void snd_usbmidi_disconnect(struct list_head* p)  	 * a timer may submit an URB. To reliably break the cycle  	 * a flag under lock must be used  	 */ +	down_write(&umidi->disc_rwsem);  	spin_lock_irq(&umidi->disc_lock);  	umidi->disconnected = 1;  	spin_unlock_irq(&umidi->disc_lock); +	up_write(&umidi->disc_rwsem); +  	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {  		struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];  		if (ep->out) @@ -1397,6 +1444,7 @@ void snd_usbmidi_disconnect(struct list_head* p)  	}  	del_timer_sync(&umidi->error_timer);  } +EXPORT_SYMBOL(snd_usbmidi_disconnect);  static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi)  { @@ -1407,10 +1455,9 @@ static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi)  static struct snd_rawmidi_substream *snd_usbmidi_find_substream(struct snd_usb_midi* umidi,  								int stream, int number)  { -	struct list_head* list; +	struct snd_rawmidi_substream *substream; -	list_for_each(list, &umidi->rmidi->streams[stream].substreams) { -		struct snd_rawmidi_substream *substream = list_entry(list, struct snd_rawmidi_substream, list); +	list_for_each_entry(substream, &umidi->rmidi->streams[stream].substreams, list) {  		if (substream->number == number)  			return substream;  	} @@ -1528,8 +1575,41 @@ static struct port_info {  	EXTERNAL_PORT(0x0582, 0x004d, 0, "%s MIDI"),  	EXTERNAL_PORT(0x0582, 0x004d, 1, "%s 1"),  	EXTERNAL_PORT(0x0582, 0x004d, 2, "%s 2"), +	/* BOSS GT-PRO */ +	CONTROL_PORT(0x0582, 0x0089, 0, "%s Control"),  	/* Edirol UM-3EX */  	CONTROL_PORT(0x0582, 0x009a, 3, "%s Control"), +	/* Roland VG-99 */ +	CONTROL_PORT(0x0582, 0x00b2, 0, "%s Control"), +	EXTERNAL_PORT(0x0582, 0x00b2, 1, "%s MIDI"), +	/* Cakewalk Sonar V-Studio 100 */ +	EXTERNAL_PORT(0x0582, 0x00eb, 0, "%s MIDI"), +	CONTROL_PORT(0x0582, 0x00eb, 1, "%s Control"), +	/* Roland VB-99 */ +	CONTROL_PORT(0x0582, 0x0102, 0, "%s Control"), +	EXTERNAL_PORT(0x0582, 0x0102, 1, "%s MIDI"), +	/* Roland A-PRO */ +	EXTERNAL_PORT(0x0582, 0x010f, 0, "%s MIDI"), +	CONTROL_PORT(0x0582, 0x010f, 1, "%s 1"), +	CONTROL_PORT(0x0582, 0x010f, 2, "%s 2"), +	/* Roland SD-50 */ +	ROLAND_SYNTH_PORT(0x0582, 0x0114, 0, "%s Synth", 128), +	EXTERNAL_PORT(0x0582, 0x0114, 1, "%s MIDI"), +	CONTROL_PORT(0x0582, 0x0114, 2, "%s Control"), +	/* Roland OCTA-CAPTURE */ +	EXTERNAL_PORT(0x0582, 0x0120, 0, "%s MIDI"), +	CONTROL_PORT(0x0582, 0x0120, 1, "%s Control"), +	EXTERNAL_PORT(0x0582, 0x0121, 0, "%s MIDI"), +	CONTROL_PORT(0x0582, 0x0121, 1, "%s Control"), +	/* Roland SPD-SX */ +	CONTROL_PORT(0x0582, 0x0145, 0, "%s Control"), +	EXTERNAL_PORT(0x0582, 0x0145, 1, "%s MIDI"), +	/* Roland A-Series */ +	CONTROL_PORT(0x0582, 0x0156, 0, "%s Keyboard"), +	EXTERNAL_PORT(0x0582, 0x0156, 1, "%s MIDI"), +	/* Roland INTEGRA-7 */ +	ROLAND_SYNTH_PORT(0x0582, 0x015b, 0, "%s Synth", 128), +	CONTROL_PORT(0x0582, 0x015b, 1, "%s Control"),  	/* M-Audio MidiSport 8x8 */  	CONTROL_PORT(0x0763, 0x1031, 8, "%s Control"),  	CONTROL_PORT(0x0763, 0x1033, 8, "%s Control"), @@ -1588,7 +1668,7 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi,  	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); +		dev_err(&umidi->dev->dev, "substream %d:%d not found\n", stream, number);  		return;  	} @@ -1637,7 +1717,7 @@ static int snd_usbmidi_create_endpoints(struct snd_usb_midi* umidi,  			}  		}  	} -	snd_printdd(KERN_INFO "created %d output and %d input ports\n", +	dev_dbg(&umidi->dev->dev, "created %d output and %d input ports\n",  		    out_ports, in_ports);  	return 0;  } @@ -1667,10 +1747,11 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,  	    ms_header->bLength >= 7 &&  	    ms_header->bDescriptorType == USB_DT_CS_INTERFACE &&  	    ms_header->bDescriptorSubtype == UAC_HEADER) -		snd_printdd(KERN_INFO "MIDIStreaming version %02x.%02x\n", +		dev_dbg(&umidi->dev->dev, "MIDIStreaming version %02x.%02x\n",  			    ms_header->bcdMSC[1], ms_header->bcdMSC[0]);  	else -		snd_printk(KERN_WARNING "MIDIStreaming interface descriptor not found\n"); +		dev_warn(&umidi->dev->dev, +			 "MIDIStreaming interface descriptor not found\n");  	epidx = 0;  	for (i = 0; i < intfd->bNumEndpoints; ++i) { @@ -1687,7 +1768,8 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,  		if (usb_endpoint_dir_out(ep)) {  			if (endpoints[epidx].out_ep) {  				if (++epidx >= MIDI_MAX_ENDPOINTS) { -					snd_printk(KERN_WARNING "too many endpoints\n"); +					dev_warn(&umidi->dev->dev, +						 "too many endpoints\n");  					break;  				}  			} @@ -1702,12 +1784,13 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,  				 */  				endpoints[epidx].out_interval = 1;  			endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; -			snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n", +			dev_dbg(&umidi->dev->dev, "EP %02X: %d jack(s)\n",  				    ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);  		} else {  			if (endpoints[epidx].in_ep) {  				if (++epidx >= MIDI_MAX_ENDPOINTS) { -					snd_printk(KERN_WARNING "too many endpoints\n"); +					dev_warn(&umidi->dev->dev, +						 "too many endpoints\n");  					break;  				}  			} @@ -1717,7 +1800,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,  			else if (snd_usb_get_speed(umidi->dev) == USB_SPEED_LOW)  				endpoints[epidx].in_interval = 1;  			endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; -			snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n", +			dev_dbg(&umidi->dev->dev, "EP %02X: %d jack(s)\n",  				    ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);  		}  	} @@ -1729,13 +1812,7 @@ static int roland_load_info(struct snd_kcontrol *kcontrol,  {  	static const char *const names[] = { "High Load", "Light Load" }; -	info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; -	info->count = 1; -	info->value.enumerated.items = 2; -	if (info->value.enumerated.item > 1) -		info->value.enumerated.item = 1; -	strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); -	return 0; +	return snd_ctl_enum_info(info, 1, 2, names);  }  static int roland_load_get(struct snd_kcontrol *kcontrol, @@ -1791,7 +1868,7 @@ static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi* umidi)  	    (get_endpoint(hostif, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)  		return; -	snd_printdd(KERN_INFO "switching to altsetting %d with int ep\n", +	dev_dbg(&umidi->dev->dev, "switching to altsetting %d with int ep\n",  		    intfd->bAlternateSetting);  	usb_set_interface(umidi->dev, intfd->bInterfaceNumber,  			  intfd->bAlternateSetting); @@ -1907,6 +1984,44 @@ static int snd_usbmidi_detect_yamaha(struct snd_usb_midi* umidi,  }  /* + * Detects the endpoints and ports of Roland devices. + */ +static int snd_usbmidi_detect_roland(struct snd_usb_midi* umidi, +				     struct snd_usb_midi_endpoint_info* endpoint) +{ +	struct usb_interface* intf; +	struct usb_host_interface *hostif; +	u8* cs_desc; + +	intf = umidi->iface; +	if (!intf) +		return -ENOENT; +	hostif = intf->altsetting; +	/* +	 * Some devices have a descriptor <06 24 F1 02 <inputs> <outputs>>, +	 * some have standard class descriptors, or both kinds, or neither. +	 */ +	for (cs_desc = hostif->extra; +	     cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2; +	     cs_desc += cs_desc[0]) { +		if (cs_desc[0] >= 6 && +		    cs_desc[1] == USB_DT_CS_INTERFACE && +		    cs_desc[2] == 0xf1 && +		    cs_desc[3] == 0x02) { +			endpoint->in_cables  = (1 << cs_desc[4]) - 1; +			endpoint->out_cables = (1 << cs_desc[5]) - 1; +			return snd_usbmidi_detect_endpoints(umidi, endpoint, 1); +		} else if (cs_desc[0] >= 7 && +			   cs_desc[1] == USB_DT_CS_INTERFACE && +			   cs_desc[2] == UAC_HEADER) { +			return snd_usbmidi_get_ms_info(umidi, endpoint); +		} +	} + +	return -ENODEV; +} + +/*   * Creates the endpoints and their ports for Midiman devices.   */  static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi, @@ -1935,25 +2050,25 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi,  	 * input bulk endpoints (at indices 1 and 3) which aren't used.  	 */  	if (intfd->bNumEndpoints < (endpoint->out_cables > 0x0001 ? 5 : 3)) { -		snd_printdd(KERN_ERR "not enough endpoints\n"); +		dev_dbg(&umidi->dev->dev, "not enough endpoints\n");  		return -ENOENT;  	}  	epd = get_endpoint(hostif, 0);  	if (!usb_endpoint_dir_in(epd) || !usb_endpoint_xfer_int(epd)) { -		snd_printdd(KERN_ERR "endpoint[0] isn't interrupt\n"); +		dev_dbg(&umidi->dev->dev, "endpoint[0] isn't interrupt\n");  		return -ENXIO;  	}  	epd = get_endpoint(hostif, 2);  	if (!usb_endpoint_dir_out(epd) || !usb_endpoint_xfer_bulk(epd)) { -		snd_printdd(KERN_ERR "endpoint[2] isn't bulk output\n"); +		dev_dbg(&umidi->dev->dev, "endpoint[2] isn't bulk output\n");  		return -ENXIO;  	}  	if (endpoint->out_cables > 0x0001) {  		epd = get_endpoint(hostif, 4);  		if (!usb_endpoint_dir_out(epd) ||  		    !usb_endpoint_xfer_bulk(epd)) { -			snd_printdd(KERN_ERR "endpoint[4] isn't bulk output\n"); +			dev_dbg(&umidi->dev->dev, "endpoint[4] isn't bulk output\n");  			return -ENXIO;  		}  	} @@ -2029,13 +2144,17 @@ void snd_usbmidi_input_stop(struct list_head* p)  	unsigned int i, j;  	umidi = list_entry(p, struct snd_usb_midi, list); +	if (!umidi->input_running) +		return;  	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {  		struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];  		if (ep->in)  			for (j = 0; j < INPUT_URBS; ++j)  				usb_kill_urb(ep->in->urbs[j]);  	} +	umidi->input_running = 0;  } +EXPORT_SYMBOL(snd_usbmidi_input_stop);  static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep)  { @@ -2059,9 +2178,13 @@ void snd_usbmidi_input_start(struct list_head* p)  	int i;  	umidi = list_entry(p, struct snd_usb_midi, list); +	if (umidi->input_running || !umidi->opened[1]) +		return;  	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)  		snd_usbmidi_input_start_ep(umidi->endpoints[i].in); +	umidi->input_running = 1;  } +EXPORT_SYMBOL(snd_usbmidi_input_start);  /*   * Creates and registers everything needed for a MIDI streaming interface. @@ -2086,6 +2209,7 @@ int snd_usbmidi_create(struct snd_card *card,  	umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;  	init_timer(&umidi->error_timer);  	spin_lock_init(&umidi->disc_lock); +	init_rwsem(&umidi->disc_rwsem);  	mutex_init(&umidi->mutex);  	umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor),  			       le16_to_cpu(umidi->dev->descriptor.idProduct)); @@ -2112,6 +2236,9 @@ int snd_usbmidi_create(struct snd_card *card,  	case QUIRK_MIDI_YAMAHA:  		err = snd_usbmidi_detect_yamaha(umidi, &endpoints[0]);  		break; +	case QUIRK_MIDI_ROLAND: +		err = snd_usbmidi_detect_roland(umidi, &endpoints[0]); +		break;  	case QUIRK_MIDI_MIDIMAN:  		umidi->usb_protocol_ops = &snd_usbmidi_midiman_ops;  		memcpy(&endpoints[0], quirk->data, @@ -2153,8 +2280,19 @@ int snd_usbmidi_create(struct snd_card *card,  		/* endpoint 1 is input-only */  		endpoints[1].out_cables = 0;  		break; +	case QUIRK_MIDI_FTDI: +		umidi->usb_protocol_ops = &snd_usbmidi_ftdi_ops; + +		/* set baud rate to 31250 (48 MHz / 16 / 96) */ +		err = usb_control_msg(umidi->dev, usb_sndctrlpipe(umidi->dev, 0), +				      3, 0x40, 0x60, 0, NULL, 0, 1000); +		if (err < 0) +			break; + +		err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); +		break;  	default: -		snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type); +		dev_err(&umidi->dev->dev, "invalid quirk type %d\n", quirk->type);  		err = -ENXIO;  		break;  	} @@ -2186,14 +2324,9 @@ int snd_usbmidi_create(struct snd_card *card,  		return err;  	} -	list_add_tail(&umidi->list, midi_list); +	usb_autopm_get_interface_no_resume(umidi->iface); -	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) -		snd_usbmidi_input_start_ep(umidi->endpoints[i].in); +	list_add_tail(&umidi->list, midi_list);  	return 0;  } -  EXPORT_SYMBOL(snd_usbmidi_create); -EXPORT_SYMBOL(snd_usbmidi_input_stop); -EXPORT_SYMBOL(snd_usbmidi_input_start); -EXPORT_SYMBOL(snd_usbmidi_disconnect);  | 
