⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gtco.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    -*- linux-c -*-GTCO digitizer USB driverUse the err(), dbg() and info() macros from usb.h for system loggingTO CHECK:  Is pressure done right on report 5?Copyright (C) 2006  GTCO CalCompThis program is free software; you can redistribute it and/ormodify it under the terms of the GNU General Public Licenseas published by the Free Software Foundation; version 2of the License.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.Permission to use, copy, modify, distribute, and sell this software and itsdocumentation for any purpose is hereby granted without fee, provided thatthe above copyright notice appear in all copies and that both thatcopyright notice and this permission notice appear in supportingdocumentation, and that the name of GTCO-CalComp not be used in advertisingor publicity pertaining to distribution of the software without specific,written prior permission. GTCO-CalComp makes no representations about thesuitability of this software for any purpose.  It is provided "as is"without express or implied warranty.GTCO-CALCOMP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NOEVENT SHALL GTCO-CALCOMP BE LIABLE FOR ANY SPECIAL, INDIRECT ORCONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHERTORTIOUS ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE ORPERFORMANCE OF THIS SOFTWARE.GTCO CalComp, Inc.7125 Riverwood DriveColumbia, MD 21046Jeremy Roberson jroberson@gtcocalcomp.comScott Hill shill@gtcocalcomp.com*//*#define DEBUG*/#include <linux/kernel.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/input.h>#include <linux/usb.h>#include <asm/uaccess.h>#include <asm/unaligned.h>#include <asm/byteorder.h>#include <linux/version.h>#include <linux/usb/input.h>/* Version with a Major number of 2 is for kernel inclusion only. */#define  GTCO_VERSION   "2.00.0006"/*   MACROS  */#define VENDOR_ID_GTCO	      0x078C#define PID_400               0x400#define PID_401               0x401#define PID_1000              0x1000#define PID_1001              0x1001#define PID_1002              0x1002/* Max size of a single report */#define REPORT_MAX_SIZE       10/* Bitmask whether pen is in range */#define MASK_INRANGE 0x20#define MASK_BUTTON  0x01F#define  PATHLENGTH     64/* DATA STRUCTURES *//* Device table */static struct usb_device_id gtco_usbid_table [] = {	{ USB_DEVICE(VENDOR_ID_GTCO, PID_400) },	{ USB_DEVICE(VENDOR_ID_GTCO, PID_401) },	{ USB_DEVICE(VENDOR_ID_GTCO, PID_1000) },	{ USB_DEVICE(VENDOR_ID_GTCO, PID_1001) },	{ USB_DEVICE(VENDOR_ID_GTCO, PID_1002) },	{ }};MODULE_DEVICE_TABLE (usb, gtco_usbid_table);/* Structure to hold all of our device specific stuff */struct gtco {	struct input_dev  *inputdevice; /* input device struct pointer  */	struct usb_device *usbdev; /* the usb device for this device */	struct urb        *urbinfo;	 /* urb for incoming reports      */	dma_addr_t        buf_dma;  /* dma addr of the data buffer*/	unsigned char *   buffer;   /* databuffer for reports */	char  usbpath[PATHLENGTH];	int   openCount;	/* Information pulled from Report Descriptor */	u32  usage;	u32  min_X;	u32  max_X;	u32  min_Y;	u32  max_Y;	s8   mintilt_X;	s8   maxtilt_X;	s8   mintilt_Y;	s8   maxtilt_Y;	u32  maxpressure;	u32  minpressure;};/*   Code for parsing the HID REPORT DESCRIPTOR          *//* From HID1.11 spec */struct hid_descriptor{	struct usb_descriptor_header header;	__le16   bcdHID;	u8       bCountryCode;	u8       bNumDescriptors;	u8       bDescriptorType;	__le16   wDescriptorLength;} __attribute__ ((packed));#define HID_DESCRIPTOR_SIZE   9#define HID_DEVICE_TYPE       33#define REPORT_DEVICE_TYPE    34#define PREF_TAG(x)     ((x)>>4)#define PREF_TYPE(x)    ((x>>2)&0x03)#define PREF_SIZE(x)    ((x)&0x03)#define TYPE_MAIN       0#define TYPE_GLOBAL     1#define TYPE_LOCAL      2#define TYPE_RESERVED   3#define TAG_MAIN_INPUT        0x8#define TAG_MAIN_OUTPUT       0x9#define TAG_MAIN_FEATURE      0xB#define TAG_MAIN_COL_START    0xA#define TAG_MAIN_COL_END      0xC#define TAG_GLOB_USAGE        0#define TAG_GLOB_LOG_MIN      1#define TAG_GLOB_LOG_MAX      2#define TAG_GLOB_PHYS_MIN     3#define TAG_GLOB_PHYS_MAX     4#define TAG_GLOB_UNIT_EXP     5#define TAG_GLOB_UNIT         6#define TAG_GLOB_REPORT_SZ    7#define TAG_GLOB_REPORT_ID    8#define TAG_GLOB_REPORT_CNT   9#define TAG_GLOB_PUSH         10#define TAG_GLOB_POP          11#define TAG_GLOB_MAX          12#define DIGITIZER_USAGE_TIP_PRESSURE   0x30#define DIGITIZER_USAGE_TILT_X         0x3D#define DIGITIZER_USAGE_TILT_Y         0x3E/* *   This is an abbreviated parser for the HID Report Descriptor.  We *   know what devices we are talking to, so this is by no means meant *   to be generic.  We can make some safe assumptions: * *   - We know there are no LONG tags, all short *   - We know that we have no MAIN Feature and MAIN Output items *   - We know what the IRQ reports are supposed to look like. * *   The main purpose of this is to use the HID report desc to figure *   out the mins and maxs of the fields in the IRQ reports.  The IRQ *   reports for 400/401 change slightly if the max X is bigger than 64K. * */static void parse_hid_report_descriptor(struct gtco *device, char * report,					int length){	int   x, i = 0;	/* Tag primitive vars */	__u8   prefix;	__u8   size;	__u8   tag;	__u8   type;	__u8   data   = 0;	__u16  data16 = 0;	__u32  data32 = 0;	/* For parsing logic */	int   inputnum = 0;	__u32 usage = 0;	/* Global Values, indexed by TAG */	__u32 globalval[TAG_GLOB_MAX];	__u32 oldval[TAG_GLOB_MAX];	/* Debug stuff */	char  maintype = 'x';	char  globtype[12];	int   indent = 0;	char  indentstr[10] = "";	dbg("======>>>>>>PARSE<<<<<<======");	/* Walk  this report and pull out the info we need */	while (i < length) {		prefix = report[i];		/* Skip over prefix */		i++;		/* Determine data size and save the data in the proper variable */		size = PREF_SIZE(prefix);		switch (size) {		case 1:			data = report[i];			break;		case 2:			data16 = le16_to_cpu(get_unaligned((__le16 *)&report[i]));			break;		case 3:			size = 4;			data32 = le32_to_cpu(get_unaligned((__le32 *)&report[i]));			break;		}		/* Skip size of data */		i += size;		/* What we do depends on the tag type */		tag  = PREF_TAG(prefix);		type = PREF_TYPE(prefix);		switch (type) {		case TYPE_MAIN:			strcpy(globtype, "");			switch (tag) {			case TAG_MAIN_INPUT:				/*				 * The INPUT MAIN tag signifies this is				 * information from a report.  We need to				 * figure out what it is and store the				 * min/max values				 */				maintype = 'I';				if (data == 2)					strcpy(globtype, "Variable");				else if (data == 3)					strcpy(globtype, "Var|Const");				dbg("::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits",				    globalval[TAG_GLOB_REPORT_ID], inputnum,				    globalval[TAG_GLOB_LOG_MAX], globalval[TAG_GLOB_LOG_MAX],				    globalval[TAG_GLOB_LOG_MIN], globalval[TAG_GLOB_LOG_MIN],				    globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]);				/*				  We can assume that the first two input items				  are always the X and Y coordinates.  After				  that, we look for everything else by				  local usage value				 */				switch (inputnum) {				case 0:  /* X coord */					dbg("GER: X Usage: 0x%x", usage);					if (device->max_X == 0) {						device->max_X = globalval[TAG_GLOB_LOG_MAX];						device->min_X = globalval[TAG_GLOB_LOG_MIN];					}					break;				case 1:  /* Y coord */					dbg("GER: Y Usage: 0x%x", usage);					if (device->max_Y == 0) {						device->max_Y = globalval[TAG_GLOB_LOG_MAX];						device->min_Y = globalval[TAG_GLOB_LOG_MIN];					}					break;				default:					/* Tilt X */					if (usage == DIGITIZER_USAGE_TILT_X) {						if (device->maxtilt_X == 0) {							device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX];							device->mintilt_X = globalval[TAG_GLOB_LOG_MIN];						}					}					/* Tilt Y */					if (usage == DIGITIZER_USAGE_TILT_Y) {						if (device->maxtilt_Y == 0) {							device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX];							device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN];						}					}					/* Pressure */					if (usage == DIGITIZER_USAGE_TIP_PRESSURE) {						if (device->maxpressure == 0) {							device->maxpressure = globalval[TAG_GLOB_LOG_MAX];							device->minpressure = globalval[TAG_GLOB_LOG_MIN];						}					}					break;				}				inputnum++;				break;			case TAG_MAIN_OUTPUT:				maintype = 'O';				break;			case TAG_MAIN_FEATURE:				maintype = 'F';				break;			case TAG_MAIN_COL_START:				maintype = 'S';				if (data == 0) {					dbg("======>>>>>> Physical");					strcpy(globtype, "Physical");				} else					dbg("======>>>>>>");				/* Indent the debug output */				indent++;				for (x = 0; x < indent; x++)					indentstr[x] = '-';				indentstr[x] = 0;				/* Save global tags */				for (x = 0; x < TAG_GLOB_MAX; x++)					oldval[x] = globalval[x];				break;			case TAG_MAIN_COL_END:				dbg("<<<<<<======");				maintype = 'E';				indent--;				for (x = 0; x < indent; x++)					indentstr[x] = '-';				indentstr[x] = 0;				/* Copy global tags back */				for (x = 0; x < TAG_GLOB_MAX; x++)					globalval[x] = oldval[x];				break;			}			switch (size) {			case 1:				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",				    indentstr, tag, maintype, size, globtype, data);				break;			case 2:				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",				    indentstr, tag, maintype, size, globtype, data16);				break;			case 4:				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",				    indentstr, tag, maintype, size, globtype, data32);				break;			}			break;		case TYPE_GLOBAL:			switch (tag) {			case TAG_GLOB_USAGE:				/*				 * First time we hit the global usage tag,				 * it should tell us the type of device				 */				if (device->usage == 0)					device->usage = data;				strcpy(globtype, "USAGE");				break;			case TAG_GLOB_LOG_MIN:				strcpy(globtype, "LOG_MIN");				break;			case TAG_GLOB_LOG_MAX:				strcpy(globtype, "LOG_MAX");				break;			case TAG_GLOB_PHYS_MIN:				strcpy(globtype, "PHYS_MIN");				break;			case TAG_GLOB_PHYS_MAX:				strcpy(globtype, "PHYS_MAX");				break;			case TAG_GLOB_UNIT_EXP:				strcpy(globtype, "EXP");				break;			case TAG_GLOB_UNIT:				strcpy(globtype, "UNIT");				break;			case TAG_GLOB_REPORT_SZ:				strcpy(globtype, "REPORT_SZ");				break;			case TAG_GLOB_REPORT_ID:				strcpy(globtype, "REPORT_ID");				/* New report, restart numbering */				inputnum = 0;				break;			case TAG_GLOB_REPORT_CNT:				strcpy(globtype, "REPORT_CNT");				break;			case TAG_GLOB_PUSH:				strcpy(globtype, "PUSH");				break;			case TAG_GLOB_POP:				strcpy(globtype, "POP");				break;			}			/* Check to make sure we have a good tag number			   so we don't overflow array */			if (tag < TAG_GLOB_MAX) {				switch (size) {				case 1:					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",					    indentstr, globtype, tag, size, data);					globalval[tag] = data;					break;				case 2:					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",					    indentstr, globtype, tag, size, data16);					globalval[tag] = data16;					break;				case 4:					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",					    indentstr, globtype, tag, size, data32);					globalval[tag] = data32;					break;				}			} else {				dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ",				    indentstr, tag, size);			}			break;		case TYPE_LOCAL:			switch (tag) {			case TAG_GLOB_USAGE:				strcpy(globtype, "USAGE");				/* Always 1 byte */				usage = data;				break;			case TAG_GLOB_LOG_MIN:				strcpy(globtype, "MIN");				break;			case TAG_GLOB_LOG_MAX:				strcpy(globtype, "MAX");				break;			default:				strcpy(globtype, "UNKNOWN");				break;			}			switch (size) {			case 1:				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",				    indentstr, tag, globtype, size, data);				break;			case 2:				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",				    indentstr, tag, globtype, size, data16);				break;			case 4:				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",				    indentstr, tag, globtype, size, data32);				break;			}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -