10f2213208f8da51bcb665309e3468f000489c04fJiri Slaby/* 20f2213208f8da51bcb665309e3468f000489c04fJiri Slaby * HID driver for some cypress "special" devices 30f2213208f8da51bcb665309e3468f000489c04fJiri Slaby * 40f2213208f8da51bcb665309e3468f000489c04fJiri Slaby * Copyright (c) 1999 Andreas Gal 50f2213208f8da51bcb665309e3468f000489c04fJiri Slaby * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> 60f2213208f8da51bcb665309e3468f000489c04fJiri Slaby * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc 70f2213208f8da51bcb665309e3468f000489c04fJiri Slaby * Copyright (c) 2006-2007 Jiri Kosina 80f2213208f8da51bcb665309e3468f000489c04fJiri Slaby * Copyright (c) 2007 Paul Walmsley 90f2213208f8da51bcb665309e3468f000489c04fJiri Slaby * Copyright (c) 2008 Jiri Slaby 100f2213208f8da51bcb665309e3468f000489c04fJiri Slaby */ 110f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 120f2213208f8da51bcb665309e3468f000489c04fJiri Slaby/* 130f2213208f8da51bcb665309e3468f000489c04fJiri Slaby * This program is free software; you can redistribute it and/or modify it 140f2213208f8da51bcb665309e3468f000489c04fJiri Slaby * under the terms of the GNU General Public License as published by the Free 150f2213208f8da51bcb665309e3468f000489c04fJiri Slaby * Software Foundation; either version 2 of the License, or (at your option) 160f2213208f8da51bcb665309e3468f000489c04fJiri Slaby * any later version. 170f2213208f8da51bcb665309e3468f000489c04fJiri Slaby */ 180f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 190f2213208f8da51bcb665309e3468f000489c04fJiri Slaby#include <linux/device.h> 200f2213208f8da51bcb665309e3468f000489c04fJiri Slaby#include <linux/hid.h> 210f2213208f8da51bcb665309e3468f000489c04fJiri Slaby#include <linux/input.h> 220f2213208f8da51bcb665309e3468f000489c04fJiri Slaby#include <linux/module.h> 230f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 240f2213208f8da51bcb665309e3468f000489c04fJiri Slaby#include "hid-ids.h" 250f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 260f2213208f8da51bcb665309e3468f000489c04fJiri Slaby#define CP_RDESC_SWAPPED_MIN_MAX 0x01 270f2213208f8da51bcb665309e3468f000489c04fJiri Slaby#define CP_2WHEEL_MOUSE_HACK 0x02 280f2213208f8da51bcb665309e3468f000489c04fJiri Slaby#define CP_2WHEEL_MOUSE_HACK_ON 0x04 290f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 300f2213208f8da51bcb665309e3468f000489c04fJiri Slaby/* 310f2213208f8da51bcb665309e3468f000489c04fJiri Slaby * Some USB barcode readers from cypress have usage min and usage max in 320f2213208f8da51bcb665309e3468f000489c04fJiri Slaby * the wrong order 330f2213208f8da51bcb665309e3468f000489c04fJiri Slaby */ 3473e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashovstatic __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc, 3573e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov unsigned int *rsize) 360f2213208f8da51bcb665309e3468f000489c04fJiri Slaby{ 370f2213208f8da51bcb665309e3468f000489c04fJiri Slaby unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); 380f2213208f8da51bcb665309e3468f000489c04fJiri Slaby unsigned int i; 390f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 400f2213208f8da51bcb665309e3468f000489c04fJiri Slaby if (!(quirks & CP_RDESC_SWAPPED_MIN_MAX)) 4173e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov return rdesc; 420f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 4373e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov for (i = 0; i < *rsize - 4; i++) 440f2213208f8da51bcb665309e3468f000489c04fJiri Slaby if (rdesc[i] == 0x29 && rdesc[i + 2] == 0x19) { 450f2213208f8da51bcb665309e3468f000489c04fJiri Slaby __u8 tmp; 460f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 470f2213208f8da51bcb665309e3468f000489c04fJiri Slaby rdesc[i] = 0x19; 480f2213208f8da51bcb665309e3468f000489c04fJiri Slaby rdesc[i + 2] = 0x29; 490f2213208f8da51bcb665309e3468f000489c04fJiri Slaby tmp = rdesc[i + 3]; 500f2213208f8da51bcb665309e3468f000489c04fJiri Slaby rdesc[i + 3] = rdesc[i + 1]; 510f2213208f8da51bcb665309e3468f000489c04fJiri Slaby rdesc[i + 1] = tmp; 520f2213208f8da51bcb665309e3468f000489c04fJiri Slaby } 5373e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov return rdesc; 540f2213208f8da51bcb665309e3468f000489c04fJiri Slaby} 550f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 560f2213208f8da51bcb665309e3468f000489c04fJiri Slabystatic int cp_input_mapped(struct hid_device *hdev, struct hid_input *hi, 570f2213208f8da51bcb665309e3468f000489c04fJiri Slaby struct hid_field *field, struct hid_usage *usage, 580f2213208f8da51bcb665309e3468f000489c04fJiri Slaby unsigned long **bit, int *max) 590f2213208f8da51bcb665309e3468f000489c04fJiri Slaby{ 600f2213208f8da51bcb665309e3468f000489c04fJiri Slaby unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); 610f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 620f2213208f8da51bcb665309e3468f000489c04fJiri Slaby if (!(quirks & CP_2WHEEL_MOUSE_HACK)) 630f2213208f8da51bcb665309e3468f000489c04fJiri Slaby return 0; 640f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 650f2213208f8da51bcb665309e3468f000489c04fJiri Slaby if (usage->type == EV_REL && usage->code == REL_WHEEL) 660f2213208f8da51bcb665309e3468f000489c04fJiri Slaby set_bit(REL_HWHEEL, *bit); 670f2213208f8da51bcb665309e3468f000489c04fJiri Slaby if (usage->hid == 0x00090005) 680f2213208f8da51bcb665309e3468f000489c04fJiri Slaby return -1; 690f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 700f2213208f8da51bcb665309e3468f000489c04fJiri Slaby return 0; 710f2213208f8da51bcb665309e3468f000489c04fJiri Slaby} 720f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 730f2213208f8da51bcb665309e3468f000489c04fJiri Slabystatic int cp_event(struct hid_device *hdev, struct hid_field *field, 740f2213208f8da51bcb665309e3468f000489c04fJiri Slaby struct hid_usage *usage, __s32 value) 750f2213208f8da51bcb665309e3468f000489c04fJiri Slaby{ 760f2213208f8da51bcb665309e3468f000489c04fJiri Slaby unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); 770f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 780f2213208f8da51bcb665309e3468f000489c04fJiri Slaby if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || 790f2213208f8da51bcb665309e3468f000489c04fJiri Slaby !usage->type || !(quirks & CP_2WHEEL_MOUSE_HACK)) 800f2213208f8da51bcb665309e3468f000489c04fJiri Slaby return 0; 810f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 820f2213208f8da51bcb665309e3468f000489c04fJiri Slaby if (usage->hid == 0x00090005) { 830f2213208f8da51bcb665309e3468f000489c04fJiri Slaby if (value) 840f2213208f8da51bcb665309e3468f000489c04fJiri Slaby quirks |= CP_2WHEEL_MOUSE_HACK_ON; 850f2213208f8da51bcb665309e3468f000489c04fJiri Slaby else 860f2213208f8da51bcb665309e3468f000489c04fJiri Slaby quirks &= ~CP_2WHEEL_MOUSE_HACK_ON; 870f2213208f8da51bcb665309e3468f000489c04fJiri Slaby hid_set_drvdata(hdev, (void *)quirks); 880f2213208f8da51bcb665309e3468f000489c04fJiri Slaby return 1; 890f2213208f8da51bcb665309e3468f000489c04fJiri Slaby } 900f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 910f2213208f8da51bcb665309e3468f000489c04fJiri Slaby if (usage->code == REL_WHEEL && (quirks & CP_2WHEEL_MOUSE_HACK_ON)) { 920f2213208f8da51bcb665309e3468f000489c04fJiri Slaby struct input_dev *input = field->hidinput->input; 930f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 940f2213208f8da51bcb665309e3468f000489c04fJiri Slaby input_event(input, usage->type, REL_HWHEEL, value); 950f2213208f8da51bcb665309e3468f000489c04fJiri Slaby return 1; 960f2213208f8da51bcb665309e3468f000489c04fJiri Slaby } 970f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 980f2213208f8da51bcb665309e3468f000489c04fJiri Slaby return 0; 990f2213208f8da51bcb665309e3468f000489c04fJiri Slaby} 1000f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 1010f2213208f8da51bcb665309e3468f000489c04fJiri Slabystatic int cp_probe(struct hid_device *hdev, const struct hid_device_id *id) 1020f2213208f8da51bcb665309e3468f000489c04fJiri Slaby{ 1030f2213208f8da51bcb665309e3468f000489c04fJiri Slaby unsigned long quirks = id->driver_data; 1040f2213208f8da51bcb665309e3468f000489c04fJiri Slaby int ret; 1050f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 1060f2213208f8da51bcb665309e3468f000489c04fJiri Slaby hid_set_drvdata(hdev, (void *)quirks); 1070f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 1080f2213208f8da51bcb665309e3468f000489c04fJiri Slaby ret = hid_parse(hdev); 1090f2213208f8da51bcb665309e3468f000489c04fJiri Slaby if (ret) { 1104291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_err(hdev, "parse failed\n"); 1110f2213208f8da51bcb665309e3468f000489c04fJiri Slaby goto err_free; 1120f2213208f8da51bcb665309e3468f000489c04fJiri Slaby } 1130f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 11493c10132a7ac160df3175b53f7ee857625412165Jiri Slaby ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 1150f2213208f8da51bcb665309e3468f000489c04fJiri Slaby if (ret) { 1164291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_err(hdev, "hw start failed\n"); 1170f2213208f8da51bcb665309e3468f000489c04fJiri Slaby goto err_free; 1180f2213208f8da51bcb665309e3468f000489c04fJiri Slaby } 1190f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 1200f2213208f8da51bcb665309e3468f000489c04fJiri Slaby return 0; 1210f2213208f8da51bcb665309e3468f000489c04fJiri Slabyerr_free: 1220f2213208f8da51bcb665309e3468f000489c04fJiri Slaby return ret; 1230f2213208f8da51bcb665309e3468f000489c04fJiri Slaby} 1240f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 1250f2213208f8da51bcb665309e3468f000489c04fJiri Slabystatic const struct hid_device_id cp_devices[] = { 1260f2213208f8da51bcb665309e3468f000489c04fJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1), 1270f2213208f8da51bcb665309e3468f000489c04fJiri Slaby .driver_data = CP_RDESC_SWAPPED_MIN_MAX }, 1280f2213208f8da51bcb665309e3468f000489c04fJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2), 1290f2213208f8da51bcb665309e3468f000489c04fJiri Slaby .driver_data = CP_RDESC_SWAPPED_MIN_MAX }, 130e8d0eab4d9eda9f5e97852f780f020bfb134f9f0Jiri Kosina { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3), 131e8d0eab4d9eda9f5e97852f780f020bfb134f9f0Jiri Kosina .driver_data = CP_RDESC_SWAPPED_MIN_MAX }, 1320f2213208f8da51bcb665309e3468f000489c04fJiri Slaby { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE), 1330f2213208f8da51bcb665309e3468f000489c04fJiri Slaby .driver_data = CP_2WHEEL_MOUSE_HACK }, 1340f2213208f8da51bcb665309e3468f000489c04fJiri Slaby { } 1350f2213208f8da51bcb665309e3468f000489c04fJiri Slaby}; 1360f2213208f8da51bcb665309e3468f000489c04fJiri SlabyMODULE_DEVICE_TABLE(hid, cp_devices); 1370f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 1380f2213208f8da51bcb665309e3468f000489c04fJiri Slabystatic struct hid_driver cp_driver = { 1390f2213208f8da51bcb665309e3468f000489c04fJiri Slaby .name = "cypress", 1400f2213208f8da51bcb665309e3468f000489c04fJiri Slaby .id_table = cp_devices, 1410f2213208f8da51bcb665309e3468f000489c04fJiri Slaby .report_fixup = cp_report_fixup, 1420f2213208f8da51bcb665309e3468f000489c04fJiri Slaby .input_mapped = cp_input_mapped, 1430f2213208f8da51bcb665309e3468f000489c04fJiri Slaby .event = cp_event, 1440f2213208f8da51bcb665309e3468f000489c04fJiri Slaby .probe = cp_probe, 1450f2213208f8da51bcb665309e3468f000489c04fJiri Slaby}; 1460f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 147a24f423bdf253ccee369adc6c5451b40a0716fbbPeter Huewestatic int __init cp_init(void) 1480f2213208f8da51bcb665309e3468f000489c04fJiri Slaby{ 1490f2213208f8da51bcb665309e3468f000489c04fJiri Slaby return hid_register_driver(&cp_driver); 1500f2213208f8da51bcb665309e3468f000489c04fJiri Slaby} 1510f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 152a24f423bdf253ccee369adc6c5451b40a0716fbbPeter Huewestatic void __exit cp_exit(void) 1530f2213208f8da51bcb665309e3468f000489c04fJiri Slaby{ 1540f2213208f8da51bcb665309e3468f000489c04fJiri Slaby hid_unregister_driver(&cp_driver); 1550f2213208f8da51bcb665309e3468f000489c04fJiri Slaby} 1560f2213208f8da51bcb665309e3468f000489c04fJiri Slaby 1570f2213208f8da51bcb665309e3468f000489c04fJiri Slabymodule_init(cp_init); 1580f2213208f8da51bcb665309e3468f000489c04fJiri Slabymodule_exit(cp_exit); 1590f2213208f8da51bcb665309e3468f000489c04fJiri SlabyMODULE_LICENSE("GPL"); 160