--- linux-2.6.10/drivers/usb/input/hid-core.c.novation	2004-12-24 16:34:58.000000000 -0500
+++ linux-2.6.10/drivers/usb/input/hid-core.c	2005-01-19 23:03:05.000000000 -0500
@@ -1469,6 +1469,9 @@
 #define USB_VENDOR_ID_DELORME		0x1163
 #define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
 
+#define USB_VENDOR_ID_NOVATION          0x1235
+#define USB_DEVICE_ID_NOVATION_XSTATION 0x0001
+
 static struct hid_blacklist {
 	__u16 idVendor;
 	__u16 idProduct;
@@ -1558,6 +1561,7 @@
 	{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28, HID_QUIRK_IGNORE },
 
 	{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_NOVATION, USB_DEVICE_ID_NOVATION_XSTATION, HID_QUIRK_IGNORE },
 
 	{ 0, 0 }
 };
--- linux-2.6.10/sound/usb/usbaudio.h.novation	2004-12-24 16:35:00.000000000 -0500
+++ linux-2.6.10/sound/usb/usbaudio.h	2005-01-21 21:40:32.000000000 -0500
@@ -157,6 +157,7 @@
 #define QUIRK_MIDI_STANDARD_INTERFACE	6
 #define QUIRK_AUDIO_EDIROL_UA700_UA25	7
 #define QUIRK_AUDIO_EDIROL_UA1000	8
+#define QUIRK_MIDI_NOVATION             9
 
 typedef struct snd_usb_audio_quirk snd_usb_audio_quirk_t;
 typedef struct snd_usb_midi_endpoint_info snd_usb_midi_endpoint_info_t;
@@ -190,6 +191,8 @@
 
 /* for QUIRK_AUDIO_EDIROL_UA700_UA25/UA1000, data is NULL */
 
+/* for QUIRK_AUDIO_NOVATION is like QUIRK_MIDI_MIDIMAN but is its
+ *  own quirk so that we can hook special input and output handling */
 /*
  */
 
--- linux-2.6.10/sound/usb/usbmidi.c.novation	2004-12-24 16:35:27.000000000 -0500
+++ linux-2.6.10/sound/usb/usbmidi.c	2005-01-21 22:11:28.000000000 -0500
@@ -201,6 +201,42 @@
 }
 
 /*
+ *  Novation complete routine.  We don't have to depacketize
+ *   this stuff, just shovel it straight up into rawmidi
+ */
+
+static void
+snd_usbmidi_in_nova_complete( struct urb* urb, struct pt_regs *regs )
+{
+	snd_usb_midi_in_endpoint_t* ep = urb->context;
+	uint8_t* tbp = (uint8_t*) urb->transfer_buffer;
+
+/* 	printk( "NovaInComplete: urb->status: %d\n", urb->status ); */
+
+	if( urb->status == 0 ) {
+		usbmidi_in_port_t* port = &ep->ports[0]; /* cable == 0 */
+
+		if (!port->substream) {
+			snd_printd("unexpected port %d!\n", cable);
+			return;
+		}
+		if (!port->substream->runtime ||
+		    !port->substream->runtime->trigger)
+			return;
+		
+		snd_rawmidi_receive(port->substream, tbp+2, tbp[0]-1);
+		if (snd_usbmidi_urb_error(urb->status) < 0)
+			return;
+  
+		if (usb_pipe_needs_resubmit(urb->pipe)) {
+			urb->dev = ep->umidi->chip->dev;
+			snd_usbmidi_submit_urb( urb, GFP_ATOMIC );
+		}
+	}
+}
+/* end Novation Input */
+
+/*
  * Converts the data read from a Midiman device to standard USB MIDI packets.
  */
 static void snd_usbmidi_in_midiman_complete(struct urb* urb, struct pt_regs *regs)
@@ -390,6 +426,53 @@
 }
 
 /*
+ * shovel out raw MIDI commands as Novation MIDI-over-USB packets
+ */
+
+static void
+novadump( uint8_t *p ) {
+	int i, n;
+
+	printk( "NovaXmit: %d (", n = *++p );
+
+	for( i = 0; i < n; ++i ) {
+		printk( " 0x%2x", *++p );
+	}
+	printk( " )\n" );
+
+}
+
+static void 
+snd_usbmidi_transmit_novation( snd_usb_midi_out_endpoint_t* ep, int port_idx)
+{
+	struct urb* urb = ep->urb;
+	usbmidi_out_port_t* port = &ep->ports[port_idx];
+	uint8_t* tbp = (uint8_t *) urb->transfer_buffer;
+	int sent;
+	
+	/* Novation devices expect to see us send packets like so:
+	 *  [unused][count][MIDIbyte1]...[MIDIbyteN]
+	 *
+	 *  where N is either 12 or 30.
+	 */
+/* 	printk( "Nova XMIT: port = %d\n", port_idx ); */
+
+	/* initialize the dummy byte on the front */
+	*tbp = 0;
+	sent = ep->max_transfer - 2;	/* sent should be 12 or 30  */
+	if( (sent =
+	     snd_rawmidi_transmit_peek(port->substream, tbp+2, sent)) <= 0 ) {
+		port->active = 0;
+		return;
+	}
+	tbp[1] = (uint8_t) sent;
+/* 	novadump( tbp ); */
+	urb->transfer_buffer_length += sent + 2;
+	snd_rawmidi_transmit_ack(port->substream, sent);
+}
+/* End Novation output */
+
+/*
  * This is called when some data should be transferred to the device
  * (from one or more substreams).
  */
@@ -398,6 +481,8 @@
 	int p;
 	struct urb* urb = ep->urb;
 	unsigned long flags;
+	void (*xmitter)(snd_usb_midi_out_endpoint_t*, int) =
+		snd_usbmidi_transmit;
 
 	spin_lock_irqsave(&ep->buffer_lock, flags);
 	if (urb->status == -EINPROGRESS || ep->umidi->chip->shutdown) {
@@ -405,10 +490,13 @@
 		return;
 	}
 
+	if( ep->umidi->quirk && ep->umidi->quirk->type == QUIRK_MIDI_NOVATION )
+		xmitter = snd_usbmidi_transmit_novation;
+	
 	urb->transfer_buffer_length = 0;
 	for (p= 0; p < 0x10; ++p)
 		if (ep->ports[p].active)
-			snd_usbmidi_transmit(ep, p);
+			xmitter(ep,p);
 
 	if (urb->transfer_buffer_length > 0) {
 		if (ep->umidi->quirk && ep->umidi->quirk->type == QUIRK_MIDI_MIDIMAN)
@@ -515,7 +603,7 @@
  * For Roland devices, use the alternate setting which uses interrupt
  * transfers for input.
  */
-static struct usb_endpoint_descriptor* snd_usbmidi_get_int_epd(snd_usb_midi_t* umidi)
+static struct usb_endpoint_descriptor* snd_usbmidi_get_roland_int_epd(snd_usb_midi_t* umidi)
 {
 	struct usb_interface* intf;
 	struct usb_host_interface *hostif;
@@ -548,7 +636,7 @@
 	return get_endpoint(hostif, 1);
 }
 
-static struct usb_endpoint_descriptor* snd_usbmidi_get_midiman_int_epd(snd_usb_midi_t* umidi)
+static struct usb_endpoint_descriptor* snd_usbmidi_get_int_epd(snd_usb_midi_t* umidi)
 {
 	struct usb_interface* intf = umidi->iface;
 	struct usb_host_interface *hostif;
@@ -574,6 +662,7 @@
 	void* buffer;
 	unsigned int pipe;
 	int length;
+	usb_complete_t complete_fn = snd_usbmidi_in_urb_complete;
 
 	rep->in = NULL;
 	ep = kcalloc(1, sizeof(*ep), GFP_KERNEL);
@@ -581,10 +670,22 @@
 		return -ENOMEM;
 	ep->umidi = umidi;
 
-	if (umidi->quirk && umidi->quirk->type == QUIRK_MIDI_MIDIMAN)
-		int_epd = snd_usbmidi_get_midiman_int_epd(umidi);
+	if( umidi->quirk )
+		switch( umidi->quirk->type ) {
+		/* both MIDIMAN and NOVATION use interrupt transfers */
+		case QUIRK_MIDI_NOVATION:
+			complete_fn = snd_usbmidi_in_nova_complete;
+		case QUIRK_MIDI_MIDIMAN:
+			int_epd = snd_usbmidi_get_int_epd(umidi);
+			break;
+		default:
+			/* Only Roland (Edirol...) will return non-NULL */
+			int_epd = snd_usbmidi_get_roland_int_epd(umidi);
+			break;
+		}
 	else
-		int_epd = snd_usbmidi_get_int_epd(umidi);
+		/* Only Non-quirky Roland (Edirol...) will return non-NULL */
+		int_epd = snd_usbmidi_get_roland_int_epd(umidi);
 
 	ep->urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!ep->urb) {
@@ -602,13 +703,14 @@
 		return -ENOMEM;
 	}
 	if (int_epd)
-		usb_fill_int_urb(ep->urb, umidi->chip->dev, pipe, buffer, length,
-				 snd_usb_complete_callback(snd_usbmidi_in_urb_complete),
-				 ep, int_epd->bInterval);
+		usb_fill_int_urb(ep->urb, umidi->chip->dev, pipe,
+				 buffer, length,
+				 snd_usb_complete_callback(complete_fn), ep,
+				 int_epd->bInterval);
 	else
-		usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer, length,
-				  snd_usb_complete_callback(snd_usbmidi_in_urb_complete),
-				  ep);
+		usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe,
+				  buffer, length,
+				  snd_usb_complete_callback(complete_fn), ep);
 
 	rep->in = ep;
 	return 0;
@@ -977,6 +1079,7 @@
 	struct usb_interface_descriptor* intfd;
 	struct usb_endpoint_descriptor* epd;
 	int i;
+	int xtype = USB_ENDPOINT_XFER_BULK;
 
 	intf = umidi->iface;
 	if (!intf || intf->num_altsetting < 1)
@@ -986,9 +1089,13 @@
 	if (intfd->bNumEndpoints < 1)
 		return -ENOENT;
 
+	if( umidi->quirk && umidi->quirk->type == QUIRK_MIDI_NOVATION ) {
+		xtype = USB_ENDPOINT_XFER_INT;
+	}
+
 	for (i = 0; i < intfd->bNumEndpoints; ++i) {
 		epd = get_endpoint(hostif, i);
-		if ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK)
+		if ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != xtype)
 			continue;
 		if (!endpoint->out_ep && endpoint->out_cables &&
 		    (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
@@ -1212,6 +1319,7 @@
 		err = snd_usbmidi_get_ms_info(umidi, endpoints);
 	} else {
 		switch (quirk->type) {
+		case QUIRK_MIDI_NOVATION:
 		case QUIRK_MIDI_FIXED_ENDPOINT:
 			memcpy(&endpoints[0], quirk->data,
 			       sizeof(snd_usb_midi_endpoint_info_t));
@@ -1225,6 +1333,7 @@
 			       sizeof(snd_usb_midi_endpoint_info_t));
 			err = 0;
 			break;
+
 		default:
 			snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
 			err = -ENXIO;
--- linux-2.6.10/sound/usb/usbquirks.h.novation	2004-12-24 16:34:32.000000000 -0500
+++ linux-2.6.10/sound/usb/usbquirks.h	2005-01-21 21:39:07.000000000 -0500
@@ -133,6 +133,89 @@
 #undef YAMAHA_DEVICE
 #undef YAMAHA_INTERFACE
 
+/* Novation Interfaces
+ *  implementation by RedHat, Inc, and Focusrite, Ltd
+ *                    (ccb@redhat.com, nick@focusrite.com)
+ *
+ * Novation devices have a proprietary OnTheWire MIDI protocol
+ *  and use interrupt transfers instead of bulk, similar to MIDIMAN
+ */
+#define NOVATION_DEVICE( PROD, SUBCLASS )             \
+  .match_flags = USB_DEVICE_ID_MATCH_VENDOR |         \
+	         USB_DEVICE_ID_MATCH_PRODUCT |        \
+	         USB_DEVICE_ID_MATCH_INT_CLASS |      \
+	         USB_DEVICE_ID_MATCH_INT_SUBCLASS,    \
+  .idVendor = 0x1235,                                 \
+  .idProduct = PROD,                                  \
+  .bInterfaceClass = USB_CLASS_VENDOR_SPEC,           \
+  .bInterfaceSubClass = SUBCLASS
+
+/* Novation X-Station and Novation ReMOTE 25 Audio are the same device
+ *  with different firmware and are indistinguishable.
+ *
+ * DO upgrade your ReMOTE25 Audio to X-Station.  It adds a 3-oscillator
+ *  8-way poly monotimbral synth with arpeggiator to an already sweet
+ *  Audio/MIDI device.  Upgrade is a free download from
+ *  www.novationmusic.com
+ *
+ * There are also X-Station 49 (49 keys) and X-Station 61 using the same
+ *  firmware.  I don't have these so it's untested.
+ */
+{
+	NOVATION_DEVICE( 0x0001, 0 ),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Novation Digital Music Systems, Ltd.",
+		.product_name = "ReMOTE 25 Audio/X-Station",
+		.ifnum = 4,
+		.type = QUIRK_MIDI_NOVATION,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x0001,
+			.in_cables  = 0x0001
+		}
+	}
+},
+
+/* Speedio is an Audio+MIDI device similar to the ReMOTE 25 Audio
+ *  absent the keyboard, control surface and dual effects processors.
+ * Untested.
+ */
+{
+	NOVATION_DEVICE( 0x0002, 0 ),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Novation Digital Music Systems, Ltd.",
+		.product_name = "Speedio",
+		.ifnum = 3,
+		.type = QUIRK_MIDI_NOVATION,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x0001,
+			.in_cables  = 0x0001
+		}
+	}
+},
+
+/* ReMOTE 25 is a MIDI keyboard controller and control surface
+ *  Like the X-Station you can program templates for controlling
+ *  any MIDI controllable studio application.  There are no
+ *  audio interfaces nor can it operate as a KS-class synth.
+ *
+ * Untested.
+ */
+{
+	NOVATION_DEVICE( 0x4661, 0 ),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Novation Digital Music Systems, Ltd.",
+		.product_name = "ReMOTE 25 (MIDI Only)",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_NOVATION,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.out_cables = 0x0001,
+			.in_cables  = 0x0001
+		}
+	}
+},
+
+/* End Novation Config */
+
 /*
  * Roland/RolandED/Edirol/BOSS devices
  */
