📄 vtplayer.c
字号:
/* * VTPlayer mouse driver - 0.4.1 * * Copyright (c) 2004-2007 Christophe Jacquet <jacquetc@free.fr> * * 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, version 2. * * This driver is based on: * - the usb-skeleton driver, version 1.1 * copyright (c) 2001-2003 Greg Kroah-Hartman <greg@kroah.com> * * - the usbmouse driver, version 1.15 * copyright (c) 1999-2001 Vojtech Pavlik <vojtech@ucw.cz> * * * History: * * 2007-10-07 - 0.4.1 - adapted to SPARC (big-endian) architecture (ok with 2.6.22) * 2007-02-25 - 0.4.0 - adapted to changes in kernel APIs (ok with 2.6.15) * 2004-12-02 - 0.3.2 - changed device file display to "/dev/usb/vtplayer%d" * 2004-03-06 - 0.3.1 - lots of code cleanup - first public release * 2004-01-26 - 0.3.0 - merge of 0.1 and 0.2 - full support * 2004-01-26 - 0.2.0 - tactile cell support, written from usb-skeleton.c * 2004-01-25 - 0.1.0 - mouse support, based on usbmouse.c adapted to * VTPlayer's specific protocol * *//* * 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 program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <linux/version.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) #include <linux/autoconf.h>#else #include <linux/config.h>#endif#include <linux/kernel.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/smp_lock.h>#include <linux/completion.h>#include <asm/uaccess.h>#include <linux/usb.h>#include <linux/input.h> /* this is an input driver, too */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)#define SLAB_GFP_ATOMIC GFP_ATOMIC#else#define SLAB_GFP_ATOMIC SLAB_ATOMIC#endif#include "vtplayer.h"/* 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.4.0"#define DRIVER_AUTHOR "Christophe Jacquet <jacquetc@free.fr>"#define DRIVER_DESC "VirTouch VTPlayer Tactile Mouse Driver"/* Default minor base */#define VTP_MINOR_BASE 192/* Module parameters *//* Debug: print out additional debugging messages - off by default */static int debug = 0;module_param(debug, int, 0);MODULE_PARM_DESC(debug, "Debug enabled or not");/* VTPlayer vendor & product IDs */#define VTP_VENDOR_ID 0x1100#define VTP_PRODUCT_ID 0x0001/* table of devices that work with this driver */static struct usb_device_id vtp_table [] = { { USB_DEVICE(VTP_VENDOR_ID, VTP_PRODUCT_ID) }, { } /* Terminating entry */};MODULE_DEVICE_TABLE (usb, vtp_table);/* Structure to hold all of our device specific stuff */struct vtplayer { struct usb_device *udev; /* save off the usb device pointer */ struct usb_interface *interface; /* the interface for this device */ unsigned char minor; /* the starting minor number for this device */ int open; /* if the port is open or not */ int present; /* if the device is not disconnected */ struct semaphore sem; /* locks this structure */ __u8 int_in_endpointAddr; /* the address of the interrupt in endpoint */ /* These fields are specifically for the input device */ struct input_dev *mouse_dev; /* associated input device */ struct urb *mouse_irq; /* URB used for IRQ transferts */ int mouse_open; /* if the input device is open or not */ signed char *mouse_data; /* buffer containing data */ dma_addr_t mouse_data_dma; /* DMA address */ char mouse_name[128]; /* device name */ char mouse_phys[64]; /* physical name */};/* prevent races between open() and disconnect() */static DECLARE_MUTEX (disconnect_sem);/* local function prototypes */static int vtp_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static int vtp_open (struct inode *inode, struct file *file);static int vtp_release (struct inode *inode, struct file *file);static int vtp_probe (struct usb_interface *interface, const struct usb_device_id *id);static void vtp_disconnect (struct usb_interface *interface);#define VTP_DATA_LENGTH 4/************* I N P U T D E V I C E ( M O U S E ) ***********************/#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)static void vtp_mouse_irq(struct urb *urb, struct pt_regs *regs)#elsestatic void vtp_mouse_irq(struct urb *urb)#endif{ struct vtplayer *mouse = urb->context; signed char *data = mouse->mouse_data; struct input_dev *dev = mouse->mouse_dev; int status; switch (urb->status) { case 0: /* success */ break; case -ECONNRESET: /* unlink */ case -ENOENT: case -ESHUTDOWN: return; /* -EPIPE: should clear the halt */ default: /* error */ goto resubmit; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) input_regs(dev, regs); #endif /* * VTPlayer protocol (as reverse-engineered on 2004-01-22): * byte 0 X motion * byte 1 Y motion * byte 2 unused (?) * byte 3 button: * 1- right top * 2- right bottom * 4- left bottom * 8- left top */ input_report_key(dev, BTN_LEFT, data[3] & 0x08); input_report_key(dev, BTN_RIGHT, data[3] & 0x01); input_report_key(dev, BTN_MIDDLE, data[3] & 0x04); input_report_key(dev, BTN_SIDE, data[3] & 0x02); input_report_rel(dev, REL_X, data[0]); input_report_rel(dev, REL_Y, data[1]); input_sync(dev);resubmit: status = usb_submit_urb (urb, SLAB_GFP_ATOMIC); if (status) err ("can't resubmit intr, %s-%s/input0, status %d", mouse->udev->bus->bus_name, mouse->udev->devpath, status);}static int vtp_mouse_open(struct input_dev *dev){ struct vtplayer *mouse = dev->private; dbg("%s", __FUNCTION__); if (mouse->mouse_open++) return 0; mouse->mouse_irq->dev = mouse->udev; if (usb_submit_urb(mouse->mouse_irq, GFP_KERNEL)) { mouse->mouse_open--; return -EIO; } return 0;}static void vtp_mouse_close(struct input_dev *dev){ struct vtplayer *mouse = dev->private; dbg("%s", __FUNCTION__); if (!--mouse->mouse_open) usb_unlink_urb(mouse->mouse_irq);}/********************** T A C T I L E P A D S ******************************//* * 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 vtp_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. */ .owner = THIS_MODULE, .ioctl = vtp_ioctl, .open = vtp_open, .release = vtp_release,};/* * usb class driver info in order to get a minor number from the usb core, * and to have the device registered with devfs and the driver core. * NOTE: the "mode" field has been removed from the structure since 2.6.15 */static struct usb_class_driver vtp_class = { .name = "vtplayer%d", .fops = &vtp_fops, .minor_base = VTP_MINOR_BASE,};/* usb specific object needed to register this driver with the usb subsystem */static struct usb_driver vtp_driver = { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) .owner = THIS_MODULE, #endif .name = "vtplayer", .probe = vtp_probe, .disconnect = vtp_disconnect, .id_table = vtp_table,};/** * vtp_delete */static inline void vtp_delete (struct vtplayer *dev){/* if (dev->bulk_in_buffer != NULL) kfree (dev->bulk_in_buffer); if (dev->bulk_out_buffer != NULL) usb_buffer_free (dev->udev, dev->bulk_out_size, dev->bulk_out_buffer, dev->write_urb->transfer_dma);*/ kfree (dev);}/** * vtp_open */static int vtp_open (struct inode *inode, struct file *file){ struct vtplayer *dev = NULL; struct usb_interface *interface; int subminor; int retval = 0; dbg("%s", __FUNCTION__); subminor = iminor(inode); /* prevent disconnects */ down (&disconnect_sem); interface = usb_find_interface (&vtp_driver, subminor); if (!interface) { err ("%s - error, can't find device for minor %d", __FUNCTION__, subminor); retval = -ENODEV; goto exit_no_device; } dev = usb_get_intfdata(interface); if (!dev) { retval = -ENODEV; goto exit_no_device; } /* lock this device */ down (&dev->sem); /* increment our usage count for the driver */ ++dev->open; /* save our object in the file's private structure */ file->private_data = dev; /* unlock this device */ up (&dev->sem);exit_no_device: up (&disconnect_sem); return retval;}/** * vtp_release */static int vtp_release (struct inode *inode, struct file *file){ struct vtplayer *dev; int retval = 0; dev = (struct vtplayer *)file->private_data; if (dev == NULL) { dbg ("%s: object is NULL", __FUNCTION__); return -ENODEV; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -