Update of /cvsroot/alsa/alsa-kernel/usb
In directory usw-pr-cvs1:/tmp/cvs-serv15463

Modified Files:
        Config.help Makefile usbaudio.c usbaudio.h usbmidi.c 
Log Message:
rewrite of usb-midi using rawmidi by Clemens.

Index: Config.help
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/usb/Config.help,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- Config.help 26 Aug 2002 16:05:42 -0000      1.2
+++ Config.help 22 Oct 2002 10:14:19 -0000      1.3
@@ -1,4 +1,2 @@
 CONFIG_SND_USB_AUDIO
-  Say 'Y' or 'M' to include support for USB audio devices.
-  To support USB MIDI devices, you need to enable ALSA sequencer support
-  (CONFIG_SND_SEQUENCER).
+  Say 'Y' or 'M' to include support for USB audio and USB MIDI devices.

Index: Makefile
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/usb/Makefile,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- Makefile    26 Aug 2002 16:05:42 -0000      1.2
+++ Makefile    22 Oct 2002 10:14:19 -0000      1.3
@@ -2,15 +2,9 @@
 # Makefile for ALSA
 #
 
-snd-usb-audio-objs := usbaudio.o usbmixer.o
-ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
-snd-usb-midi-objs := usbmidi.o
-endif
+snd-usb-audio-objs := usbaudio.o usbmixer.o usbmidi.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-audio.o
-ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
-obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-midi.o
-endif
 
 include $(TOPDIR)/Rules.make

Index: usbaudio.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/usb/usbaudio.c,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -r1.20 -r1.21
--- usbaudio.c  21 Oct 2002 18:28:26 -0000      1.20
+++ usbaudio.c  22 Oct 2002 10:14:19 -0000      1.21
@@ -1833,11 +1833,6 @@
 /*
  * parse audio control descriptor and create pcm/midi streams
  */
-
-static int snd_usb_create_midi_interface(snd_usb_audio_t *chip,
-                                        struct usb_interface *iface,
-                                        const snd_usb_audio_quirk_t *quirk);
-
 static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif,
                                  unsigned char *buffer, int buflen)
 {
@@ -1893,32 +1888,6 @@
                usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1);
        }
 
-       return 0;
-}
-
-static int snd_usb_create_midi_interface(snd_usb_audio_t *chip,
-                                        struct usb_interface *iface,
-                                        const snd_usb_audio_quirk_t *quirk)
-{
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
-       snd_seq_device_t *seq_device;
-       snd_usb_midi_t *umidi;
-       int err;
-
-       err = snd_seq_device_new(chip->card, chip->next_seq_device,
-                                SNDRV_SEQ_DEV_ID_USBMIDI,
-                                sizeof(snd_usb_midi_t), &seq_device);
-       if (err < 0)
-               return err;
-       chip->next_seq_device++;
-       strcpy(seq_device->name, chip->card->shortname);
-       umidi = (snd_usb_midi_t *)SNDRV_SEQ_DEVICE_ARGPTR(seq_device);
-       umidi->chip = chip;
-       umidi->iface = iface;
-       umidi->ifnum = iface->altsetting->bInterfaceNumber;
-       umidi->quirk = quirk;
-       umidi->seq_client = -1;
-#endif
        return 0;
 }
 

Index: usbaudio.h
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/usb/usbaudio.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- usbaudio.h  4 Oct 2002 16:05:28 -0000       1.4
+++ usbaudio.h  22 Oct 2002 10:14:19 -0000      1.5
@@ -123,8 +123,6 @@
 /* maximum number of endpoints per interface */
 #define MIDI_MAX_ENDPOINTS 2
 
-#define SNDRV_SEQ_DEV_ID_USBMIDI "usb-midi"
-
 /*
  */
 
@@ -140,9 +138,7 @@
        struct list_head pcm_list;      /* list of pcm streams */
        int pcm_devs;
 
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
-       int next_seq_device;
-#endif
+       int next_midi_device;
 };  
 
 /*
@@ -177,31 +173,6 @@
 /* for QUIRK_MIDI_MIDIMAN, data is the number of ports */
 
 /*
- * USB MIDI sequencer device data
- */
-typedef struct snd_usb_midi snd_usb_midi_t;
-typedef struct snd_usb_midi_endpoint snd_usb_midi_endpoint_t;
-typedef struct snd_usb_midi_out_endpoint snd_usb_midi_out_endpoint_t;
-typedef struct snd_usb_midi_in_endpoint snd_usb_midi_in_endpoint_t;
-
-struct snd_usb_midi {
-       /* filled by usbaudio.c */
-       snd_usb_audio_t *chip;
-       struct usb_interface *iface;
-       int ifnum;
-       const snd_usb_audio_quirk_t *quirk;
-
-       /* used internally in usbmidi.c */
-       int seq_client;
-       struct snd_usb_midi_endpoint {
-               snd_usb_midi_out_endpoint_t *out;
-               snd_usb_midi_in_endpoint_t *in;
-               snd_rawmidi_t *rmidi[0x10];
-       } endpoints[MIDI_MAX_ENDPOINTS];
-};
-
-
-/*
  */
 
 #define combine_word(s)    ((*s) | ((unsigned int)(s)[1] << 8))
@@ -214,5 +185,7 @@
 void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsubtype, 
int iface, int altsetting);
 
 int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif, unsigned char *buffer, 
int buflen);
+
+int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *iface, 
+const snd_usb_audio_quirk_t *quirk);
 
 #endif /* __USBAUDIO_H */

Index: usbmidi.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/usb/usbmidi.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- usbmidi.c   4 Oct 2002 16:05:30 -0000       1.7
+++ usbmidi.c   22 Oct 2002 10:14:19 -0000      1.8
@@ -46,34 +46,9 @@
 #include <linux/usb.h>
 #include <sound/core.h>
 #include <sound/minors.h>
-#include <sound/asequencer.h>
-#include <sound/seq_device.h>
-#include <sound/seq_kernel.h>
-#include <sound/seq_virmidi.h>
-#include <sound/seq_midi_event.h>
-#include <sound/initval.h>
+#include <sound/rawmidi.h>
 #include "usbaudio.h"
 
-MODULE_AUTHOR("Clemens Ladisch <[EMAIL PROTECTED]>");
-MODULE_DESCRIPTION("USB MIDI");
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_CLASSES("{sound}");
-
-/* size of the per-endpoint output buffer, must be a multiple of 4 */
-#define OUTPUT_BUFFER_SIZE 0x400
-
-/* max. size of incoming sysex messages */
-#define INPUT_BUFFER_SIZE 0x200
-
-typedef struct usb_driver usb_driver_t;
-typedef struct usb_device usb_device_t;
-typedef struct usb_device_id usb_device_id_t;
-typedef struct usb_interface usb_interface_t;
-typedef struct usb_interface_descriptor usb_interface_descriptor_t;
-typedef struct usb_ms_header_descriptor usb_ms_header_descriptor_t;
-typedef struct usb_endpoint_descriptor usb_endpoint_descriptor_t;
-typedef struct usb_ms_endpoint_descriptor usb_ms_endpoint_descriptor_t;
-
 struct usb_ms_header_descriptor {
        __u8  bLength;
        __u8  bDescriptorType;
@@ -90,35 +65,56 @@
        __u8  baAssocJackID[0];
 } __attribute__ ((packed));
 
+typedef struct snd_usb_midi snd_usb_midi_t;
+typedef struct snd_usb_midi_endpoint snd_usb_midi_endpoint_t;
+typedef struct snd_usb_midi_out_endpoint snd_usb_midi_out_endpoint_t;
+typedef struct snd_usb_midi_in_endpoint snd_usb_midi_in_endpoint_t;
 typedef struct usbmidi_out_port usbmidi_out_port_t;
 typedef struct usbmidi_in_port usbmidi_in_port_t;
 
+struct snd_usb_midi {
+       snd_usb_audio_t *chip;
+       struct usb_interface *iface;
+       const snd_usb_audio_quirk_t *quirk;
+       snd_rawmidi_t* rmidi;
+
+       struct snd_usb_midi_endpoint {
+               snd_usb_midi_out_endpoint_t *out;
+               snd_usb_midi_in_endpoint_t *in;
+       } endpoints[MIDI_MAX_ENDPOINTS];
+};
+
 struct snd_usb_midi_out_endpoint {
        snd_usb_midi_t* umidi;
        struct urb* urb;
        int max_transfer;               /* size of urb buffer */
        struct tasklet_struct tasklet;
 
-       uint8_t buffer[OUTPUT_BUFFER_SIZE]; /* ring buffer */
-       int data_begin;
-       int data_size;
        spinlock_t buffer_lock;
 
        struct usbmidi_out_port {
                snd_usb_midi_out_endpoint_t* ep;
+               snd_rawmidi_substream_t* substream;
+               int active;
                uint8_t cable;          /* cable number << 4 */
-               uint8_t sysex_len;
-               uint8_t sysex[2];
+               uint8_t state;
+#define STATE_UNKNOWN  0
+#define STATE_1PARAM   1
+#define STATE_2PARAM_1 2
+#define STATE_2PARAM_2 3
+#define STATE_SYSEX_0  4
+#define STATE_SYSEX_1  5
+#define STATE_SYSEX_2  6
+               uint8_t data[2];
        } ports[0x10];
 };
 
 struct snd_usb_midi_in_endpoint {
        snd_usb_midi_t* umidi;
-       snd_usb_midi_endpoint_t* ep;
        struct urb* urb;
        struct usbmidi_in_port {
-               int seq_port;
-               snd_midi_event_t* midi_event;
+               snd_rawmidi_substream_t* substream;
+               int active;
        } ports[0x10];
 };
 
@@ -155,28 +151,18 @@
 }
 
 /*
- * Converts a USB MIDI packet into an ALSA sequencer event.
+ * Receives a USB MIDI packet.
  */
 static void snd_usbmidi_input_packet(snd_usb_midi_in_endpoint_t* ep,
                                     uint8_t packet[4])
 {
        int cable = packet[0] >> 4;
        usbmidi_in_port_t* port = &ep->ports[cable];
-       snd_seq_event_t ev;
 
-       if (!port->midi_event)
+       if (!port->active)
                return;
-       memset(&ev, 0, sizeof(ev));
-       if (snd_midi_event_encode(port->midi_event, &packet[1],
-                                 snd_usbmidi_cin_length[packet[0] & 0x0f], &ev) > 0
-           && ev.type != SNDRV_SEQ_EVENT_NONE) {
-               ev.source.port = port->seq_port;
-               ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
-               snd_seq_kernel_client_dispatch(ep->umidi->seq_client,
-                                              &ev, 1, 0);
-               if (ep->ep->rmidi[cable])
-                       snd_virmidi_receive(ep->ep->rmidi[cable], &ev);
-       }
+       snd_rawmidi_receive(port->substream, &packet[1],
+                           snd_usbmidi_cin_length[packet[0] & 0x0f]);
 }
 
 /*
@@ -239,15 +225,12 @@
 static void snd_usbmidi_out_urb_complete(struct urb* urb)
 {
        snd_usb_midi_out_endpoint_t* ep = snd_magic_cast(snd_usb_midi_out_endpoint_t, 
urb->context, return);
-       unsigned long flags;
 
        if (urb->status < 0) {
                if (snd_usbmidi_urb_error(urb->status) < 0)
                        return;
        }
-       spin_lock_irqsave(&ep->buffer_lock, flags);
        snd_usbmidi_do_output(ep);
-       spin_unlock_irqrestore(&ep->buffer_lock, flags);
 }
 
 /*
@@ -268,261 +251,255 @@
 }
 
 /*
+ * Adds one USB MIDI packet to the output buffer.
+ */
+static inline void output_packet(struct urb* urb,
+                                uint8_t p0, uint8_t p1, uint8_t p2, uint8_t p3)
+{
+
+       uint8_t* buf = (uint8_t*)urb->transfer_buffer + urb->transfer_buffer_length;
+       buf[0] = p0;
+       buf[1] = p1;
+       buf[2] = p2;
+       buf[3] = p3;
+       urb->transfer_buffer_length += 4;
+}
+
+/*
+ * Converts MIDI commands to USB MIDI packets.
+ */
+static void snd_usbmidi_transmit_byte(usbmidi_out_port_t* port,
+                                     uint8_t b, struct urb* urb)
+{
+       uint8_t p0 = port->cable;
+
+       if (b >= 0xf8) {
+               output_packet(urb, p0 | 0x0f, b, 0, 0);
+       } else if (b >= 0xf0) {
+               switch (b) {
+               case 0xf0:
+                       port->data[0] = b;
+                       port->state = STATE_SYSEX_1;
+                       break;
+               case 0xf1:
+               case 0xf3:
+                       port->data[0] = b;
+                       port->state = STATE_1PARAM;
+                       break;
+               case 0xf2:
+                       port->data[0] = b;
+                       port->state = STATE_2PARAM_1;
+                       break;
+               case 0xf4:
+               case 0xf5:
+                       port->state = STATE_UNKNOWN;
+                       break;
+               case 0xf6:
+                       output_packet(urb, p0 | 0x05, 0xf6, 0, 0);
+                       port->state = STATE_UNKNOWN;
+                       break;
+               case 0xf7:
+                       switch (port->state) {
+                       case STATE_SYSEX_0:
+                               output_packet(urb, p0 | 0x05, 0xf7, 0, 0);
+                               break;
+                       case STATE_SYSEX_1:
+                               output_packet(urb, p0 | 0x06, port->data[0], 0xf7, 0);
+                               break;
+                       case STATE_SYSEX_2:
+                               output_packet(urb, p0 | 0x07, port->data[0], 
+port->data[1], 0xf7);
+                               break;
+                       }
+                       port->state = STATE_UNKNOWN;
+                       break;
+               }
+       } else if (b >= 0x80) {
+               port->data[0] = b;
+               if (b >= 0xc0 && b <= 0xdf)
+                       port->state = STATE_1PARAM;
+               else
+                       port->state = STATE_2PARAM_1;
+       } else { /* b < 0x80 */
+               switch (port->state) {
+               case STATE_1PARAM:
+                       if (port->data[0] < 0xf0) {
+                               p0 |= port->data[0] >> 4;
+                       } else {
+                               p0 |= 0x02;
+                               port->state = STATE_UNKNOWN;
+                       }
+                       output_packet(urb, p0, port->data[0], b, 0);
+                       break;
+               case STATE_2PARAM_1:
+                       port->data[1] = b;
+                       port->state = STATE_2PARAM_2;
+                       break;
+               case STATE_2PARAM_2:
+                       if (port->data[0] < 0xf0) {
+                               p0 |= port->data[0] >> 4;
+                               port->state = STATE_2PARAM_1;
+                       } else {
+                               p0 |= 0x03;
+                               port->state = STATE_UNKNOWN;
+                       }
+                       output_packet(urb, p0, port->data[0], port->data[1], b);
+                       break;
+               case STATE_SYSEX_0:
+                       port->data[0] = b;
+                       port->state = STATE_SYSEX_1;
+                       break;
+               case STATE_SYSEX_1:
+                       port->data[1] = b;
+                       port->state = STATE_SYSEX_2;
+                       break;
+               case STATE_SYSEX_2:
+                       output_packet(urb, p0 | 0x04, port->data[0], port->data[1], b);
+                       port->state = STATE_SYSEX_0;
+                       break;
+               }
+       }
+}
+
+/*
+ * Moves data from one substream buffer to the URB transfer buffer.
+ */
+static void snd_usbmidi_transmit(snd_usb_midi_out_endpoint_t* ep, int port_idx)
+{
+       struct urb* urb = ep->urb;
+       usbmidi_out_port_t* port = &ep->ports[port_idx];
+
+       while (urb->transfer_buffer_length < ep->max_transfer) {
+               uint8_t b;
+               if (snd_rawmidi_transmit_peek(port->substream, &b, 1) != 1) {
+                       port->active = 0;
+                       break;
+               }
+               snd_usbmidi_transmit_byte(port, b, urb);
+               snd_rawmidi_transmit_ack(port->substream, 1);
+       }
+}
+
+/*
  * This is called when some data should be transferred to the device
- * (after the reception of one or more sequencer events, or after completion
- * of the previous transfer). ep->buffer_lock must be held.
+ * (from one or more substreams).
  */
 static void snd_usbmidi_do_output(snd_usb_midi_out_endpoint_t* ep)
 {
-       int len;
-       uint8_t* buffer;
-
-       if (ep->urb->status == -EINPROGRESS ||
-           ep->data_size == 0)
+       int p;
+       struct urb* urb = ep->urb;
+       unsigned long flags;
+       
+       spin_lock_irqsave(&ep->buffer_lock, flags);
+       if (urb->status == -EINPROGRESS) {
+               spin_unlock_irqrestore(&ep->buffer_lock, flags);
                return;
-       buffer = (uint8_t*)ep->urb->transfer_buffer;
-
-       /* first chunk, up to the end of the buffer */
-       len = OUTPUT_BUFFER_SIZE - ep->data_begin;
-       if (len > ep->data_size)
-               len = ep->data_size;
-       if (len > ep->max_transfer)
-               len = ep->max_transfer;
-       if (len > 0) {
-               memcpy(buffer, ep->buffer + ep->data_begin, len);
-               ep->data_begin = (ep->data_begin + len) % OUTPUT_BUFFER_SIZE;
-               ep->data_size -= len;
-               buffer += len;
-               ep->urb->transfer_buffer_length = len;
-       }
-
-       /* second chunk (after wraparound) */
-       if (ep->data_begin == 0 && ep->data_size > 0 &&
-           len < ep->max_transfer) {
-               len = ep->max_transfer - len;
-               if (len > ep->data_size)
-                       len = ep->data_size;
-               memcpy(buffer, ep->buffer, len);
-               ep->data_begin = len;
-               ep->data_size -= len;
-               ep->urb->transfer_buffer_length += len;
        }
 
-       if (len > 0) {
+       urb->transfer_buffer_length = 0;
+       for (p= 0; p < 0x10; ++p)
+               if (ep->ports[p].active)
+                       snd_usbmidi_transmit(ep, p);
+
+       if (urb->transfer_buffer_length > 0) {
                if (ep->umidi->quirk && ep->umidi->quirk->type == QUIRK_MIDI_MIDIMAN)
-                       snd_usbmidi_convert_to_midiman(ep->urb);
+                       snd_usbmidi_convert_to_midiman(urb);
 
-               ep->urb->dev = ep->umidi->chip->dev;
-               snd_usbmidi_submit_urb(ep->urb, GFP_ATOMIC);
+               urb->dev = ep->umidi->chip->dev;
+               snd_usbmidi_submit_urb(urb, GFP_ATOMIC);
        }
+       spin_unlock_irqrestore(&ep->buffer_lock, flags);
 }
 
 static void snd_usbmidi_out_tasklet(unsigned long data)
 {
        snd_usb_midi_out_endpoint_t* ep = snd_magic_cast(snd_usb_midi_out_endpoint_t, 
(void*)data, return);
-       unsigned long flags;
        
-       spin_lock_irqsave(&ep->buffer_lock, flags);
        snd_usbmidi_do_output(ep);
-       spin_unlock_irqrestore(&ep->buffer_lock, flags);
 }
 
-/*
- * Adds one USB MIDI packet to the output buffer.
- */
-static void output_packet(usbmidi_out_port_t* port,
-                         uint8_t p0, uint8_t p1, uint8_t p2, uint8_t p3)
+static int snd_usbmidi_output_open(snd_rawmidi_substream_t* substream)
 {
-       snd_usb_midi_out_endpoint_t* ep = port->ep;
-       unsigned long flags;
+       snd_usb_midi_t* umidi = snd_magic_cast(snd_usb_midi_t, 
+substream->rmidi->private_data, return -ENXIO);
+       usbmidi_out_port_t* port = NULL;
+       int i, j;
 
-       spin_lock_irqsave(&ep->buffer_lock, flags);
-       if (ep->data_size < OUTPUT_BUFFER_SIZE) {
-               uint8_t* buf = ep->buffer + (ep->data_begin + ep->data_size) % 
OUTPUT_BUFFER_SIZE;
-               buf[0] = p0;
-               buf[1] = p1;
-               buf[2] = p2;
-               buf[3] = p3;
-               ep->data_size += 4;
-               if (ep->data_size == ep->max_transfer)
-                       snd_usbmidi_do_output(ep);
-       }
-       spin_unlock_irqrestore(&ep->buffer_lock, flags);
+       for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
+               if (umidi->endpoints[i].out)
+                       for (j = 0; j < 0x10; ++j)
+                               if (umidi->endpoints[i].out->ports[j].substream == 
+substream) {
+                                       port = &umidi->endpoints[i].out->ports[j];
+                                       break;
+                               }
+       if (!port)
+               return -ENXIO;
+       substream->runtime->private_data = port;
+       port->state = STATE_UNKNOWN;
+       return 0;
 }
 
-/*
- * Callback for snd_seq_dump_var_event.
- */
-static int snd_usbmidi_sysex_dump(void* ptr, void* buf, int count)
+static int snd_usbmidi_output_close(snd_rawmidi_substream_t* substream)
 {
-       usbmidi_out_port_t* port = (usbmidi_out_port_t*)ptr;
-       const uint8_t* dump = (const uint8_t*)buf;
+       return 0;
+}
 
-       for (; count; --count) {
-               uint8_t byte = *dump++;
-
-               if (byte == 0xf0 && port->sysex_len > 0) {
-                       /*
-                        * The previous SysEx wasn't terminated correctly.
-                        * Send the last bytes anyway, and hope that the
-                        * receiving device won't be too upset about the
-                        * missing F7.
-                        */
-                       output_packet(port,
-                                     port->cable | (0x04 + port->sysex_len),
-                                     port->sysex[0],
-                                     port->sysex_len >= 2 ? port->sysex[1] : 0,
-                                     0);
-                       port->sysex_len = 0;
-               }
-               if (byte != 0xf7) {
-                       if (port->sysex_len >= 2) {
-                               output_packet(port,
-                                             port->cable | 0x04,
-                                             port->sysex[0],
-                                             port->sysex[1],
-                                             byte);
-                               port->sysex_len = 0;
-                       } else {
-                               port->sysex[port->sysex_len++] = byte;
-                       }
-               } else {
-                       uint8_t cin, data[3];
-                       int i;
+static void snd_usbmidi_output_trigger(snd_rawmidi_substream_t* substream, int up)
+{
+       usbmidi_out_port_t* port = 
+(usbmidi_out_port_t*)substream->runtime->private_data;
 
-                       for (i = 0; i < port->sysex_len; ++i)
-                               data[i] = port->sysex[i];
-                       data[i++] = 0xf7;
-                       cin = port->cable | (0x04 + i);
-                       for (; i < 3; ++i)
-                               data[i] = 0;
-                       /*
-                        * cin,data[] is x5,{F7 00 00}
-                        *            or x6,{xx F7 00}
-                        *            or x7,{xx xx F7}
-                        */
-                       output_packet(port, cin, data[0], data[1], data[2]);
-                       port->sysex_len = 0;
-               }
-       }
-       return 0;
+       port->active = up;
+       if (up)
+               tasklet_hi_schedule(&port->ep->tasklet);
 }
 
-/*
- * Converts an ALSA sequencer event into USB MIDI packets.
- */
-static int snd_usbmidi_event_input(snd_seq_event_t* ev, int direct,
-                                  void* private_data, int atomic, int hop)
+static int snd_usbmidi_input_open(snd_rawmidi_substream_t* substream)
 {
-       usbmidi_out_port_t* port = (usbmidi_out_port_t*)private_data;
-       int err;
-       uint8_t p0, p1;
+       snd_usb_midi_t* umidi = snd_magic_cast(snd_usb_midi_t, 
+substream->rmidi->private_data, return -ENXIO);
+       usbmidi_in_port_t* port = NULL;
+       int i, j;
 
-       p0 = port->cable;
-       p1 = ev->data.note.channel & 0xf;
+       for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
+               if (umidi->endpoints[i].in)
+                       for (j = 0; j < 0x10; ++j)
+                               if (umidi->endpoints[i].in->ports[j].substream == 
+substream) {
+                                       port = &umidi->endpoints[i].in->ports[j];
+                                       break;
+                               }
+       if (!port)
+               return -ENXIO;
+       substream->runtime->private_data = port;
+       return 0;
+}
 
-       switch (ev->type) {
-       case SNDRV_SEQ_EVENT_NOTEON:
-               output_packet(port, p0 | 0x09, p1 | 0x90,
-                             ev->data.note.note & 0x7f,
-                             ev->data.note.velocity & 0x7f);
-               break;
-       case SNDRV_SEQ_EVENT_NOTEOFF:
-               output_packet(port, p0 | 0x08, p1 | 0x80,
-                             ev->data.note.note & 0x7f,
-                             ev->data.note.velocity & 0x7f);
-               break;
-       case SNDRV_SEQ_EVENT_KEYPRESS:
-               output_packet(port, p0 | 0x0a, p1 | 0xa0,
-                             ev->data.note.note & 0x7f,
-                             ev->data.note.velocity & 0x7f);
-               break;
-       case SNDRV_SEQ_EVENT_CONTROLLER:
-               output_packet(port, p0 | 0x0b, p1 | 0xb0,
-                             ev->data.control.param & 0x7f,
-                             ev->data.control.value & 0x7f);
-               break;
-       case SNDRV_SEQ_EVENT_PGMCHANGE:
-               output_packet(port, p0 | 0x0c, p1 | 0xc0,
-                             ev->data.control.value & 0x7f, 0);
-               break;
-       case SNDRV_SEQ_EVENT_CHANPRESS:
-               output_packet(port, p0 | 0x0d, p1 | 0xd0,
-                             ev->data.control.value & 0x7f, 0);
-               break;
-       case SNDRV_SEQ_EVENT_PITCHBEND:
-               output_packet(port, p0 | 0x0e, p1 | 0xe0,
-                             (ev->data.control.value + 0x2000) & 0x7f,
-                             ((ev->data.control.value + 0x2000) >> 7) & 0x7f);
-               break;
-       case SNDRV_SEQ_EVENT_CONTROL14:
-               if (ev->data.control.param < 0x20) {
-                       output_packet(port, p0 | 0x0b, p1 | 0xb0,
-                                     ev->data.control.param,
-                                     (ev->data.control.value >> 7) & 0x7f);
-                       output_packet(port, p0 | 0x0b, p1 | 0xb0,
-                                     ev->data.control.param + 0x20,
-                                     ev->data.control.value & 0x7f);
-               } else {
-                       output_packet(port, p0 | 0x0b, p1 | 0xb0,
-                                     ev->data.control.param & 0x7f,
-                                     ev->data.control.value & 0x7f);
-               }
-               break;
-       case SNDRV_SEQ_EVENT_SONGPOS:
-               output_packet(port, p0 | 0x03, 0xf2,
-                             ev->data.control.value & 0x7f,
-                             (ev->data.control.value >> 7) & 0x7f);
-               break;
-       case SNDRV_SEQ_EVENT_SONGSEL:
-               output_packet(port, p0 | 0x02, 0xf3,
-                             ev->data.control.value & 0x7f, 0);
-               break;
-       case SNDRV_SEQ_EVENT_QFRAME:
-               output_packet(port, p0 | 0x02, 0xf1,
-                             ev->data.control.value & 0x7f, 0);
-               break;
-       case SNDRV_SEQ_EVENT_START:
-               output_packet(port, p0 | 0x0f, 0xfa, 0, 0);
-               break;
-       case SNDRV_SEQ_EVENT_CONTINUE:
-               output_packet(port, p0 | 0x0f, 0xfb, 0, 0);
-               break;
-       case SNDRV_SEQ_EVENT_STOP:
-               output_packet(port, p0 | 0x0f, 0xfc, 0, 0);
-               break;
-       case SNDRV_SEQ_EVENT_CLOCK:
-               output_packet(port, p0 | 0x0f, 0xf8, 0, 0);
-               break;
-       case SNDRV_SEQ_EVENT_TUNE_REQUEST:
-               output_packet(port, p0 | 0x05, 0xf6, 0, 0);
-               break;
-       case SNDRV_SEQ_EVENT_RESET:
-               output_packet(port, p0 | 0x0f, 0xff, 0, 0);
-               break;
-       case SNDRV_SEQ_EVENT_SENSING:
-               output_packet(port, p0 | 0x0f, 0xfe, 0, 0);
-               break;
-       case SNDRV_SEQ_EVENT_SYSEX:
-               err = snd_seq_dump_var_event(ev, snd_usbmidi_sysex_dump, port);
-               if (err < 0)
-                       return err;
-               break;
-       default:
-               return 0;
-       }
-       tasklet_hi_schedule(&port->ep->tasklet);
+static int snd_usbmidi_input_close(snd_rawmidi_substream_t* substream)
+{
        return 0;
 }
 
+static void snd_usbmidi_input_trigger(snd_rawmidi_substream_t* substream, int up)
+{
+       usbmidi_in_port_t* port = (usbmidi_in_port_t*)substream->runtime->private_data;
+
+       port->active = up;
+}
+
+static snd_rawmidi_ops_t snd_usbmidi_output_ops = {
+       .open = snd_usbmidi_output_open,
+       .close = snd_usbmidi_output_close,
+       .trigger = snd_usbmidi_output_trigger,
+};
+
+static snd_rawmidi_ops_t snd_usbmidi_input_ops = {
+       .open = snd_usbmidi_input_open,
+       .close = snd_usbmidi_input_close,
+       .trigger = snd_usbmidi_input_trigger
+};
+
 /*
  * Frees an input endpoint.
  * May be called when ep hasn't been initialized completely.
  */
 static void snd_usbmidi_in_endpoint_delete(snd_usb_midi_in_endpoint_t* ep)
 {
-       int i;
-
        if (ep->urb) {
                if (ep->urb->transfer_buffer) {
                        usb_unlink_urb(ep->urb);
@@ -530,9 +507,6 @@
                }
                usb_free_urb(ep->urb);
        }
-       for (i = 0; i < 0x10; ++i)
-               if (ep->ports[i].midi_event)
-                       snd_midi_event_free(ep->ports[i].midi_event);
        snd_magic_kfree(ep);
 }
 
@@ -540,11 +514,10 @@
  * For Roland devices, use the alternate setting which uses interrupt
  * transfers for input.
  */
-static usb_endpoint_descriptor_t* snd_usbmidi_get_int_epd(snd_usb_midi_t* umidi,
-                                                         uint8_t epnum)
+static struct usb_endpoint_descriptor* snd_usbmidi_get_int_epd(snd_usb_midi_t* umidi)
 {
-       usb_interface_t* intf;
-       usb_interface_descriptor_t* intfd;
+       struct usb_interface* intf;
+       struct usb_interface_descriptor* intfd;
 
        if (umidi->chip->dev->descriptor.idVendor != 0x0582)
                return NULL;
@@ -569,41 +542,37 @@
        return &intfd->endpoint[1];
 }
 
-static usb_endpoint_descriptor_t* snd_usbmidi_get_midiman_int_epd(snd_usb_midi_t* 
umidi)
+static struct usb_endpoint_descriptor* 
+snd_usbmidi_get_midiman_int_epd(snd_usb_midi_t* umidi)
 {
-       usb_interface_t* intf = umidi->iface;
-       if (!intf)
+       struct usb_interface* intf = umidi->iface;
+       if (!intf || intf->altsetting[0].bNumEndpoints < 1)
                return NULL;
        return &intf->altsetting[0].endpoint[0];
 }
 
 /*
- * Creates an input endpoint, and initalizes input ports.
- * ALSA ports are created later.
+ * Creates an input endpoint.
  */
 static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi,
                                          snd_usb_midi_endpoint_info_t* ep_info,
                                          snd_usb_midi_endpoint_t* rep)
 {
        snd_usb_midi_in_endpoint_t* ep;
-       usb_endpoint_descriptor_t* int_epd;
+       struct usb_endpoint_descriptor* int_epd;
        void* buffer;
        unsigned int pipe;
-       int length, i, err;
+       int length;
 
        rep->in = NULL;
        ep = snd_magic_kcalloc(snd_usb_midi_in_endpoint_t, 0, GFP_KERNEL);
        if (!ep)
                return -ENOMEM;
        ep->umidi = umidi;
-       ep->ep = rep;
-       for (i = 0; i < 0x10; ++i)
-               ep->ports[i].seq_port = -1;
 
        if (umidi->quirk && umidi->quirk->type == QUIRK_MIDI_MIDIMAN)
                int_epd = snd_usbmidi_get_midiman_int_epd(umidi);
        else
-               int_epd = snd_usbmidi_get_int_epd(umidi, ep_info->epnum);
+               int_epd = snd_usbmidi_get_int_epd(umidi);
 
        ep->urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!ep->urb) {
@@ -627,16 +596,6 @@
                FILL_BULK_URB(ep->urb, umidi->chip->dev, pipe, buffer, length,
                              snd_usbmidi_in_urb_complete, ep);
 
-       for (i = 0; i < 0x10; ++i)
-               if (ep_info->in_cables & (1 << i)) {
-                       err = snd_midi_event_new(INPUT_BUFFER_SIZE,
-                                                &ep->ports[i].midi_event);
-                       if (err < 0) {
-                               snd_usbmidi_in_endpoint_delete(ep);
-                               return -ENOMEM;
-                       }
-               }
-
        rep->in = ep;
        return 0;
 }
@@ -670,7 +629,6 @@
 
 /*
  * Creates an output endpoint, and initializes output ports.
- * ALSA ports are created later.
  */
 static int snd_usbmidi_out_endpoint_create(snd_usb_midi_t* umidi,
                                           snd_usb_midi_endpoint_info_t* ep_info,
@@ -716,143 +674,54 @@
 }
 
 /*
- * Frees the sequencer client, endpoints and ports.
+ * Frees everything.
  */
-static int snd_usbmidi_seq_device_delete(snd_seq_device_t* seq_device)
+static void snd_usbmidi_free(snd_usb_midi_t* umidi)
 {
-       snd_usb_midi_t* umidi;
-       int i, j;
-
-       umidi = (snd_usb_midi_t*)SNDRV_SEQ_DEVICE_ARGPTR(seq_device);
+       int i;
 
-       if (umidi->seq_client >= 0) {
-               snd_seq_delete_kernel_client(umidi->seq_client);
-               umidi->seq_client = -1;
-       }
        for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
                snd_usb_midi_endpoint_t* ep = &umidi->endpoints[i];
-               if (ep->out) {
+               if (ep->out)
                        snd_usbmidi_out_endpoint_delete(ep->out);
-                       ep->out = NULL;
-               }
-               if (ep->in) {
+               if (ep->in)
                        snd_usbmidi_in_endpoint_delete(ep->in);
-                       ep->in = NULL;
-               }
-               for (j = 0; j < 0x10; ++j)
-                       if (ep->rmidi[j]) {
-                               snd_device_free(umidi->chip->card, ep->rmidi[j]);
-                               ep->rmidi[j] = NULL;
-                       }
        }
-       return 0;
+       snd_magic_kfree(umidi);
 }
 
-/*
- * Creates a sequencer port for an input/output cable pair.
- */
-static int snd_usbmidi_create_port(snd_usb_midi_t* umidi,
-                                  snd_usb_midi_out_endpoint_t* out_ep,
-                                  snd_usb_midi_in_endpoint_t* in_ep,
-                                  int cable, int port_idx)
-{
-       int cap, type, port;
-       snd_seq_port_callback_t port_callback;
-       char port_name[48];
-
-       cap = 0;
-       memset(&port_callback, 0, sizeof(port_callback));
-       port_callback.owner = THIS_MODULE;
-       if (out_ep) {
-               port_callback.event_input = snd_usbmidi_event_input;
-               port_callback.private_data = &out_ep->ports[cable];
-               cap |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
-       }
-       if (in_ep) {
-               cap |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
-       }
-       if (out_ep && in_ep) {
-               cap |= SNDRV_SEQ_PORT_CAP_DUPLEX;
-       }
-       /* TODO: read type bits from element descriptor */
-       type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
-       /* TODO: read port name from jack descriptor */
-       snprintf(port_name, sizeof(port_name), "%s Port %d",
-                umidi->chip->card->shortname, port_idx);
-       port = snd_seq_event_port_attach(umidi->seq_client, &port_callback,
-                                        cap, type, port_name);
-       if (port < 0) {
-               snd_printk(KERN_ERR "cannot create port (error code %d)\n", port);
-               return port;
-       }
-       if (in_ep)
-               in_ep->ports[cable].seq_port = port;
-       return port;
+static void snd_usbmidi_rawmidi_free(snd_rawmidi_t* rmidi)
+{
+       snd_usb_midi_t* umidi = snd_magic_cast(snd_usb_midi_t, rmidi->private_data, 
+return);
+       snd_usbmidi_free(umidi);
 }
 
-/*
- * Creates a virmidi port emulating rawmidi for the sequencer port.
- */
-static int snd_usbmidi_create_virmidi(snd_usb_midi_t* umidi, int port,
-                                     int port_idx, snd_rawmidi_t** rrmidi)
+static snd_rawmidi_substream_t* snd_usbmidi_find_substream(snd_usb_midi_t* umidi,
+                                                          int stream, int number)
 {
-       snd_rawmidi_t *rmidi;
-       snd_virmidi_dev_t *rdev;
-       int err;
+       struct list_head* list;
 
-       *rrmidi = NULL;
-       err = snd_virmidi_new(umidi->chip->card, port_idx, &rmidi);
-       if (err < 0)
-               return err;
-       sprintf(rmidi->name, "%s MIDI %d", umidi->chip->card->shortname, port_idx);
-       rdev = snd_magic_cast(snd_virmidi_dev_t, rmidi->private_data, return -ENXIO);
-       rdev->seq_mode = SNDRV_VIRMIDI_SEQ_ATTACH;
-       rdev->client = umidi->seq_client;
-       rdev->port = port;
-       err = snd_device_register(umidi->chip->card, rmidi);
-       if (err < 0) {
-               snd_device_free(umidi->chip->card, rmidi);
-               return err;
+       list_for_each(list, &umidi->rmidi->streams[stream].substreams) {
+               snd_rawmidi_substream_t* substream = list_entry(list, 
+snd_rawmidi_substream_t, list);
+               if (substream->number == number)
+                       return substream;
        }
-       *rrmidi = rmidi;
-       return 0;
+       return NULL;
 }
 
-/*
- * After input and output endpoints have been initialized, create
- * the ALSA port for each input/output port pair in the endpoint.
- * *port_idx is the port number, which must be unique over all endpoints.
- */
-static int snd_usbmidi_create_endpoint_ports(snd_usb_midi_t* umidi,
-                                            snd_usb_midi_endpoint_t* endpoint,
-                                            int* port_idx,
-                                            snd_usb_midi_endpoint_info_t* ep_info)
-{
-       int cable;
-
-       for (cable = 0; cable < 0x10; ++cable) {
-               int port, err;
-               int out = ep_info->out_cables & (1 << cable);
-               int in = ep_info->in_cables & (1 << cable);
-               if (!(in || out))
-                       continue;
-
-               port = snd_usbmidi_create_port(umidi,
-                                              out ? endpoint->out : NULL,
-                                              in ? endpoint->in : NULL,
-                                              cable, *port_idx);
-               if (port < 0)
-                       return port;
-
-               if (*port_idx < SNDRV_MINOR_RAWMIDIS) {
-                       err = snd_usbmidi_create_virmidi(umidi, port, *port_idx,
-                                                        &endpoint->rmidi[cable]);
-                       if (err < 0)
-                               return err;
-               }
-               ++*port_idx;
+static void snd_usbmidi_init_substream(snd_usb_midi_t* umidi,
+                                      int stream, int number,
+                                      snd_rawmidi_substream_t** rsubstream)
+{
+       snd_rawmidi_substream_t* substream = snd_usbmidi_find_substream(umidi, stream, 
+number);
+       if (!substream) {
+               snd_printd(KERN_ERR "substream %d:%d not found\n", stream, number);
+               return;
        }
-       return 0;
+       /* TODO: read port name from jack descriptor */
+       snprintf(substream->name, sizeof(substream->name),
+                "%s Port %d", umidi->chip->card->shortname, number);
+       *rsubstream = substream;
 }
 
 /*
@@ -861,7 +730,8 @@
 static int snd_usbmidi_create_endpoints(snd_usb_midi_t* umidi,
                                        snd_usb_midi_endpoint_info_t* endpoints)
 {
-       int i, err, port_idx = 0;
+       int i, j, err;
+       int out_ports = 0, in_ports = 0;
 
        for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
                if (!endpoints[i].epnum)
@@ -878,15 +748,22 @@
                        if (err < 0)
                                return err;
                }
-               err = snd_usbmidi_create_endpoint_ports(umidi, &umidi->endpoints[i],
-                                                       &port_idx, &endpoints[i]);
-               if (err < 0)
-                       return err;
-               printk(KERN_INFO "snd-usb-midi: endpoint %d: created %d output and %d 
input ports\n",
-                      endpoints[i].epnum,
-                      snd_usbmidi_count_bits(endpoints[i].out_cables),
-                      snd_usbmidi_count_bits(endpoints[i].in_cables));
+
+               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;
+                       }
+               }
        }
+       printk(KERN_INFO "snd-usb-midi: created %d output and %d input ports\n",
+              out_ports, in_ports);
        return 0;
 }
 
@@ -896,18 +773,18 @@
 static int snd_usbmidi_get_ms_info(snd_usb_midi_t* umidi,
                                   snd_usb_midi_endpoint_info_t* endpoints)
 {
-       usb_interface_t* intf;
-       usb_interface_descriptor_t* intfd;
-       usb_ms_header_descriptor_t* ms_header;
-       usb_endpoint_descriptor_t* ep;
-       usb_ms_endpoint_descriptor_t* ms_ep;
+       struct usb_interface* intf;
+       struct usb_interface_descriptor* intfd;
+       struct usb_ms_header_descriptor* ms_header;
+       struct usb_endpoint_descriptor* ep;
+       struct usb_ms_endpoint_descriptor* ms_ep;
        int i, epidx;
 
        intf = umidi->iface;
        if (!intf)
                return -ENXIO;
        intfd = &intf->altsetting[0];
-       ms_header = (usb_ms_header_descriptor_t*)intfd->extra;
+       ms_header = (struct usb_ms_header_descriptor*)intfd->extra;
        if (intfd->extralen >= 7 &&
            ms_header->bLength >= 7 &&
            ms_header->bDescriptorType == USB_DT_CS_INTERFACE &&
@@ -922,7 +799,7 @@
                ep = &intfd->endpoint[i];
                if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != 
USB_ENDPOINT_XFER_BULK)
                        continue;
-               ms_ep = (usb_ms_endpoint_descriptor_t*)ep->extra;
+               ms_ep = (struct usb_ms_endpoint_descriptor*)ep->extra;
                if (ep->extralen < 4 ||
                    ms_ep->bLength < 4 ||
                    ms_ep->bDescriptorType != USB_DT_CS_ENDPOINT ||
@@ -957,9 +834,9 @@
 static int snd_usbmidi_detect_endpoint(snd_usb_midi_t* umidi, 
                                       snd_usb_midi_endpoint_info_t* endpoint)
 {
-       usb_interface_t* intf;
-       usb_interface_descriptor_t* intfd;
-       usb_endpoint_descriptor_t* epd;
+       struct usb_interface* intf;
+       struct usb_interface_descriptor* intfd;
+       struct usb_endpoint_descriptor* epd;
 
        if (endpoint->epnum == -1) {
                intf = umidi->iface;
@@ -980,8 +857,8 @@
 static int snd_usbmidi_detect_yamaha(snd_usb_midi_t* umidi, 
                                     snd_usb_midi_endpoint_info_t* endpoint)
 {
-       usb_interface_t* intf;
-       usb_interface_descriptor_t* intfd;
+       struct usb_interface* intf;
+       struct usb_interface_descriptor* intfd;
        uint8_t* cs_desc;
 
        intf = umidi->iface;
@@ -1014,9 +891,9 @@
 static int snd_usbmidi_create_endpoints_midiman(snd_usb_midi_t* umidi, int ports)
 {
        snd_usb_midi_endpoint_info_t ep_info;
-       usb_interface_t* intf;
-       usb_interface_descriptor_t* intfd;
-       usb_endpoint_descriptor_t* epd;
+       struct usb_interface* intf;
+       struct usb_interface_descriptor* intfd;
+       struct usb_endpoint_descriptor* epd;
        int cable, err;
 
        intf = umidi->iface;
@@ -1071,77 +948,65 @@
        }
 
        for (cable = 0; cable < ports; ++cable) {
-               int port = snd_usbmidi_create_port(umidi,
-                                                  umidi->endpoints[cable & 1].out,
-                                                  umidi->endpoints[0].in,
-                                                  cable, cable);
-               if (port < 0)
-                       return port;
-
-               if (cable < SNDRV_MINOR_RAWMIDIS) {
-                       int err = snd_usbmidi_create_virmidi(umidi, port, cable,
-                                                            
&umidi->endpoints[0].rmidi[cable]);
-                       if (err < 0)
-                               return err;
-               }
+               snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_OUTPUT, cable,
+                                          &umidi->endpoints[cable & 
+1].out->ports[cable].substream);
+               snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_INPUT, cable,
+                                          
+&umidi->endpoints[0].in->ports[cable].substream);
        }
        return 0;
 }
 
+static int snd_usbmidi_create_rawmidi(snd_usb_midi_t* umidi,
+                                     int out_ports, int in_ports)
+{
+       snd_rawmidi_t* rmidi;
+       int err;
+
+       err = snd_rawmidi_new(umidi->chip->card, "USB MIDI",
+                             umidi->chip->next_midi_device++,
+                             out_ports, in_ports, &rmidi);
+       if (err < 0)
+               return err;
+       strcpy(rmidi->name, umidi->chip->card->longname);
+       rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
+                           SNDRV_RAWMIDI_INFO_INPUT |
+                           SNDRV_RAWMIDI_INFO_DUPLEX;
+       rmidi->private_data = umidi;
+       rmidi->private_free = snd_usbmidi_rawmidi_free;
+       snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, 
+&snd_usbmidi_output_ops);
+       snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_usbmidi_input_ops);
+
+       umidi->rmidi = rmidi;
+       return 0;
+}
+
 /*
- * Initialize the sequencer device.
+ * Creates and registers everything needed for a MIDI streaming interface.
  */
-static int snd_usbmidi_seq_device_new(snd_seq_device_t* seq_device)
+int snd_usb_create_midi_interface(snd_usb_audio_t* chip,
+                                 struct usb_interface* iface,
+                                 const snd_usb_audio_quirk_t* quirk)
 {
        snd_usb_midi_t* umidi;
-       usb_device_t* dev;
-       snd_seq_client_callback_t client_callback;
-       snd_seq_client_info_t client_info;
        snd_usb_midi_endpoint_info_t endpoints[MIDI_MAX_ENDPOINTS];
+       int out_ports, in_ports;
        int i, err;
 
-       umidi = (snd_usb_midi_t*)SNDRV_SEQ_DEVICE_ARGPTR(seq_device);
-
-       memset(&client_callback, 0, sizeof(client_callback));
-       client_callback.allow_output = 1;
-       client_callback.allow_input = 1;
-       umidi->seq_client = snd_seq_create_kernel_client(umidi->chip->card, 0,
-                                                        &client_callback);
-       if (umidi->seq_client < 0)
-               return umidi->seq_client;
-
-       /* set the client name */
-       memset(&client_info, 0, sizeof(client_info));
-       client_info.client = umidi->seq_client;
-       client_info.type = KERNEL_CLIENT;
-       dev = umidi->chip->dev;
-       if (dev->descriptor.iProduct)
-               err = usb_string(dev, dev->descriptor.iProduct,
-                                client_info.name, sizeof(client_info.name));
-       else
-               err = 0;
-       if (err <= 0) {
-               if (umidi->quirk && umidi->quirk->product_name) {
-                       strncpy(client_info.name, umidi->quirk->product_name,
-                               sizeof(client_info.name) - 1);
-                       client_info.name[sizeof(client_info.name) - 1] = '\0';
-               } else {
-                       sprintf(client_info.name, "USB Device %#04x:%#04x",
-                               dev->descriptor.idVendor, dev->descriptor.idProduct);
-               }
-       }
-       snd_seq_kernel_client_ctl(umidi->seq_client,
-                                 SNDRV_SEQ_IOCTL_SET_CLIENT_INFO,
-                                 &client_info);
+       umidi = snd_magic_kcalloc(snd_usb_midi_t, 0, GFP_KERNEL);
+       if (!umidi)
+               return -ENOMEM;
+       umidi->chip = chip;
+       umidi->iface = iface;
+       umidi->quirk = quirk;
 
        /* detect the endpoint(s) to use */
        memset(endpoints, 0, sizeof(endpoints));
-       if (!umidi->quirk) {
+       if (!quirk) {
                err = snd_usbmidi_get_ms_info(umidi, endpoints);
        } else {
-               switch (umidi->quirk->type) {
+               switch (quirk->type) {
                case QUIRK_MIDI_FIXED_ENDPOINT:
-                       memcpy(&endpoints[0], umidi->quirk->data,
+                       memcpy(&endpoints[0], quirk->data,
                               sizeof(snd_usb_midi_endpoint_info_t));
                        err = snd_usbmidi_detect_endpoint(umidi, &endpoints[0]);
                        break;
@@ -1152,21 +1017,40 @@
                        err = 0;
                        break;
                default:
-                       snd_printd(KERN_ERR "invalid quirk type %d\n", 
umidi->quirk->type);
+                       snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
                        err = -ENXIO;
                        break;
                }
        }
+       if (err < 0) {
+               snd_magic_kfree(umidi);
+               return err;
+       }
 
-       /* create ports */
-       if (err >= 0) {
-               if (umidi->quirk && umidi->quirk->type == QUIRK_MIDI_MIDIMAN)
-                       err = snd_usbmidi_create_endpoints_midiman(umidi, 
(int)umidi->quirk->data);
-               else
-                       err = snd_usbmidi_create_endpoints(umidi, endpoints);
+       /* create rawmidi device */
+       if (quirk && quirk->type == QUIRK_MIDI_MIDIMAN) {
+               in_ports = out_ports = (int)quirk->data;
+       } else {
+               out_ports = 0;
+               in_ports = 0;
+               for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
+                       out_ports += snd_usbmidi_count_bits(endpoints[i].out_cables);
+                       in_ports += snd_usbmidi_count_bits(endpoints[i].in_cables);
+               }
+       }
+       err = snd_usbmidi_create_rawmidi(umidi, out_ports, in_ports);
+       if (err < 0) {
+               snd_magic_kfree(umidi);
+               return err;
        }
+
+       /* create endpoint/port structures */
+       if (quirk && quirk->type == QUIRK_MIDI_MIDIMAN)
+               err = snd_usbmidi_create_endpoints_midiman(umidi, (int)quirk->data);
+       else
+               err = snd_usbmidi_create_endpoints(umidi, endpoints);
        if (err < 0) {
-               snd_usbmidi_seq_device_delete(seq_device);
+               snd_usbmidi_free(umidi);
                return err;
        }
 
@@ -1176,22 +1060,3 @@
                                               GFP_KERNEL);
        return 0;
 }
-
-static int __init snd_usbmidi_module_init(void)
-{
-       static snd_seq_dev_ops_t ops = {
-               snd_usbmidi_seq_device_new,
-               snd_usbmidi_seq_device_delete
-       };
-
-       return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_USBMIDI, &ops,
-                                             sizeof(snd_usb_midi_t));
-}
-
-static void __exit snd_usbmidi_module_exit(void)
-{
-       snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_USBMIDI);
-}
-
-module_init(snd_usbmidi_module_init)
-module_exit(snd_usbmidi_module_exit)



-------------------------------------------------------
This sf.net emial is sponsored by: Influence the future of 
Java(TM) technology. Join the Java Community Process(SM) (JCP(SM)) 
program now. http://ad.doubleclick.net/clk;4699841;7576301;v?
http://www.sun.com/javavote
_______________________________________________
Alsa-cvslog mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/alsa-cvslog

Reply via email to