--- drivers/usb/Makefile | 1 drivers/usb/misc/Kconfig | 10 + drivers/usb/misc/Makefile | 3 drivers/usb/misc/gotemp.c | 296 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 309 insertions(+), 1 deletion(-) --- gregkh-2.6.orig/drivers/usb/misc/Kconfig 2005-08-15 23:39:54.000000000 -0700 +++ gregkh-2.6/drivers/usb/misc/Kconfig 2005-08-15 23:40:24.000000000 -0700 @@ -101,6 +101,16 @@ To compile this driver as a module, choose M here: the module will be called cytherm. +config USB_GOTEMP + tristate "GoTemp USB thermometer driver support" + depends on USB + help + Say Y here if you want to connect a GoTemp USB thermometer + device to your computer's USB port. + + To compile this driver as a module, choose M here: the + module will be called gotemp. + config USB_PHIDGETKIT tristate "USB PhidgetKit support" depends on USB --- gregkh-2.6.orig/drivers/usb/misc/Makefile 2005-08-15 23:39:54.000000000 -0700 +++ gregkh-2.6/drivers/usb/misc/Makefile 2005-08-15 23:40:24.000000000 -0700 @@ -7,6 +7,7 @@ obj-$(CONFIG_USB_CYTHERM) += cytherm.o obj-$(CONFIG_USB_EMI26) += emi26.o obj-$(CONFIG_USB_EMI62) += emi62.o +obj-$(CONFIG_USB_GOTEMP) += gotemp.o obj-$(CONFIG_USB_IDMOUSE) += idmouse.o obj-$(CONFIG_USB_LCD) += usblcd.o obj-$(CONFIG_USB_LD) += ldusb.o @@ -18,4 +19,4 @@ obj-$(CONFIG_USB_TEST) += usbtest.o obj-$(CONFIG_USB_USS720) += uss720.o -obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ \ No newline at end of file +obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gregkh-2.6/drivers/usb/misc/gotemp.c 2005-08-15 23:40:24.000000000 -0700 @@ -0,0 +1,296 @@ +/* + * USB GoTemp driver + * + * Copyright (C) 2005 Greg Kroah-Hartman (greg@kroah.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include +#ifdef CONFIG_USB_DEBUG + #define DEBUG 1 +#endif +#include +#include +#include +#include +#include +#include + + +#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com" +#define DRIVER_DESC "USB GoTemp driver" + +#define VENDOR_ID 0x08f7 +#define PRODUCT_ID 0x0002 + +/* table of devices that work with this driver */ +static struct usb_device_id id_table [] = { + { USB_DEVICE(VENDOR_ID, PRODUCT_ID) }, + { }, +}; +MODULE_DEVICE_TABLE (usb, id_table); + +struct gotemp { + struct usb_device *udev; + int temp; + unsigned char *int_in_buffer; /* the buffer to receive data */ + __u8 int_in_endpointAddr; /* the address of the bulk in endpoint */ + struct urb *int_in_urb; +}; + +#define CMD_ID_GET_STATUS 0x10 +#define CMD_ID_WRITE_LOCAL_NV_MEM_1BYTE 0x11 +#define CMD_ID_WRITE_LOCAL_NV_MEM_2BYTES 0x12 +#define CMD_ID_WRITE_LOCAL_NV_MEM_3BYTES 0x13 +#define CMD_ID_WRITE_LOCAL_NV_MEM_4BYTES 0x14 +#define CMD_ID_WRITE_LOCAL_NV_MEM_5BYTES 0x15 +#define CMD_ID_WRITE_LOCAL_NV_MEM_6BYTES 0x16 +#define CMD_ID_READ_LOCAL_NV_MEM 0x17 +#define CMD_ID_START_MEASUREMENTS 0x18 +#define CMD_ID_STOP_MEASUREMENTS 0x19 +#define CMD_ID_INIT 0x1A +#define CMD_ID_SET_MEASUREMENT_PERIOD 0x1B +#define CMD_ID_GET_MEASUREMENT_PERIOD 0x1C +#define CMD_ID_SET_LED_STATE 0x1D +#define CMD_ID_GET_LED_STATE 0x1E +#define CMD_ID_GET_SERIAL_NUMBER 0x20 + +struct output_packet { + u8 cmd; + u8 params[7]; +} __attribute__ ((packed)); + +struct measurement_packet { + u8 measurements_in_packet; + u8 rolling_counter; + __le16 measurement0; + __le16 measurement1; + __le16 measurement2; +} __attribute__ ((packed)); + +static int send_cmd(struct gotemp *gdev, u8 cmd) +{ + struct output_packet *pkt; + int retval; + + pkt = kmalloc(sizeof(*pkt), GFP_ATOMIC); + if (!pkt) + return -ENOMEM; + memset(pkt, sizeof(*pkt), 0x00); + pkt->cmd = cmd; + + retval = usb_control_msg(gdev->udev, + usb_sndctrlpipe(gdev->udev, 0), + 0x09, /* bRequest = SET_REPORT */ + 0x21, /* bRequestType = 00100001 */ + 0x0200, /* or is it 0x0002? */ + 0x0000, /* interface 0 */ + pkt, sizeof(*pkt), 10000); + dev_dbg(&gdev->udev->dev, "retval=%d\n", retval); + if (retval == sizeof(*pkt)) + retval = 0; + + kfree(pkt); + return retval; +} + +static void init_dev(struct gotemp *gdev) +{ + int retval; + + /* First send an init message */ + send_cmd(gdev, CMD_ID_INIT); + + /* hack hack hack */ + /* problem is, we want a usb_interrupt_msg() call to read the interrupt + * endpoint right now. only after it is flushed, can we properly start + * up the measurements. */ + msleep(1000); + + /* kick off interrupt urb */ + retval = usb_submit_urb(gdev->int_in_urb, GFP_KERNEL); + if (retval) + dev_err(&gdev->udev->dev, "%s - Error %d submitting interrupt urb\n", + __FUNCTION__, retval); + + msleep(3000); + send_cmd(gdev, CMD_ID_START_MEASUREMENTS); +} + +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct gotemp *gdev = usb_get_intfdata(intf); + + return sprintf(buf, "%d\n", gdev->temp); +} + +static DEVICE_ATTR(temp, S_IRUGO, show_temp, NULL); + +static void read_int_callback(struct urb *urb, struct pt_regs *regs) +{ + struct gotemp *gdev = urb->context; + unsigned char *data = urb->transfer_buffer; + struct measurement_packet *measurement = urb->transfer_buffer; + int retval; + int i; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", + __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", + __FUNCTION__, urb->status); + goto exit; + } + + dev_info(&urb->dev->dev, "int read data: "); + + for (i = 0; i < urb->actual_length; ++i) + printk("%02x ", data[i]); + printk("\n"); + + dev_dbg(&urb->dev->dev, "counter %d, temp=%d\n", + measurement->rolling_counter, + measurement->measurement0); + gdev->temp = le16_to_cpu(measurement->measurement0); + +exit: + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + dev_err(&urb->dev->dev, "%s - Error %d submitting interrupt urb\n", + __FUNCTION__, retval); +} + +static int gotemp_probe(struct usb_interface *interface, const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(interface); + struct gotemp *gdev = NULL; + int retval = -ENOMEM; + int i; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint = NULL; + size_t buffer_size = 0; + + gdev = kmalloc(sizeof(struct gotemp), GFP_KERNEL); + if (gdev == NULL) { + dev_err(&interface->dev, "Out of memory\n"); + goto error; + } + memset (gdev, 0x00, sizeof (*gdev)); + + gdev->udev = usb_get_dev(udev); + + /* find the one control endpoint of this device */ + iface_desc = interface->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if ((endpoint->bEndpointAddress & USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_INT)) { + buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + gdev->int_in_endpointAddr = endpoint->bEndpointAddress; + gdev->int_in_buffer = kmalloc(buffer_size, GFP_KERNEL); + if (!gdev->int_in_buffer) { + dev_err(&interface->dev, + "Could not allocate buffer"); + goto error; + } + break; + } + } + if (!gdev->int_in_endpointAddr) { + dev_err(&interface->dev, "Could not find int-in endpoint"); + retval = -ENODEV; + goto error; + } + + gdev->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!gdev->int_in_urb) { + dev_err(&interface->dev, "No free urbs available\n"); + goto error; + } + usb_fill_int_urb(gdev->int_in_urb, udev, + usb_rcvintpipe(udev, + endpoint->bEndpointAddress), + gdev->int_in_buffer, buffer_size, + read_int_callback, gdev, + endpoint->bInterval); + + usb_set_intfdata (interface, gdev); + + device_create_file(&interface->dev, &dev_attr_temp); + + init_dev(gdev); + + dev_info(&interface->dev, "USB GoTemp device now attached\n"); + return 0; + +error: + usb_free_urb(gdev->int_in_urb); + kfree(gdev->int_in_buffer); + kfree(gdev); + return retval; +} + +static void gotemp_disconnect(struct usb_interface *interface) +{ + struct gotemp *gdev; + + gdev = usb_get_intfdata (interface); + usb_set_intfdata (interface, NULL); + + device_remove_file(&interface->dev, &dev_attr_temp); + + usb_put_dev(gdev->udev); + + usb_kill_urb(gdev->int_in_urb); + usb_free_urb(gdev->int_in_urb); + kfree(gdev->int_in_buffer); + kfree(gdev); + + dev_info(&interface->dev, "USB GoTemp now disconnected\n"); +} + +static struct usb_driver gotemp_driver = { + .owner = THIS_MODULE, + .name = "gotemp", + .probe = gotemp_probe, + .disconnect = gotemp_disconnect, + .id_table = id_table, +}; + +static int __init gotemp_init(void) +{ + int retval = 0; + + retval = usb_register(&gotemp_driver); + if (retval) + err("usb_register failed. Error number %d", retval); + return retval; +} + +static void __exit gotemp_exit(void) +{ + usb_deregister(&gotemp_driver); +} + +module_init (gotemp_init); +module_exit (gotemp_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); --- gregkh-2.6.orig/drivers/usb/Makefile 2005-08-15 23:40:17.000000000 -0700 +++ gregkh-2.6/drivers/usb/Makefile 2005-08-15 23:40:24.000000000 -0700 @@ -64,6 +64,7 @@ obj-$(CONFIG_USB_CYTHERM) += misc/ obj-$(CONFIG_USB_EMI26) += misc/ obj-$(CONFIG_USB_EMI62) += misc/ +obj-$(CONFIG_USB_GOTEMP) += misc/ obj-$(CONFIG_USB_IDMOUSE) += misc/ obj-$(CONFIG_USB_LCD) += misc/ obj-$(CONFIG_USB_LD) += misc/