2005-04-16 15:20:36 -07:00
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/input.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/usb.h>
# include <asm/unaligned.h>
# include <asm/byteorder.h>
/*
* Version Information
* v0 .0 .1 - Original , extremely basic version , 2.4 . xx only
* v0 .0 .2 - Updated , works with 2.5 .62 and 2.4 .20 ;
* - added pressure - threshold modules param code from
* Alex Perry < alex . perry @ ieee . org >
*/
# define DRIVER_VERSION "v0.0.2"
# define DRIVER_AUTHOR "Josh Myer <josh@joshisanerd.com>"
# define DRIVER_DESC "USB KB Gear JamStudio Tablet driver"
# define DRIVER_LICENSE "GPL"
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( DRIVER_LICENSE ) ;
# define USB_VENDOR_ID_KBGEAR 0x084e
static int kb_pressure_click = 0x10 ;
module_param ( kb_pressure_click , int , 0 ) ;
MODULE_PARM_DESC ( kb_pressure_click , " pressure threshold for clicks " ) ;
struct kbtab {
signed char * data ;
dma_addr_t data_dma ;
struct input_dev dev ;
struct usb_device * usbdev ;
struct urb * irq ;
int open ;
int x , y ;
int button ;
int pressure ;
__u32 serial [ 2 ] ;
char phys [ 32 ] ;
} ;
static void kbtab_irq ( struct urb * urb , struct pt_regs * regs )
{
struct kbtab * kbtab = urb - > context ;
unsigned char * data = kbtab - > data ;
struct input_dev * dev = & kbtab - > dev ;
int retval ;
switch ( urb - > status ) {
case 0 :
/* success */
break ;
case - ECONNRESET :
case - ENOENT :
case - ESHUTDOWN :
/* this urb is terminated, clean up */
dbg ( " %s - urb shutting down with status: %d " , __FUNCTION__ , urb - > status ) ;
return ;
default :
dbg ( " %s - nonzero urb status received: %d " , __FUNCTION__ , urb - > status ) ;
goto exit ;
}
kbtab - > x = le16_to_cpu ( get_unaligned ( ( __le16 * ) & data [ 1 ] ) ) ;
kbtab - > y = le16_to_cpu ( get_unaligned ( ( __le16 * ) & data [ 3 ] ) ) ;
kbtab - > pressure = ( data [ 5 ] ) ;
input_report_key ( dev , BTN_TOOL_PEN , 1 ) ;
input_report_abs ( dev , ABS_X , kbtab - > x ) ;
input_report_abs ( dev , ABS_Y , kbtab - > y ) ;
/*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/
input_report_key ( dev , BTN_RIGHT , data [ 0 ] & 0x02 ) ;
2005-05-29 02:29:01 -05:00
if ( - 1 = = kb_pressure_click ) {
2005-04-16 15:20:36 -07:00
input_report_abs ( dev , ABS_PRESSURE , kbtab - > pressure ) ;
} else {
input_report_key ( dev , BTN_LEFT , ( kbtab - > pressure > kb_pressure_click ) ? 1 : 0 ) ;
} ;
2005-05-29 02:29:01 -05:00
2005-04-16 15:20:36 -07:00
input_sync ( dev ) ;
exit :
retval = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( retval )
err ( " %s - usb_submit_urb failed with result %d " ,
__FUNCTION__ , retval ) ;
}
static struct usb_device_id kbtab_ids [ ] = {
{ USB_DEVICE ( USB_VENDOR_ID_KBGEAR , 0x1001 ) , . driver_info = 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( usb , kbtab_ids ) ;
static int kbtab_open ( struct input_dev * dev )
{
struct kbtab * kbtab = dev - > private ;
if ( kbtab - > open + + )
return 0 ;
kbtab - > irq - > dev = kbtab - > usbdev ;
if ( usb_submit_urb ( kbtab - > irq , GFP_KERNEL ) ) {
kbtab - > open - - ;
return - EIO ;
}
return 0 ;
}
static void kbtab_close ( struct input_dev * dev )
{
struct kbtab * kbtab = dev - > private ;
if ( ! - - kbtab - > open )
usb_kill_urb ( kbtab - > irq ) ;
}
static int kbtab_probe ( struct usb_interface * intf , const struct usb_device_id * id )
{
struct usb_device * dev = interface_to_usbdev ( intf ) ;
struct usb_endpoint_descriptor * endpoint ;
struct kbtab * kbtab ;
char path [ 64 ] ;
if ( ! ( kbtab = kmalloc ( sizeof ( struct kbtab ) , GFP_KERNEL ) ) )
return - ENOMEM ;
memset ( kbtab , 0 , sizeof ( struct kbtab ) ) ;
kbtab - > data = usb_buffer_alloc ( dev , 8 , GFP_KERNEL , & kbtab - > data_dma ) ;
if ( ! kbtab - > data ) {
kfree ( kbtab ) ;
return - ENOMEM ;
}
kbtab - > irq = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
if ( ! kbtab - > irq ) {
usb_buffer_free ( dev , 10 , kbtab - > data , kbtab - > data_dma ) ;
kfree ( kbtab ) ;
return - ENOMEM ;
}
kbtab - > dev . evbit [ 0 ] | = BIT ( EV_KEY ) | BIT ( EV_ABS ) | BIT ( EV_MSC ) ;
kbtab - > dev . absbit [ 0 ] | = BIT ( ABS_X ) | BIT ( ABS_Y ) | BIT ( ABS_PRESSURE ) ;
kbtab - > dev . keybit [ LONG ( BTN_LEFT ) ] | = BIT ( BTN_LEFT ) | BIT ( BTN_RIGHT ) | BIT ( BTN_MIDDLE ) ;
kbtab - > dev . keybit [ LONG ( BTN_DIGI ) ] | = BIT ( BTN_TOOL_PEN ) | BIT ( BTN_TOUCH ) ;
kbtab - > dev . mscbit [ 0 ] | = BIT ( MSC_SERIAL ) ;
kbtab - > dev . absmax [ ABS_X ] = 0x2000 ;
kbtab - > dev . absmax [ ABS_Y ] = 0x1750 ;
kbtab - > dev . absmax [ ABS_PRESSURE ] = 0xff ;
2005-05-29 02:29:01 -05:00
2005-04-16 15:20:36 -07:00
kbtab - > dev . absfuzz [ ABS_X ] = 4 ;
kbtab - > dev . absfuzz [ ABS_Y ] = 4 ;
kbtab - > dev . private = kbtab ;
kbtab - > dev . open = kbtab_open ;
kbtab - > dev . close = kbtab_close ;
usb_make_path ( dev , path , 64 ) ;
sprintf ( kbtab - > phys , " %s/input0 " , path ) ;
kbtab - > dev . name = " KB Gear Tablet " ;
kbtab - > dev . phys = kbtab - > phys ;
kbtab - > dev . id . bustype = BUS_USB ;
kbtab - > dev . id . vendor = le16_to_cpu ( dev - > descriptor . idVendor ) ;
kbtab - > dev . id . product = le16_to_cpu ( dev - > descriptor . idProduct ) ;
kbtab - > dev . id . version = le16_to_cpu ( dev - > descriptor . bcdDevice ) ;
kbtab - > dev . dev = & intf - > dev ;
kbtab - > usbdev = dev ;
endpoint = & intf - > cur_altsetting - > endpoint [ 0 ] . desc ;
usb_fill_int_urb ( kbtab - > irq , dev ,
usb_rcvintpipe ( dev , endpoint - > bEndpointAddress ) ,
kbtab - > data , 8 ,
kbtab_irq , kbtab , endpoint - > bInterval ) ;
kbtab - > irq - > transfer_dma = kbtab - > data_dma ;
kbtab - > irq - > transfer_flags | = URB_NO_TRANSFER_DMA_MAP ;
input_register_device ( & kbtab - > dev ) ;
printk ( KERN_INFO " input: KB Gear Tablet on %s \n " , path ) ;
usb_set_intfdata ( intf , kbtab ) ;
return 0 ;
}
static void kbtab_disconnect ( struct usb_interface * intf )
{
struct kbtab * kbtab = usb_get_intfdata ( intf ) ;
usb_set_intfdata ( intf , NULL ) ;
if ( kbtab ) {
usb_kill_urb ( kbtab - > irq ) ;
input_unregister_device ( & kbtab - > dev ) ;
usb_free_urb ( kbtab - > irq ) ;
usb_buffer_free ( interface_to_usbdev ( intf ) , 10 , kbtab - > data , kbtab - > data_dma ) ;
kfree ( kbtab ) ;
}
}
static struct usb_driver kbtab_driver = {
. owner = THIS_MODULE ,
. name = " kbtab " ,
. probe = kbtab_probe ,
. disconnect = kbtab_disconnect ,
. id_table = kbtab_ids ,
} ;
static int __init kbtab_init ( void )
{
int retval ;
retval = usb_register ( & kbtab_driver ) ;
if ( retval )
goto out ;
info ( DRIVER_VERSION " : " DRIVER_DESC ) ;
out :
return retval ;
}
static void __exit kbtab_exit ( void )
{
usb_deregister ( & kbtab_driver ) ;
}
module_init ( kbtab_init ) ;
module_exit ( kbtab_exit ) ;