Danny Rathjens asked:

Did you ever get this working? I couldn't find anything later than your
post to linux-usb-devel last year asking for help debugging the driver
you based on usb-skeleton.
I tried using that driver and it seems that the device is not even
being registered properly.(-ENODEV after attempting to get data from minor_table)
I am kind of a kernel newbie, but I am aware that a few changes were
made to the usb subsystem in 2.4.20 because I had to modify a touchscreen
driver to use the new usb_ctrlrequest struct, but I am not sure how
the changes affect the magtek.


Shawn Campbell replied:

I did get my driver working and it has been in production for about a year now. When I call read() against the device, I must always read the exact size of the report sent from the device. The driver doesn't crash the kernel if you don't read the exact amount, you just don't get all of the data you want. I am using the driver with a 2.4.20 kernel right now and it works. I did not test the driver on an SMP system. I did not implements ioctls for accessing some of the device features like the serial number option. I plan on rewriting the driver this summer and trying to get it into the main kernel. I have attached the driver source and the Makefile that I use to build it. Let me know if it is helpful.

Shawn Campbell says to linux-usb-devel:

I received a request concerning my progress with a driver for a USB HID magtek swipe reader. After asking questions on this mailing list and reading Linux Device Drivers 2nd Edition, I was able to post a broken driver to this list. The input I received on what I was doing wrong in my driver helped me to get the driver working for my purposes. I was not able to test the driver in an SMP scenario. The driver does not provide complete functionality for the device since the device has two parameters that can be set/get, probably best through ioctl calls. To get complete data back from the device, a read the exact size of the report must be issued which seems undesireable, but I am not sure what good behavior would be in this situation. I am open to suggestions. I also wasn't sure what to put in the driver comments, so I put whatever I felt inspired to. I could not have developed the driver without the usb skeleton driver and the help of this list. Since I have received a request for a working copy of the driver, I decided to post the source on the list so others will have access to it. The magtek readers themselves are only around $75/unit and if someone else is able to rewrite the driver to make it kernel worthy, that would be great. I am hoping I get the chance to do so as well. I am going to take out the email addresses in the source below since the list is public. I hope this helps someone.

Makefile:

# Change it here or specify it on the "make" command line
KERNELDIR = /usr/src/linux

include $(KERNELDIR)/.config

CFLAGS = -D__KERNEL__ -DMODULE -I$(KERNELDIR)/include -O -Wall

ifdef CONFIG_SMP
        CFLAGS += -D__SMP__ -DSMP
endif

all: magtek.o

magtek.c:

/*
* USB Magtek Swipe Reader Device Driver
*
* Created by Shawn Campbell from the usb-skeleton
* driver created by Greg Kroah-Hartman.
*
* Special thanks to Greg Kroah-Hartman, Paul Stewart, and Oliver Neukum
* for all of there assistance in helping me develop a driver for the
* Magtek USB Swipe Reader.
*
* For anyone wanting to get into driver development, I recommend
* Linux Device Drivers (2nd edition or newer) for kernel 2.4.x development.
* I also recommend reading the USB 1.1 specification and the HID specification
* (available as a pdf). I also recommend the irc channel and website kernelnewbies
* and the mailing list [EMAIL PROTECTED] Happy kernel
* developing.
*
* USB Skeleton driver - 0.6
*
* Copyright (c) 2001 Greg Kroah-Hartman
*
* 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.
*
*
* This driver is to be used as a skeleton driver to be able to create a
* USB driver quickly. The design of it is based on the usb-serial and
* dc2xx drivers.
*
* Thanks to Oliver Neukum and David Brownell for their help in debugging
* this driver.
*
* TODO:
* - fix urb->status race condition in write sequence
* - move minor_table to a dynamic list.
*
* History:
*
* 2001_11_05 - 0.6 - fix minor locking problem in skel_disconnect.
* Thanks to Pete Zaitcev for the fix.
* 2001_09_04 - 0.5 - fix devfs bug in skel_disconnect. Thanks to wim delvaux
* 2001_08_21 - 0.4 - more small bug fixes.
* 2001_05_29 - 0.3 - more bug fixes based on review from linux-usb-devel
* 2001_05_24 - 0.2 - bug fixes based on review from linux-usb-devel people
* 2001_05_01 - 0.1 - first version
*
*/


#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/smp_lock.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/usb.h>

#ifdef CONFIG_USB_DEBUG
        static int debug = 1;
#else
        static int debug = 0;
#endif

/* Use our own dbg macro */
#undef dbg
#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0)



/* Version Information */ #define DRIVER_VERSION "v0.1" #define DRIVER_AUTHOR "Greg Kroah-Hartman" #define DRIVER_DESC "USB Magtek Swipe Reader"

/* Module paramaters */
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Debug enabled or not");


/* Define these values to match your device */ #define USB_MAGTEK_VENDOR_ID 0x0801 #define USB_MAGTEK_PRODUCT_ID 0x0002

/* This character should never appear in a report from the device
 * The character is used to decide where one report ends and
 * begins.
*/
static const char USB_NEW_REPORT = 255;

/* table of devices that work with this driver */
static struct usb_device_id magtek_table [] = {
        { USB_DEVICE(USB_MAGTEK_VENDOR_ID, USB_MAGTEK_PRODUCT_ID) },
        { }                                     /* Terminating entry */
};

MODULE_DEVICE_TABLE (usb, magtek_table);


/* Get a minor range for your devices from the usb maintainer */ #define USB_MAGTEK_MINOR_BASE 200

/* we can have up to this number of device plugged in at once */
#define MAX_DEVICES             16

/* define alpha/beta buffer size */
#define USB_ALPHA_BUFFER_SIZE 64
#define USB_BETA_BUFFER_SIZE 512

/* Structure to hold all of our device specific stuff */
struct usb_magtek {
struct usb_device * udev; /* save off the usb device pointer */
devfs_handle_t devfs; /* devfs device node */
unsigned char minor; /* the starting minor number for this device */


unsigned char alpha_buffer[USB_ALPHA_BUFFER_SIZE]; /* the buffer to receive data from the device */
unsigned char beta_buffer[USB_BETA_BUFFER_SIZE]; /* ship to process buffer */
int data_size; /* size of the data in the buffer */
int packet_size; /* size of the packets returned by usb device */
struct urb* urb; /* urb for this device */


int report_flag; /* full report present? */
int open_count; /* number of times this port has been opened */
int disconnect_flag; /* flag to wake up on disconnect */
spinlock_t lock; /* locks this structure */


};


/* the global usb devfs handle */ extern devfs_handle_t usb_devfs_handle;


/* local function prototypes */
static ssize_t magtek_read (struct file *file, char *buffer, size_t count, loff_t *ppos);
static int magtek_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
static int magtek_open (struct inode *inode, struct file *file);
static int magtek_release (struct inode *inode, struct file *file);


static void * magtek_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id);
static void magtek_disconnect (struct usb_device *dev, void *ptr);
static void magtek_irq (struct urb *urb);


/* array of pointers to our devices that are currently connected */
static struct usb_magtek        *minor_table[MAX_DEVICES];

/* lock to protect the minor_table structure */
static DECLARE_MUTEX (minor_table_mutex);

/* declare a wait queue */
static DECLARE_WAIT_QUEUE_HEAD(queue);

/*
 * File operations needed when we register this driver.
 * This assumes that this driver NEEDS file operations,
 * of course, which means that the driver is expected
 * to have a node in the /dev directory. If the USB
 * device were for a network interface then the driver
 * would use "struct net_driver" instead, and a serial
 * device would use "struct tty_driver".
 */
static struct file_operations magtek_fops = {
        /*
        * The owner field is part of the module-locking
        * mechanism. The idea is that the kernel knows
        * which module to increment the use-counter of
        * BEFORE it calls the device's open() function.
        * This also means that the kernel can decrement
        * the use-counter again before calling release()
        * or should the open() function fail.
        *
        * Not all device structures have an "owner" field
        * yet. "struct file_operations" and "struct net_device"
        * do, while "struct tty_driver" does not. If the struct
        * has an "owner" field, then initialize it to the value
        * THIS_MODULE and the kernel will handle all module
        * locking for you automatically. Otherwise, you must
        * increment the use-counter in the open() function
        * and decrement it again in the release() function
        * yourself.
        */
        owner:          THIS_MODULE,

        read:           magtek_read,
        ioctl:          magtek_ioctl,
        open:           magtek_open,
        release:        magtek_release,
};


/* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver magtek_driver = { name: "magtek", probe: magtek_probe, disconnect: magtek_disconnect, fops: &magtek_fops, minor: USB_MAGTEK_MINOR_BASE, id_table: magtek_table, };

/**
 *      magtek_irq
 */
static void magtek_irq(struct urb* urb)
{
        struct usb_magtek* priv = urb->context;

        if(urb->status != USB_ST_NOERROR) return;
        if(urb->actual_length < 0) return;

spin_lock(&priv->lock);

        /* previous report cleared? */
        if(priv->report_flag) {
                priv->report_flag=0;
                priv->data_size=0;
                err("Lost a report!");
        }

/* check for buffer overflow */
/* NOTE: Increase USB_BETA_BUFFER_SIZE to equal or exceed your report size */
else if((priv->data_size + urb->actual_length) > USB_BETA_BUFFER_SIZE) {
/* data too big */
err("Beta Buffer Overflow!");
priv->data_size=0;
spin_unlock(&priv->lock);
return;
}


        /* copy report fragment */
        
memcpy(priv->beta_buffer+priv->data_size,priv->alpha_buffer,urb->actual_length);
        priv->data_size = priv->data_size + urb->actual_length;

        /* notify any processes */
        if(urb->actual_length < priv->packet_size) {
                priv->report_flag=1;
                wake_up_interruptible(&queue);
        }

        spin_unlock(&priv->lock);
}

/**
 *      magtek_open
 */
static int magtek_open (struct inode *inode, struct file *file)
{
        struct usb_magtek *dev = NULL;
        int subminor;

        subminor = MINOR (inode->i_rdev) - USB_MAGTEK_MINOR_BASE;
        if ((subminor < 0) ||
            (subminor >= MAX_DEVICES)) {
                return -ENODEV;
        }

        /* lock our minor table and get our local data for this minor */
        down (&minor_table_mutex);
        dev = minor_table[subminor];
        if (dev == NULL) {
                up (&minor_table_mutex);
                return -ENODEV;
        }

        /* unlock the minor table */
        up (&minor_table_mutex);

        /* lock this device */
        spin_lock(&dev->lock);

        if(dev->open_count) {
                /* device already open by another process */
                spin_unlock(&dev->lock);
                return -EBUSY;
        }

        /* increment our usage count for the driver */
        ++dev->open_count;

        /* save our object in the file's private structure */
        file->private_data = dev;

        /* unlock this device */
        spin_unlock(&dev->lock);

        return 0;
}


/** * magtek_release */ static int magtek_release (struct inode *inode, struct file *file) { struct usb_magtek *dev; int retval = 0;

        dev = (struct usb_magtek *)file->private_data;
        if (dev == NULL) {
                if(debug) dbg (__FUNCTION__ " - object is NULL");
                return -ENODEV;
        }

if(debug) dbg(__FUNCTION__ " - minor %d", dev->minor);

        /* lock our minor table */
        down (&minor_table_mutex);

        /* lock our device */
        spin_lock (&dev->lock);

        if (dev->open_count <= 0) {
                if(debug) dbg (__FUNCTION__ " - device not opened");
                retval = -ENODEV;
                goto exit_not_opened;
        }

        if (dev->udev == NULL) {
                /* the device was unplugged before the file was released */
                if(dev->urb) kfree(dev);
                retval = -ENODEV;
        }
        else {
                /* decrement our usage count for the device */
                --dev->open_count;
        }


exit_not_opened: spin_unlock (&dev->lock); up (&minor_table_mutex);

        return retval;
}


/**
* magtek_read
*/
static ssize_t magtek_read (struct file *file, char *buffer, size_t count, loff_t *ppos)
{
struct usb_magtek *dev;
unsigned long flags;
ssize_t size;


        /* any non-zero seek is invalid */
        if(*ppos) return -ESPIPE;

        /* buffer too small */
        if(count < 1) return -EFAULT;

dev = (struct usb_magtek *)file->private_data;

if(debug) dbg(__FUNCTION__ " - ppos %d, minor %d, count = %d", (int)(*ppos), dev->minor, count);

        /* lock this object */
        spin_lock_irqsave(&dev->lock,flags);

        /* verify that the device wasn't unplugged */
        if (dev->udev == NULL) {
                spin_unlock_irqrestore (&dev->lock,flags);
                return -ENODEV;
        }

        /* unlock this object */
        spin_unlock_irqrestore(&dev->lock,flags);

/* sleep until data or signal */
if(wait_event_interruptible(queue, dev->report_flag || dev->disconnect_flag)) return -EINTR;


        /* was device disconnected? */
        if(dev->disconnect_flag) return -EIO;


/* ensure that only the correct number of bytes are copied back */ spin_lock_irqsave(&dev->lock,flags);

        if(((ssize_t)dev->data_size < (ssize_t)count)) {
                /* normal */
                size=(ssize_t)dev->data_size;
        }
        else {
                /* too much data, data lost */
                err("Data was lost!");
                size=(ssize_t)count;
        }

spin_unlock_irqrestore(&dev->lock,flags);

        /* copy data to userspace */
        if (copy_to_user (buffer, dev->beta_buffer, (unsigned long)size))
        {
                spin_unlock_irqrestore(&dev->lock,flags);
                return -EFAULT;
        }

spin_lock_irqsave(&dev->lock,flags);

        dev->data_size=0; /* mark the buffer as empty */
        dev->report_flag=0; /* indicate that reported was received */

        /* unlock the device */
        spin_unlock_irqrestore (&dev->lock,flags);

        return size;
}

/**
* magtek_ioctl
*/
static int magtek_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
struct usb_magtek *dev;
unsigned long flags;


dev = (struct usb_magtek *)file->private_data;

        /* lock this object */
        spin_lock_irqsave (&dev->lock,flags);

        /* verify that the device wasn't unplugged */
        if (dev->udev == NULL) {
                spin_unlock_irqrestore (&dev->lock,flags);
                return -ENODEV;
        }

        if(debug) dbg(__FUNCTION__ " - minor %d, cmd 0x%.4x, arg %ld",
            dev->minor, cmd, arg);


/* fill in your device specific stuff here */


        /* unlock the device */
        spin_unlock_irqrestore (&dev->lock,flags);

        /* return that we did not understand this ioctl call */
        return -ENOTTY;
}


/**
* magtek_probe
*
* Called by the usb core when a new device is connected that it thinks
* this driver might be interested in.
*/
static void * magtek_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
{
struct usb_magtek *dev = NULL;
struct usb_interface *interface;
struct usb_interface_descriptor *iface_desc;
struct usb_endpoint_descriptor *endpoint;
int minor;
int i;
char name[10];
int pipe, maxp;


        /* See if the device offered us matches what we can accept */
        if ((udev->descriptor.idVendor != USB_MAGTEK_VENDOR_ID) ||
            (udev->descriptor.idProduct != USB_MAGTEK_PRODUCT_ID)) {
                return NULL;
        }

/* select a "subminor" number (part of a minor number) */
down (&minor_table_mutex);
for (minor = 0; minor < MAX_DEVICES; ++minor) {
if (minor_table[minor] == NULL)
break;
}
if (minor >= MAX_DEVICES) {
info ("Too many devices plugged in, can not handle this device.");
up(&minor_table_mutex);
return NULL;
}


        /* allocate memory for our device state and intialize it */
        dev = kmalloc (sizeof(struct usb_magtek), GFP_KERNEL);
        if (dev == NULL) {
                err ("Out of memory");
                up(&minor_table_mutex);
                return NULL;
        }

        /* zero the data structure (note:  dev->data is set to zero here) */
        memset(dev,0,sizeof(struct usb_magtek));

interface = &udev->actconfig->interface[ifnum];

        /* setup device specific data structure */
        dev->udev = udev;
        /* dev->interface = interface; */
        dev->minor = minor;

        /* set up the endpoint information */
        /* check out the endpoints */
        iface_desc = &interface->altsetting[0];
        for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
                endpoint = &iface_desc->endpoint[i];

if ((endpoint->bEndpointAddress & 0x80) && ((endpoint->bmAttributes & 3) == 0x03))
break; /* we found an interrupt in endpoint */
}
if(i>=iface_desc->bNumEndpoints){
info("No supported endpoints found.");
up(&minor_table_mutex);
kfree(dev);
return NULL;
}


        /* initialize the devfs node for this device and register it */
        sprintf(name, "magtek%d", dev->minor);

        dev->devfs = devfs_register (usb_devfs_handle, name,
                                     DEVFS_FL_DEFAULT, USB_MAJOR,
                                     USB_MAGTEK_MINOR_BASE + dev->minor,
                                     S_IFCHR | S_IRUSR | S_IWUSR |
                                     S_IRGRP | S_IWGRP | S_IROTH,
                                     &magtek_fops, NULL);

/* let the user know what node this device is now attached to */
info ("USB Magtek Swipe Reader device now attached to USBMagtek%d", dev->minor);


        /* submit a urb */
        /* allocate and zero the device urb */
        dev->urb=kmalloc(sizeof(struct urb), GFP_KERNEL);
        if(dev->urb == NULL) {
                err("Out of memory");
                kfree(dev);
                up(&minor_table_mutex);
                return NULL;
        }
        memset(dev->urb, 0, sizeof(struct urb));

        /* fill the URB data structure */
        pipe=usb_rcvintpipe(dev->udev, endpoint->bEndpointAddress);
        maxp = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));

usb_fill_int_urb(dev->urb, dev->udev, pipe, dev->alpha_buffer, maxp > USB_ALPHA_BUFFER_SIZE ? USB_ALPHA_BUFFER_SIZE : maxp, magtek_irq, dev, endpoint->bInterval);

        /* register the URB within the USB subsystem */
        if (usb_submit_urb(dev->urb)) {
                kfree(dev->urb);
                kfree(dev);
                up(&minor_table_mutex);
                return NULL;
        }

dev->packet_size = maxp > USB_ALPHA_BUFFER_SIZE ? USB_ALPHA_BUFFER_SIZE : maxp;
dev->disconnect_flag=0;
dev->report_flag=0; /* not a full report */


        minor_table[minor] = dev;
        up(&minor_table_mutex);
        return dev;
}


/** * magtek_disconnect * * Called by the usb core when the device is removed from the system. */ static void magtek_disconnect(struct usb_device *udev, void *ptr) { struct usb_magtek *dev; int minor; unsigned long flags;

dev = (struct usb_magtek *)ptr;

spin_lock_irqsave (&dev->lock,flags);

minor = dev->minor;

        /* remove our devfs node */
        devfs_unregister(dev->devfs);

spin_unlock_irqrestore (&dev->lock,flags);

if(dev->urb != NULL) usb_unlink_urb(dev->urb);

spin_lock_irqsave (&dev->lock,flags);

        /* if the device is not opened, then we clean up right now */
        if (!dev->open_count) {
                kfree(dev);
                down(&minor_table_mutex);
                minor_table[dev->minor]=NULL;
                up(&minor_table_mutex);
                spin_unlock_irqrestore(&dev->lock,flags);
                info("USB Magtek Swipe Reader #%d now disconnected", minor);
        } else {
                dev->udev = NULL;
                down(&minor_table_mutex);
                minor_table[dev->minor]=NULL;
                up (&minor_table_mutex);
                spin_unlock_irqrestore (&dev->lock,flags);
                info("USB Magtek Swipe Reader #%d now disconnected", minor);
                dev->disconnect_flag=1;
                wake_up_interruptible(&queue);
        }

}



/**
 *      usb_magtek_init
 */
static int __init usb_magtek_init(void)
{
        int result;

/* register this driver with the USB subsystem */
result = usb_register(&magtek_driver);
if (result < 0) {
err("usb_register failed for the "__FILE__" driver. Error number %d",
result);
return -1;
}


        info(DRIVER_DESC " " DRIVER_VERSION);
        return 0;
}


/** * usb_magtek_exit */ static void __exit usb_magtek_exit(void) { /* deregister this driver with the USB subsystem */ usb_deregister(&magtek_driver); }


module_init (usb_magtek_init); module_exit (usb_magtek_exit);

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");




---------------------------------
Ideals are like stars; you will not succeed in touching them with your hands...you choose them as your guides, and following them you will reach your destiny. --Carl Schultz




-------------------------------------------------------
This SF.net email is sponsored by: ValueWeb: Dedicated Hosting for just $79/mo with 500 GB of bandwidth! No other company gives more support or power for your dedicated server
http://click.atdmt.com/AFF/go/sdnxxaff00300020aff/direct/01/
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to