Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /* Siemens ID Mouse driver v0.6
0003 
0004   Copyright (C) 2004-5 by Florian 'Floe' Echtler  <echtler@fs.tum.de>
0005                       and Andreas  'ad'  Deresch <aderesch@fs.tum.de>
0006 
0007   Derived from the USB Skeleton driver 1.1,
0008   Copyright (C) 2003 Greg Kroah-Hartman (greg@kroah.com)
0009 
0010   Additional information provided by Martin Reising
0011   <Martin.Reising@natural-computing.de>
0012 
0013 */
0014 
0015 #include <linux/kernel.h>
0016 #include <linux/sched/signal.h>
0017 #include <linux/errno.h>
0018 #include <linux/delay.h>
0019 #include <linux/slab.h>
0020 #include <linux/module.h>
0021 #include <linux/completion.h>
0022 #include <linux/mutex.h>
0023 #include <linux/uaccess.h>
0024 #include <linux/usb.h>
0025 
0026 /* image constants */
0027 #define WIDTH 225
0028 #define HEIGHT 289
0029 #define HEADER "P5 225 289 255 "
0030 #define IMGSIZE ((WIDTH * HEIGHT) + sizeof(HEADER)-1)
0031 
0032 #define DRIVER_SHORT   "idmouse"
0033 #define DRIVER_AUTHOR  "Florian 'Floe' Echtler <echtler@fs.tum.de>"
0034 #define DRIVER_DESC    "Siemens ID Mouse FingerTIP Sensor Driver"
0035 
0036 /* minor number for misc USB devices */
0037 #define USB_IDMOUSE_MINOR_BASE 132
0038 
0039 /* vendor and device IDs */
0040 #define ID_SIEMENS 0x0681
0041 #define ID_IDMOUSE 0x0005
0042 #define ID_CHERRY  0x0010
0043 
0044 /* device ID table */
0045 static const struct usb_device_id idmouse_table[] = {
0046     {USB_DEVICE(ID_SIEMENS, ID_IDMOUSE)}, /* Siemens ID Mouse (Professional) */
0047     {USB_DEVICE(ID_SIEMENS, ID_CHERRY )}, /* Cherry FingerTIP ID Board       */
0048     {}                                    /* terminating null entry          */
0049 };
0050 
0051 /* sensor commands */
0052 #define FTIP_RESET   0x20
0053 #define FTIP_ACQUIRE 0x21
0054 #define FTIP_RELEASE 0x22
0055 #define FTIP_BLINK   0x23  /* LSB of value = blink pulse width */
0056 #define FTIP_SCROLL  0x24
0057 
0058 #define ftip_command(dev, command, value, index) \
0059     usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), command, \
0060     USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, value, index, NULL, 0, 1000)
0061 
0062 MODULE_DEVICE_TABLE(usb, idmouse_table);
0063 
0064 /* structure to hold all of our device specific stuff */
0065 struct usb_idmouse {
0066 
0067     struct usb_device *udev; /* save off the usb device pointer */
0068     struct usb_interface *interface; /* the interface for this device */
0069 
0070     unsigned char *bulk_in_buffer; /* the buffer to receive data */
0071     size_t bulk_in_size; /* the maximum bulk packet size */
0072     size_t orig_bi_size; /* same as above, but reported by the device */
0073     __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
0074 
0075     int open; /* if the port is open or not */
0076     int present; /* if the device is not disconnected */
0077     struct mutex lock; /* locks this structure */
0078 
0079 };
0080 
0081 /* local function prototypes */
0082 static ssize_t idmouse_read(struct file *file, char __user *buffer,
0083                 size_t count, loff_t * ppos);
0084 
0085 static int idmouse_open(struct inode *inode, struct file *file);
0086 static int idmouse_release(struct inode *inode, struct file *file);
0087 
0088 static int idmouse_probe(struct usb_interface *interface,
0089                 const struct usb_device_id *id);
0090 
0091 static void idmouse_disconnect(struct usb_interface *interface);
0092 static int idmouse_suspend(struct usb_interface *intf, pm_message_t message);
0093 static int idmouse_resume(struct usb_interface *intf);
0094 
0095 /* file operation pointers */
0096 static const struct file_operations idmouse_fops = {
0097     .owner = THIS_MODULE,
0098     .read = idmouse_read,
0099     .open = idmouse_open,
0100     .release = idmouse_release,
0101     .llseek = default_llseek,
0102 };
0103 
0104 /* class driver information */
0105 static struct usb_class_driver idmouse_class = {
0106     .name = "idmouse%d",
0107     .fops = &idmouse_fops,
0108     .minor_base = USB_IDMOUSE_MINOR_BASE,
0109 };
0110 
0111 /* usb specific object needed to register this driver with the usb subsystem */
0112 static struct usb_driver idmouse_driver = {
0113     .name = DRIVER_SHORT,
0114     .probe = idmouse_probe,
0115     .disconnect = idmouse_disconnect,
0116     .suspend = idmouse_suspend,
0117     .resume = idmouse_resume,
0118     .reset_resume = idmouse_resume,
0119     .id_table = idmouse_table,
0120     .supports_autosuspend = 1,
0121 };
0122 
0123 static int idmouse_create_image(struct usb_idmouse *dev)
0124 {
0125     int bytes_read;
0126     int bulk_read;
0127     int result;
0128 
0129     memcpy(dev->bulk_in_buffer, HEADER, sizeof(HEADER)-1);
0130     bytes_read = sizeof(HEADER)-1;
0131 
0132     /* reset the device and set a fast blink rate */
0133     result = ftip_command(dev, FTIP_RELEASE, 0, 0);
0134     if (result < 0)
0135         goto reset;
0136     result = ftip_command(dev, FTIP_BLINK,   1, 0);
0137     if (result < 0)
0138         goto reset;
0139 
0140     /* initialize the sensor - sending this command twice */
0141     /* significantly reduces the rate of failed reads     */
0142     result = ftip_command(dev, FTIP_ACQUIRE, 0, 0);
0143     if (result < 0)
0144         goto reset;
0145     result = ftip_command(dev, FTIP_ACQUIRE, 0, 0);
0146     if (result < 0)
0147         goto reset;
0148 
0149     /* start the readout - sending this command twice */
0150     /* presumably enables the high dynamic range mode */
0151     result = ftip_command(dev, FTIP_RESET,   0, 0);
0152     if (result < 0)
0153         goto reset;
0154     result = ftip_command(dev, FTIP_RESET,   0, 0);
0155     if (result < 0)
0156         goto reset;
0157 
0158     /* loop over a blocking bulk read to get data from the device */
0159     while (bytes_read < IMGSIZE) {
0160         result = usb_bulk_msg(dev->udev,
0161                 usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
0162                 dev->bulk_in_buffer + bytes_read,
0163                 dev->bulk_in_size, &bulk_read, 5000);
0164         if (result < 0) {
0165             /* Maybe this error was caused by the increased packet size? */
0166             /* Reset to the original value and tell userspace to retry.  */
0167             if (dev->bulk_in_size != dev->orig_bi_size) {
0168                 dev->bulk_in_size = dev->orig_bi_size;
0169                 result = -EAGAIN;
0170             }
0171             break;
0172         }
0173         if (signal_pending(current)) {
0174             result = -EINTR;
0175             break;
0176         }
0177         bytes_read += bulk_read;
0178     }
0179 
0180     /* reset the device */
0181 reset:
0182     ftip_command(dev, FTIP_RELEASE, 0, 0);
0183 
0184     /* check for valid image */
0185     /* right border should be black (0x00) */
0186     for (bytes_read = sizeof(HEADER)-1 + WIDTH-1; bytes_read < IMGSIZE; bytes_read += WIDTH)
0187         if (dev->bulk_in_buffer[bytes_read] != 0x00)
0188             return -EAGAIN;
0189 
0190     /* lower border should be white (0xFF) */
0191     for (bytes_read = IMGSIZE-WIDTH; bytes_read < IMGSIZE-1; bytes_read++)
0192         if (dev->bulk_in_buffer[bytes_read] != 0xFF)
0193             return -EAGAIN;
0194 
0195     /* should be IMGSIZE == 65040 */
0196     dev_dbg(&dev->interface->dev, "read %d bytes fingerprint data\n",
0197         bytes_read);
0198     return result;
0199 }
0200 
0201 /* PM operations are nops as this driver does IO only during open() */
0202 static int idmouse_suspend(struct usb_interface *intf, pm_message_t message)
0203 {
0204     return 0;
0205 }
0206 
0207 static int idmouse_resume(struct usb_interface *intf)
0208 {
0209     return 0;
0210 }
0211 
0212 static inline void idmouse_delete(struct usb_idmouse *dev)
0213 {
0214     kfree(dev->bulk_in_buffer);
0215     kfree(dev);
0216 }
0217 
0218 static int idmouse_open(struct inode *inode, struct file *file)
0219 {
0220     struct usb_idmouse *dev;
0221     struct usb_interface *interface;
0222     int result;
0223 
0224     /* get the interface from minor number and driver information */
0225     interface = usb_find_interface(&idmouse_driver, iminor(inode));
0226     if (!interface)
0227         return -ENODEV;
0228 
0229     /* get the device information block from the interface */
0230     dev = usb_get_intfdata(interface);
0231     if (!dev)
0232         return -ENODEV;
0233 
0234     /* lock this device */
0235     mutex_lock(&dev->lock);
0236 
0237     /* check if already open */
0238     if (dev->open) {
0239 
0240         /* already open, so fail */
0241         result = -EBUSY;
0242 
0243     } else {
0244 
0245         /* create a new image and check for success */
0246         result = usb_autopm_get_interface(interface);
0247         if (result)
0248             goto error;
0249         result = idmouse_create_image(dev);
0250         usb_autopm_put_interface(interface);
0251         if (result)
0252             goto error;
0253 
0254         /* increment our usage count for the driver */
0255         ++dev->open;
0256 
0257         /* save our object in the file's private structure */
0258         file->private_data = dev;
0259 
0260     } 
0261 
0262 error:
0263 
0264     /* unlock this device */
0265     mutex_unlock(&dev->lock);
0266     return result;
0267 }
0268 
0269 static int idmouse_release(struct inode *inode, struct file *file)
0270 {
0271     struct usb_idmouse *dev;
0272 
0273     dev = file->private_data;
0274 
0275     if (dev == NULL)
0276         return -ENODEV;
0277 
0278     /* lock our device */
0279     mutex_lock(&dev->lock);
0280 
0281     --dev->open;
0282 
0283     if (!dev->present) {
0284         /* the device was unplugged before the file was released */
0285         mutex_unlock(&dev->lock);
0286         idmouse_delete(dev);
0287     } else {
0288         mutex_unlock(&dev->lock);
0289     }
0290     return 0;
0291 }
0292 
0293 static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count,
0294                 loff_t * ppos)
0295 {
0296     struct usb_idmouse *dev = file->private_data;
0297     int result;
0298 
0299     /* lock this object */
0300     mutex_lock(&dev->lock);
0301 
0302     /* verify that the device wasn't unplugged */
0303     if (!dev->present) {
0304         mutex_unlock(&dev->lock);
0305         return -ENODEV;
0306     }
0307 
0308     result = simple_read_from_buffer(buffer, count, ppos,
0309                     dev->bulk_in_buffer, IMGSIZE);
0310     /* unlock the device */
0311     mutex_unlock(&dev->lock);
0312     return result;
0313 }
0314 
0315 static int idmouse_probe(struct usb_interface *interface,
0316                 const struct usb_device_id *id)
0317 {
0318     struct usb_device *udev = interface_to_usbdev(interface);
0319     struct usb_idmouse *dev;
0320     struct usb_host_interface *iface_desc;
0321     struct usb_endpoint_descriptor *endpoint;
0322     int result;
0323 
0324     /* check if we have gotten the data or the hid interface */
0325     iface_desc = interface->cur_altsetting;
0326     if (iface_desc->desc.bInterfaceClass != 0x0A)
0327         return -ENODEV;
0328 
0329     if (iface_desc->desc.bNumEndpoints < 1)
0330         return -ENODEV;
0331 
0332     /* allocate memory for our device state and initialize it */
0333     dev = kzalloc(sizeof(*dev), GFP_KERNEL);
0334     if (dev == NULL)
0335         return -ENOMEM;
0336 
0337     mutex_init(&dev->lock);
0338     dev->udev = udev;
0339     dev->interface = interface;
0340 
0341     /* set up the endpoint information - use only the first bulk-in endpoint */
0342     result = usb_find_bulk_in_endpoint(iface_desc, &endpoint);
0343     if (result) {
0344         dev_err(&interface->dev, "Unable to find bulk-in endpoint.\n");
0345         idmouse_delete(dev);
0346         return result;
0347     }
0348 
0349     dev->orig_bi_size = usb_endpoint_maxp(endpoint);
0350     dev->bulk_in_size = 0x200; /* works _much_ faster */
0351     dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
0352     dev->bulk_in_buffer = kmalloc(IMGSIZE + dev->bulk_in_size, GFP_KERNEL);
0353     if (!dev->bulk_in_buffer) {
0354         idmouse_delete(dev);
0355         return -ENOMEM;
0356     }
0357 
0358     /* allow device read, write and ioctl */
0359     dev->present = 1;
0360 
0361     /* we can register the device now, as it is ready */
0362     usb_set_intfdata(interface, dev);
0363     result = usb_register_dev(interface, &idmouse_class);
0364     if (result) {
0365         /* something prevented us from registering this device */
0366         dev_err(&interface->dev, "Unable to allocate minor number.\n");
0367         idmouse_delete(dev);
0368         return result;
0369     }
0370 
0371     /* be noisy */
0372     dev_info(&interface->dev,"%s now attached\n",DRIVER_DESC);
0373 
0374     return 0;
0375 }
0376 
0377 static void idmouse_disconnect(struct usb_interface *interface)
0378 {
0379     struct usb_idmouse *dev = usb_get_intfdata(interface);
0380 
0381     /* give back our minor */
0382     usb_deregister_dev(interface, &idmouse_class);
0383 
0384     /* lock the device */
0385     mutex_lock(&dev->lock);
0386 
0387     /* prevent device read, write and ioctl */
0388     dev->present = 0;
0389 
0390     /* if the device is opened, idmouse_release will clean this up */
0391     if (!dev->open) {
0392         mutex_unlock(&dev->lock);
0393         idmouse_delete(dev);
0394     } else {
0395         /* unlock */
0396         mutex_unlock(&dev->lock);
0397     }
0398 
0399     dev_info(&interface->dev, "disconnected\n");
0400 }
0401 
0402 module_usb_driver(idmouse_driver);
0403 
0404 MODULE_AUTHOR(DRIVER_AUTHOR);
0405 MODULE_DESCRIPTION(DRIVER_DESC);
0406 MODULE_LICENSE("GPL");
0407