diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2006-01-11 13:32:52 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-01-11 13:32:52 -0800 |
commit | 4677f245b5fbfd83b8a025f0d8f4558b4c83ab91 (patch) | |
tree | e8a20161296d5ddac4881fe13b5b9d0aaeacbc06 /usb | |
parent | c4a28a4f7fe1269989bb7e46f14231ef67316bb3 (diff) | |
download | patches-4677f245b5fbfd83b8a025f0d8f4558b4c83ab91.tar.gz |
new patches
Diffstat (limited to 'usb')
-rw-r--r-- | usb/usb-remove-the-obsolete-usb_midi-driver.patch | 2395 |
1 files changed, 2395 insertions, 0 deletions
diff --git a/usb/usb-remove-the-obsolete-usb_midi-driver.patch b/usb/usb-remove-the-obsolete-usb_midi-driver.patch new file mode 100644 index 0000000000000..bcd01431c99d1 --- /dev/null +++ b/usb/usb-remove-the-obsolete-usb_midi-driver.patch @@ -0,0 +1,2395 @@ +From bunk@stusta.de Wed Jan 11 13:13:22 2006 +Date: Fri, 6 Jan 2006 03:25:57 +0100 +From: Adrian Bunk <bunk@stusta.de> +To: Greg KH <gregkh@suse.de> +Subject: USB: remove the obsolete USB_MIDI driver +Message-ID: <20060106022557.GV12313@stusta.de> +Content-Disposition: inline + + +This patch removes the obsolete USB_MIDI driver. + + +Signed-off-by: Adrian Bunk <bunk@stusta.de> + +--- + drivers/usb/Makefile | 1 + drivers/usb/class/Kconfig | 23 + drivers/usb/class/Makefile | 1 + drivers/usb/class/usb-midi.c | 2153 ------------------------------------------- + drivers/usb/class/usb-midi.h | 164 --- + 5 files changed, 2342 deletions(-) + +--- gregkh-2.6.orig/drivers/usb/class/Kconfig ++++ gregkh-2.6/drivers/usb/class/Kconfig +@@ -28,29 +28,6 @@ config USB_AUDIO + To compile this driver as a module, choose M here: the + module will be called audio. + +-config USB_MIDI +- tristate "USB MIDI support" +- depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER +- ---help--- +- Say Y here if you want to connect a USB MIDI device to your +- computer's USB port. You only need this if you use the OSS +- sound system; USB MIDI devices are supported by ALSA's USB +- audio driver. This driver is for devices that comply with +- 'Universal Serial Bus Device Class Definition for MIDI Device'. +- +- The following devices are known to work: +- * Steinberg USB2MIDI +- * Roland MPU64 +- * Roland PC-300 +- * Roland SC8850 +- * Roland UM-1 +- * Roland UM-2 +- * Roland UA-100 +- * Yamaha MU1000 +- +- To compile this driver as a module, choose M here: the +- module will be called usb-midi. +- + config USB_ACM + tristate "USB Modem (CDC ACM) support" + depends on USB +--- gregkh-2.6.orig/drivers/usb/Makefile ++++ gregkh-2.6/drivers/usb/Makefile +@@ -18,7 +18,6 @@ obj-$(CONFIG_ETRAX_USB_HOST) += host/ + + obj-$(CONFIG_USB_ACM) += class/ + obj-$(CONFIG_USB_AUDIO) += class/ +-obj-$(CONFIG_USB_MIDI) += class/ + obj-$(CONFIG_USB_PRINTER) += class/ + + obj-$(CONFIG_USB_STORAGE) += storage/ +--- gregkh-2.6.orig/drivers/usb/class/Makefile ++++ gregkh-2.6/drivers/usb/class/Makefile +@@ -5,5 +5,4 @@ + + obj-$(CONFIG_USB_ACM) += cdc-acm.o + obj-$(CONFIG_USB_AUDIO) += audio.o +-obj-$(CONFIG_USB_MIDI) += usb-midi.o + obj-$(CONFIG_USB_PRINTER) += usblp.o +--- gregkh-2.6.orig/drivers/usb/class/usb-midi.h ++++ /dev/null +@@ -1,164 +0,0 @@ +-/* +- usb-midi.h -- USB-MIDI driver +- +- Copyright (C) 2001 +- NAGANO Daisuke <breeze.nagano@nifty.ne.jp> +- +- This program is free software; you can redistribute it and/or modify +- it under the terms of the GNU General Public License as published by +- the Free Software Foundation; either version 2, or (at your option) +- any later version. +- +- This program is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- GNU General Public License for more details. +- +- You should have received a copy of the GNU General Public License +- along with this program; if not, write to the Free Software +- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +- */ +- +-/* ------------------------------------------------------------------------- */ +- +-#ifndef _USB_MIDI_H_ +-#define _USB_MIDI_H_ +- +-#ifndef USB_SUBCLASS_MIDISTREAMING +-#define USB_SUBCLASS_MIDISTREAMING 3 +-#endif +- +-/* ------------------------------------------------------------------------- */ +-/* Roland MIDI Devices */ +- +-#define USB_VENDOR_ID_ROLAND 0x0582 +-#define USBMIDI_ROLAND_UA100G 0x0000 +-#define USBMIDI_ROLAND_MPU64 0x0002 +-#define USBMIDI_ROLAND_SC8850 0x0003 +-#define USBMIDI_ROLAND_SC8820 0x0007 +-#define USBMIDI_ROLAND_UM2 0x0005 +-#define USBMIDI_ROLAND_UM1 0x0009 +-#define USBMIDI_ROLAND_PC300 0x0008 +- +-/* YAMAHA MIDI Devices */ +-#define USB_VENDOR_ID_YAMAHA 0x0499 +-#define USBMIDI_YAMAHA_MU1000 0x1001 +- +-/* Steinberg MIDI Devices */ +-#define USB_VENDOR_ID_STEINBERG 0x0763 +-#define USBMIDI_STEINBERG_USB2MIDI 0x1001 +- +-/* Mark of the Unicorn MIDI Devices */ +-#define USB_VENDOR_ID_MOTU 0x07fd +-#define USBMIDI_MOTU_FASTLANE 0x0001 +- +-/* ------------------------------------------------------------------------- */ +-/* Supported devices */ +- +-struct usb_midi_endpoint { +- int endpoint; +- int cableId; /* if bit-n == 1 then cableId-n is enabled (n: 0 - 15) */ +-}; +- +-struct usb_midi_device { +- char *deviceName; +- +- u16 idVendor; +- u16 idProduct; +- int interface; +- int altSetting; /* -1: auto detect */ +- +- struct usb_midi_endpoint in[15]; +- struct usb_midi_endpoint out[15]; +-}; +- +-static struct usb_midi_device usb_midi_devices[] = { +- { /* Roland UM-1 */ +- "Roland UM-1", +- USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1, 2, -1, +- { { 0x81, 1 }, {-1, -1} }, +- { { 0x01, 1,}, {-1, -1} }, +- }, +- +- { /* Roland UM-2 */ +- "Roland UM-2" , +- USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2, 2, -1, +- { { 0x81, 3 }, {-1, -1} }, +- { { 0x01, 3,}, {-1, -1} }, +- }, +- +-/** Next entry courtesy research by Michael Minn <michael@michaelminn.com> **/ +- { /* Roland UA-100 */ +- "Roland UA-100", +- USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G, 2, -1, +- { { 0x82, 7 }, {-1, -1} }, /** cables 0,1 and 2 for SYSEX **/ +- { { 0x02, 7 }, {-1, -1} }, +- }, +- +-/** Next entry courtesy research by Michael Minn <michael@michaelminn.com> **/ +- { /* Roland SC8850 */ +- "Roland SC8850", +- USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850, 2, -1, +- { { 0x81, 0x3f }, {-1, -1} }, +- { { 0x01, 0x3f }, {-1, -1} }, +- }, +- +- { /* Roland SC8820 */ +- "Roland SC8820", +- USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820, 2, -1, +- { { 0x81, 0x13 }, {-1, -1} }, +- { { 0x01, 0x13 }, {-1, -1} }, +- }, +- +- { /* Roland SC8820 */ +- "Roland SC8820", +- USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820, 2, -1, +- { { 0x81, 17 }, {-1, -1} }, +- { { 0x01, 17 }, {-1, -1} }, +- }, +- +- { /* YAMAHA MU1000 */ +- "YAMAHA MU1000", +- USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000, 0, -1, +- { { 0x81, 1 }, {-1, -1} }, +- { { 0x01, 15 }, {-1, -1} }, +- }, +- { /* Roland PC-300 */ +- "Roland PC-300", +- USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300, 2, -1, +- { { 0x81, 1 }, {-1, -1} }, +- { { 0x01, 1 }, {-1, -1} }, +- }, +- { /* MOTU Fastlane USB */ +- "MOTU Fastlane USB", +- USB_VENDOR_ID_MOTU, USBMIDI_MOTU_FASTLANE, 1, 0, +- { { 0x82, 3 }, {-1, -1} }, +- { { 0x02, 3 }, {-1, -1} }, +- } +-}; +- +-#define VENDOR_SPECIFIC_USB_MIDI_DEVICES (sizeof(usb_midi_devices)/sizeof(struct usb_midi_device)) +- +-/* for Hot-Plugging */ +- +-static struct usb_device_id usb_midi_ids [] = { +- { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS), +- .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING}, +- { USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1 ) }, +- { USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2 ) }, +- { USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G ) }, +- { USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300 ) }, +- { USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850 ) }, +- { USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820 ) }, +- { USB_DEVICE( USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000 ) }, +- { USB_DEVICE( USB_VENDOR_ID_MOTU, USBMIDI_MOTU_FASTLANE ) }, +-/* { USB_DEVICE( USB_VENDOR_ID_STEINBERG, USBMIDI_STEINBERG_USB2MIDI ) },*/ +- { } /* Terminating entry */ +-}; +- +-MODULE_DEVICE_TABLE (usb, usb_midi_ids); +- +-/* ------------------------------------------------------------------------- */ +-#endif /* _USB_MIDI_H_ */ +- +- +--- gregkh-2.6.orig/drivers/usb/class/usb-midi.c ++++ /dev/null +@@ -1,2153 +0,0 @@ +-/* +- usb-midi.c -- USB-MIDI driver +- +- Copyright (C) 2001 +- NAGANO Daisuke <breeze.nagano@nifty.ne.jp> +- +- This program is free software; you can redistribute it and/or modify +- it under the terms of the GNU General Public License as published by +- the Free Software Foundation; either version 2, or (at your option) +- any later version. +- +- This program is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- GNU General Public License for more details. +- +- You should have received a copy of the GNU General Public License +- along with this program; if not, write to the Free Software +- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +- +- This driver is based on: +- - 'Universal Serial Bus Device Class Definition for MIDI Device' +- - linux/drivers/sound/es1371.c, linux/drivers/usb/audio.c +- - alsa/lowlevel/pci/cs64xx.c +- - umidi.c for NetBSD +- */ +- +-/* ------------------------------------------------------------------------- */ +- +- +-#include <linux/module.h> +-#include <linux/kernel.h> +-#include <linux/sched.h> +-#include <linux/list.h> +-#include <linux/slab.h> +-#include <linux/usb.h> +-#include <linux/poll.h> +-#include <linux/sound.h> +-#include <linux/init.h> +-#include <asm/semaphore.h> +- +-#include "usb-midi.h" +- +-/* ------------------------------------------------------------------------- */ +- +-/* More verbose on syslog */ +-#undef MIDI_DEBUG +- +-#define MIDI_IN_BUFSIZ 1024 +- +-#define HAVE_SUPPORT_USB_MIDI_CLASS +- +-#undef HAVE_SUPPORT_ALSA +- +-/* ------------------------------------------------------------------------- */ +- +-static int singlebyte = 0; +-module_param(singlebyte, int, 0); +-MODULE_PARM_DESC(singlebyte,"Enable sending MIDI messages with single message packet"); +- +-static int maxdevices = 4; +-module_param(maxdevices, int, 0); +-MODULE_PARM_DESC(maxdevices,"Max number of allocatable MIDI device"); +- +-static int uvendor = -1; +-module_param(uvendor, int, 0); +-MODULE_PARM_DESC(uvendor, "The USB Vendor ID of a semi-compliant interface"); +- +-static int uproduct = -1; +-module_param(uproduct, int, 0); +-MODULE_PARM_DESC(uproduct, "The USB Product ID of a semi-compliant interface"); +- +-static int uinterface = -1; +-module_param(uinterface, int, 0); +-MODULE_PARM_DESC(uinterface, "The Interface number of a semi-compliant interface"); +- +-static int ualt = -1; +-module_param(ualt, int, 0); +-MODULE_PARM_DESC(ualt, "The optional alternative setting of a semi-compliant interface"); +- +-static int umin = -1; +-module_param(umin, int, 0); +-MODULE_PARM_DESC(umin, "The input endpoint of a semi-compliant interface"); +- +-static int umout = -1; +-module_param(umout, int, 0); +-MODULE_PARM_DESC(umout, "The output endpoint of a semi-compliant interface"); +- +-static int ucable = -1; +-module_param(ucable, int, 0); +-MODULE_PARM_DESC(ucable, "The cable number used for a semi-compliant interface"); +- +-/** Note -- the usb_string() returns only Latin-1 characters. +- * (unicode chars <= 255). To support Japanese, a unicode16LE-to-EUC or +- * unicode16LE-to-JIS routine is needed to wrap around usb_get_string(). +- **/ +-static unsigned short ulangid = 0x0409; /** 0x0411 for Japanese **/ +-module_param(ulangid, ushort, 0); +-MODULE_PARM_DESC(ulangid, "The optional preferred USB Language ID for all devices"); +- +-MODULE_AUTHOR("NAGANO Daisuke <breeze.nagano@nifty.ne.jp>"); +-MODULE_DESCRIPTION("USB-MIDI driver"); +-MODULE_LICENSE("GPL"); +- +-/* ------------------------------------------------------------------------- */ +- +-/** MIDIStreaming Class-Specific Interface Descriptor Subtypes **/ +- +-#define MS_DESCRIPTOR_UNDEFINED 0 +-#define MS_HEADER 1 +-#define MIDI_IN_JACK 2 +-#define MIDI_OUT_JACK 3 +-/* Spec reads: ELEMENT */ +-#define ELEMENT_DESCRIPTOR 4 +- +-#define MS_HEADER_LENGTH 7 +- +-/** MIDIStreaming Class-Specific Endpoint Descriptor Subtypes **/ +- +-#define DESCRIPTOR_UNDEFINED 0 +-/* Spec reads: MS_GENERAL */ +-#define MS_GENERAL_ENDPOINT 1 +- +-/** MIDIStreaming MIDI IN and OUT Jack Types **/ +- +-#define JACK_TYPE_UNDEFINED 0 +-/* Spec reads: EMBEDDED */ +-#define EMBEDDED_JACK 1 +-/* Spec reads: EXTERNAL */ +-#define EXTERNAL_JACK 2 +- +- +-/* structure summary +- +- usb_midi_state usb_device +- | | +- *| *| per ep +- in_ep out_ep +- | | +- *| *| per cable +- min mout +- | | (cable to device pairing magic) +- | | +- usb_midi_dev dev_id (major,minor) == file->private_data +- +-*/ +- +-/* usb_midi_state: corresponds to a USB-MIDI module */ +-struct usb_midi_state { +- struct list_head mididev; +- +- struct usb_device *usbdev; +- +- struct list_head midiDevList; +- struct list_head inEndpointList; +- struct list_head outEndpointList; +- +- spinlock_t lock; +- +- unsigned int count; /* usage counter */ +-}; +- +-/* midi_out_endpoint: corresponds to an output endpoint */ +-struct midi_out_endpoint { +- struct list_head list; +- +- struct usb_device *usbdev; +- int endpoint; +- spinlock_t lock; +- wait_queue_head_t wait; +- +- unsigned char *buf; +- int bufWrPtr; +- int bufSize; +- +- struct urb *urb; +-}; +- +-/* midi_in_endpoint: corresponds to an input endpoint */ +-struct midi_in_endpoint { +- struct list_head list; +- +- struct usb_device *usbdev; +- int endpoint; +- spinlock_t lock; +- wait_queue_head_t wait; +- +- struct usb_mididev *cables[16]; // cables open for read +- int readers; // number of cables open for read +- +- struct urb *urb; +- unsigned char *recvBuf; +- int recvBufSize; +- int urbSubmitted; //FIXME: == readers > 0 +-}; +- +-/* usb_mididev: corresponds to a logical device */ +-struct usb_mididev { +- struct list_head list; +- +- struct usb_midi_state *midi; +- int dev_midi; +- mode_t open_mode; +- +- struct { +- struct midi_in_endpoint *ep; +- int cableId; +- +-// as we are pushing data from usb_bulk_read to usb_midi_read, +-// we need a larger, cyclic buffer here. +- unsigned char buf[MIDI_IN_BUFSIZ]; +- int bufRdPtr; +- int bufWrPtr; +- int bufRemains; +- } min; +- +- struct { +- struct midi_out_endpoint *ep; +- int cableId; +- +- unsigned char buf[3]; +- int bufPtr; +- int bufRemains; +- +- int isInExclusive; +- unsigned char lastEvent; +- } mout; +- +- int singlebyte; +-}; +- +-/** Map the high nybble of MIDI voice messages to number of Message bytes. +- * High nyble ranges from 0x8 to 0xe +- */ +- +-static int remains_80e0[] = { +- 3, /** 0x8X Note Off **/ +- 3, /** 0x9X Note On **/ +- 3, /** 0xAX Poly-key pressure **/ +- 3, /** 0xBX Control Change **/ +- 2, /** 0xCX Program Change **/ +- 2, /** 0xDX Channel pressure **/ +- 3 /** 0xEX PitchBend Change **/ +-}; +- +-/** Map the messages to a number of Message bytes. +- * +- **/ +-static int remains_f0f6[] = { +- 0, /** 0xF0 **/ +- 2, /** 0XF1 **/ +- 3, /** 0XF2 **/ +- 2, /** 0XF3 **/ +- 2, /** 0XF4 (Undefined by MIDI Spec, and subject to change) **/ +- 2, /** 0XF5 (Undefined by MIDI Spec, and subject to change) **/ +- 1 /** 0XF6 **/ +-}; +- +-/** Map the messages to a CIN (Code Index Number). +- * +- **/ +-static int cin_f0ff[] = { +- 4, /** 0xF0 System Exclusive Message Start (special cases may be 6 or 7) */ +- 2, /** 0xF1 **/ +- 3, /** 0xF2 **/ +- 2, /** 0xF3 **/ +- 2, /** 0xF4 **/ +- 2, /** 0xF5 **/ +- 5, /** 0xF6 **/ +- 5, /** 0xF7 End of System Exclusive Message (May be 6 or 7) **/ +- 5, /** 0xF8 **/ +- 5, /** 0xF9 **/ +- 5, /** 0xFA **/ +- 5, /** 0xFB **/ +- 5, /** 0xFC **/ +- 5, /** 0xFD **/ +- 5, /** 0xFE **/ +- 5 /** 0xFF **/ +-}; +- +-/** Map MIDIStreaming Event packet Code Index Number (low nybble of byte 0) +- * to the number of bytes of valid MIDI data. +- * +- * CIN of 0 and 1 are NOT USED in MIDIStreaming 1.0. +- * +- **/ +-static int cin_to_len[] = { +- 0, 0, 2, 3, +- 3, 1, 2, 3, +- 3, 3, 3, 3, +- 2, 2, 3, 1 +-}; +- +- +-/* ------------------------------------------------------------------------- */ +- +-static struct list_head mididevs = LIST_HEAD_INIT(mididevs); +- +-static DECLARE_MUTEX(open_sem); +-static DECLARE_WAIT_QUEUE_HEAD(open_wait); +- +- +-/* ------------------------------------------------------------------------- */ +- +-static void usb_write_callback(struct urb *urb, struct pt_regs *regs) +-{ +- struct midi_out_endpoint *ep = (struct midi_out_endpoint *)urb->context; +- +- if ( waitqueue_active( &ep->wait ) ) +- wake_up_interruptible( &ep->wait ); +-} +- +- +-static int usb_write( struct midi_out_endpoint *ep, unsigned char *buf, int len ) +-{ +- struct usb_device *d; +- int pipe; +- int ret = 0; +- int status; +- int maxretry = 50; +- +- DECLARE_WAITQUEUE(wait,current); +- init_waitqueue_head(&ep->wait); +- +- d = ep->usbdev; +- pipe = usb_sndbulkpipe(d, ep->endpoint); +- usb_fill_bulk_urb( ep->urb, d, pipe, (unsigned char*)buf, len, +- usb_write_callback, ep ); +- +- status = usb_submit_urb(ep->urb, GFP_KERNEL); +- +- if (status) { +- printk(KERN_ERR "usbmidi: Cannot submit urb (%d)\n",status); +- ret = -EIO; +- goto error; +- } +- +- add_wait_queue( &ep->wait, &wait ); +- set_current_state( TASK_INTERRUPTIBLE ); +- +- while( ep->urb->status == -EINPROGRESS ) { +- if ( maxretry-- < 0 ) { +- printk(KERN_ERR "usbmidi: usb_bulk_msg timed out\n"); +- ret = -ETIME; +- break; +- } +- interruptible_sleep_on_timeout( &ep->wait, 10 ); +- } +- set_current_state( TASK_RUNNING ); +- remove_wait_queue( &ep->wait, &wait ); +- +-error: +- return ret; +-} +- +- +-/** Copy data from URB to In endpoint buf. +- * Discard if CIN == 0 or CIN = 1. +- * +- * +- **/ +- +-static void usb_bulk_read(struct urb *urb, struct pt_regs *regs) +-{ +- struct midi_in_endpoint *ep = (struct midi_in_endpoint *)(urb->context); +- unsigned char *data = urb->transfer_buffer; +- int i, j, wake; +- +- if ( !ep->urbSubmitted ) { +- return; +- } +- +- if ( (urb->status == 0) && (urb->actual_length > 0) ) { +- wake = 0; +- spin_lock( &ep->lock ); +- +- for(j = 0; j < urb->actual_length; j += 4) { +- int cin = (data[j]>>0)&0xf; +- int cab = (data[j]>>4)&0xf; +- struct usb_mididev *cable = ep->cables[cab]; +- if ( cable ) { +- int len = cin_to_len[cin]; /** length of MIDI data **/ +- for (i = 0; i < len; i++) { +- cable->min.buf[cable->min.bufWrPtr] = data[1+i+j]; +- cable->min.bufWrPtr = (cable->min.bufWrPtr+1)%MIDI_IN_BUFSIZ; +- if (cable->min.bufRemains < MIDI_IN_BUFSIZ) +- cable->min.bufRemains += 1; +- else /** need to drop data **/ +- cable->min.bufRdPtr += (cable->min.bufRdPtr+1)%MIDI_IN_BUFSIZ; +- wake = 1; +- } +- } +- } +- +- spin_unlock ( &ep->lock ); +- if ( wake ) { +- wake_up( &ep->wait ); +- } +- } +- +- /* urb->dev must be reinitialized on 2.4.x kernels */ +- urb->dev = ep->usbdev; +- +- urb->actual_length = 0; +- usb_submit_urb(urb, GFP_ATOMIC); +-} +- +- +- +-/* ------------------------------------------------------------------------- */ +- +-/* This routine must be called with spin_lock */ +- +-/** Wrapper around usb_write(). +- * This routine must be called with spin_lock held on ep. +- * Called by midiWrite(), putOneMidiEvent(), and usb_midi_write(); +- **/ +-static int flush_midi_buffer( struct midi_out_endpoint *ep ) +-{ +- int ret=0; +- +- if ( ep->bufWrPtr > 0 ) { +- ret = usb_write( ep, ep->buf, ep->bufWrPtr ); +- ep->bufWrPtr = 0; +- } +- +- return ret; +-} +- +- +-/* ------------------------------------------------------------------------- */ +- +- +-/** Given a MIDI Event, determine size of data to be attached to +- * USB-MIDI packet. +- * Returns 1, 2 or 3. +- * Called by midiWrite(); +- * Uses remains_80e0 and remains_f0f6; +- **/ +-static int get_remains(int event) +-{ +- int ret; +- +- if ( event < 0x80 ) { +- ret = 1; +- } else if ( event < 0xf0 ) { +- ret = remains_80e0[((event-0x80)>>4)&0x0f]; +- } else if ( event < 0xf7 ) { +- ret = remains_f0f6[event-0xf0]; +- } else { +- ret = 1; +- } +- +- return ret; +-} +- +-/** Given the output MIDI data in the output buffer, computes a reasonable +- * CIN. +- * Called by putOneMidiEvent(). +- **/ +-static int get_CIN( struct usb_mididev *m ) +-{ +- int cin; +- +- if ( m->mout.buf[0] == 0xf7 ) { +- cin = 5; +- } +- else if ( m->mout.buf[1] == 0xf7 ) { +- cin = 6; +- } +- else if ( m->mout.buf[2] == 0xf7 ) { +- cin = 7; +- } +- else { +- if ( m->mout.isInExclusive == 1 ) { +- cin = 4; +- } else if ( m->mout.buf[0] < 0x80 ) { +- /** One byte that we know nothing about. **/ +- cin = 0xF; +- } else if ( m->mout.buf[0] < 0xf0 ) { +- /** MIDI Voice messages 0x8X to 0xEX map to cin 0x8 to 0xE. **/ +- cin = (m->mout.buf[0]>>4)&0x0f; +- } +- else { +- /** Special lookup table exists for real-time events. **/ +- cin = cin_f0ff[m->mout.buf[0]-0xf0]; +- } +- } +- +- return cin; +-} +- +- +-/* ------------------------------------------------------------------------- */ +- +- +- +-/** Move data to USB endpoint buffer. +- * +- **/ +-static int put_one_midi_event(struct usb_mididev *m) +-{ +- int cin; +- unsigned long flags; +- struct midi_out_endpoint *ep = m->mout.ep; +- int ret=0; +- +- cin = get_CIN( m ); +- if ( cin > 0x0f || cin < 0 ) { +- return -EINVAL; +- } +- +- spin_lock_irqsave( &ep->lock, flags ); +- ep->buf[ep->bufWrPtr++] = (m->mout.cableId<<4) | cin; +- ep->buf[ep->bufWrPtr++] = m->mout.buf[0]; +- ep->buf[ep->bufWrPtr++] = m->mout.buf[1]; +- ep->buf[ep->bufWrPtr++] = m->mout.buf[2]; +- if ( ep->bufWrPtr >= ep->bufSize ) { +- ret = flush_midi_buffer( ep ); +- } +- spin_unlock_irqrestore( &ep->lock, flags); +- +- m->mout.buf[0] = m->mout.buf[1] = m->mout.buf[2] = 0; +- m->mout.bufPtr = 0; +- +- return ret; +-} +- +-/** Write the MIDI message v on the midi device. +- * Called by usb_midi_write(); +- * Responsible for packaging a MIDI data stream into USB-MIDI packets. +- **/ +- +-static int midi_write( struct usb_mididev *m, int v ) +-{ +- unsigned long flags; +- struct midi_out_endpoint *ep = m->mout.ep; +- int ret=0; +- unsigned char c = (unsigned char)v; +- unsigned char sysrt_buf[4]; +- +- if ( m->singlebyte != 0 ) { +- /** Simple code to handle the single-byte USB-MIDI protocol. */ +- spin_lock_irqsave( &ep->lock, flags ); +- if ( ep->bufWrPtr+4 > ep->bufSize ) { +- ret = flush_midi_buffer( ep ); +- if ( !ret ) { +- spin_unlock_irqrestore( &ep->lock, flags ); +- return ret; +- } +- } +- ep->buf[ep->bufWrPtr++] = (m->mout.cableId<<4) | 0x0f; /* single byte */ +- ep->buf[ep->bufWrPtr++] = c; +- ep->buf[ep->bufWrPtr++] = 0; +- ep->buf[ep->bufWrPtr++] = 0; +- if ( ep->bufWrPtr >= ep->bufSize ) { +- ret = flush_midi_buffer( ep ); +- } +- spin_unlock_irqrestore( &ep->lock, flags ); +- +- return ret; +- } +- /** Normal USB-MIDI protocol begins here. */ +- +- if ( c > 0xf7 ) { /* system: Realtime messages */ +- /** Realtime messages are written IMMEDIATELY. */ +- sysrt_buf[0] = (m->mout.cableId<<4) | 0x0f; +- sysrt_buf[1] = c; +- sysrt_buf[2] = 0; +- sysrt_buf[3] = 0; +- spin_lock_irqsave( &ep->lock, flags ); +- ret = usb_write( ep, sysrt_buf, 4 ); +- spin_unlock_irqrestore( &ep->lock, flags ); +- /* m->mout.lastEvent = 0; */ +- +- return ret; +- } +- +- if ( c >= 0x80 ) { +- if ( c < 0xf0 ) { +- m->mout.lastEvent = c; +- m->mout.isInExclusive = 0; +- m->mout.bufRemains = get_remains(c); +- } else if ( c == 0xf0 ) { +- /* m->mout.lastEvent = 0; */ +- m->mout.isInExclusive = 1; +- m->mout.bufRemains = get_remains(c); +- } else if ( c == 0xf7 && m->mout.isInExclusive == 1 ) { +- /* m->mout.lastEvent = 0; */ +- m->mout.isInExclusive = 0; +- m->mout.bufRemains = 1; +- } else if ( c > 0xf0 ) { +- /* m->mout.lastEvent = 0; */ +- m->mout.isInExclusive = 0; +- m->mout.bufRemains = get_remains(c); +- } +- +- } else if ( m->mout.bufRemains == 0 && m->mout.isInExclusive == 0 ) { +- if ( m->mout.lastEvent == 0 ) { +- return 0; /* discard, waiting for the first event */ +- } +- /** track status **/ +- m->mout.buf[0] = m->mout.lastEvent; +- m->mout.bufPtr = 1; +- m->mout.bufRemains = get_remains(m->mout.lastEvent)-1; +- } +- +- m->mout.buf[m->mout.bufPtr++] = c; +- m->mout.bufRemains--; +- if ( m->mout.bufRemains == 0 || m->mout.bufPtr >= 3) { +- ret = put_one_midi_event(m); +- } +- +- return ret; +-} +- +- +-/* ------------------------------------------------------------------------- */ +- +-/** Basic operation on /dev/midiXX as registered through struct file_operations. +- * +- * Basic contract: Used to change the current read/write position in a file. +- * On success, the non-negative position is reported. +- * On failure, the negative of an error code is reported. +- * +- * Because a MIDIStream is not a file, all seek operations are doomed to fail. +- * +- **/ +-static loff_t usb_midi_llseek(struct file *file, loff_t offset, int origin) +-{ +- /** Tell user you cannot seek on a PIPE-like device. **/ +- return -ESPIPE; +-} +- +- +-/** Basic operation on /dev/midiXX as registered through struct file_operations. +- * +- * Basic contract: Block until count bytes have been read or an error occurs. +- * +- **/ +- +-static ssize_t usb_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) +-{ +- struct usb_mididev *m = (struct usb_mididev *)file->private_data; +- struct midi_in_endpoint *ep = m->min.ep; +- ssize_t ret; +- DECLARE_WAITQUEUE(wait, current); +- +- if ( !access_ok(VERIFY_READ, buffer, count) ) { +- return -EFAULT; +- } +- if ( count == 0 ) { +- return 0; +- } +- +- add_wait_queue( &ep->wait, &wait ); +- ret = 0; +- while( count > 0 ) { +- int cnt; +- int d = (int)count; +- +- cnt = m->min.bufRemains; +- if ( cnt > d ) { +- cnt = d; +- } +- +- if ( cnt <= 0 ) { +- if ( file->f_flags & O_NONBLOCK ) { +- if (!ret) +- ret = -EAGAIN; +- break; +- } +- __set_current_state(TASK_INTERRUPTIBLE); +- schedule(); +- if (signal_pending(current)) { +- if(!ret) +- ret=-ERESTARTSYS; +- break; +- } +- continue; +- } +- +- { +- int i; +- unsigned long flags; /* used to synchronize access to the endpoint */ +- spin_lock_irqsave( &ep->lock, flags ); +- for (i = 0; i < cnt; i++) { +- if ( copy_to_user( buffer+i, m->min.buf+m->min.bufRdPtr, 1 ) ) { +- if ( !ret ) +- ret = -EFAULT; +- break; +- } +- m->min.bufRdPtr = (m->min.bufRdPtr+1)%MIDI_IN_BUFSIZ; +- m->min.bufRemains -= 1; +- } +- spin_unlock_irqrestore( &ep->lock, flags ); +- } +- +- count-=cnt; +- buffer+=cnt; +- ret+=cnt; +- +- break; +- } +- +- remove_wait_queue( &ep->wait, &wait ); +- set_current_state(TASK_RUNNING); +- +- return ret; +-} +- +- +-/** Basic operation on /dev/midiXX as registered through struct file_operations. +- * +- * Basic Contract: Take MIDI data byte-by-byte and pass it to +- * writeMidi() which packages MIDI data into USB-MIDI stream. +- * Then flushMidiData() is called to ensure all bytes have been written +- * in a timely fashion. +- * +- **/ +- +-static ssize_t usb_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +-{ +- struct usb_mididev *m = (struct usb_mididev *)file->private_data; +- ssize_t ret; +- unsigned long int flags; +- +- if ( !access_ok(VERIFY_READ, buffer, count) ) { +- return -EFAULT; +- } +- if ( count == 0 ) { +- return 0; +- } +- +- ret = 0; +- while( count > 0 ) { +- unsigned char c; +- +- if (copy_from_user((unsigned char *)&c, buffer, 1)) { +- if ( ret == 0 ) +- ret = -EFAULT; +- break; +- } +- if( midi_write(m, (int)c) ) { +- if ( ret == 0 ) +- ret = -EFAULT; +- break; +- } +- count--; +- buffer++; +- ret++; +- } +- +- spin_lock_irqsave( &m->mout.ep->lock, flags ); +- if ( flush_midi_buffer(m->mout.ep) < 0 ) { +- ret = -EFAULT; +- } +- spin_unlock_irqrestore( &m->mout.ep->lock, flags ); +- +- return ret; +-} +- +-/** Basic operation on /dev/midiXX as registered through struct file_operations. +- * +- * Basic contract: Wait (spin) until ready to read or write on the file. +- * +- **/ +-static unsigned int usb_midi_poll(struct file *file, struct poll_table_struct *wait) +-{ +- struct usb_mididev *m = (struct usb_mididev *)file->private_data; +- struct midi_in_endpoint *iep = m->min.ep; +- struct midi_out_endpoint *oep = m->mout.ep; +- unsigned long flags; +- unsigned int mask = 0; +- +- if ( file->f_mode & FMODE_READ ) { +- poll_wait( file, &iep->wait, wait ); +- spin_lock_irqsave( &iep->lock, flags ); +- if ( m->min.bufRemains > 0 ) +- mask |= POLLIN | POLLRDNORM; +- spin_unlock_irqrestore( &iep->lock, flags ); +- } +- +- if ( file->f_mode & FMODE_WRITE ) { +- poll_wait( file, &oep->wait, wait ); +- spin_lock_irqsave( &oep->lock, flags ); +- if ( oep->bufWrPtr < oep->bufSize ) +- mask |= POLLOUT | POLLWRNORM; +- spin_unlock_irqrestore( &oep->lock, flags ); +- } +- +- return mask; +-} +- +- +-/** Basic operation on /dev/midiXX as registered through struct file_operations. +- * +- * Basic contract: This is always the first operation performed on the +- * device node. If no method is defined, the open succeeds without any +- * notification given to the module. +- * +- **/ +- +-static int usb_midi_open(struct inode *inode, struct file *file) +-{ +- int minor = iminor(inode); +- DECLARE_WAITQUEUE(wait, current); +- struct usb_midi_state *s; +- struct usb_mididev *m; +- unsigned long flags; +- int succeed = 0; +- +-#if 0 +- printk(KERN_INFO "usb-midi: Open minor= %d.\n", minor); +-#endif +- +- for(;;) { +- down(&open_sem); +- list_for_each_entry(s, &mididevs, mididev) { +- list_for_each_entry(m, &s->midiDevList, list) { +- if ( !((m->dev_midi ^ minor) & ~0xf) ) +- goto device_found; +- } +- } +- up(&open_sem); +- return -ENODEV; +- +- device_found: +- if ( !s->usbdev ) { +- up(&open_sem); +- return -EIO; +- } +- if ( !(m->open_mode & file->f_mode) ) { +- break; +- } +- if ( file->f_flags & O_NONBLOCK ) { +- up(&open_sem); +- return -EBUSY; +- } +- __set_current_state(TASK_INTERRUPTIBLE); +- add_wait_queue( &open_wait, &wait ); +- up(&open_sem); +- schedule(); +- remove_wait_queue( &open_wait, &wait ); +- if ( signal_pending(current) ) { +- return -ERESTARTSYS; +- } +- } +- +- file->private_data = m; +- spin_lock_irqsave( &s->lock, flags ); +- +- if ( !(m->open_mode & (FMODE_READ | FMODE_WRITE)) ) { +- //FIXME: intented semantics unclear here +- m->min.bufRdPtr = 0; +- m->min.bufWrPtr = 0; +- m->min.bufRemains = 0; +- spin_lock_init(&m->min.ep->lock); +- +- m->mout.bufPtr = 0; +- m->mout.bufRemains = 0; +- m->mout.isInExclusive = 0; +- m->mout.lastEvent = 0; +- spin_lock_init(&m->mout.ep->lock); +- } +- +- if ( (file->f_mode & FMODE_READ) && m->min.ep != NULL ) { +- unsigned long int flagsep; +- spin_lock_irqsave( &m->min.ep->lock, flagsep ); +- m->min.ep->cables[m->min.cableId] = m; +- m->min.ep->readers += 1; +- m->min.bufRdPtr = 0; +- m->min.bufWrPtr = 0; +- m->min.bufRemains = 0; +- spin_unlock_irqrestore( &m->min.ep->lock, flagsep ); +- +- if ( !(m->min.ep->urbSubmitted)) { +- +- /* urb->dev must be reinitialized on 2.4.x kernels */ +- m->min.ep->urb->dev = m->min.ep->usbdev; +- +- if ( usb_submit_urb(m->min.ep->urb, GFP_ATOMIC) ) { +- printk(KERN_ERR "usbmidi: Cannot submit urb for MIDI-IN\n"); +- } +- m->min.ep->urbSubmitted = 1; +- } +- m->open_mode |= FMODE_READ; +- succeed = 1; +- } +- +- if ( (file->f_mode & FMODE_WRITE) && m->mout.ep != NULL ) { +- m->mout.bufPtr = 0; +- m->mout.bufRemains = 0; +- m->mout.isInExclusive = 0; +- m->mout.lastEvent = 0; +- m->open_mode |= FMODE_WRITE; +- succeed = 1; +- } +- +- spin_unlock_irqrestore( &s->lock, flags ); +- +- s->count++; +- up(&open_sem); +- +- /** Changed to prevent extra increments to USE_COUNT. **/ +- if (!succeed) { +- return -EBUSY; +- } +- +-#if 0 +- printk(KERN_INFO "usb-midi: Open Succeeded. minor= %d.\n", minor); +-#endif +- +- return nonseekable_open(inode, file); /** Success. **/ +-} +- +- +-/** Basic operation on /dev/midiXX as registered through struct file_operations. +- * +- * Basic contract: Close an opened file and deallocate anything we allocated. +- * Like open(), this can be missing. If open set file->private_data, +- * release() must clear it. +- * +- **/ +- +-static int usb_midi_release(struct inode *inode, struct file *file) +-{ +- struct usb_mididev *m = (struct usb_mididev *)file->private_data; +- struct usb_midi_state *s = (struct usb_midi_state *)m->midi; +- +-#if 0 +- printk(KERN_INFO "usb-midi: Close.\n"); +-#endif +- +- down(&open_sem); +- +- if ( m->open_mode & FMODE_WRITE ) { +- m->open_mode &= ~FMODE_WRITE; +- usb_kill_urb( m->mout.ep->urb ); +- } +- +- if ( m->open_mode & FMODE_READ ) { +- unsigned long int flagsep; +- spin_lock_irqsave( &m->min.ep->lock, flagsep ); +- m->min.ep->cables[m->min.cableId] = NULL; // discard cable +- m->min.ep->readers -= 1; +- m->open_mode &= ~FMODE_READ; +- if ( m->min.ep->readers == 0 && +- m->min.ep->urbSubmitted ) { +- m->min.ep->urbSubmitted = 0; +- usb_kill_urb(m->min.ep->urb); +- } +- spin_unlock_irqrestore( &m->min.ep->lock, flagsep ); +- } +- +- s->count--; +- +- up(&open_sem); +- wake_up(&open_wait); +- +- file->private_data = NULL; +- return 0; +-} +- +-static struct file_operations usb_midi_fops = { +- .owner = THIS_MODULE, +- .llseek = usb_midi_llseek, +- .read = usb_midi_read, +- .write = usb_midi_write, +- .poll = usb_midi_poll, +- .open = usb_midi_open, +- .release = usb_midi_release, +-}; +- +-/* ------------------------------------------------------------------------- */ +- +-/** Returns filled midi_in_endpoint structure or null on failure. +- * +- * Parameters: +- * d - a usb_device +- * endPoint - An usb endpoint in the range 0 to 15. +- * Called by allocUsbMidiDev(); +- * +- **/ +- +-static struct midi_in_endpoint *alloc_midi_in_endpoint( struct usb_device *d, int endPoint ) +-{ +- struct midi_in_endpoint *ep; +- int bufSize; +- int pipe; +- +- endPoint &= 0x0f; /* Silently force endPoint to lie in range 0 to 15. */ +- +- pipe = usb_rcvbulkpipe( d, endPoint ); +- bufSize = usb_maxpacket( d, pipe, 0 ); +- /* usb_pipein() = ! usb_pipeout() = true for an in Endpoint */ +- +- ep = (struct midi_in_endpoint *)kmalloc(sizeof(struct midi_in_endpoint), GFP_KERNEL); +- if ( !ep ) { +- printk(KERN_ERR "usbmidi: no memory for midi in-endpoint\n"); +- return NULL; +- } +- memset( ep, 0, sizeof(struct midi_in_endpoint) ); +-// this sets cables[] and readers to 0, too. +-// for (i=0; i<16; i++) ep->cables[i] = 0; // discard cable +-// ep->readers = 0; +- +- ep->endpoint = endPoint; +- +- ep->recvBuf = (unsigned char *)kmalloc(sizeof(unsigned char)*(bufSize), GFP_KERNEL); +- if ( !ep->recvBuf ) { +- printk(KERN_ERR "usbmidi: no memory for midi in-endpoint buffer\n"); +- kfree(ep); +- return NULL; +- } +- +- ep->urb = usb_alloc_urb(0, GFP_KERNEL); /* no ISO */ +- if ( !ep->urb ) { +- printk(KERN_ERR "usbmidi: no memory for midi in-endpoint urb\n"); +- kfree(ep->recvBuf); +- kfree(ep); +- return NULL; +- } +- usb_fill_bulk_urb( ep->urb, d, +- usb_rcvbulkpipe(d, endPoint), +- (unsigned char *)ep->recvBuf, bufSize, +- usb_bulk_read, ep ); +- +- /* ep->bufRdPtr = 0; */ +- /* ep->bufWrPtr = 0; */ +- /* ep->bufRemains = 0; */ +- /* ep->urbSubmitted = 0; */ +- ep->recvBufSize = bufSize; +- +- init_waitqueue_head(&ep->wait); +- +- return ep; +-} +- +-static int remove_midi_in_endpoint( struct midi_in_endpoint *min ) +-{ +- usb_kill_urb( min->urb ); +- usb_free_urb( min->urb ); +- kfree( min->recvBuf ); +- kfree( min ); +- +- return 0; +-} +- +-/** Returns filled midi_out_endpoint structure or null on failure. +- * +- * Parameters: +- * d - a usb_device +- * endPoint - An usb endpoint in the range 0 to 15. +- * Called by allocUsbMidiDev(); +- * +- **/ +-static struct midi_out_endpoint *alloc_midi_out_endpoint( struct usb_device *d, int endPoint ) +-{ +- struct midi_out_endpoint *ep = NULL; +- int pipe; +- int bufSize; +- +- endPoint &= 0x0f; +- pipe = usb_sndbulkpipe( d, endPoint ); +- bufSize = usb_maxpacket( d, pipe, 1 ); +- +- ep = (struct midi_out_endpoint *)kmalloc(sizeof(struct midi_out_endpoint), GFP_KERNEL); +- if ( !ep ) { +- printk(KERN_ERR "usbmidi: no memory for midi out-endpoint\n"); +- return NULL; +- } +- memset( ep, 0, sizeof(struct midi_out_endpoint) ); +- +- ep->endpoint = endPoint; +- ep->buf = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL); +- if ( !ep->buf ) { +- printk(KERN_ERR "usbmidi: no memory for midi out-endpoint buffer\n"); +- kfree(ep); +- return NULL; +- } +- +- ep->urb = usb_alloc_urb(0, GFP_KERNEL); /* no ISO */ +- if ( !ep->urb ) { +- printk(KERN_ERR "usbmidi: no memory for midi out-endpoint urb\n"); +- kfree(ep->buf); +- kfree(ep); +- return NULL; +- } +- +- ep->bufSize = bufSize; +- /* ep->bufWrPtr = 0; */ +- +- init_waitqueue_head(&ep->wait); +- +- return ep; +-} +- +- +-static int remove_midi_out_endpoint( struct midi_out_endpoint *mout ) +-{ +- usb_kill_urb( mout->urb ); +- usb_free_urb( mout->urb ); +- kfree( mout->buf ); +- kfree( mout ); +- +- return 0; +-} +- +- +-/** Returns a filled usb_mididev structure, registered as a Linux MIDI device. +- * +- * Returns null if memory is not available or the device cannot be registered. +- * Called by allocUsbMidiDev(); +- * +- **/ +-static struct usb_mididev *allocMidiDev( +- struct usb_midi_state *s, +- struct midi_in_endpoint *min, +- struct midi_out_endpoint *mout, +- int inCableId, +- int outCableId ) +-{ +- struct usb_mididev *m; +- +- m = (struct usb_mididev *)kmalloc(sizeof(struct usb_mididev), GFP_KERNEL); +- if (!m) { +- printk(KERN_ERR "usbmidi: no memory for midi device\n"); +- return NULL; +- } +- +- memset(m, 0, sizeof(struct usb_mididev)); +- +- if ((m->dev_midi = register_sound_midi(&usb_midi_fops, -1)) < 0) { +- printk(KERN_ERR "usbmidi: cannot register midi device\n"); +- kfree(m); +- return NULL; +- } +- +- m->midi = s; +- /* m->open_mode = 0; */ +- +- if ( min ) { +- m->min.ep = min; +- m->min.ep->usbdev = s->usbdev; +- m->min.cableId = inCableId; +- } +- /* m->min.bufPtr = 0; */ +- /* m->min.bufRemains = 0; */ +- +- if ( mout ) { +- m->mout.ep = mout; +- m->mout.ep->usbdev = s->usbdev; +- m->mout.cableId = outCableId; +- } +- /* m->mout.bufPtr = 0; */ +- /* m->mout.bufRemains = 0; */ +- /* m->mout.isInExclusive = 0; */ +- /* m->mout.lastEvent = 0; */ +- +- m->singlebyte = singlebyte; +- +- return m; +-} +- +- +-static void release_midi_device( struct usb_midi_state *s ) +-{ +- struct usb_mididev *m; +- struct midi_in_endpoint *min; +- struct midi_out_endpoint *mout; +- +- if ( s->count > 0 ) { +- up(&open_sem); +- return; +- } +- up( &open_sem ); +- wake_up( &open_wait ); +- +- while(!list_empty(&s->inEndpointList)) { +- min = list_entry(s->inEndpointList.next, struct midi_in_endpoint, list); +- list_del(&min->list); +- remove_midi_in_endpoint(min); +- } +- +- while(!list_empty(&s->outEndpointList)) { +- mout = list_entry(s->outEndpointList.next, struct midi_out_endpoint, list); +- list_del(&mout->list); +- remove_midi_out_endpoint(mout); +- } +- +- while(!list_empty(&s->midiDevList)) { +- m = list_entry(s->midiDevList.next, struct usb_mididev, list); +- list_del(&m->list); +- kfree(m); +- } +- +- kfree(s); +- +- return; +-} +- +- +-/* ------------------------------------------------------------------------- */ +- +-/** Utility routine to find a descriptor in a dump of many descriptors. +- * Returns start of descriptor or NULL if not found. +- * descStart pointer to list of interfaces. +- * descLength length (in bytes) of dump +- * after (ignored if NULL) this routine returns only descriptors after "after" +- * dtype (mandatory) The descriptor type. +- * iface (ignored if -1) returns descriptor at/following given interface +- * altSetting (ignored if -1) returns descriptor at/following given altSetting +- * +- * +- * Called by parseDescriptor(), find_csinterface_descriptor(); +- * +- */ +-static void *find_descriptor( void *descStart, unsigned int descLength, void *after, unsigned char dtype, int iface, int altSetting ) +-{ +- unsigned char *p, *end, *next; +- int interfaceNumber = -1, altSet = -1; +- +- p = descStart; +- end = p + descLength; +- for( ; p < end; ) { +- if ( p[0] < 2 ) +- return NULL; +- next = p + p[0]; +- if ( next > end ) +- return NULL; +- if ( p[1] == USB_DT_INTERFACE ) { +- if ( p[0] < USB_DT_INTERFACE_SIZE ) +- return NULL; +- interfaceNumber = p[2]; +- altSet = p[3]; +- } +- if ( p[1] == dtype && +- ( !after || ( p > (unsigned char *)after) ) && +- ( ( iface == -1) || (iface == interfaceNumber) ) && +- ( (altSetting == -1) || (altSetting == altSet) )) { +- return p; +- } +- p = next; +- } +- return NULL; +-} +- +-/** Utility to find a class-specific interface descriptor. +- * dsubtype is a descriptor subtype +- * Called by parseDescriptor(); +- **/ +-static void *find_csinterface_descriptor(void *descStart, unsigned int descLength, void *after, u8 dsubtype, int iface, int altSetting) +-{ +- unsigned char *p; +- +- p = find_descriptor( descStart, descLength, after, USB_DT_CS_INTERFACE, iface, altSetting ); +- while ( p ) { +- if ( p[0] >= 3 && p[2] == dsubtype ) +- return p; +- p = find_descriptor( descStart, descLength, p, USB_DT_CS_INTERFACE, +- iface, altSetting ); +- } +- return NULL; +-} +- +- +-/** The magic of making a new usb_midi_device from config happens here. +- * +- * The caller is responsible for free-ing this return value (if not NULL). +- * +- **/ +-static struct usb_midi_device *parse_descriptor( struct usb_device *d, unsigned char *buffer, int bufSize, unsigned int ifnum , unsigned int altSetting, int quirks) +-{ +- struct usb_midi_device *u; +- unsigned char *p1; +- unsigned char *p2; +- unsigned char *next; +- int iep, oep; +- int length; +- unsigned long longBits; +- int pins, nbytes, offset, shift, jack; +-#ifdef HAVE_JACK_STRINGS +- /** Jacks can have associated names. **/ +- unsigned char jack2string[256]; +-#endif +- +- u = NULL; +- /* find audiocontrol interface */ +- p1 = find_csinterface_descriptor( buffer, bufSize, NULL, +- MS_HEADER, ifnum, altSetting); +- +- if ( !p1 ) { +- goto error_end; +- } +- +- if ( p1[0] < MS_HEADER_LENGTH ) { +- goto error_end; +- } +- +- /* Assume success. Since the device corresponds to USB-MIDI spec, we assume +- that the rest of the USB 2.0 spec is obeyed. */ +- +- u = (struct usb_midi_device *)kmalloc( sizeof(struct usb_midi_device), GFP_KERNEL ); +- if ( !u ) { +- return NULL; +- } +- u->deviceName = NULL; +- u->idVendor = le16_to_cpu(d->descriptor.idVendor); +- u->idProduct = le16_to_cpu(d->descriptor.idProduct); +- u->interface = ifnum; +- u->altSetting = altSetting; +- u->in[0].endpoint = -1; +- u->in[0].cableId = -1; +- u->out[0].endpoint = -1; +- u->out[0].cableId = -1; +- +- +- printk(KERN_INFO "usb-midi: Found MIDIStreaming device corresponding to Release %d.%02d of spec.\n", +- (p1[4] >> 4) * 10 + (p1[4] & 0x0f ), +- (p1[3] >> 4) * 10 + (p1[3] & 0x0f ) +- ); +- +- length = p1[5] | (p1[6] << 8); +- +-#ifdef HAVE_JACK_STRINGS +- memset(jack2string, 0, sizeof(unsigned char) * 256); +-#endif +- +- length -= p1[0]; +- for (p2 = p1 + p1[0]; length > 0; p2 = next) { +- next = p2 + p2[0]; +- length -= p2[0]; +- +- if (p2[0] < 2 ) +- break; +- if (p2[1] != USB_DT_CS_INTERFACE) +- break; +- if (p2[2] == MIDI_IN_JACK && p2[0] >= 6 ) { +- jack = p2[4]; +-#ifdef HAVE_JACK_STRINGS +- jack2string[jack] = p2[5]; +-#endif +- printk(KERN_INFO "usb-midi: Found IN Jack 0x%02x %s\n", +- jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL" ); +- } else if ( p2[2] == MIDI_OUT_JACK && p2[0] >= 6) { +- pins = p2[5]; +- if ( p2[0] < (6 + 2 * pins) ) +- continue; +- jack = p2[4]; +-#ifdef HAVE_JACK_STRINGS +- jack2string[jack] = p2[5 + 2 * pins]; +-#endif +- printk(KERN_INFO "usb-midi: Found OUT Jack 0x%02x %s, %d pins\n", +- jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL", pins ); +- } else if ( p2[2] == ELEMENT_DESCRIPTOR && p2[0] >= 10) { +- pins = p2[4]; +- if ( p2[0] < (9 + 2 * pins ) ) +- continue; +- nbytes = p2[8 + 2 * pins ]; +- if ( p2[0] < (10 + 2 * pins + nbytes) ) +- continue; +- longBits = 0L; +- for ( offset = 0, shift = 0; offset < nbytes && offset < 8; offset ++, shift += 8) { +- longBits |= ((long)(p2[9 + 2 * pins + offset])) << shift; +- } +- jack = p2[3]; +-#ifdef HAVE_JACK_STRINGS +- jack2string[jack] = p2[9 + 2 * pins + nbytes]; +-#endif +- printk(KERN_INFO "usb-midi: Found ELEMENT 0x%02x, %d/%d pins in/out, bits: 0x%016lx\n", +- jack, pins, (int)(p2[5 + 2 * pins]), (long)longBits ); +- } else { +- } +- } +- +- iep=0; +- oep=0; +- +- if (quirks==0) { +- /* MIDISTREAM */ +- p2 = NULL; +- for (p1 = find_descriptor(buffer, bufSize, NULL, USB_DT_ENDPOINT, +- ifnum, altSetting ); p1; p1 = next ) { +- next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT, +- ifnum, altSetting ); +- p2 = find_descriptor(buffer, bufSize, p1, USB_DT_CS_ENDPOINT, +- ifnum, altSetting ); +- +- if ( p2 && next && ( p2 > next ) ) +- p2 = NULL; +- +- if ( p1[0] < 9 || !p2 || p2[0] < 4 ) +- continue; +- +- if ( (p1[2] & 0x80) == 0x80 ) { +- if ( iep < 15 ) { +- pins = p2[3]; /* not pins -- actually "cables" */ +- if ( pins > 16 ) +- pins = 16; +- u->in[iep].endpoint = p1[2]; +- u->in[iep].cableId = ( 1 << pins ) - 1; +- if ( u->in[iep].cableId ) +- iep ++; +- if ( iep < 15 ) { +- u->in[iep].endpoint = -1; +- u->in[iep].cableId = -1; +- } +- } +- } else { +- if ( oep < 15 ) { +- pins = p2[3]; /* not pins -- actually "cables" */ +- if ( pins > 16 ) +- pins = 16; +- u->out[oep].endpoint = p1[2]; +- u->out[oep].cableId = ( 1 << pins ) - 1; +- if ( u->out[oep].cableId ) +- oep ++; +- if ( oep < 15 ) { +- u->out[oep].endpoint = -1; +- u->out[oep].cableId = -1; +- } +- } +- } +- +- } +- } else if (quirks==1) { +- /* YAMAHA quirks */ +- for (p1 = find_descriptor(buffer, bufSize, NULL, USB_DT_ENDPOINT, +- ifnum, altSetting ); p1; p1 = next ) { +- next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT, +- ifnum, altSetting ); +- +- if ( p1[0] < 7 ) +- continue; +- +- if ( (p1[2] & 0x80) == 0x80 ) { +- if ( iep < 15 ) { +- pins = iep+1; +- if ( pins > 16 ) +- pins = 16; +- u->in[iep].endpoint = p1[2]; +- u->in[iep].cableId = ( 1 << pins ) - 1; +- if ( u->in[iep].cableId ) +- iep ++; +- if ( iep < 15 ) { +- u->in[iep].endpoint = -1; +- u->in[iep].cableId = -1; +- } +- } +- } else { +- if ( oep < 15 ) { +- pins = oep+1; +- u->out[oep].endpoint = p1[2]; +- u->out[oep].cableId = ( 1 << pins ) - 1; +- if ( u->out[oep].cableId ) +- oep ++; +- if ( oep < 15 ) { +- u->out[oep].endpoint = -1; +- u->out[oep].cableId = -1; +- } +- } +- } +- +- } +- } +- +- if ( !iep && ! oep ) { +- goto error_end; +- } +- +- return u; +- +-error_end: +- kfree(u); +- return NULL; +-} +- +-/* ------------------------------------------------------------------------- */ +- +-/** Returns number between 0 and 16. +- * +- **/ +-static int on_bits( unsigned short v ) +-{ +- int i; +- int ret=0; +- +- for ( i=0 ; i<16 ; i++ ) { +- if ( v & (1<<i) ) +- ret++; +- } +- +- return ret; +-} +- +- +-/** USB-device will be interrogated for altSetting. +- * +- * Returns negative on error. +- * Called by allocUsbMidiDev(); +- * +- **/ +- +-static int get_alt_setting( struct usb_device *d, int ifnum ) +-{ +- int alts, alt=0; +- struct usb_interface *iface; +- struct usb_host_interface *interface; +- struct usb_endpoint_descriptor *ep; +- int epin, epout; +- int i; +- +- iface = usb_ifnum_to_if( d, ifnum ); +- alts = iface->num_altsetting; +- +- for ( alt=0 ; alt<alts ; alt++ ) { +- interface = &iface->altsetting[alt]; +- epin = -1; +- epout = -1; +- +- for ( i=0 ; i<interface->desc.bNumEndpoints ; i++ ) { +- ep = &interface->endpoint[i].desc; +- if ( (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ) { +- continue; +- } +- if ( (ep->bEndpointAddress & USB_DIR_IN) && epin < 0 ) { +- epin = i; +- } else if ( epout < 0 ) { +- epout = i; +- } +- if ( epin >= 0 && epout >= 0 ) { +- return interface->desc.bAlternateSetting; +- } +- } +- } +- +- return -ENODEV; +-} +- +- +-/* ------------------------------------------------------------------------- */ +- +- +-/** Returns 0 if successful in allocating and registering internal structures. +- * Returns negative on failure. +- * Calls allocMidiDev which additionally registers /dev/midiXX devices. +- * Writes messages on success to indicate which /dev/midiXX is which physical +- * endpoint. +- * +- **/ +-static int alloc_usb_midi_device( struct usb_device *d, struct usb_midi_state *s, struct usb_midi_device *u ) +-{ +- struct usb_mididev **mdevs=NULL; +- struct midi_in_endpoint *mins[15], *min; +- struct midi_out_endpoint *mouts[15], *mout; +- int inDevs=0, outDevs=0; +- int inEndpoints=0, outEndpoints=0; +- int inEndpoint, outEndpoint; +- int inCableId, outCableId; +- int i; +- int devices = 0; +- int alt = 0; +- +- /* Obtain altSetting or die.. */ +- alt = u->altSetting; +- if ( alt < 0 ) { +- alt = get_alt_setting( d, u->interface ); +- } +- if ( alt < 0 ) +- return -ENXIO; +- +- /* Configure interface */ +- if ( usb_set_interface( d, u->interface, alt ) < 0 ) { +- return -ENXIO; +- } +- +- for ( i = 0 ; i < 15 ; i++ ) { +- mins[i] = NULL; +- mouts[i] = NULL; +- } +- +- /* Begin Allocation */ +- while( inEndpoints < 15 +- && inDevs < maxdevices +- && u->in[inEndpoints].cableId >= 0 ) { +- inDevs += on_bits((unsigned short)u->in[inEndpoints].cableId); +- mins[inEndpoints] = alloc_midi_in_endpoint( d, u->in[inEndpoints].endpoint ); +- if ( mins[inEndpoints] == NULL ) +- goto error_end; +- inEndpoints++; +- } +- +- while( outEndpoints < 15 +- && outDevs < maxdevices +- && u->out[outEndpoints].cableId >= 0 ) { +- outDevs += on_bits((unsigned short)u->out[outEndpoints].cableId); +- mouts[outEndpoints] = alloc_midi_out_endpoint( d, u->out[outEndpoints].endpoint ); +- if ( mouts[outEndpoints] == NULL ) +- goto error_end; +- outEndpoints++; +- } +- +- devices = inDevs > outDevs ? inDevs : outDevs; +- devices = maxdevices > devices ? devices : maxdevices; +- +- /* obtain space for device name (iProduct) if not known. */ +- if ( ! u->deviceName ) { +- mdevs = (struct usb_mididev **) +- kmalloc(sizeof(struct usb_mididevs *)*devices +- + sizeof(char) * 256, GFP_KERNEL); +- } else { +- mdevs = (struct usb_mididev **) +- kmalloc(sizeof(struct usb_mididevs *)*devices, GFP_KERNEL); +- } +- +- if ( !mdevs ) { +- /* devices = 0; */ +- /* 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 = { +- .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 */ +- |