From 09779678d12482024e06380cacc4c3ff2f129f23 Mon Sep 17 00:00:00 2001 From: Stelian Pop Date: Tue, 28 Oct 2008 23:20:46 -0400 Subject: Input: appletouch - driver refactoring The appletouch driver has grown up from supporting only a couple of touchpads into supporting many touchpads, which can have different number of sensors, different aspect ratios etc. This patch cleans up the current driver code and makes it easy to support the features of each different touchpad. As a side effect, this patch also modifies the 'Y' multiplication factor of the 'geyser3' and 'geyser4' touchpads (found on Core Duo and Core2 Duo MacBook and MacBook Pro laptops) in order to make the touchpad output match the aspect ratio of the touchpad (Y factor changed from 43 to 64). [dtor@mail.ru: make atp_info constant] Signed-off-by: Stelian Pop Acked-by: Johannes Berg Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/appletouch.c | 274 +++++++++++++++++++-------------------- 1 file changed, 136 insertions(+), 138 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c index 079816e6b23b..454b96112f03 100644 --- a/drivers/input/mouse/appletouch.c +++ b/drivers/input/mouse/appletouch.c @@ -3,7 +3,7 @@ * * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2005-2008 Johannes Berg (johannes@sipsolutions.net) - * Copyright (C) 2005 Stelian Pop (stelian@popies.net) + * Copyright (C) 2005-2008 Stelian Pop (stelian@popies.net) * Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de) * Copyright (C) 2005 Peter Osterlund (petero2@telia.com) * Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch) @@ -35,16 +35,74 @@ #include #include -/* Type of touchpad */ -enum atp_touchpad_type { - ATP_FOUNTAIN, - ATP_GEYSER1, - ATP_GEYSER2, - ATP_GEYSER3, - ATP_GEYSER4 +/* + * Note: We try to keep the touchpad aspect ratio while still doing only + * simple arithmetics: + * 0 <= x <= (xsensors - 1) * xfact + * 0 <= y <= (ysensors - 1) * yfact + */ +struct atp_info { + int xsensors; /* number of X sensors */ + int xsensors_17; /* 17" models have more sensors */ + int ysensors; /* number of Y sensors */ + int xfact; /* X multiplication factor */ + int yfact; /* Y multiplication factor */ + int datalen; /* size of USB transfers */ + void (*callback)(struct urb *); /* callback function */ +}; + +static void atp_complete_geyser_1_2(struct urb *urb); +static void atp_complete_geyser_3_4(struct urb *urb); + +static const struct atp_info fountain_info = { + .xsensors = 16, + .xsensors_17 = 26, + .ysensors = 16, + .xfact = 64, + .yfact = 43, + .datalen = 81, + .callback = atp_complete_geyser_1_2, +}; + +static const struct atp_info geyser1_info = { + .xsensors = 16, + .xsensors_17 = 26, + .ysensors = 16, + .xfact = 64, + .yfact = 43, + .datalen = 81, + .callback = atp_complete_geyser_1_2, +}; + +static const struct atp_info geyser2_info = { + .xsensors = 15, + .xsensors_17 = 20, + .ysensors = 9, + .xfact = 64, + .yfact = 43, + .datalen = 64, + .callback = atp_complete_geyser_1_2, +}; + +static const struct atp_info geyser3_info = { + .xsensors = 20, + .ysensors = 10, + .xfact = 64, + .yfact = 64, + .datalen = 64, + .callback = atp_complete_geyser_3_4, }; -#define ATP_DEVICE(prod, type) \ +static const struct atp_info geyser4_info = { + .xsensors = 20, + .ysensors = 10, + .xfact = 64, + .yfact = 64, + .datalen = 64, + .callback = atp_complete_geyser_3_4, +}; + +#define ATP_DEVICE(prod, info) \ { \ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ USB_DEVICE_ID_MATCH_INT_CLASS | \ @@ -53,7 +111,7 @@ enum atp_touchpad_type { .idProduct = (prod), \ .bInterfaceClass = 0x03, \ .bInterfaceProtocol = 0x02, \ - .driver_info = ATP_ ## type, \ + .driver_info = (unsigned long) &info, \ } /* @@ -62,43 +120,39 @@ enum atp_touchpad_type { * According to Info.plist Geyser IV is the same as Geyser III.) */ -static struct usb_device_id atp_table [] = { +static struct usb_device_id atp_table[] = { /* PowerBooks Feb 2005, iBooks G4 */ - ATP_DEVICE(0x020e, FOUNTAIN), /* FOUNTAIN ANSI */ - ATP_DEVICE(0x020f, FOUNTAIN), /* FOUNTAIN ISO */ - ATP_DEVICE(0x030a, FOUNTAIN), /* FOUNTAIN TP ONLY */ - ATP_DEVICE(0x030b, GEYSER1), /* GEYSER 1 TP ONLY */ + ATP_DEVICE(0x020e, fountain_info), /* FOUNTAIN ANSI */ + ATP_DEVICE(0x020f, fountain_info), /* FOUNTAIN ISO */ + ATP_DEVICE(0x030a, fountain_info), /* FOUNTAIN TP ONLY */ + ATP_DEVICE(0x030b, geyser1_info), /* GEYSER 1 TP ONLY */ /* PowerBooks Oct 2005 */ - ATP_DEVICE(0x0214, GEYSER2), /* GEYSER 2 ANSI */ - ATP_DEVICE(0x0215, GEYSER2), /* GEYSER 2 ISO */ - ATP_DEVICE(0x0216, GEYSER2), /* GEYSER 2 JIS */ + ATP_DEVICE(0x0214, geyser2_info), /* GEYSER 2 ANSI */ + ATP_DEVICE(0x0215, geyser2_info), /* GEYSER 2 ISO */ + ATP_DEVICE(0x0216, geyser2_info), /* GEYSER 2 JIS */ /* Core Duo MacBook & MacBook Pro */ - ATP_DEVICE(0x0217, GEYSER3), /* GEYSER 3 ANSI */ - ATP_DEVICE(0x0218, GEYSER3), /* GEYSER 3 ISO */ - ATP_DEVICE(0x0219, GEYSER3), /* GEYSER 3 JIS */ + ATP_DEVICE(0x0217, geyser3_info), /* GEYSER 3 ANSI */ + ATP_DEVICE(0x0218, geyser3_info), /* GEYSER 3 ISO */ + ATP_DEVICE(0x0219, geyser3_info), /* GEYSER 3 JIS */ /* Core2 Duo MacBook & MacBook Pro */ - ATP_DEVICE(0x021a, GEYSER4), /* GEYSER 4 ANSI */ - ATP_DEVICE(0x021b, GEYSER4), /* GEYSER 4 ISO */ - ATP_DEVICE(0x021c, GEYSER4), /* GEYSER 4 JIS */ + ATP_DEVICE(0x021a, geyser4_info), /* GEYSER 4 ANSI */ + ATP_DEVICE(0x021b, geyser4_info), /* GEYSER 4 ISO */ + ATP_DEVICE(0x021c, geyser4_info), /* GEYSER 4 JIS */ /* Core2 Duo MacBook3,1 */ - ATP_DEVICE(0x0229, GEYSER4), /* GEYSER 4 HF ANSI */ - ATP_DEVICE(0x022a, GEYSER4), /* GEYSER 4 HF ISO */ - ATP_DEVICE(0x022b, GEYSER4), /* GEYSER 4 HF JIS */ + ATP_DEVICE(0x0229, geyser4_info), /* GEYSER 4 HF ANSI */ + ATP_DEVICE(0x022a, geyser4_info), /* GEYSER 4 HF ISO */ + ATP_DEVICE(0x022b, geyser4_info), /* GEYSER 4 HF JIS */ /* Terminating entry */ { } }; MODULE_DEVICE_TABLE(usb, atp_table); -/* - * number of sensors. Note that only 16 instead of 26 X (horizontal) - * sensors exist on 12" and 15" PowerBooks. All models have 16 Y - * (vertical) sensors. - */ +/* maximum number of sensors */ #define ATP_XSENSORS 26 #define ATP_YSENSORS 16 @@ -107,21 +161,6 @@ MODULE_DEVICE_TABLE(usb, atp_table); /* maximum pressure this driver will report */ #define ATP_PRESSURE 300 -/* - * multiplication factor for the X and Y coordinates. - * We try to keep the touchpad aspect ratio while still doing only simple - * arithmetics. - * The factors below give coordinates like: - * - * 0 <= x < 960 on 12" and 15" Powerbooks - * 0 <= x < 1600 on 17" Powerbooks and 17" MacBook Pro - * 0 <= x < 1216 on MacBooks and 15" MacBook Pro - * - * 0 <= y < 646 on all Powerbooks - * 0 <= y < 774 on all MacBooks - */ -#define ATP_XFACT 64 -#define ATP_YFACT 43 /* * Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is @@ -159,7 +198,7 @@ struct atp { struct urb *urb; /* usb request block */ u8 *data; /* transferred data */ struct input_dev *input; /* input dev */ - enum atp_touchpad_type type; /* type of touchpad */ + const struct atp_info *info; /* touchpad model */ bool open; bool valid; /* are the samples valid? */ bool size_detect_done; @@ -169,7 +208,6 @@ struct atp { signed char xy_cur[ATP_XSENSORS + ATP_YSENSORS]; signed char xy_old[ATP_XSENSORS + ATP_YSENSORS]; int xy_acc[ATP_XSENSORS + ATP_YSENSORS]; - int datalen; /* size of USB transfer */ int idlecount; /* number of empty packets */ struct work_struct work; }; @@ -359,7 +397,7 @@ static int atp_status_check(struct urb *urb) if (!dev->overflow_warned) { printk(KERN_WARNING "appletouch: OVERFLOW with data " "length %d, actual length is %d\n", - dev->datalen, dev->urb->actual_length); + dev->info->datalen, dev->urb->actual_length); dev->overflow_warned = true; } case -ECONNRESET: @@ -377,7 +415,7 @@ static int atp_status_check(struct urb *urb) } /* drop incomplete datasets */ - if (dev->urb->actual_length != dev->datalen) { + if (dev->urb->actual_length != dev->info->datalen) { dprintk("appletouch: incomplete data package" " (first byte: %d, length: %d).\n", dev->data[0], dev->urb->actual_length); @@ -387,6 +425,25 @@ static int atp_status_check(struct urb *urb) return ATP_URB_STATUS_SUCCESS; } +static void atp_detect_size(struct atp *dev) +{ + int i; + + /* 17" Powerbooks have extra X sensors */ + for (i = dev->info->xsensors; i < ATP_XSENSORS; i++) { + if (dev->xy_cur[i]) { + + printk(KERN_INFO "appletouch: 17\" model detected.\n"); + + input_set_abs_params(dev->input, ABS_X, 0, + (dev->info->xsensors_17 - 1) * + dev->info->xfact - 1, + ATP_FUZZ, 0); + break; + } + } +} + /* * USB interrupt callback functions */ @@ -407,7 +464,7 @@ static void atp_complete_geyser_1_2(struct urb *urb) goto exit; /* reorder the sensors values */ - if (dev->type == ATP_GEYSER2) { + if (dev->info == &geyser2_info) { memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); /* @@ -437,8 +494,8 @@ static void atp_complete_geyser_1_2(struct urb *urb) dev->xy_cur[i + 24] = dev->data[5 * i + 44]; /* Y values */ - dev->xy_cur[i + 26] = dev->data[5 * i + 1]; - dev->xy_cur[i + 34] = dev->data[5 * i + 3]; + dev->xy_cur[ATP_XSENSORS + i] = dev->data[5 * i + 1]; + dev->xy_cur[ATP_XSENSORS + i + 8] = dev->data[5 * i + 3]; } } @@ -453,32 +510,8 @@ static void atp_complete_geyser_1_2(struct urb *urb) memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); /* Perform size detection, if not done already */ - if (!dev->size_detect_done) { - - /* 17" Powerbooks have extra X sensors */ - for (i = (dev->type == ATP_GEYSER2 ? 15 : 16); - i < ATP_XSENSORS; i++) { - if (!dev->xy_cur[i]) - continue; - - printk(KERN_INFO - "appletouch: 17\" model detected.\n"); - - if (dev->type == ATP_GEYSER2) - input_set_abs_params(dev->input, ABS_X, - 0, - (20 - 1) * - ATP_XFACT - 1, - ATP_FUZZ, 0); - else - input_set_abs_params(dev->input, ABS_X, - 0, - (26 - 1) * - ATP_XFACT - 1, - ATP_FUZZ, 0); - break; - } - + if (unlikely(!dev->size_detect_done)) { + atp_detect_size(dev); dev->size_detect_done = 1; goto exit; } @@ -499,10 +532,10 @@ static void atp_complete_geyser_1_2(struct urb *urb) dbg_dump("accumulator", dev->xy_acc); x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS, - ATP_XFACT, &x_z, &x_f); + dev->info->xfact, &x_z, &x_f); y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS, - ATP_YFACT, &y_z, &y_f); - key = dev->data[dev->datalen - 1] & ATP_STATUS_BUTTON; + dev->info->yfact, &y_z, &y_f); + key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON; if (x && y) { if (dev->x_old != -1) { @@ -583,7 +616,7 @@ static void atp_complete_geyser_3_4(struct urb *urb) dbg_dump("sample", dev->xy_cur); /* Just update the base values (i.e. touchpad in untouched state) */ - if (dev->data[dev->datalen - 1] & ATP_STATUS_BASE_UPDATE) { + if (dev->data[dev->info->datalen - 1] & ATP_STATUS_BASE_UPDATE) { dprintk(KERN_DEBUG "appletouch: updated base values\n"); @@ -610,10 +643,10 @@ static void atp_complete_geyser_3_4(struct urb *urb) dbg_dump("accumulator", dev->xy_acc); x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS, - ATP_XFACT, &x_z, &x_f); + dev->info->xfact, &x_z, &x_f); y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS, - ATP_YFACT, &y_z, &y_f); - key = dev->data[dev->datalen - 1] & ATP_STATUS_BUTTON; + dev->info->yfact, &y_z, &y_f); + key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON; if (x && y) { if (dev->x_old != -1) { @@ -705,7 +738,7 @@ static int atp_handle_geyser(struct atp *dev) { struct usb_device *udev = dev->udev; - if (dev->type != ATP_FOUNTAIN) { + if (dev->info != &fountain_info) { /* switch to raw sensor mode */ if (atp_geyser_init(udev)) return -EIO; @@ -726,6 +759,7 @@ static int atp_probe(struct usb_interface *iface, struct usb_endpoint_descriptor *endpoint; int int_in_endpointAddr = 0; int i, error = -ENOMEM; + const struct atp_info *info = (const struct atp_info *)id->driver_info; /* set up the endpoint information */ /* use only the first interrupt-in endpoint */ @@ -753,35 +787,22 @@ static int atp_probe(struct usb_interface *iface, dev->udev = udev; dev->input = input_dev; - dev->type = id->driver_info; + dev->info = info; dev->overflow_warned = false; - if (dev->type == ATP_FOUNTAIN || dev->type == ATP_GEYSER1) - dev->datalen = 81; - else - dev->datalen = 64; dev->urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->urb) goto err_free_devs; - dev->data = usb_buffer_alloc(dev->udev, dev->datalen, GFP_KERNEL, + dev->data = usb_buffer_alloc(dev->udev, dev->info->datalen, GFP_KERNEL, &dev->urb->transfer_dma); if (!dev->data) goto err_free_urb; - /* Select the USB complete (callback) function */ - if (dev->type == ATP_FOUNTAIN || - dev->type == ATP_GEYSER1 || - dev->type == ATP_GEYSER2) - usb_fill_int_urb(dev->urb, udev, - usb_rcvintpipe(udev, int_in_endpointAddr), - dev->data, dev->datalen, - atp_complete_geyser_1_2, dev, 1); - else - usb_fill_int_urb(dev->urb, udev, - usb_rcvintpipe(udev, int_in_endpointAddr), - dev->data, dev->datalen, - atp_complete_geyser_3_4, dev, 1); + usb_fill_int_urb(dev->urb, udev, + usb_rcvintpipe(udev, int_in_endpointAddr), + dev->data, dev->info->datalen, + dev->info->callback, dev, 1); error = atp_handle_geyser(dev); if (error) @@ -802,35 +823,12 @@ static int atp_probe(struct usb_interface *iface, set_bit(EV_ABS, input_dev->evbit); - if (dev->type == ATP_GEYSER3 || dev->type == ATP_GEYSER4) { - /* - * MacBook have 20 X sensors, 10 Y sensors - */ - input_set_abs_params(input_dev, ABS_X, 0, - ((20 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0); - input_set_abs_params(input_dev, ABS_Y, 0, - ((10 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0); - } else if (dev->type == ATP_GEYSER2) { - /* - * Oct 2005 15" PowerBooks have 15 X sensors, 17" are detected - * later. - */ - input_set_abs_params(input_dev, ABS_X, 0, - ((15 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0); - input_set_abs_params(input_dev, ABS_Y, 0, - ((9 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0); - } else { - /* - * 12" and 15" Powerbooks only have 16 x sensors, - * 17" models are detected later. - */ - input_set_abs_params(input_dev, ABS_X, 0, - (16 - 1) * ATP_XFACT - 1, - ATP_FUZZ, 0); - input_set_abs_params(input_dev, ABS_Y, 0, - (ATP_YSENSORS - 1) * ATP_YFACT - 1, - ATP_FUZZ, 0); - } + input_set_abs_params(input_dev, ABS_X, 0, + (dev->info->xsensors - 1) * dev->info->xfact - 1, + ATP_FUZZ, 0); + input_set_abs_params(input_dev, ABS_Y, 0, + (dev->info->ysensors - 1) * dev->info->yfact - 1, + ATP_FUZZ, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0); set_bit(EV_KEY, input_dev->evbit); @@ -852,7 +850,7 @@ static int atp_probe(struct usb_interface *iface, return 0; err_free_buffer: - usb_buffer_free(dev->udev, dev->datalen, + usb_buffer_free(dev->udev, dev->info->datalen, dev->data, dev->urb->transfer_dma); err_free_urb: usb_free_urb(dev->urb); @@ -871,7 +869,7 @@ static void atp_disconnect(struct usb_interface *iface) if (dev) { usb_kill_urb(dev->urb); input_unregister_device(dev->input); - usb_buffer_free(dev->udev, dev->datalen, + usb_buffer_free(dev->udev, dev->info->datalen, dev->data, dev->urb->transfer_dma); usb_free_urb(dev->urb); kfree(dev); -- cgit v1.2.2 From e42b6646a8298fe06a33a0f68dab661335f5db6e Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 20 Nov 2008 15:24:42 -0500 Subject: Input: synaptics - report multi-taps only if supported by the device According to Section 2.4.4 of the Synaptics TouchPad Interfacing Guide, bit 2 specifies if multi-finger detection is provided by the touchpad. Thus, only set BTN_TOOL_DOUBLETAP and BTN_TOOL_TRIPLETAP if the device actually supports it. Signed-off-by: Peter Hutterer Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index d349c4a5e3e8..865fc69e9bc3 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -445,12 +445,14 @@ static void synaptics_process_packet(struct psmouse *psmouse) input_report_abs(dev, ABS_TOOL_WIDTH, finger_width); input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1); - input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2); - input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3); - input_report_key(dev, BTN_LEFT, hw.left); input_report_key(dev, BTN_RIGHT, hw.right); + if (SYN_CAP_MULTIFINGER(priv->capabilities)) { + input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2); + input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3); + } + if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) input_report_key(dev, BTN_MIDDLE, hw.middle); @@ -543,12 +545,14 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) set_bit(EV_KEY, dev->evbit); set_bit(BTN_TOUCH, dev->keybit); set_bit(BTN_TOOL_FINGER, dev->keybit); - set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); - set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); - set_bit(BTN_LEFT, dev->keybit); set_bit(BTN_RIGHT, dev->keybit); + if (SYN_CAP_MULTIFINGER(priv->capabilities)) { + set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); + set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); + } + if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) set_bit(BTN_MIDDLE, dev->keybit); -- cgit v1.2.2 From 8bbf2703c4f676e6e5414672dd460f7d2f979ed5 Mon Sep 17 00:00:00 2001 From: Paul Fox Date: Sat, 20 Dec 2008 03:58:11 -0500 Subject: Input: psmouse - add module parameters to control OLPC touchpad delays The HPGK touchpad that is found on the XO driver has historically exhibitted eratic behaviour in various environments (very dry, very humid, etc) that can be worked around via some delays. This patch turns those delays into module parameters to make testing simpler. Signed-off-by: Paul Fox Signed-off-by: Deepak Saxena Acked-By: Andres Salomon Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/hgpk.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c index 88f04bf2ad6c..81e6ebf323e9 100644 --- a/drivers/input/mouse/hgpk.c +++ b/drivers/input/mouse/hgpk.c @@ -48,6 +48,30 @@ module_param(recalib_delta, int, 0644); MODULE_PARM_DESC(recalib_delta, "packets containing a delta this large will cause a recalibration."); +static int jumpy_delay = 1000; +module_param(jumpy_delay, int, 0644); +MODULE_PARM_DESC(jumpy_delay, + "delay (ms) before recal after jumpiness detected"); + +static int spew_delay = 1000; +module_param(spew_delay, int, 0644); +MODULE_PARM_DESC(spew_delay, + "delay (ms) before recal after packet spew detected"); + +static int recal_guard_time = 2000; +module_param(recal_guard_time, int, 0644); +MODULE_PARM_DESC(recal_guard_time, + "interval (ms) during which recal will be restarted if packet received"); + +static int post_interrupt_delay = 1000; +module_param(post_interrupt_delay, int, 0644); +MODULE_PARM_DESC(post_interrupt_delay, + "delay (ms) before recal after recal interrupt detected"); + +static int autorecal = 1; +module_param(autorecal, int, 0644); +MODULE_PARM_DESC(autorecal, "enable recalibration in the driver"); + /* * When the touchpad gets ultra-sensitive, one can keep their finger 1/2" * above the pad and still have it send packets. This causes a jump cursor @@ -66,7 +90,7 @@ static void hgpk_jumpy_hack(struct psmouse *psmouse, int x, int y) /* My car gets forty rods to the hogshead and that's the * way I likes it! */ psmouse_queue_work(psmouse, &priv->recalib_wq, - msecs_to_jiffies(1000)); + msecs_to_jiffies(jumpy_delay)); } } @@ -103,7 +127,7 @@ static void hgpk_spewing_hack(struct psmouse *psmouse, hgpk_dbg(psmouse, "packet spew detected (%d,%d)\n", priv->x_tally, priv->y_tally); psmouse_queue_work(psmouse, &priv->recalib_wq, - msecs_to_jiffies(1000)); + msecs_to_jiffies(spew_delay)); } /* reset every 100 packets */ priv->count = 0; @@ -181,7 +205,7 @@ static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse) "packet inside calibration window, " "queueing another recalibration\n"); psmouse_queue_work(psmouse, &priv->recalib_wq, - msecs_to_jiffies(1000)); + msecs_to_jiffies(post_interrupt_delay)); } priv->recalib_window = 0; } @@ -231,7 +255,7 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse) * If someone's finger *was* on the touchpad, it's probably * miscalibrated. So, we should schedule another recalibration */ - priv->recalib_window = jiffies + msecs_to_jiffies(2000); + priv->recalib_window = jiffies + msecs_to_jiffies(recal_guard_time); return 0; } -- cgit v1.2.2 From 0de048aba1b751ee19a747dc4c82636579e47b85 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Sat, 20 Dec 2008 05:19:43 -0500 Subject: Input: make some variables and functions static Signed-off-by: Roel Kluin Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/gpio_mouse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/gpio_mouse.c b/drivers/input/mouse/gpio_mouse.c index 72cf5e33790e..0db8d16c5edd 100644 --- a/drivers/input/mouse/gpio_mouse.c +++ b/drivers/input/mouse/gpio_mouse.c @@ -173,7 +173,7 @@ static int __devexit gpio_mouse_remove(struct platform_device *pdev) /* work with hotplug and coldplug */ MODULE_ALIAS("platform:gpio_mouse"); -struct platform_driver gpio_mouse_device_driver = { +static struct platform_driver gpio_mouse_device_driver = { .remove = __devexit_p(gpio_mouse_remove), .driver = { .name = "gpio_mouse", -- cgit v1.2.2 From 105ca2398f89d141b87542d3dd58df90bc539275 Mon Sep 17 00:00:00 2001 From: Yong Yao Date: Mon, 29 Dec 2008 03:59:59 -0800 Subject: Input: add support for trackball on pxa930 and pxa935 Signed-off-by: Yong Yao Signed-off-by: Eric Miao Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/Kconfig | 6 + drivers/input/mouse/Makefile | 27 ++-- drivers/input/mouse/pxa930_trkball.c | 269 +++++++++++++++++++++++++++++++++++ 3 files changed, 289 insertions(+), 13 deletions(-) create mode 100644 drivers/input/mouse/pxa930_trkball.c (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 4e9934259775..093c8c1bca74 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -286,4 +286,10 @@ config MOUSE_GPIO To compile this driver as a module, choose M here: the module will be called gpio_mouse. +config MOUSE_PXA930_TRKBALL + tristate "PXA930 Trackball mouse" + depends on CPU_PXA930 || CPU_PXA935 + help + Say Y here to support PXA930 Trackball mouse. + endif diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 96f1dd8037f8..8c8a1f236e28 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -4,19 +4,20 @@ # Each configuration option enables a list of files. -obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o -obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o -obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o -obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o -obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o -obj-$(CONFIG_MOUSE_INPORT) += inport.o -obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o -obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o -obj-$(CONFIG_MOUSE_PS2) += psmouse.o -obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o -obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o -obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o -obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o +obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o +obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o +obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o +obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o +obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o +obj-$(CONFIG_MOUSE_INPORT) += inport.o +obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o +obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o +obj-$(CONFIG_MOUSE_PS2) += psmouse.o +obj-$(CONFIG_MOUSE_PXA930_TRKBALL) += pxa930_trkball.o +obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o +obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o +obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o +obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o psmouse-objs := psmouse-base.o synaptics.o diff --git a/drivers/input/mouse/pxa930_trkball.c b/drivers/input/mouse/pxa930_trkball.c new file mode 100644 index 000000000000..a0f45c4fc198 --- /dev/null +++ b/drivers/input/mouse/pxa930_trkball.c @@ -0,0 +1,269 @@ +/* + * PXA930 track ball mouse driver + * + * Copyright (C) 2007 Marvell International Ltd. + * 2008-02-28: Yong Yao + * initial version + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* Trackball Controller Register Definitions */ +#define TBCR (0x000C) +#define TBCNTR (0x0010) +#define TBSBC (0x0014) + +#define TBCR_TBRST (1 << 1) +#define TBCR_TBSB (1 << 10) + +#define TBCR_Y_FLT(n) (((n) & 0xf) << 6) +#define TBCR_X_FLT(n) (((n) & 0xf) << 2) + +#define TBCNTR_YM(n) (((n) >> 24) & 0xff) +#define TBCNTR_YP(n) (((n) >> 16) & 0xff) +#define TBCNTR_XM(n) (((n) >> 8) & 0xff) +#define TBCNTR_XP(n) ((n) & 0xff) + +#define TBSBC_TBSBC (0x1) + +struct pxa930_trkball { + struct pxa930_trkball_platform_data *pdata; + + /* Memory Mapped Register */ + struct resource *mem; + void __iomem *mmio_base; + + struct input_dev *input; +}; + +static irqreturn_t pxa930_trkball_interrupt(int irq, void *dev_id) +{ + struct pxa930_trkball *trkball = dev_id; + struct input_dev *input = trkball->input; + int tbcntr, x, y; + + /* According to the spec software must read TBCNTR twice: + * if the read value is the same, the reading is valid + */ + tbcntr = __raw_readl(trkball->mmio_base + TBCNTR); + + if (tbcntr == __raw_readl(trkball->mmio_base + TBCNTR)) { + x = (TBCNTR_XP(tbcntr) - TBCNTR_XM(tbcntr)) / 2; + y = (TBCNTR_YP(tbcntr) - TBCNTR_YM(tbcntr)) / 2; + + input_report_rel(input, REL_X, x); + input_report_rel(input, REL_Y, y); + input_sync(input); + } + + __raw_writel(TBSBC_TBSBC, trkball->mmio_base + TBSBC); + __raw_writel(0, trkball->mmio_base + TBSBC); + + return IRQ_HANDLED; +} + +/* For TBCR, we need to wait for a while to make sure it has been modified. */ +static int write_tbcr(struct pxa930_trkball *trkball, int v) +{ + int i = 100; + + __raw_writel(v, trkball->mmio_base + TBCR); + + while (i--) { + if (__raw_readl(trkball->mmio_base + TBCR) == v) + break; + msleep(1); + } + + if (i == 0) { + pr_err("%s: timed out writing TBCR(%x)!\n", __func__, v); + return -ETIMEDOUT; + } + + return 0; +} + +static void pxa930_trkball_config(struct pxa930_trkball *trkball) +{ + uint32_t tbcr; + + /* According to spec, need to write the filters of x,y to 0xf first! */ + tbcr = __raw_readl(trkball->mmio_base + TBCR); + write_tbcr(trkball, tbcr | TBCR_X_FLT(0xf) | TBCR_Y_FLT(0xf)); + write_tbcr(trkball, TBCR_X_FLT(trkball->pdata->x_filter) | + TBCR_Y_FLT(trkball->pdata->y_filter)); + + /* According to spec, set TBCR_TBRST first, before clearing it! */ + tbcr = __raw_readl(trkball->mmio_base + TBCR); + write_tbcr(trkball, tbcr | TBCR_TBRST); + write_tbcr(trkball, tbcr & ~TBCR_TBRST); + + __raw_writel(TBSBC_TBSBC, trkball->mmio_base + TBSBC); + __raw_writel(0, trkball->mmio_base + TBSBC); + + pr_debug("%s: final TBCR=%x!\n", __func__, + __raw_readl(trkball->mmio_base + TBCR)); +} + +static int pxa930_trkball_open(struct input_dev *dev) +{ + struct pxa930_trkball *trkball = input_get_drvdata(dev); + + pxa930_trkball_config(trkball); + + return 0; +} + +static void pxa930_trkball_disable(struct pxa930_trkball *trkball) +{ + uint32_t tbcr = __raw_readl(trkball->mmio_base + TBCR); + + /* Held in reset, gate the 32-KHz input clock off */ + write_tbcr(trkball, tbcr | TBCR_TBRST); +} + +static void pxa930_trkball_close(struct input_dev *dev) +{ + struct pxa930_trkball *trkball = input_get_drvdata(dev); + + pxa930_trkball_disable(trkball); +} + +static int __devinit pxa930_trkball_probe(struct platform_device *pdev) +{ + struct pxa930_trkball *trkball; + struct input_dev *input; + struct resource *res; + int irq, error; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get trkball irq\n"); + return -ENXIO; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to get register memory\n"); + return -ENXIO; + } + + trkball = kzalloc(sizeof(struct pxa930_trkball), GFP_KERNEL); + if (!trkball) + return -ENOMEM; + + trkball->pdata = pdev->dev.platform_data; + if (!trkball->pdata) { + dev_err(&pdev->dev, "no platform data defined\n"); + error = -EINVAL; + goto failed; + } + + trkball->mmio_base = ioremap_nocache(res->start, resource_size(res)); + if (!trkball->mmio_base) { + dev_err(&pdev->dev, "failed to ioremap registers\n"); + error = -ENXIO; + goto failed; + } + + /* held the module in reset, will be enabled in open() */ + pxa930_trkball_disable(trkball); + + error = request_irq(irq, pxa930_trkball_interrupt, IRQF_DISABLED, + pdev->name, trkball); + if (error) { + dev_err(&pdev->dev, "failed to request irq: %d\n", ret); + goto failed_free_io; + } + + platform_set_drvdata(pdev, trkball); + + input = input_allocate_device(); + if (!input) { + dev_err(&pdev->dev, "failed to allocate input device\n"); + error = -ENOMEM; + goto failed_free_irq; + } + + input->name = pdev->name; + input->id.bustype = BUS_HOST; + input->open = pxa930_trkball_open; + input->close = pxa930_trkball_close; + input->dev.parent = &pdev->dev; + input_set_drvdata(input, trkball); + + trkball->input = input; + + input_set_capability(input, EV_REL, REL_X); + input_set_capability(input, EV_REL, REL_Y); + + error = input_register_device(input); + if (error) { + dev_err(&pdev->dev, "unable to register input device\n"); + goto failed_free_input; + } + + return 0; + +failed_free_input: + input_free_device(input); +failed_free_irq: + free_irq(irq, trkball); +failed_free_io: + iounmap(trkball->mmio_base); +failed: + kfree(trkball); + return ret; +} + +static int __devexit pxa930_trkball_remove(struct platform_device *pdev) +{ + struct pxa930_trkball *trkball = platform_get_drvdata(pdev); + int irq = platform_get_irq(pdev, 0); + + input_unregister_device(trkball->input); + free_irq(irq, trkball); + iounmap(trkball->mmio_base); + kfree(trkball); + + return 0; +} + +static struct platform_driver pxa930_trkball_driver = { + .driver = { + .name = "pxa930-trkball", + }, + .probe = pxa930_trkball_probe, + .remove = __devexit_p(pxa930_trkball_remove), +}; + +static int __init pxa930_trkball_init(void) +{ + return platform_driver_register(&pxa930_trkball_driver); +} + +static void __exit pxa930_trkball_exit(void) +{ + platform_driver_unregister(&pxa930_trkball_driver); +} + +module_init(pxa930_trkball_init); +module_exit(pxa930_trkball_exit); + +MODULE_AUTHOR("Yong Yao "); +MODULE_DESCRIPTION("PXA930 Trackball Mouse Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From c10a93a0a36b245ce48493f134b9e243a8bfddd1 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 29 Dec 2008 04:44:44 -0800 Subject: Input: HIL drivers - add MODULE_ALIAS() Add MODULE_ALIAS() to the HIL keyboard (hil_kbd.c) and HIL mouse (hil_ptr.c) drivers to make kernel module autoloader functional. Report HIL port number ID in serio id.id field. Signed-off-by: Helge Deller Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/hil_ptr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c index e532c48410ea..3263ce083bf0 100644 --- a/drivers/input/mouse/hil_ptr.c +++ b/drivers/input/mouse/hil_ptr.c @@ -46,7 +46,7 @@ MODULE_AUTHOR("Brian S. Julin "); MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver"); MODULE_LICENSE("Dual BSD/GPL"); - +MODULE_ALIAS("serio:ty03pr25id0Fex*"); #define TABLET_SIMULATES_MOUSE /* allow tablet to be used as mouse */ #undef TABLET_AUTOADJUST /* auto-adjust valid tablet ranges */ -- cgit v1.2.2