18c2ecf20Sopenharmony_ci/* -*- linux-c -*- 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ciGTCO digitizer USB driver 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ciTO CHECK: Is pressure done right on report 5? 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ciCopyright (C) 2006 GTCO CalComp 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ciThis program is free software; you can redistribute it and/or 108c2ecf20Sopenharmony_cimodify it under the terms of the GNU General Public License 118c2ecf20Sopenharmony_cias published by the Free Software Foundation; version 2 128c2ecf20Sopenharmony_ciof the License. 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ciThis program is distributed in the hope that it will be useful, 158c2ecf20Sopenharmony_cibut WITHOUT ANY WARRANTY; without even the implied warranty of 168c2ecf20Sopenharmony_ciMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 178c2ecf20Sopenharmony_ciGNU General Public License for more details. 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ciYou should have received a copy of the GNU General Public License 208c2ecf20Sopenharmony_cialong with this program; if not, write to the Free Software 218c2ecf20Sopenharmony_ciFoundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ciPermission to use, copy, modify, distribute, and sell this software and its 248c2ecf20Sopenharmony_cidocumentation for any purpose is hereby granted without fee, provided that 258c2ecf20Sopenharmony_cithe above copyright notice appear in all copies and that both that 268c2ecf20Sopenharmony_cicopyright notice and this permission notice appear in supporting 278c2ecf20Sopenharmony_cidocumentation, and that the name of GTCO-CalComp not be used in advertising 288c2ecf20Sopenharmony_cior publicity pertaining to distribution of the software without specific, 298c2ecf20Sopenharmony_ciwritten prior permission. GTCO-CalComp makes no representations about the 308c2ecf20Sopenharmony_cisuitability of this software for any purpose. It is provided "as is" 318c2ecf20Sopenharmony_ciwithout express or implied warranty. 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ciGTCO-CALCOMP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 348c2ecf20Sopenharmony_ciINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 358c2ecf20Sopenharmony_ciEVENT SHALL GTCO-CALCOMP BE LIABLE FOR ANY SPECIAL, INDIRECT OR 368c2ecf20Sopenharmony_ciCONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 378c2ecf20Sopenharmony_ciDATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 388c2ecf20Sopenharmony_ciTORTIOUS ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 398c2ecf20Sopenharmony_ciPERFORMANCE OF THIS SOFTWARE. 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciGTCO CalComp, Inc. 428c2ecf20Sopenharmony_ci7125 Riverwood Drive 438c2ecf20Sopenharmony_ciColumbia, MD 21046 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ciJeremy Roberson jroberson@gtcocalcomp.com 468c2ecf20Sopenharmony_ciScott Hill shill@gtcocalcomp.com 478c2ecf20Sopenharmony_ci*/ 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/*#define DEBUG*/ 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#include <linux/kernel.h> 548c2ecf20Sopenharmony_ci#include <linux/module.h> 558c2ecf20Sopenharmony_ci#include <linux/errno.h> 568c2ecf20Sopenharmony_ci#include <linux/slab.h> 578c2ecf20Sopenharmony_ci#include <linux/input.h> 588c2ecf20Sopenharmony_ci#include <linux/usb.h> 598c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 608c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 618c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 628c2ecf20Sopenharmony_ci#include <linux/bitops.h> 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#include <linux/usb/input.h> 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* Version with a Major number of 2 is for kernel inclusion only. */ 678c2ecf20Sopenharmony_ci#define GTCO_VERSION "2.00.0006" 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* MACROS */ 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define VENDOR_ID_GTCO 0x078C 738c2ecf20Sopenharmony_ci#define PID_400 0x400 748c2ecf20Sopenharmony_ci#define PID_401 0x401 758c2ecf20Sopenharmony_ci#define PID_1000 0x1000 768c2ecf20Sopenharmony_ci#define PID_1001 0x1001 778c2ecf20Sopenharmony_ci#define PID_1002 0x1002 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* Max size of a single report */ 808c2ecf20Sopenharmony_ci#define REPORT_MAX_SIZE 10 818c2ecf20Sopenharmony_ci#define MAX_COLLECTION_LEVELS 10 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* Bitmask whether pen is in range */ 858c2ecf20Sopenharmony_ci#define MASK_INRANGE 0x20 868c2ecf20Sopenharmony_ci#define MASK_BUTTON 0x01F 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#define PATHLENGTH 64 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* DATA STRUCTURES */ 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* Device table */ 938c2ecf20Sopenharmony_cistatic const struct usb_device_id gtco_usbid_table[] = { 948c2ecf20Sopenharmony_ci { USB_DEVICE(VENDOR_ID_GTCO, PID_400) }, 958c2ecf20Sopenharmony_ci { USB_DEVICE(VENDOR_ID_GTCO, PID_401) }, 968c2ecf20Sopenharmony_ci { USB_DEVICE(VENDOR_ID_GTCO, PID_1000) }, 978c2ecf20Sopenharmony_ci { USB_DEVICE(VENDOR_ID_GTCO, PID_1001) }, 988c2ecf20Sopenharmony_ci { USB_DEVICE(VENDOR_ID_GTCO, PID_1002) }, 998c2ecf20Sopenharmony_ci { } 1008c2ecf20Sopenharmony_ci}; 1018c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE (usb, gtco_usbid_table); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* Structure to hold all of our device specific stuff */ 1058c2ecf20Sopenharmony_cistruct gtco { 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci struct input_dev *inputdevice; /* input device struct pointer */ 1088c2ecf20Sopenharmony_ci struct usb_interface *intf; /* the usb interface for this device */ 1098c2ecf20Sopenharmony_ci struct urb *urbinfo; /* urb for incoming reports */ 1108c2ecf20Sopenharmony_ci dma_addr_t buf_dma; /* dma addr of the data buffer*/ 1118c2ecf20Sopenharmony_ci unsigned char * buffer; /* databuffer for reports */ 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci char usbpath[PATHLENGTH]; 1148c2ecf20Sopenharmony_ci int openCount; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci /* Information pulled from Report Descriptor */ 1178c2ecf20Sopenharmony_ci u32 usage; 1188c2ecf20Sopenharmony_ci u32 min_X; 1198c2ecf20Sopenharmony_ci u32 max_X; 1208c2ecf20Sopenharmony_ci u32 min_Y; 1218c2ecf20Sopenharmony_ci u32 max_Y; 1228c2ecf20Sopenharmony_ci s8 mintilt_X; 1238c2ecf20Sopenharmony_ci s8 maxtilt_X; 1248c2ecf20Sopenharmony_ci s8 mintilt_Y; 1258c2ecf20Sopenharmony_ci s8 maxtilt_Y; 1268c2ecf20Sopenharmony_ci u32 maxpressure; 1278c2ecf20Sopenharmony_ci u32 minpressure; 1288c2ecf20Sopenharmony_ci}; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/* Code for parsing the HID REPORT DESCRIPTOR */ 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/* From HID1.11 spec */ 1358c2ecf20Sopenharmony_cistruct hid_descriptor 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct usb_descriptor_header header; 1388c2ecf20Sopenharmony_ci __le16 bcdHID; 1398c2ecf20Sopenharmony_ci u8 bCountryCode; 1408c2ecf20Sopenharmony_ci u8 bNumDescriptors; 1418c2ecf20Sopenharmony_ci u8 bDescriptorType; 1428c2ecf20Sopenharmony_ci __le16 wDescriptorLength; 1438c2ecf20Sopenharmony_ci} __attribute__ ((packed)); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci#define HID_DESCRIPTOR_SIZE 9 1478c2ecf20Sopenharmony_ci#define HID_DEVICE_TYPE 33 1488c2ecf20Sopenharmony_ci#define REPORT_DEVICE_TYPE 34 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci#define PREF_TAG(x) ((x)>>4) 1528c2ecf20Sopenharmony_ci#define PREF_TYPE(x) ((x>>2)&0x03) 1538c2ecf20Sopenharmony_ci#define PREF_SIZE(x) ((x)&0x03) 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci#define TYPE_MAIN 0 1568c2ecf20Sopenharmony_ci#define TYPE_GLOBAL 1 1578c2ecf20Sopenharmony_ci#define TYPE_LOCAL 2 1588c2ecf20Sopenharmony_ci#define TYPE_RESERVED 3 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci#define TAG_MAIN_INPUT 0x8 1618c2ecf20Sopenharmony_ci#define TAG_MAIN_OUTPUT 0x9 1628c2ecf20Sopenharmony_ci#define TAG_MAIN_FEATURE 0xB 1638c2ecf20Sopenharmony_ci#define TAG_MAIN_COL_START 0xA 1648c2ecf20Sopenharmony_ci#define TAG_MAIN_COL_END 0xC 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci#define TAG_GLOB_USAGE 0 1678c2ecf20Sopenharmony_ci#define TAG_GLOB_LOG_MIN 1 1688c2ecf20Sopenharmony_ci#define TAG_GLOB_LOG_MAX 2 1698c2ecf20Sopenharmony_ci#define TAG_GLOB_PHYS_MIN 3 1708c2ecf20Sopenharmony_ci#define TAG_GLOB_PHYS_MAX 4 1718c2ecf20Sopenharmony_ci#define TAG_GLOB_UNIT_EXP 5 1728c2ecf20Sopenharmony_ci#define TAG_GLOB_UNIT 6 1738c2ecf20Sopenharmony_ci#define TAG_GLOB_REPORT_SZ 7 1748c2ecf20Sopenharmony_ci#define TAG_GLOB_REPORT_ID 8 1758c2ecf20Sopenharmony_ci#define TAG_GLOB_REPORT_CNT 9 1768c2ecf20Sopenharmony_ci#define TAG_GLOB_PUSH 10 1778c2ecf20Sopenharmony_ci#define TAG_GLOB_POP 11 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci#define TAG_GLOB_MAX 12 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci#define DIGITIZER_USAGE_TIP_PRESSURE 0x30 1828c2ecf20Sopenharmony_ci#define DIGITIZER_USAGE_TILT_X 0x3D 1838c2ecf20Sopenharmony_ci#define DIGITIZER_USAGE_TILT_Y 0x3E 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/* 1878c2ecf20Sopenharmony_ci * This is an abbreviated parser for the HID Report Descriptor. We 1888c2ecf20Sopenharmony_ci * know what devices we are talking to, so this is by no means meant 1898c2ecf20Sopenharmony_ci * to be generic. We can make some safe assumptions: 1908c2ecf20Sopenharmony_ci * 1918c2ecf20Sopenharmony_ci * - We know there are no LONG tags, all short 1928c2ecf20Sopenharmony_ci * - We know that we have no MAIN Feature and MAIN Output items 1938c2ecf20Sopenharmony_ci * - We know what the IRQ reports are supposed to look like. 1948c2ecf20Sopenharmony_ci * 1958c2ecf20Sopenharmony_ci * The main purpose of this is to use the HID report desc to figure 1968c2ecf20Sopenharmony_ci * out the mins and maxs of the fields in the IRQ reports. The IRQ 1978c2ecf20Sopenharmony_ci * reports for 400/401 change slightly if the max X is bigger than 64K. 1988c2ecf20Sopenharmony_ci * 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_cistatic void parse_hid_report_descriptor(struct gtco *device, char * report, 2018c2ecf20Sopenharmony_ci int length) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct device *ddev = &device->intf->dev; 2048c2ecf20Sopenharmony_ci int x, i = 0; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* Tag primitive vars */ 2078c2ecf20Sopenharmony_ci __u8 prefix; 2088c2ecf20Sopenharmony_ci __u8 size; 2098c2ecf20Sopenharmony_ci __u8 tag; 2108c2ecf20Sopenharmony_ci __u8 type; 2118c2ecf20Sopenharmony_ci __u8 data = 0; 2128c2ecf20Sopenharmony_ci __u16 data16 = 0; 2138c2ecf20Sopenharmony_ci __u32 data32 = 0; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* For parsing logic */ 2168c2ecf20Sopenharmony_ci int inputnum = 0; 2178c2ecf20Sopenharmony_ci __u32 usage = 0; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* Global Values, indexed by TAG */ 2208c2ecf20Sopenharmony_ci __u32 globalval[TAG_GLOB_MAX]; 2218c2ecf20Sopenharmony_ci __u32 oldval[TAG_GLOB_MAX]; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci /* Debug stuff */ 2248c2ecf20Sopenharmony_ci char maintype = 'x'; 2258c2ecf20Sopenharmony_ci char globtype[12]; 2268c2ecf20Sopenharmony_ci int indent = 0; 2278c2ecf20Sopenharmony_ci char indentstr[MAX_COLLECTION_LEVELS + 1] = { 0 }; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci dev_dbg(ddev, "======>>>>>>PARSE<<<<<<======\n"); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* Walk this report and pull out the info we need */ 2328c2ecf20Sopenharmony_ci while (i < length) { 2338c2ecf20Sopenharmony_ci prefix = report[i++]; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci /* Determine data size and save the data in the proper variable */ 2368c2ecf20Sopenharmony_ci size = (1U << PREF_SIZE(prefix)) >> 1; 2378c2ecf20Sopenharmony_ci if (i + size > length) { 2388c2ecf20Sopenharmony_ci dev_err(ddev, 2398c2ecf20Sopenharmony_ci "Not enough data (need %d, have %d)\n", 2408c2ecf20Sopenharmony_ci i + size, length); 2418c2ecf20Sopenharmony_ci break; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci switch (size) { 2458c2ecf20Sopenharmony_ci case 1: 2468c2ecf20Sopenharmony_ci data = report[i]; 2478c2ecf20Sopenharmony_ci break; 2488c2ecf20Sopenharmony_ci case 2: 2498c2ecf20Sopenharmony_ci data16 = get_unaligned_le16(&report[i]); 2508c2ecf20Sopenharmony_ci break; 2518c2ecf20Sopenharmony_ci case 4: 2528c2ecf20Sopenharmony_ci data32 = get_unaligned_le32(&report[i]); 2538c2ecf20Sopenharmony_ci break; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci /* Skip size of data */ 2578c2ecf20Sopenharmony_ci i += size; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* What we do depends on the tag type */ 2608c2ecf20Sopenharmony_ci tag = PREF_TAG(prefix); 2618c2ecf20Sopenharmony_ci type = PREF_TYPE(prefix); 2628c2ecf20Sopenharmony_ci switch (type) { 2638c2ecf20Sopenharmony_ci case TYPE_MAIN: 2648c2ecf20Sopenharmony_ci strcpy(globtype, ""); 2658c2ecf20Sopenharmony_ci switch (tag) { 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci case TAG_MAIN_INPUT: 2688c2ecf20Sopenharmony_ci /* 2698c2ecf20Sopenharmony_ci * The INPUT MAIN tag signifies this is 2708c2ecf20Sopenharmony_ci * information from a report. We need to 2718c2ecf20Sopenharmony_ci * figure out what it is and store the 2728c2ecf20Sopenharmony_ci * min/max values 2738c2ecf20Sopenharmony_ci */ 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci maintype = 'I'; 2768c2ecf20Sopenharmony_ci if (data == 2) 2778c2ecf20Sopenharmony_ci strcpy(globtype, "Variable"); 2788c2ecf20Sopenharmony_ci else if (data == 3) 2798c2ecf20Sopenharmony_ci strcpy(globtype, "Var|Const"); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci dev_dbg(ddev, "::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits\n", 2828c2ecf20Sopenharmony_ci globalval[TAG_GLOB_REPORT_ID], inputnum, 2838c2ecf20Sopenharmony_ci globalval[TAG_GLOB_LOG_MAX], globalval[TAG_GLOB_LOG_MAX], 2848c2ecf20Sopenharmony_ci globalval[TAG_GLOB_LOG_MIN], globalval[TAG_GLOB_LOG_MIN], 2858c2ecf20Sopenharmony_ci globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* 2898c2ecf20Sopenharmony_ci We can assume that the first two input items 2908c2ecf20Sopenharmony_ci are always the X and Y coordinates. After 2918c2ecf20Sopenharmony_ci that, we look for everything else by 2928c2ecf20Sopenharmony_ci local usage value 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_ci switch (inputnum) { 2958c2ecf20Sopenharmony_ci case 0: /* X coord */ 2968c2ecf20Sopenharmony_ci dev_dbg(ddev, "GER: X Usage: 0x%x\n", usage); 2978c2ecf20Sopenharmony_ci if (device->max_X == 0) { 2988c2ecf20Sopenharmony_ci device->max_X = globalval[TAG_GLOB_LOG_MAX]; 2998c2ecf20Sopenharmony_ci device->min_X = globalval[TAG_GLOB_LOG_MIN]; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci break; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci case 1: /* Y coord */ 3048c2ecf20Sopenharmony_ci dev_dbg(ddev, "GER: Y Usage: 0x%x\n", usage); 3058c2ecf20Sopenharmony_ci if (device->max_Y == 0) { 3068c2ecf20Sopenharmony_ci device->max_Y = globalval[TAG_GLOB_LOG_MAX]; 3078c2ecf20Sopenharmony_ci device->min_Y = globalval[TAG_GLOB_LOG_MIN]; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci break; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci default: 3128c2ecf20Sopenharmony_ci /* Tilt X */ 3138c2ecf20Sopenharmony_ci if (usage == DIGITIZER_USAGE_TILT_X) { 3148c2ecf20Sopenharmony_ci if (device->maxtilt_X == 0) { 3158c2ecf20Sopenharmony_ci device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX]; 3168c2ecf20Sopenharmony_ci device->mintilt_X = globalval[TAG_GLOB_LOG_MIN]; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* Tilt Y */ 3218c2ecf20Sopenharmony_ci if (usage == DIGITIZER_USAGE_TILT_Y) { 3228c2ecf20Sopenharmony_ci if (device->maxtilt_Y == 0) { 3238c2ecf20Sopenharmony_ci device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX]; 3248c2ecf20Sopenharmony_ci device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN]; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* Pressure */ 3298c2ecf20Sopenharmony_ci if (usage == DIGITIZER_USAGE_TIP_PRESSURE) { 3308c2ecf20Sopenharmony_ci if (device->maxpressure == 0) { 3318c2ecf20Sopenharmony_ci device->maxpressure = globalval[TAG_GLOB_LOG_MAX]; 3328c2ecf20Sopenharmony_ci device->minpressure = globalval[TAG_GLOB_LOG_MIN]; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci break; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci inputnum++; 3408c2ecf20Sopenharmony_ci break; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci case TAG_MAIN_OUTPUT: 3438c2ecf20Sopenharmony_ci maintype = 'O'; 3448c2ecf20Sopenharmony_ci break; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci case TAG_MAIN_FEATURE: 3478c2ecf20Sopenharmony_ci maintype = 'F'; 3488c2ecf20Sopenharmony_ci break; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci case TAG_MAIN_COL_START: 3518c2ecf20Sopenharmony_ci maintype = 'S'; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (indent == MAX_COLLECTION_LEVELS) { 3548c2ecf20Sopenharmony_ci dev_err(ddev, "Collection level %d would exceed limit of %d\n", 3558c2ecf20Sopenharmony_ci indent + 1, 3568c2ecf20Sopenharmony_ci MAX_COLLECTION_LEVELS); 3578c2ecf20Sopenharmony_ci break; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (data == 0) { 3618c2ecf20Sopenharmony_ci dev_dbg(ddev, "======>>>>>> Physical\n"); 3628c2ecf20Sopenharmony_ci strcpy(globtype, "Physical"); 3638c2ecf20Sopenharmony_ci } else 3648c2ecf20Sopenharmony_ci dev_dbg(ddev, "======>>>>>>\n"); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* Indent the debug output */ 3678c2ecf20Sopenharmony_ci indent++; 3688c2ecf20Sopenharmony_ci for (x = 0; x < indent; x++) 3698c2ecf20Sopenharmony_ci indentstr[x] = '-'; 3708c2ecf20Sopenharmony_ci indentstr[x] = 0; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* Save global tags */ 3738c2ecf20Sopenharmony_ci for (x = 0; x < TAG_GLOB_MAX; x++) 3748c2ecf20Sopenharmony_ci oldval[x] = globalval[x]; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci break; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci case TAG_MAIN_COL_END: 3798c2ecf20Sopenharmony_ci maintype = 'E'; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (indent == 0) { 3828c2ecf20Sopenharmony_ci dev_err(ddev, "Collection level already at zero\n"); 3838c2ecf20Sopenharmony_ci break; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci dev_dbg(ddev, "<<<<<<======\n"); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci indent--; 3898c2ecf20Sopenharmony_ci for (x = 0; x < indent; x++) 3908c2ecf20Sopenharmony_ci indentstr[x] = '-'; 3918c2ecf20Sopenharmony_ci indentstr[x] = 0; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* Copy global tags back */ 3948c2ecf20Sopenharmony_ci for (x = 0; x < TAG_GLOB_MAX; x++) 3958c2ecf20Sopenharmony_ci globalval[x] = oldval[x]; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci switch (size) { 4018c2ecf20Sopenharmony_ci case 1: 4028c2ecf20Sopenharmony_ci dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n", 4038c2ecf20Sopenharmony_ci indentstr, tag, maintype, size, globtype, data); 4048c2ecf20Sopenharmony_ci break; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci case 2: 4078c2ecf20Sopenharmony_ci dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n", 4088c2ecf20Sopenharmony_ci indentstr, tag, maintype, size, globtype, data16); 4098c2ecf20Sopenharmony_ci break; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci case 4: 4128c2ecf20Sopenharmony_ci dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n", 4138c2ecf20Sopenharmony_ci indentstr, tag, maintype, size, globtype, data32); 4148c2ecf20Sopenharmony_ci break; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci break; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci case TYPE_GLOBAL: 4198c2ecf20Sopenharmony_ci switch (tag) { 4208c2ecf20Sopenharmony_ci case TAG_GLOB_USAGE: 4218c2ecf20Sopenharmony_ci /* 4228c2ecf20Sopenharmony_ci * First time we hit the global usage tag, 4238c2ecf20Sopenharmony_ci * it should tell us the type of device 4248c2ecf20Sopenharmony_ci */ 4258c2ecf20Sopenharmony_ci if (device->usage == 0) 4268c2ecf20Sopenharmony_ci device->usage = data; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci strcpy(globtype, "USAGE"); 4298c2ecf20Sopenharmony_ci break; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci case TAG_GLOB_LOG_MIN: 4328c2ecf20Sopenharmony_ci strcpy(globtype, "LOG_MIN"); 4338c2ecf20Sopenharmony_ci break; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci case TAG_GLOB_LOG_MAX: 4368c2ecf20Sopenharmony_ci strcpy(globtype, "LOG_MAX"); 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci case TAG_GLOB_PHYS_MIN: 4408c2ecf20Sopenharmony_ci strcpy(globtype, "PHYS_MIN"); 4418c2ecf20Sopenharmony_ci break; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci case TAG_GLOB_PHYS_MAX: 4448c2ecf20Sopenharmony_ci strcpy(globtype, "PHYS_MAX"); 4458c2ecf20Sopenharmony_ci break; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci case TAG_GLOB_UNIT_EXP: 4488c2ecf20Sopenharmony_ci strcpy(globtype, "EXP"); 4498c2ecf20Sopenharmony_ci break; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci case TAG_GLOB_UNIT: 4528c2ecf20Sopenharmony_ci strcpy(globtype, "UNIT"); 4538c2ecf20Sopenharmony_ci break; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci case TAG_GLOB_REPORT_SZ: 4568c2ecf20Sopenharmony_ci strcpy(globtype, "REPORT_SZ"); 4578c2ecf20Sopenharmony_ci break; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci case TAG_GLOB_REPORT_ID: 4608c2ecf20Sopenharmony_ci strcpy(globtype, "REPORT_ID"); 4618c2ecf20Sopenharmony_ci /* New report, restart numbering */ 4628c2ecf20Sopenharmony_ci inputnum = 0; 4638c2ecf20Sopenharmony_ci break; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci case TAG_GLOB_REPORT_CNT: 4668c2ecf20Sopenharmony_ci strcpy(globtype, "REPORT_CNT"); 4678c2ecf20Sopenharmony_ci break; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci case TAG_GLOB_PUSH: 4708c2ecf20Sopenharmony_ci strcpy(globtype, "PUSH"); 4718c2ecf20Sopenharmony_ci break; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci case TAG_GLOB_POP: 4748c2ecf20Sopenharmony_ci strcpy(globtype, "POP"); 4758c2ecf20Sopenharmony_ci break; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci /* Check to make sure we have a good tag number 4798c2ecf20Sopenharmony_ci so we don't overflow array */ 4808c2ecf20Sopenharmony_ci if (tag < TAG_GLOB_MAX) { 4818c2ecf20Sopenharmony_ci switch (size) { 4828c2ecf20Sopenharmony_ci case 1: 4838c2ecf20Sopenharmony_ci dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n", 4848c2ecf20Sopenharmony_ci indentstr, globtype, tag, size, data); 4858c2ecf20Sopenharmony_ci globalval[tag] = data; 4868c2ecf20Sopenharmony_ci break; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci case 2: 4898c2ecf20Sopenharmony_ci dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n", 4908c2ecf20Sopenharmony_ci indentstr, globtype, tag, size, data16); 4918c2ecf20Sopenharmony_ci globalval[tag] = data16; 4928c2ecf20Sopenharmony_ci break; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci case 4: 4958c2ecf20Sopenharmony_ci dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n", 4968c2ecf20Sopenharmony_ci indentstr, globtype, tag, size, data32); 4978c2ecf20Sopenharmony_ci globalval[tag] = data32; 4988c2ecf20Sopenharmony_ci break; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci } else { 5018c2ecf20Sopenharmony_ci dev_dbg(ddev, "%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d\n", 5028c2ecf20Sopenharmony_ci indentstr, tag, size); 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci break; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci case TYPE_LOCAL: 5078c2ecf20Sopenharmony_ci switch (tag) { 5088c2ecf20Sopenharmony_ci case TAG_GLOB_USAGE: 5098c2ecf20Sopenharmony_ci strcpy(globtype, "USAGE"); 5108c2ecf20Sopenharmony_ci /* Always 1 byte */ 5118c2ecf20Sopenharmony_ci usage = data; 5128c2ecf20Sopenharmony_ci break; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci case TAG_GLOB_LOG_MIN: 5158c2ecf20Sopenharmony_ci strcpy(globtype, "MIN"); 5168c2ecf20Sopenharmony_ci break; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci case TAG_GLOB_LOG_MAX: 5198c2ecf20Sopenharmony_ci strcpy(globtype, "MAX"); 5208c2ecf20Sopenharmony_ci break; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci default: 5238c2ecf20Sopenharmony_ci strcpy(globtype, "UNKNOWN"); 5248c2ecf20Sopenharmony_ci break; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci switch (size) { 5288c2ecf20Sopenharmony_ci case 1: 5298c2ecf20Sopenharmony_ci dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n", 5308c2ecf20Sopenharmony_ci indentstr, tag, globtype, size, data); 5318c2ecf20Sopenharmony_ci break; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci case 2: 5348c2ecf20Sopenharmony_ci dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n", 5358c2ecf20Sopenharmony_ci indentstr, tag, globtype, size, data16); 5368c2ecf20Sopenharmony_ci break; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci case 4: 5398c2ecf20Sopenharmony_ci dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n", 5408c2ecf20Sopenharmony_ci indentstr, tag, globtype, size, data32); 5418c2ecf20Sopenharmony_ci break; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci break; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci/* INPUT DRIVER Routines */ 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci/* 5528c2ecf20Sopenharmony_ci * Called when opening the input device. This will submit the URB to 5538c2ecf20Sopenharmony_ci * the usb system so we start getting reports 5548c2ecf20Sopenharmony_ci */ 5558c2ecf20Sopenharmony_cistatic int gtco_input_open(struct input_dev *inputdev) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci struct gtco *device = input_get_drvdata(inputdev); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci device->urbinfo->dev = interface_to_usbdev(device->intf); 5608c2ecf20Sopenharmony_ci if (usb_submit_urb(device->urbinfo, GFP_KERNEL)) 5618c2ecf20Sopenharmony_ci return -EIO; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci return 0; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci/* 5678c2ecf20Sopenharmony_ci * Called when closing the input device. This will unlink the URB 5688c2ecf20Sopenharmony_ci */ 5698c2ecf20Sopenharmony_cistatic void gtco_input_close(struct input_dev *inputdev) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci struct gtco *device = input_get_drvdata(inputdev); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci usb_kill_urb(device->urbinfo); 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci/* 5788c2ecf20Sopenharmony_ci * Setup input device capabilities. Tell the input system what this 5798c2ecf20Sopenharmony_ci * device is capable of generating. 5808c2ecf20Sopenharmony_ci * 5818c2ecf20Sopenharmony_ci * This information is based on what is read from the HID report and 5828c2ecf20Sopenharmony_ci * placed in the struct gtco structure 5838c2ecf20Sopenharmony_ci * 5848c2ecf20Sopenharmony_ci */ 5858c2ecf20Sopenharmony_cistatic void gtco_setup_caps(struct input_dev *inputdev) 5868c2ecf20Sopenharmony_ci{ 5878c2ecf20Sopenharmony_ci struct gtco *device = input_get_drvdata(inputdev); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci /* Which events */ 5908c2ecf20Sopenharmony_ci inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) | 5918c2ecf20Sopenharmony_ci BIT_MASK(EV_MSC); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci /* Misc event menu block */ 5948c2ecf20Sopenharmony_ci inputdev->mscbit[0] = BIT_MASK(MSC_SCAN) | BIT_MASK(MSC_SERIAL) | 5958c2ecf20Sopenharmony_ci BIT_MASK(MSC_RAW); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci /* Absolute values based on HID report info */ 5988c2ecf20Sopenharmony_ci input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X, 5998c2ecf20Sopenharmony_ci 0, 0); 6008c2ecf20Sopenharmony_ci input_set_abs_params(inputdev, ABS_Y, device->min_Y, device->max_Y, 6018c2ecf20Sopenharmony_ci 0, 0); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci /* Proximity */ 6048c2ecf20Sopenharmony_ci input_set_abs_params(inputdev, ABS_DISTANCE, 0, 1, 0, 0); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* Tilt & pressure */ 6078c2ecf20Sopenharmony_ci input_set_abs_params(inputdev, ABS_TILT_X, device->mintilt_X, 6088c2ecf20Sopenharmony_ci device->maxtilt_X, 0, 0); 6098c2ecf20Sopenharmony_ci input_set_abs_params(inputdev, ABS_TILT_Y, device->mintilt_Y, 6108c2ecf20Sopenharmony_ci device->maxtilt_Y, 0, 0); 6118c2ecf20Sopenharmony_ci input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure, 6128c2ecf20Sopenharmony_ci device->maxpressure, 0, 0); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* Transducer */ 6158c2ecf20Sopenharmony_ci input_set_abs_params(inputdev, ABS_MISC, 0, 0xFF, 0, 0); 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci/* USB Routines */ 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci/* 6218c2ecf20Sopenharmony_ci * URB callback routine. Called when we get IRQ reports from the 6228c2ecf20Sopenharmony_ci * digitizer. 6238c2ecf20Sopenharmony_ci * 6248c2ecf20Sopenharmony_ci * This bridges the USB and input device worlds. It generates events 6258c2ecf20Sopenharmony_ci * on the input device based on the USB reports. 6268c2ecf20Sopenharmony_ci */ 6278c2ecf20Sopenharmony_cistatic void gtco_urb_callback(struct urb *urbinfo) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci struct gtco *device = urbinfo->context; 6308c2ecf20Sopenharmony_ci struct input_dev *inputdev; 6318c2ecf20Sopenharmony_ci int rc; 6328c2ecf20Sopenharmony_ci u32 val = 0; 6338c2ecf20Sopenharmony_ci char le_buffer[2]; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci inputdev = device->inputdevice; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci /* Was callback OK? */ 6388c2ecf20Sopenharmony_ci if (urbinfo->status == -ECONNRESET || 6398c2ecf20Sopenharmony_ci urbinfo->status == -ENOENT || 6408c2ecf20Sopenharmony_ci urbinfo->status == -ESHUTDOWN) { 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci /* Shutdown is occurring. Return and don't queue up any more */ 6438c2ecf20Sopenharmony_ci return; 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci if (urbinfo->status != 0) { 6478c2ecf20Sopenharmony_ci /* 6488c2ecf20Sopenharmony_ci * Some unknown error. Hopefully temporary. Just go and 6498c2ecf20Sopenharmony_ci * requeue an URB 6508c2ecf20Sopenharmony_ci */ 6518c2ecf20Sopenharmony_ci goto resubmit; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci /* 6558c2ecf20Sopenharmony_ci * Good URB, now process 6568c2ecf20Sopenharmony_ci */ 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci /* PID dependent when we interpret the report */ 6598c2ecf20Sopenharmony_ci if (inputdev->id.product == PID_1000 || 6608c2ecf20Sopenharmony_ci inputdev->id.product == PID_1001 || 6618c2ecf20Sopenharmony_ci inputdev->id.product == PID_1002) { 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* 6648c2ecf20Sopenharmony_ci * Switch on the report ID 6658c2ecf20Sopenharmony_ci * Conveniently, the reports have more information, the higher 6668c2ecf20Sopenharmony_ci * the report number. We can just fall through the case 6678c2ecf20Sopenharmony_ci * statements if we start with the highest number report 6688c2ecf20Sopenharmony_ci */ 6698c2ecf20Sopenharmony_ci switch (device->buffer[0]) { 6708c2ecf20Sopenharmony_ci case 5: 6718c2ecf20Sopenharmony_ci /* Pressure is 9 bits */ 6728c2ecf20Sopenharmony_ci val = ((u16)(device->buffer[8]) << 1); 6738c2ecf20Sopenharmony_ci val |= (u16)(device->buffer[7] >> 7); 6748c2ecf20Sopenharmony_ci input_report_abs(inputdev, ABS_PRESSURE, 6758c2ecf20Sopenharmony_ci device->buffer[8]); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci /* Mask out the Y tilt value used for pressure */ 6788c2ecf20Sopenharmony_ci device->buffer[7] = (u8)((device->buffer[7]) & 0x7F); 6798c2ecf20Sopenharmony_ci fallthrough; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci case 4: 6828c2ecf20Sopenharmony_ci /* Tilt */ 6838c2ecf20Sopenharmony_ci input_report_abs(inputdev, ABS_TILT_X, 6848c2ecf20Sopenharmony_ci sign_extend32(device->buffer[6], 6)); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci input_report_abs(inputdev, ABS_TILT_Y, 6878c2ecf20Sopenharmony_ci sign_extend32(device->buffer[7], 6)); 6888c2ecf20Sopenharmony_ci fallthrough; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci case 2: 6918c2ecf20Sopenharmony_ci case 3: 6928c2ecf20Sopenharmony_ci /* Convert buttons, only 5 bits possible */ 6938c2ecf20Sopenharmony_ci val = (device->buffer[5]) & MASK_BUTTON; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* We don't apply any meaning to the bitmask, 6968c2ecf20Sopenharmony_ci just report */ 6978c2ecf20Sopenharmony_ci input_event(inputdev, EV_MSC, MSC_SERIAL, val); 6988c2ecf20Sopenharmony_ci fallthrough; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci case 1: 7018c2ecf20Sopenharmony_ci /* All reports have X and Y coords in the same place */ 7028c2ecf20Sopenharmony_ci val = get_unaligned_le16(&device->buffer[1]); 7038c2ecf20Sopenharmony_ci input_report_abs(inputdev, ABS_X, val); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci val = get_unaligned_le16(&device->buffer[3]); 7068c2ecf20Sopenharmony_ci input_report_abs(inputdev, ABS_Y, val); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* Ditto for proximity bit */ 7098c2ecf20Sopenharmony_ci val = device->buffer[5] & MASK_INRANGE ? 1 : 0; 7108c2ecf20Sopenharmony_ci input_report_abs(inputdev, ABS_DISTANCE, val); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci /* Report 1 is an exception to how we handle buttons */ 7138c2ecf20Sopenharmony_ci /* Buttons are an index, not a bitmask */ 7148c2ecf20Sopenharmony_ci if (device->buffer[0] == 1) { 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci /* 7178c2ecf20Sopenharmony_ci * Convert buttons, 5 bit index 7188c2ecf20Sopenharmony_ci * Report value of index set as one, 7198c2ecf20Sopenharmony_ci * the rest as 0 7208c2ecf20Sopenharmony_ci */ 7218c2ecf20Sopenharmony_ci val = device->buffer[5] & MASK_BUTTON; 7228c2ecf20Sopenharmony_ci dev_dbg(&device->intf->dev, 7238c2ecf20Sopenharmony_ci "======>>>>>>REPORT 1: val 0x%X(%d)\n", 7248c2ecf20Sopenharmony_ci val, val); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci /* 7278c2ecf20Sopenharmony_ci * We don't apply any meaning to the button 7288c2ecf20Sopenharmony_ci * index, just report it 7298c2ecf20Sopenharmony_ci */ 7308c2ecf20Sopenharmony_ci input_event(inputdev, EV_MSC, MSC_SERIAL, val); 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci break; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci case 7: 7358c2ecf20Sopenharmony_ci /* Menu blocks */ 7368c2ecf20Sopenharmony_ci input_event(inputdev, EV_MSC, MSC_SCAN, 7378c2ecf20Sopenharmony_ci device->buffer[1]); 7388c2ecf20Sopenharmony_ci break; 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* Other pid class */ 7438c2ecf20Sopenharmony_ci if (inputdev->id.product == PID_400 || 7448c2ecf20Sopenharmony_ci inputdev->id.product == PID_401) { 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci /* Report 2 */ 7478c2ecf20Sopenharmony_ci if (device->buffer[0] == 2) { 7488c2ecf20Sopenharmony_ci /* Menu blocks */ 7498c2ecf20Sopenharmony_ci input_event(inputdev, EV_MSC, MSC_SCAN, device->buffer[1]); 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* Report 1 */ 7538c2ecf20Sopenharmony_ci if (device->buffer[0] == 1) { 7548c2ecf20Sopenharmony_ci char buttonbyte; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci /* IF X max > 64K, we still a bit from the y report */ 7578c2ecf20Sopenharmony_ci if (device->max_X > 0x10000) { 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci val = (u16)(((u16)(device->buffer[2] << 8)) | (u8)device->buffer[1]); 7608c2ecf20Sopenharmony_ci val |= (u32)(((u8)device->buffer[3] & 0x1) << 16); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci input_report_abs(inputdev, ABS_X, val); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci le_buffer[0] = (u8)((u8)(device->buffer[3]) >> 1); 7658c2ecf20Sopenharmony_ci le_buffer[0] |= (u8)((device->buffer[3] & 0x1) << 7); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci le_buffer[1] = (u8)(device->buffer[4] >> 1); 7688c2ecf20Sopenharmony_ci le_buffer[1] |= (u8)((device->buffer[5] & 0x1) << 7); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci val = get_unaligned_le16(le_buffer); 7718c2ecf20Sopenharmony_ci input_report_abs(inputdev, ABS_Y, val); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci /* 7748c2ecf20Sopenharmony_ci * Shift the button byte right by one to 7758c2ecf20Sopenharmony_ci * make it look like the standard report 7768c2ecf20Sopenharmony_ci */ 7778c2ecf20Sopenharmony_ci buttonbyte = device->buffer[5] >> 1; 7788c2ecf20Sopenharmony_ci } else { 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci val = get_unaligned_le16(&device->buffer[1]); 7818c2ecf20Sopenharmony_ci input_report_abs(inputdev, ABS_X, val); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci val = get_unaligned_le16(&device->buffer[3]); 7848c2ecf20Sopenharmony_ci input_report_abs(inputdev, ABS_Y, val); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci buttonbyte = device->buffer[5]; 7878c2ecf20Sopenharmony_ci } 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci /* BUTTONS and PROXIMITY */ 7908c2ecf20Sopenharmony_ci val = buttonbyte & MASK_INRANGE ? 1 : 0; 7918c2ecf20Sopenharmony_ci input_report_abs(inputdev, ABS_DISTANCE, val); 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci /* Convert buttons, only 4 bits possible */ 7948c2ecf20Sopenharmony_ci val = buttonbyte & 0x0F; 7958c2ecf20Sopenharmony_ci#ifdef USE_BUTTONS 7968c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) 7978c2ecf20Sopenharmony_ci input_report_key(inputdev, BTN_DIGI + i, val & (1 << i)); 7988c2ecf20Sopenharmony_ci#else 7998c2ecf20Sopenharmony_ci /* We don't apply any meaning to the bitmask, just report */ 8008c2ecf20Sopenharmony_ci input_event(inputdev, EV_MSC, MSC_SERIAL, val); 8018c2ecf20Sopenharmony_ci#endif 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci /* TRANSDUCER */ 8048c2ecf20Sopenharmony_ci input_report_abs(inputdev, ABS_MISC, device->buffer[6]); 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* Everybody gets report ID's */ 8098c2ecf20Sopenharmony_ci input_event(inputdev, EV_MSC, MSC_RAW, device->buffer[0]); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci /* Sync it up */ 8128c2ecf20Sopenharmony_ci input_sync(inputdev); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci resubmit: 8158c2ecf20Sopenharmony_ci rc = usb_submit_urb(urbinfo, GFP_ATOMIC); 8168c2ecf20Sopenharmony_ci if (rc != 0) 8178c2ecf20Sopenharmony_ci dev_err(&device->intf->dev, 8188c2ecf20Sopenharmony_ci "usb_submit_urb failed rc=0x%x\n", rc); 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci/* 8228c2ecf20Sopenharmony_ci * The probe routine. This is called when the kernel find the matching USB 8238c2ecf20Sopenharmony_ci * vendor/product. We do the following: 8248c2ecf20Sopenharmony_ci * 8258c2ecf20Sopenharmony_ci * - Allocate mem for a local structure to manage the device 8268c2ecf20Sopenharmony_ci * - Request a HID Report Descriptor from the device and parse it to 8278c2ecf20Sopenharmony_ci * find out the device parameters 8288c2ecf20Sopenharmony_ci * - Create an input device and assign it attributes 8298c2ecf20Sopenharmony_ci * - Allocate an URB so the device can talk to us when the input 8308c2ecf20Sopenharmony_ci * queue is open 8318c2ecf20Sopenharmony_ci */ 8328c2ecf20Sopenharmony_cistatic int gtco_probe(struct usb_interface *usbinterface, 8338c2ecf20Sopenharmony_ci const struct usb_device_id *id) 8348c2ecf20Sopenharmony_ci{ 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci struct gtco *gtco; 8378c2ecf20Sopenharmony_ci struct input_dev *input_dev; 8388c2ecf20Sopenharmony_ci struct hid_descriptor *hid_desc; 8398c2ecf20Sopenharmony_ci char *report; 8408c2ecf20Sopenharmony_ci int result = 0, retry; 8418c2ecf20Sopenharmony_ci int error; 8428c2ecf20Sopenharmony_ci struct usb_endpoint_descriptor *endpoint; 8438c2ecf20Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(usbinterface); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci /* Allocate memory for device structure */ 8468c2ecf20Sopenharmony_ci gtco = kzalloc(sizeof(struct gtco), GFP_KERNEL); 8478c2ecf20Sopenharmony_ci input_dev = input_allocate_device(); 8488c2ecf20Sopenharmony_ci if (!gtco || !input_dev) { 8498c2ecf20Sopenharmony_ci dev_err(&usbinterface->dev, "No more memory\n"); 8508c2ecf20Sopenharmony_ci error = -ENOMEM; 8518c2ecf20Sopenharmony_ci goto err_free_devs; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* Set pointer to the input device */ 8558c2ecf20Sopenharmony_ci gtco->inputdevice = input_dev; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci /* Save interface information */ 8588c2ecf20Sopenharmony_ci gtco->intf = usbinterface; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci /* Allocate some data for incoming reports */ 8618c2ecf20Sopenharmony_ci gtco->buffer = usb_alloc_coherent(udev, REPORT_MAX_SIZE, 8628c2ecf20Sopenharmony_ci GFP_KERNEL, >co->buf_dma); 8638c2ecf20Sopenharmony_ci if (!gtco->buffer) { 8648c2ecf20Sopenharmony_ci dev_err(&usbinterface->dev, "No more memory for us buffers\n"); 8658c2ecf20Sopenharmony_ci error = -ENOMEM; 8668c2ecf20Sopenharmony_ci goto err_free_devs; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci /* Allocate URB for reports */ 8708c2ecf20Sopenharmony_ci gtco->urbinfo = usb_alloc_urb(0, GFP_KERNEL); 8718c2ecf20Sopenharmony_ci if (!gtco->urbinfo) { 8728c2ecf20Sopenharmony_ci dev_err(&usbinterface->dev, "Failed to allocate URB\n"); 8738c2ecf20Sopenharmony_ci error = -ENOMEM; 8748c2ecf20Sopenharmony_ci goto err_free_buf; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci /* Sanity check that a device has an endpoint */ 8788c2ecf20Sopenharmony_ci if (usbinterface->cur_altsetting->desc.bNumEndpoints < 1) { 8798c2ecf20Sopenharmony_ci dev_err(&usbinterface->dev, 8808c2ecf20Sopenharmony_ci "Invalid number of endpoints\n"); 8818c2ecf20Sopenharmony_ci error = -EINVAL; 8828c2ecf20Sopenharmony_ci goto err_free_urb; 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci endpoint = &usbinterface->cur_altsetting->endpoint[0].desc; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci /* Some debug */ 8888c2ecf20Sopenharmony_ci dev_dbg(&usbinterface->dev, "gtco # interfaces: %d\n", usbinterface->num_altsetting); 8898c2ecf20Sopenharmony_ci dev_dbg(&usbinterface->dev, "num endpoints: %d\n", usbinterface->cur_altsetting->desc.bNumEndpoints); 8908c2ecf20Sopenharmony_ci dev_dbg(&usbinterface->dev, "interface class: %d\n", usbinterface->cur_altsetting->desc.bInterfaceClass); 8918c2ecf20Sopenharmony_ci dev_dbg(&usbinterface->dev, "endpoint: attribute:0x%x type:0x%x\n", endpoint->bmAttributes, endpoint->bDescriptorType); 8928c2ecf20Sopenharmony_ci if (usb_endpoint_xfer_int(endpoint)) 8938c2ecf20Sopenharmony_ci dev_dbg(&usbinterface->dev, "endpoint: we have interrupt endpoint\n"); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci dev_dbg(&usbinterface->dev, "interface extra len:%d\n", 8968c2ecf20Sopenharmony_ci usbinterface->cur_altsetting->extralen); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci /* 8998c2ecf20Sopenharmony_ci * Find the HID descriptor so we can find out the size of the 9008c2ecf20Sopenharmony_ci * HID report descriptor 9018c2ecf20Sopenharmony_ci */ 9028c2ecf20Sopenharmony_ci if (usb_get_extra_descriptor(usbinterface->cur_altsetting, 9038c2ecf20Sopenharmony_ci HID_DEVICE_TYPE, &hid_desc) != 0) { 9048c2ecf20Sopenharmony_ci dev_err(&usbinterface->dev, 9058c2ecf20Sopenharmony_ci "Can't retrieve exta USB descriptor to get hid report descriptor length\n"); 9068c2ecf20Sopenharmony_ci error = -EIO; 9078c2ecf20Sopenharmony_ci goto err_free_urb; 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci dev_dbg(&usbinterface->dev, 9118c2ecf20Sopenharmony_ci "Extra descriptor success: type:%d len:%d\n", 9128c2ecf20Sopenharmony_ci hid_desc->bDescriptorType, hid_desc->wDescriptorLength); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci report = kzalloc(le16_to_cpu(hid_desc->wDescriptorLength), GFP_KERNEL); 9158c2ecf20Sopenharmony_ci if (!report) { 9168c2ecf20Sopenharmony_ci dev_err(&usbinterface->dev, "No more memory for report\n"); 9178c2ecf20Sopenharmony_ci error = -ENOMEM; 9188c2ecf20Sopenharmony_ci goto err_free_urb; 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci /* Couple of tries to get reply */ 9228c2ecf20Sopenharmony_ci for (retry = 0; retry < 3; retry++) { 9238c2ecf20Sopenharmony_ci result = usb_control_msg(udev, 9248c2ecf20Sopenharmony_ci usb_rcvctrlpipe(udev, 0), 9258c2ecf20Sopenharmony_ci USB_REQ_GET_DESCRIPTOR, 9268c2ecf20Sopenharmony_ci USB_RECIP_INTERFACE | USB_DIR_IN, 9278c2ecf20Sopenharmony_ci REPORT_DEVICE_TYPE << 8, 9288c2ecf20Sopenharmony_ci 0, /* interface */ 9298c2ecf20Sopenharmony_ci report, 9308c2ecf20Sopenharmony_ci le16_to_cpu(hid_desc->wDescriptorLength), 9318c2ecf20Sopenharmony_ci 5000); /* 5 secs */ 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci dev_dbg(&usbinterface->dev, "usb_control_msg result: %d\n", result); 9348c2ecf20Sopenharmony_ci if (result == le16_to_cpu(hid_desc->wDescriptorLength)) { 9358c2ecf20Sopenharmony_ci parse_hid_report_descriptor(gtco, report, result); 9368c2ecf20Sopenharmony_ci break; 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci kfree(report); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci /* If we didn't get the report, fail */ 9438c2ecf20Sopenharmony_ci if (result != le16_to_cpu(hid_desc->wDescriptorLength)) { 9448c2ecf20Sopenharmony_ci dev_err(&usbinterface->dev, 9458c2ecf20Sopenharmony_ci "Failed to get HID Report Descriptor of size: %d\n", 9468c2ecf20Sopenharmony_ci hid_desc->wDescriptorLength); 9478c2ecf20Sopenharmony_ci error = -EIO; 9488c2ecf20Sopenharmony_ci goto err_free_urb; 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci /* Create a device file node */ 9528c2ecf20Sopenharmony_ci usb_make_path(udev, gtco->usbpath, sizeof(gtco->usbpath)); 9538c2ecf20Sopenharmony_ci strlcat(gtco->usbpath, "/input0", sizeof(gtco->usbpath)); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci /* Set Input device functions */ 9568c2ecf20Sopenharmony_ci input_dev->open = gtco_input_open; 9578c2ecf20Sopenharmony_ci input_dev->close = gtco_input_close; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci /* Set input device information */ 9608c2ecf20Sopenharmony_ci input_dev->name = "GTCO_CalComp"; 9618c2ecf20Sopenharmony_ci input_dev->phys = gtco->usbpath; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci input_set_drvdata(input_dev, gtco); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci /* Now set up all the input device capabilities */ 9668c2ecf20Sopenharmony_ci gtco_setup_caps(input_dev); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci /* Set input device required ID information */ 9698c2ecf20Sopenharmony_ci usb_to_input_id(udev, &input_dev->id); 9708c2ecf20Sopenharmony_ci input_dev->dev.parent = &usbinterface->dev; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci /* Setup the URB, it will be posted later on open of input device */ 9738c2ecf20Sopenharmony_ci usb_fill_int_urb(gtco->urbinfo, 9748c2ecf20Sopenharmony_ci udev, 9758c2ecf20Sopenharmony_ci usb_rcvintpipe(udev, 9768c2ecf20Sopenharmony_ci endpoint->bEndpointAddress), 9778c2ecf20Sopenharmony_ci gtco->buffer, 9788c2ecf20Sopenharmony_ci REPORT_MAX_SIZE, 9798c2ecf20Sopenharmony_ci gtco_urb_callback, 9808c2ecf20Sopenharmony_ci gtco, 9818c2ecf20Sopenharmony_ci endpoint->bInterval); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci gtco->urbinfo->transfer_dma = gtco->buf_dma; 9848c2ecf20Sopenharmony_ci gtco->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci /* Save gtco pointer in USB interface gtco */ 9878c2ecf20Sopenharmony_ci usb_set_intfdata(usbinterface, gtco); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci /* All done, now register the input device */ 9908c2ecf20Sopenharmony_ci error = input_register_device(input_dev); 9918c2ecf20Sopenharmony_ci if (error) 9928c2ecf20Sopenharmony_ci goto err_free_urb; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci return 0; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci err_free_urb: 9978c2ecf20Sopenharmony_ci usb_free_urb(gtco->urbinfo); 9988c2ecf20Sopenharmony_ci err_free_buf: 9998c2ecf20Sopenharmony_ci usb_free_coherent(udev, REPORT_MAX_SIZE, 10008c2ecf20Sopenharmony_ci gtco->buffer, gtco->buf_dma); 10018c2ecf20Sopenharmony_ci err_free_devs: 10028c2ecf20Sopenharmony_ci input_free_device(input_dev); 10038c2ecf20Sopenharmony_ci kfree(gtco); 10048c2ecf20Sopenharmony_ci return error; 10058c2ecf20Sopenharmony_ci} 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci/* 10088c2ecf20Sopenharmony_ci * This function is a standard USB function called when the USB device 10098c2ecf20Sopenharmony_ci * is disconnected. We will get rid of the URV, de-register the input 10108c2ecf20Sopenharmony_ci * device, and free up allocated memory 10118c2ecf20Sopenharmony_ci */ 10128c2ecf20Sopenharmony_cistatic void gtco_disconnect(struct usb_interface *interface) 10138c2ecf20Sopenharmony_ci{ 10148c2ecf20Sopenharmony_ci /* Grab private device ptr */ 10158c2ecf20Sopenharmony_ci struct gtco *gtco = usb_get_intfdata(interface); 10168c2ecf20Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(interface); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci /* Now reverse all the registration stuff */ 10198c2ecf20Sopenharmony_ci if (gtco) { 10208c2ecf20Sopenharmony_ci input_unregister_device(gtco->inputdevice); 10218c2ecf20Sopenharmony_ci usb_kill_urb(gtco->urbinfo); 10228c2ecf20Sopenharmony_ci usb_free_urb(gtco->urbinfo); 10238c2ecf20Sopenharmony_ci usb_free_coherent(udev, REPORT_MAX_SIZE, 10248c2ecf20Sopenharmony_ci gtco->buffer, gtco->buf_dma); 10258c2ecf20Sopenharmony_ci kfree(gtco); 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci dev_info(&interface->dev, "gtco driver disconnected\n"); 10298c2ecf20Sopenharmony_ci} 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci/* STANDARD MODULE LOAD ROUTINES */ 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_cistatic struct usb_driver gtco_driverinfo_table = { 10348c2ecf20Sopenharmony_ci .name = "gtco", 10358c2ecf20Sopenharmony_ci .id_table = gtco_usbid_table, 10368c2ecf20Sopenharmony_ci .probe = gtco_probe, 10378c2ecf20Sopenharmony_ci .disconnect = gtco_disconnect, 10388c2ecf20Sopenharmony_ci}; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_cimodule_usb_driver(gtco_driverinfo_table); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("GTCO digitizer USB driver"); 10438c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1044