--- hid-core.c.orig	2005-06-05 16:42:34.867003480 -0700
+++ drivers/usb/input/hid-core.c	2005-06-05 16:46:00.432752736 -0700
@@ -1494,12 +1494,16 @@
 #define USB_VENDOR_ID_DELORME		0x1163
 #define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
 
+#define USB_VENDOR_ID_MAGTEK           0x0801
+#define USB_DEVICE_ID_MAGTEK_02                0x0002
+
 static struct hid_blacklist {
 	__u16 idVendor;
 	__u16 idProduct;
 	unsigned quirks;
 } hid_blacklist[] = {
 
+	{ USB_VENDOR_ID_MAGTEK, USB_DEVICE_ID_MAGTEK_02, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE },
--- Kconfig.orig	2005-06-05 16:42:10.984634152 -0700
+++ drivers/usb/serial/Kconfig	2005-06-05 16:44:01.155885576 -0700
@@ -361,6 +361,17 @@
           Note that you need a current CT-API.
           To compile this driver as a module, choose M here: the
 	  module will be called kobil_sct.
+config USB_SERIAL_MAGTEK
+       tristate "USB Magtek Card Swipe Reader"
+       depends on USB_SERIAL
+       ---help---
+         Say Y here if you want to use a USB Magtek Card Swipe Reader. This
+         module will create a USB serial device that uses the same protocol as
+         the Serial Magtek Card Swipe Reader.
+
+         To compile this driver as a module, choose M here: the
+         module will be called magtek.
+
 
 config USB_SERIAL_MCT_U232
 	tristate "USB MCT Single Port Serial Driver"
--- Makefile.orig	2005-06-05 16:42:17.007718504 -0700
+++ drivers/usb/serial/Makefile	2005-06-05 16:44:53.624909072 -0700
@@ -27,6 +27,7 @@
 obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA)		+= keyspan_pda.o
 obj-$(CONFIG_USB_SERIAL_KLSI)			+= kl5kusb105.o
 obj-$(CONFIG_USB_SERIAL_KOBIL_SCT)		+= kobil_sct.o
+obj-$(CONFIG_USB_SERIAL_MAGTEK)			+= magtek.o
 obj-$(CONFIG_USB_SERIAL_MCT_U232)		+= mct_u232.o
 obj-$(CONFIG_USB_SERIAL_OMNINET)		+= omninet.o
 obj-$(CONFIG_USB_SERIAL_PL2303)			+= pl2303.o
--- /dev/null	2005-04-06 06:07:23.000000000 -0700
+++ drivers/usb/serial/magtek.c	2005-06-05 16:39:57.369946672 -0700
@@ -0,0 +1,276 @@
+/*
+  MagTek USB Card Swipe Reader driver
+
+  Copyright 2005 Jesse Dutton <jessedutton@gmail.com>
+  
+  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 of the License, or
+  (at your option) any later version.
+
+  MagTek produces three versions of their card swipe reader. The serial version
+  and the USB keyboard version provide card stripe data with a '?' at the end
+  of each of three possible stripes, and a '\r' at the end of each card swipe.
+  Errors are indicated with a capital E. The third device, is called a USB HID
+  device by MagTek. It provides data over an interrup_in_urb. We mimic the
+  behaviour of the serial and keyboard devices by providing a serial tty that
+  produces the same kind of output. 
+
+*/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <linux/usb.h>
+#include "usb-serial.h"
+
+#define DRIVER_VERSION "v0.1"
+#define DRIVER_AUTHOR "Jesse Dutton <jessedutton@gmail.com>"
+#define DRIVER_DESC "Magtek USB HID Card Reader"
+
+static int  magtek_attach (struct usb_serial *serial);
+static void magtek_shutdown (struct usb_serial *serial);
+static int  magtek_open (struct usb_serial_port *port, struct file *filp);
+static void magtek_close (struct usb_serial_port *port, struct file *filp);
+static void magtek_read_int_callback (struct urb *urb, struct pt_regs *regs);
+
+// This macro spits a char out the tty. Assumes a var named tty is valid
+#define MAGTEK_OUT(c_out) if(tty->flip.count >= TTY_FLIPBUF_SIZE) { \
+	tty_flip_buffer_push(tty); }\
+	tty_insert_flip_char(tty, c_out, 0)
+
+#define MAGTEK_VENDOR 0x0801
+#define MAGTEK_PRODUCT 0x0002
+static struct usb_device_id magtek_ids [] = {
+	{ USB_DEVICE(MAGTEK_VENDOR, MAGTEK_PRODUCT) },
+	{ }
+};
+
+MODULE_DEVICE_TABLE (usb, magtek_ids);
+
+static struct usb_driver magtek_driver = {
+	.owner =	THIS_MODULE,
+	.name =		"magtek",
+	.probe =	usb_serial_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	magtek_ids,
+};
+
+static struct usb_serial_device_type magtek_device = {
+	.owner =		THIS_MODULE,
+	.name =			"Magtek USB HID Card Reader",
+	.short_name =		"magtek",
+	.id_table =		magtek_ids,
+	.num_interrupt_in =	1,
+	.num_bulk_in =		0,
+	.num_bulk_out =		0,
+	.num_ports =		1,
+	.open =			magtek_open,
+	.close =		magtek_close,
+	.read_int_callback =	magtek_read_int_callback,
+	.attach =		magtek_attach,
+	.shutdown =		magtek_shutdown,
+};
+
+
+struct magtek_private {
+	short	offset;
+	short	skip;
+	short	track1_error;
+	short	track2_error;
+	short	track3_error;
+	
+};
+
+static int magtek_attach (struct usb_serial *serial)
+{
+	struct magtek_private *priv;
+
+	priv = kmalloc(sizeof(struct magtek_private), GFP_KERNEL);
+	if (!priv)
+		return (-1);
+	priv->offset=-1;
+	priv->skip=1;
+
+	// only one port
+	usb_set_serial_port_data(serial->port[0], priv);
+	
+	return (0);
+}
+
+
+static void magtek_shutdown (struct usb_serial *serial)
+{
+	struct magtek_private *priv;
+	int i;
+	
+	for (i=0; i < serial->num_ports; ++i) {
+		priv = usb_get_serial_port_data(serial->port[i]);
+		if (priv)
+			kfree(priv);
+	}
+}
+
+
+static int  magtek_open (struct usb_serial_port *port, struct file *filp)
+{
+	int retval = 0;
+
+	port->interrupt_in_urb->dev = port->serial->dev;
+	retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+	if (retval) {
+		usb_unlink_urb(port->read_urb);
+		err("%s -- usb_submit_urb(read int) failed", __FUNCTION__);
+	}
+
+	return retval;
+}
+
+
+static void magtek_close (struct usb_serial_port *port, struct file *filp)
+{
+	usb_unlink_urb (port->interrupt_in_urb);
+}
+
+
+static void magtek_read_int_callback (struct urb *urb, struct pt_regs *regs)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct magtek_private *priv;
+	unsigned char *data = urb->transfer_buffer;
+	struct tty_struct *tty;
+	int i,retval,len;
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		return;
+	default:
+		goto exit;
+	}
+
+	priv = usb_get_serial_port_data(port);
+	if (!priv){
+		err("%s -- strange, private data is lost.\n", __FUNCTION__);
+		goto exit;
+	}
+
+	// copy data to tty device
+        tty = port->tty;
+	// make sure there is data
+	len = urb->actual_length;
+	if (len) {
+		// get status fields out of data stream
+		if (priv->offset == -1 || (len > 7 && data[7]=='%')){
+			priv->skip=1;		// don't output status info
+			priv->offset=-1;	// reset the offset counter
+			priv->track1_error = data[0];
+			priv->track2_error = data[1];
+			priv->track3_error = data[2];
+		}
+		// the data comes 8 bytes at a time, but forms a 336 byte
+		// logical packet. Hence the offset stuff.
+		for (i = 0; i < len ; i++) {
+			// figure out where the stream ends
+			priv->offset++;
+			if (priv->offset == 336 && !priv->skip){
+				// to make it work like the serial version,
+				// we spit out CR. It would make more sense to
+				// use a \n in my opinion, but interoperability
+				// is better.
+				MAGTEK_OUT('\r');
+				priv->offset=-1;
+				continue;
+			}
+			
+			// look for start byte
+			if (priv->skip && i==7 && data[i]=='%'){
+				priv->skip=0;
+			}
+
+			// insert error markers
+			if (priv->offset == 7 && priv->track1_error){
+				MAGTEK_OUT('%');
+				MAGTEK_OUT('E');
+				MAGTEK_OUT('?');
+			}
+			if (priv->offset == 117 && priv->track2_error){
+				MAGTEK_OUT(';');
+				MAGTEK_OUT('E');
+				MAGTEK_OUT('?');
+			}
+			if (priv->offset == 227 && priv->track3_error){
+				MAGTEK_OUT('%');
+				MAGTEK_OUT('E');
+				MAGTEK_OUT('?');
+				// output the line ending here, since the
+				// device will sometimes truncate the data when
+				// an error happens on track 3.
+				MAGTEK_OUT('\r');
+				priv->skip=1;
+			}
+			
+			// some logic to skip null or garbage parts
+			if (data[i] < 32 || data[i] > 126){
+				continue;
+			}
+			if (!priv->skip){
+				MAGTEK_OUT(data[i]);
+			}
+		}
+		tty_flip_buffer_push(tty);
+	} else {
+		err("%s -- zero length urb", __FUNCTION__);
+	}
+
+exit:
+	retval = usb_submit_urb (urb, GFP_ATOMIC);
+	if (retval)
+		err ("%s - usb_submit_urb failed with result %d",
+		     __FUNCTION__, retval);
+}
+
+static int __init magtek_init (void)
+{
+	int retval;
+	retval = usb_serial_register(&magtek_device);
+	if (retval)
+		goto failed_usb_serial_register;
+	retval = usb_register(&magtek_driver);
+	if (retval)
+		goto failed_usb_register;
+	info(DRIVER_DESC " " DRIVER_VERSION);
+	return 0;
+failed_usb_register:
+	usb_serial_deregister(&magtek_device);
+failed_usb_serial_register:
+	return retval;
+}
+
+
+static void __exit magtek_exit (void)
+{
+	usb_deregister (&magtek_driver);
+	usb_serial_deregister (&magtek_device);
+}
+
+
+module_init (magtek_init);
+module_exit (magtek_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+
