---
 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-28 16:41:01.000000000 -0700
+++ gregkh-2.6/drivers/usb/misc/Kconfig	2005-08-30 12:47:29.000000000 -0700
@@ -101,6 +101,16 @@ config USB_CYTHERM
 	  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-28 16:41:01.000000000 -0700
+++ gregkh-2.6/drivers/usb/misc/Makefile	2005-08-30 12:47:29.000000000 -0700
@@ -7,6 +7,7 @@ obj-$(CONFIG_USB_AUERSWALD)	+= auerswald
 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_RIO500)	+= rio500.o
 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-30 12:47:29.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 <linux/config.h>
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG	1
+#endif
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+
+#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-30 12:18:04.000000000 -0700
+++ gregkh-2.6/drivers/usb/Makefile	2005-08-30 12:47:29.000000000 -0700
@@ -63,6 +63,7 @@ obj-$(CONFIG_USB_AUERSWALD)	+= misc/
 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/