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