📄 gtco.c
字号:
break; } }}/* INPUT DRIVER Routines *//* * Called when opening the input device. This will submit the URB to * the usb system so we start getting reports */static int gtco_input_open(struct input_dev *inputdev){ struct gtco *device = input_get_drvdata(inputdev); device->urbinfo->dev = device->usbdev; if (usb_submit_urb(device->urbinfo, GFP_KERNEL)) return -EIO; return 0;}/* * Called when closing the input device. This will unlink the URB */static void gtco_input_close(struct input_dev *inputdev){ struct gtco *device = input_get_drvdata(inputdev); usb_kill_urb(device->urbinfo);}/* * Setup input device capabilities. Tell the input system what this * device is capable of generating. * * This information is based on what is read from the HID report and * placed in the struct gtco structure * */static void gtco_setup_caps(struct input_dev *inputdev){ struct gtco *device = input_get_drvdata(inputdev); /* Which events */ inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) | BIT_MASK(EV_MSC); /* Misc event menu block */ inputdev->mscbit[0] = BIT_MASK(MSC_SCAN) | BIT_MASK(MSC_SERIAL) | BIT_MASK(MSC_RAW); /* Absolute values based on HID report info */ input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X, 0, 0); input_set_abs_params(inputdev, ABS_Y, device->min_Y, device->max_Y, 0, 0); /* Proximity */ input_set_abs_params(inputdev, ABS_DISTANCE, 0, 1, 0, 0); /* Tilt & pressure */ input_set_abs_params(inputdev, ABS_TILT_X, device->mintilt_X, device->maxtilt_X, 0, 0); input_set_abs_params(inputdev, ABS_TILT_Y, device->mintilt_Y, device->maxtilt_Y, 0, 0); input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure, device->maxpressure, 0, 0); /* Transducer */ input_set_abs_params(inputdev, ABS_MISC, 0, 0xFF, 0, 0);}/* USB Routines *//* * URB callback routine. Called when we get IRQ reports from the * digitizer. * * This bridges the USB and input device worlds. It generates events * on the input device based on the USB reports. */static void gtco_urb_callback(struct urb *urbinfo){ struct gtco *device = urbinfo->context; struct input_dev *inputdev; int rc; u32 val = 0; s8 valsigned = 0; char le_buffer[2]; inputdev = device->inputdevice; /* Was callback OK? */ if (urbinfo->status == -ECONNRESET || urbinfo->status == -ENOENT || urbinfo->status == -ESHUTDOWN) { /* Shutdown is occurring. Return and don't queue up any more */ return; } if (urbinfo->status != 0) { /* * Some unknown error. Hopefully temporary. Just go and * requeue an URB */ goto resubmit; } /* * Good URB, now process */ /* PID dependent when we interpret the report */ if (inputdev->id.product == PID_1000 || inputdev->id.product == PID_1001 || inputdev->id.product == PID_1002) { /* * Switch on the report ID * Conveniently, the reports have more information, the higher * the report number. We can just fall through the case * statements if we start with the highest number report */ switch (device->buffer[0]) { case 5: /* Pressure is 9 bits */ val = ((u16)(device->buffer[8]) << 1); val |= (u16)(device->buffer[7] >> 7); input_report_abs(inputdev, ABS_PRESSURE, device->buffer[8]); /* Mask out the Y tilt value used for pressure */ device->buffer[7] = (u8)((device->buffer[7]) & 0x7F); /* Fall thru */ case 4: /* Tilt */ /* Sign extend these 7 bit numbers. */ if (device->buffer[6] & 0x40) device->buffer[6] |= 0x80; if (device->buffer[7] & 0x40) device->buffer[7] |= 0x80; valsigned = (device->buffer[6]); input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned); valsigned = (device->buffer[7]); input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned); /* Fall thru */ case 2: case 3: /* Convert buttons, only 5 bits possible */ val = (device->buffer[5]) & MASK_BUTTON; /* We don't apply any meaning to the bitmask, just report */ input_event(inputdev, EV_MSC, MSC_SERIAL, val); /* Fall thru */ case 1: /* All reports have X and Y coords in the same place */ val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1])); input_report_abs(inputdev, ABS_X, val); val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3])); input_report_abs(inputdev, ABS_Y, val); /* Ditto for proximity bit */ val = device->buffer[5] & MASK_INRANGE ? 1 : 0; input_report_abs(inputdev, ABS_DISTANCE, val); /* Report 1 is an exception to how we handle buttons */ /* Buttons are an index, not a bitmask */ if (device->buffer[0] == 1) { /* * Convert buttons, 5 bit index * Report value of index set as one, * the rest as 0 */ val = device->buffer[5] & MASK_BUTTON; dbg("======>>>>>>REPORT 1: val 0x%X(%d)", val, val); /* * We don't apply any meaning to the button * index, just report it */ input_event(inputdev, EV_MSC, MSC_SERIAL, val); } break; case 7: /* Menu blocks */ input_event(inputdev, EV_MSC, MSC_SCAN, device->buffer[1]); break; } } /* Other pid class */ if (inputdev->id.product == PID_400 || inputdev->id.product == PID_401) { /* Report 2 */ if (device->buffer[0] == 2) { /* Menu blocks */ input_event(inputdev, EV_MSC, MSC_SCAN, device->buffer[1]); } /* Report 1 */ if (device->buffer[0] == 1) { char buttonbyte; /* IF X max > 64K, we still a bit from the y report */ if (device->max_X > 0x10000) { val = (u16)(((u16)(device->buffer[2] << 8)) | (u8)device->buffer[1]); val |= (u32)(((u8)device->buffer[3] & 0x1) << 16); input_report_abs(inputdev, ABS_X, val); le_buffer[0] = (u8)((u8)(device->buffer[3]) >> 1); le_buffer[0] |= (u8)((device->buffer[3] & 0x1) << 7); le_buffer[1] = (u8)(device->buffer[4] >> 1); le_buffer[1] |= (u8)((device->buffer[5] & 0x1) << 7); val = le16_to_cpu(get_unaligned((__le16 *)le_buffer)); input_report_abs(inputdev, ABS_Y, val); /* * Shift the button byte right by one to * make it look like the standard report */ buttonbyte = device->buffer[5] >> 1; } else { val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1])); input_report_abs(inputdev, ABS_X, val); val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3])); input_report_abs(inputdev, ABS_Y, val); buttonbyte = device->buffer[5]; } /* BUTTONS and PROXIMITY */ val = buttonbyte & MASK_INRANGE ? 1 : 0; input_report_abs(inputdev, ABS_DISTANCE, val); /* Convert buttons, only 4 bits possible */ val = buttonbyte & 0x0F;#ifdef USE_BUTTONS for (i = 0; i < 5; i++) input_report_key(inputdev, BTN_DIGI + i, val & (1 << i));#else /* We don't apply any meaning to the bitmask, just report */ input_event(inputdev, EV_MSC, MSC_SERIAL, val);#endif /* TRANSDUCER */ input_report_abs(inputdev, ABS_MISC, device->buffer[6]); } } /* Everybody gets report ID's */ input_event(inputdev, EV_MSC, MSC_RAW, device->buffer[0]); /* Sync it up */ input_sync(inputdev); resubmit: rc = usb_submit_urb(urbinfo, GFP_ATOMIC); if (rc != 0) err("usb_submit_urb failed rc=0x%x", rc);}/* * The probe routine. This is called when the kernel find the matching USB * vendor/product. We do the following: * * - Allocate mem for a local structure to manage the device * - Request a HID Report Descriptor from the device and parse it to * find out the device parameters * - Create an input device and assign it attributes * - Allocate an URB so the device can talk to us when the input * queue is open */static int gtco_probe(struct usb_interface *usbinterface, const struct usb_device_id *id){ struct gtco *gtco; struct input_dev *input_dev; struct hid_descriptor *hid_desc; char *report = NULL; int result = 0, retry; int error; struct usb_endpoint_descriptor *endpoint; /* Allocate memory for device structure */ gtco = kzalloc(sizeof(struct gtco), GFP_KERNEL); input_dev = input_allocate_device(); if (!gtco || !input_dev) { err("No more memory"); error = -ENOMEM; goto err_free_devs; } /* Set pointer to the input device */ gtco->inputdevice = input_dev; /* Save interface information */ gtco->usbdev = usb_get_dev(interface_to_usbdev(usbinterface)); /* Allocate some data for incoming reports */ gtco->buffer = usb_buffer_alloc(gtco->usbdev, REPORT_MAX_SIZE, GFP_KERNEL, >co->buf_dma); if (!gtco->buffer) { err("No more memory for us buffers"); error = -ENOMEM; goto err_free_devs; } /* Allocate URB for reports */ gtco->urbinfo = usb_alloc_urb(0, GFP_KERNEL); if (!gtco->urbinfo) { err("Failed to allocate URB"); return -ENOMEM; goto err_free_buf; } /* * The endpoint is always altsetting 0, we know this since we know * this device only has one interrupt endpoint */ endpoint = &usbinterface->altsetting[0].endpoint[0].desc; /* Some debug */ dbg("gtco # interfaces: %d", usbinterface->num_altsetting); dbg("num endpoints: %d", usbinterface->cur_altsetting->desc.bNumEndpoints); dbg("interface class: %d", usbinterface->cur_altsetting->desc.bInterfaceClass); dbg("endpoint: attribute:0x%x type:0x%x", endpoint->bmAttributes, endpoint->bDescriptorType); if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) dbg("endpoint: we have interrupt endpoint\n"); dbg("endpoint extra len:%d ", usbinterface->altsetting[0].extralen); /* * Find the HID descriptor so we can find out the size of the * HID report descriptor */ if (usb_get_extra_descriptor(usbinterface->cur_altsetting, HID_DEVICE_TYPE, &hid_desc) != 0){ err("Can't retrieve exta USB descriptor to get hid report descriptor length"); error = -EIO; goto err_free_urb; } dbg("Extra descriptor success: type:%d len:%d", hid_desc->bDescriptorType, hid_desc->wDescriptorLength); report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL); if (!report) { err("No more memory for report"); error = -ENOMEM; goto err_free_urb; } /* Couple of tries to get reply */ for (retry = 0; retry < 3; retry++) { result = usb_control_msg(gtco->usbdev, usb_rcvctrlpipe(gtco->usbdev, 0), USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN, REPORT_DEVICE_TYPE << 8, 0, /* interface */ report, hid_desc->wDescriptorLength, 5000); /* 5 secs */ if (result == hid_desc->wDescriptorLength) break; } /* If we didn't get the report, fail */ dbg("usb_control_msg result: :%d", result); if (result != hid_desc->wDescriptorLength) { err("Failed to get HID Report Descriptor of size: %d", hid_desc->wDescriptorLength); error = -EIO; goto err_free_urb; } /* Now we parse the report */ parse_hid_report_descriptor(gtco, report, result); /* Now we delete it */ kfree(report); /* Create a device file node */ usb_make_path(gtco->usbdev, gtco->usbpath, sizeof(gtco->usbpath)); strlcat(gtco->usbpath, "/input0", sizeof(gtco->usbpath)); /* Set Input device functions */ input_dev->open = gtco_input_open; input_dev->close = gtco_input_close; /* Set input device information */ input_dev->name = "GTCO_CalComp"; input_dev->phys = gtco->usbpath; input_set_drvdata(input_dev, gtco); /* Now set up all the input device capabilities */ gtco_setup_caps(input_dev); /* Set input device required ID information */ usb_to_input_id(gtco->usbdev, &input_dev->id); input_dev->dev.parent = &usbinterface->dev; /* Setup the URB, it will be posted later on open of input device */ endpoint = &usbinterface->altsetting[0].endpoint[0].desc; usb_fill_int_urb(gtco->urbinfo, gtco->usbdev, usb_rcvintpipe(gtco->usbdev, endpoint->bEndpointAddress), gtco->buffer, REPORT_MAX_SIZE, gtco_urb_callback, gtco, endpoint->bInterval); gtco->urbinfo->transfer_dma = gtco->buf_dma; gtco->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* Save gtco pointer in USB interface gtco */ usb_set_intfdata(usbinterface, gtco); /* All done, now register the input device */ error = input_register_device(input_dev); if (error) goto err_free_urb; return 0; err_free_urb: usb_free_urb(gtco->urbinfo); err_free_buf: usb_buffer_free(gtco->usbdev, REPORT_MAX_SIZE, gtco->buffer, gtco->buf_dma); err_free_devs: kfree(report); input_free_device(input_dev); kfree(gtco); return error;}/* * This function is a standard USB function called when the USB device * is disconnected. We will get rid of the URV, de-register the input * device, and free up allocated memory */static void gtco_disconnect(struct usb_interface *interface){ /* Grab private device ptr */ struct gtco *gtco = usb_get_intfdata(interface); /* Now reverse all the registration stuff */ if (gtco) { input_unregister_device(gtco->inputdevice); usb_kill_urb(gtco->urbinfo); usb_free_urb(gtco->urbinfo); usb_buffer_free(gtco->usbdev, REPORT_MAX_SIZE, gtco->buffer, gtco->buf_dma); kfree(gtco); } info("gtco driver disconnected");}/* STANDARD MODULE LOAD ROUTINES */static struct usb_driver gtco_driverinfo_table = { .name = "gtco", .id_table = gtco_usbid_table, .probe = gtco_probe, .disconnect = gtco_disconnect,};/* * Register this module with the USB subsystem */static int __init gtco_init(void){ int error; error = usb_register(>co_driverinfo_table); if (error) { err("usb_register() failed rc=0x%x", error); return error; } printk("GTCO usb driver version: %s", GTCO_VERSION); return 0;}/* * Deregister this module with the USB subsystem */static void __exit gtco_exit(void){ usb_deregister(>co_driverinfo_table);}module_init(gtco_init);module_exit(gtco_exit);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -