ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / usb / misc / cytherm.c
1 /* -*- linux-c -*-
2  * Cypress USB Thermometer driver 
3  * 
4  * Copyright (c) 2004 Erik Rigtorp <erkki@linux.nu> <erik@rigtorp.com>
5  * 
6  * This driver works with Elektor magazine USB Interface as published in 
7  * issue #291. It should also work with the original starter kit/demo board
8  * from Cypress.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation, version 2.
13  *
14  */
15
16
17 #include <linux/config.h>
18 #include <linux/kernel.h>
19 #include <linux/errno.h>
20 #include <linux/init.h>
21 #include <linux/module.h>
22 #include <linux/usb.h>
23
24 #define DRIVER_VERSION "v1.0"
25 #define DRIVER_AUTHOR "Erik Rigtorp"
26 #define DRIVER_DESC "Cypress USB Thermometer driver"
27
28 #define USB_SKEL_VENDOR_ID      0x04b4
29 #define USB_SKEL_PRODUCT_ID     0x0002
30
31 static struct usb_device_id id_table [] = {
32         { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
33         { }
34 };
35 MODULE_DEVICE_TABLE (usb, id_table);
36
37 /* Structure to hold all of our device specific stuff */
38 struct usb_cytherm {
39         struct usb_device    *udev;      /* save off the usb device pointer */
40         struct usb_interface *interface; /* the interface for this device */
41         int brightness;
42 };
43
44
45 /* local function prototypes */
46 static int cytherm_probe(struct usb_interface *interface, 
47                          const struct usb_device_id *id);
48 static void cytherm_disconnect(struct usb_interface *interface);
49 int vendor_command(struct usb_device *dev, unsigned char request, 
50                    unsigned char value, unsigned char index,
51                    void *buf, int size);
52
53
54 /* usb specific object needed to register this driver with the usb subsystem */
55 static struct usb_driver cytherm_driver = {
56         .owner =        THIS_MODULE,
57         .name =         "cytherm",
58         .probe =        cytherm_probe,
59         .disconnect =   cytherm_disconnect,
60         .id_table =     id_table,
61 };
62
63 /* Vendor requests */
64 /* They all operate on one byte at a time */
65 #define PING       0x00
66 #define READ_ROM   0x01 /* Reads form ROM, value = address */
67 #define READ_RAM   0x02 /* Reads form RAM, value = address */
68 #define WRITE_RAM  0x03 /* Write to RAM, value = address, index = data */
69 #define READ_PORT  0x04 /* Reads from port, value = address */
70 #define WRITE_PORT 0x05 /* Write to port, value = address, index = data */ 
71
72
73 /* Send a vendor command to device */
74 int vendor_command(struct usb_device *dev, unsigned char request, 
75                    unsigned char value, unsigned char index,
76                    void *buf, int size)
77 {
78         return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
79                                request, 
80                                USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
81                                value, 
82                                index, buf, size,
83                                HZ * USB_CTRL_GET_TIMEOUT);
84 }
85
86
87
88 #define BRIGHTNESS 0x2c     /* RAM location for brightness value */
89 #define BRIGHTNESS_SEM 0x2b /* RAM location for brightness semaphore */
90
91 static ssize_t show_brightness(struct device *dev, char *buf)
92 {
93         struct usb_interface *intf = to_usb_interface(dev);    
94         struct usb_cytherm *cytherm = usb_get_intfdata(intf);     
95
96         return sprintf(buf, "%i", cytherm->brightness);
97 }
98
99 static ssize_t set_brightness(struct device *dev, const char *buf, 
100                               size_t count)
101 {
102         struct usb_interface *intf = to_usb_interface(dev);
103         struct usb_cytherm *cytherm = usb_get_intfdata(intf);
104
105         unsigned char *buffer;
106         int retval;
107    
108         buffer = kmalloc(8, GFP_KERNEL);
109         if (!buffer) {
110                 dev_err(&cytherm->udev->dev, "out of memory\n");
111                 return 0;
112         }
113
114         cytherm->brightness = simple_strtoul(buf, NULL, 10);
115    
116         if (cytherm->brightness > 0xFF)
117                 cytherm->brightness = 0xFF;
118         else if (cytherm->brightness < 0)
119                 cytherm->brightness = 0;
120    
121         /* Set brightness */
122         retval = vendor_command(cytherm->udev, WRITE_RAM, BRIGHTNESS, 
123                                 cytherm->brightness, buffer, 8);
124         if (retval)
125                 dev_dbg(&led->udev->dev, "retval = %d\n", retval);
126         /* Inform µC that we have changed the brightness setting */
127         retval = vendor_command(cytherm->udev, WRITE_RAM, BRIGHTNESS_SEM,
128                                 0x01, buffer, 8);
129         if (retval)
130                 dev_dbg(&led->udev->dev, "retval = %d\n", retval);
131    
132         kfree(buffer);
133    
134         return count;
135 }
136
137 static DEVICE_ATTR(brightness, S_IRUGO | S_IWUSR | S_IWGRP, 
138                    show_brightness, set_brightness);
139
140
141 #define TEMP 0x33 /* RAM location for temperature */
142 #define SIGN 0x34 /* RAM location for temperature sign */
143
144 static ssize_t show_temp(struct device *dev, char *buf)
145 {
146
147         struct usb_interface *intf = to_usb_interface(dev);
148         struct usb_cytherm *cytherm = usb_get_intfdata(intf);
149
150         int retval;
151         unsigned char *buffer;
152
153         int temp, sign;
154    
155         buffer = kmalloc(8, GFP_KERNEL);
156         if (!buffer) {
157                 dev_err(&cytherm->udev->dev, "out of memory\n");
158                 return 0;
159         }
160
161         /* read temperature */
162         retval = vendor_command(cytherm->udev, READ_RAM, TEMP, 0, buffer, 8);
163         if (retval)
164                 dev_dbg(&led->udev->dev, "retval = %d\n", retval);
165         temp = buffer[1];
166    
167         /* read sign */
168         retval = vendor_command(cytherm->udev, READ_RAM, SIGN, 0, buffer, 8);
169         if (retval)
170                 dev_dbg(&led->udev->dev, "retval = %d\n", retval);
171         sign = buffer[1];
172
173         kfree(buffer);
174    
175         return sprintf(buf, "%c%i.%i", sign ? '-' : '+', temp >> 1,
176                        5*(temp - ((temp >> 1) << 1)));
177 }
178
179
180 static ssize_t set_temp(struct device *dev, const char *buf, size_t count)
181 {
182         return count;
183 }
184
185 static DEVICE_ATTR(temp, S_IRUGO, show_temp, set_temp);
186
187
188 #define BUTTON 0x7a
189
190 static ssize_t show_button(struct device *dev, char *buf)
191 {
192
193         struct usb_interface *intf = to_usb_interface(dev);
194         struct usb_cytherm *cytherm = usb_get_intfdata(intf);
195
196         int retval;
197         unsigned char *buffer;
198
199         buffer = kmalloc(8, GFP_KERNEL);
200         if (!buffer) {
201                 dev_err(&cytherm->udev->dev, "out of memory\n");
202                 return 0;
203         }
204
205         /* check button */
206         retval = vendor_command(cytherm->udev, READ_RAM, BUTTON, 0, buffer, 8);
207         if (retval)
208                 dev_dbg(&led->udev->dev, "retval = %d\n", retval);
209    
210         retval = buffer[1];
211
212         kfree(buffer);
213
214         if (retval)
215                 return sprintf(buf, "1");
216         else
217                 return sprintf(buf, "0");
218 }
219
220
221 static ssize_t set_button(struct device *dev, const char *buf, size_t count)
222 {
223         return count;
224 }
225
226 static DEVICE_ATTR(button, S_IRUGO, show_button, set_button);
227
228
229 static ssize_t show_port0(struct device *dev, char *buf)
230 {
231         struct usb_interface *intf = to_usb_interface(dev);
232         struct usb_cytherm *cytherm = usb_get_intfdata(intf);
233
234         int retval;
235         unsigned char *buffer;
236
237         buffer = kmalloc(8, GFP_KERNEL);
238         if (!buffer) {
239                 dev_err(&cytherm->udev->dev, "out of memory\n");
240                 return 0;
241         }
242
243         retval = vendor_command(cytherm->udev, READ_PORT, 0, 0, buffer, 8);
244         if (retval)
245                 dev_dbg(&led->udev->dev, "retval = %d\n", retval);
246
247         retval = buffer[1];
248
249         kfree(buffer);
250
251         return sprintf(buf, "%d", retval);
252 }
253
254
255 static ssize_t set_port0(struct device *dev, const char *buf, size_t count)
256 {
257         struct usb_interface *intf = to_usb_interface(dev);
258         struct usb_cytherm *cytherm = usb_get_intfdata(intf);
259
260         unsigned char *buffer;
261         int retval;
262         int tmp;
263    
264         buffer = kmalloc(8, GFP_KERNEL);
265         if (!buffer) {
266                 dev_err(&cytherm->udev->dev, "out of memory\n");
267                 return 0;
268         }
269
270         tmp = simple_strtoul(buf, NULL, 10);
271    
272         if (tmp > 0xFF)
273                 tmp = 0xFF;
274         else if (tmp < 0)
275                 tmp = 0;
276    
277         retval = vendor_command(cytherm->udev, WRITE_PORT, 0,
278                                 tmp, buffer, 8);
279         if (retval)
280                 dev_dbg(&led->udev->dev, "retval = %d\n", retval);
281
282         kfree(buffer);
283
284         return count;
285 }
286
287 static DEVICE_ATTR(port0, S_IRUGO | S_IWUSR | S_IWGRP, show_port0, set_port0);
288
289 static ssize_t show_port1(struct device *dev, char *buf)
290 {
291         struct usb_interface *intf = to_usb_interface(dev);
292         struct usb_cytherm *cytherm = usb_get_intfdata(intf);
293
294         int retval;
295         unsigned char *buffer;
296
297         buffer = kmalloc(8, GFP_KERNEL);
298         if (!buffer) {
299                 dev_err(&cytherm->udev->dev, "out of memory\n");
300                 return 0;
301         }
302
303         retval = vendor_command(cytherm->udev, READ_PORT, 1, 0, buffer, 8);
304         if (retval)
305                 dev_dbg(&led->udev->dev, "retval = %d\n", retval);
306    
307         retval = buffer[1];
308
309         kfree(buffer);
310
311         return sprintf(buf, "%d", retval);
312 }
313
314
315 static ssize_t set_port1(struct device *dev, const char *buf, size_t count)
316 {
317         struct usb_interface *intf = to_usb_interface(dev);
318         struct usb_cytherm *cytherm = usb_get_intfdata(intf);
319
320         unsigned char *buffer;
321         int retval;
322         int tmp;
323    
324         buffer = kmalloc(8, GFP_KERNEL);
325         if (!buffer) {
326                 dev_err(&cytherm->udev->dev, "out of memory\n");
327                 return 0;
328         }
329
330         tmp = simple_strtoul(buf, NULL, 10);
331    
332         if (tmp > 0xFF)
333                 tmp = 0xFF;
334         else if (tmp < 0)
335                 tmp = 0;
336    
337         retval = vendor_command(cytherm->udev, WRITE_PORT, 1,
338                                 tmp, buffer, 8);
339         if (retval)
340                 dev_dbg(&led->udev->dev, "retval = %d\n", retval);
341
342         kfree(buffer);
343
344         return count;
345 }
346
347 static DEVICE_ATTR(port1, S_IRUGO | S_IWUSR | S_IWGRP, show_port1, set_port1);
348
349
350
351 static int cytherm_probe(struct usb_interface *interface, 
352                          const struct usb_device_id *id)
353 {
354         struct usb_device *udev = interface_to_usbdev(interface);
355         struct usb_cytherm *dev = NULL;
356         int retval = -ENOMEM;
357
358         dev = kmalloc (sizeof(struct usb_cytherm), GFP_KERNEL);
359         if (dev == NULL) {
360                 dev_err (&interface->dev, "Out of memory\n");
361                 goto error;
362         }
363         memset (dev, 0x00, sizeof (*dev));
364
365         dev->udev = usb_get_dev(udev);
366
367         usb_set_intfdata (interface, dev);
368
369         dev->brightness = 0xFF;
370
371         device_create_file(&interface->dev, &dev_attr_brightness);   
372         device_create_file(&interface->dev, &dev_attr_temp);
373         device_create_file(&interface->dev, &dev_attr_button);
374         device_create_file(&interface->dev, &dev_attr_port0);
375         device_create_file(&interface->dev, &dev_attr_port1);
376
377         dev_info (&interface->dev, 
378                   "Cypress thermometer device now attached\n");
379         return 0;
380
381  error:
382         kfree(dev);
383         return retval;
384 }
385
386 static void cytherm_disconnect(struct usb_interface *interface)
387 {
388         struct usb_cytherm *dev;
389
390         dev = usb_get_intfdata (interface);
391         usb_set_intfdata (interface, NULL);
392
393         device_remove_file(&interface->dev, &dev_attr_brightness);
394         device_remove_file(&interface->dev, &dev_attr_temp);
395         device_remove_file(&interface->dev, &dev_attr_button);
396         device_remove_file(&interface->dev, &dev_attr_port0);
397         device_remove_file(&interface->dev, &dev_attr_port1);
398
399         usb_put_dev(dev->udev);
400
401         kfree(dev);
402
403         dev_info(&interface->dev, "Cypress thermometer now disconnected\n");
404 }
405
406
407 static int __init usb_cytherm_init(void)
408 {
409         int result;
410
411         result = usb_register(&cytherm_driver);
412         if (result) 
413         {       
414                 err("usb_register failed. Error number %d", result);
415                 return result;
416         }
417
418         info(DRIVER_VERSION ":" DRIVER_DESC);
419         return 0;
420 }
421
422 static void __exit usb_cytherm_exit(void)
423 {
424         usb_deregister(&cytherm_driver);
425 }
426
427
428 module_init (usb_cytherm_init);
429 module_exit (usb_cytherm_exit);
430
431 MODULE_AUTHOR(DRIVER_AUTHOR);
432 MODULE_DESCRIPTION(DRIVER_DESC);
433 MODULE_LICENSE("GPL");