Merge branch 'mm-pkeys-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.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/slab.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 const 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                 return 0;
106
107         cytherm->brightness = simple_strtoul(buf, NULL, 10);
108    
109         if (cytherm->brightness > 0xFF)
110                 cytherm->brightness = 0xFF;
111         else if (cytherm->brightness < 0)
112                 cytherm->brightness = 0;
113    
114         /* Set brightness */
115         retval = vendor_command(cytherm->udev, WRITE_RAM, BRIGHTNESS, 
116                                 cytherm->brightness, buffer, 8);
117         if (retval)
118                 dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
119         /* Inform µC that we have changed the brightness setting */
120         retval = vendor_command(cytherm->udev, WRITE_RAM, BRIGHTNESS_SEM,
121                                 0x01, buffer, 8);
122         if (retval)
123                 dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
124    
125         kfree(buffer);
126    
127         return count;
128 }
129
130 static DEVICE_ATTR(brightness, S_IRUGO | S_IWUSR | S_IWGRP, 
131                    show_brightness, set_brightness);
132
133
134 #define TEMP 0x33 /* RAM location for temperature */
135 #define SIGN 0x34 /* RAM location for temperature sign */
136
137 static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf)
138 {
139
140         struct usb_interface *intf = to_usb_interface(dev);
141         struct usb_cytherm *cytherm = usb_get_intfdata(intf);
142
143         int retval;
144         unsigned char *buffer;
145
146         int temp, sign;
147    
148         buffer = kmalloc(8, GFP_KERNEL);
149         if (!buffer)
150                 return 0;
151
152         /* read temperature */
153         retval = vendor_command(cytherm->udev, READ_RAM, TEMP, 0, buffer, 8);
154         if (retval)
155                 dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
156         temp = buffer[1];
157    
158         /* read sign */
159         retval = vendor_command(cytherm->udev, READ_RAM, SIGN, 0, buffer, 8);
160         if (retval)
161                 dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
162         sign = buffer[1];
163
164         kfree(buffer);
165    
166         return sprintf(buf, "%c%i.%i", sign ? '-' : '+', temp >> 1,
167                        5*(temp - ((temp >> 1) << 1)));
168 }
169
170
171 static ssize_t set_temp(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
172 {
173         return count;
174 }
175
176 static DEVICE_ATTR(temp, S_IRUGO, show_temp, set_temp);
177
178
179 #define BUTTON 0x7a
180
181 static ssize_t show_button(struct device *dev, struct device_attribute *attr, char *buf)
182 {
183
184         struct usb_interface *intf = to_usb_interface(dev);
185         struct usb_cytherm *cytherm = usb_get_intfdata(intf);
186
187         int retval;
188         unsigned char *buffer;
189
190         buffer = kmalloc(8, GFP_KERNEL);
191         if (!buffer)
192                 return 0;
193
194         /* check button */
195         retval = vendor_command(cytherm->udev, READ_RAM, BUTTON, 0, buffer, 8);
196         if (retval)
197                 dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
198    
199         retval = buffer[1];
200
201         kfree(buffer);
202
203         if (retval)
204                 return sprintf(buf, "1");
205         else
206                 return sprintf(buf, "0");
207 }
208
209
210 static ssize_t set_button(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
211 {
212         return count;
213 }
214
215 static DEVICE_ATTR(button, S_IRUGO, show_button, set_button);
216
217
218 static ssize_t show_port0(struct device *dev, struct device_attribute *attr, char *buf)
219 {
220         struct usb_interface *intf = to_usb_interface(dev);
221         struct usb_cytherm *cytherm = usb_get_intfdata(intf);
222
223         int retval;
224         unsigned char *buffer;
225
226         buffer = kmalloc(8, GFP_KERNEL);
227         if (!buffer)
228                 return 0;
229
230         retval = vendor_command(cytherm->udev, READ_PORT, 0, 0, buffer, 8);
231         if (retval)
232                 dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
233
234         retval = buffer[1];
235
236         kfree(buffer);
237
238         return sprintf(buf, "%d", retval);
239 }
240
241
242 static ssize_t set_port0(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
243 {
244         struct usb_interface *intf = to_usb_interface(dev);
245         struct usb_cytherm *cytherm = usb_get_intfdata(intf);
246
247         unsigned char *buffer;
248         int retval;
249         int tmp;
250    
251         buffer = kmalloc(8, GFP_KERNEL);
252         if (!buffer)
253                 return 0;
254
255         tmp = simple_strtoul(buf, NULL, 10);
256    
257         if (tmp > 0xFF)
258                 tmp = 0xFF;
259         else if (tmp < 0)
260                 tmp = 0;
261    
262         retval = vendor_command(cytherm->udev, WRITE_PORT, 0,
263                                 tmp, buffer, 8);
264         if (retval)
265                 dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
266
267         kfree(buffer);
268
269         return count;
270 }
271
272 static DEVICE_ATTR(port0, S_IRUGO | S_IWUSR | S_IWGRP, show_port0, set_port0);
273
274 static ssize_t show_port1(struct device *dev, struct device_attribute *attr, char *buf)
275 {
276         struct usb_interface *intf = to_usb_interface(dev);
277         struct usb_cytherm *cytherm = usb_get_intfdata(intf);
278
279         int retval;
280         unsigned char *buffer;
281
282         buffer = kmalloc(8, GFP_KERNEL);
283         if (!buffer)
284                 return 0;
285
286         retval = vendor_command(cytherm->udev, READ_PORT, 1, 0, buffer, 8);
287         if (retval)
288                 dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
289    
290         retval = buffer[1];
291
292         kfree(buffer);
293
294         return sprintf(buf, "%d", retval);
295 }
296
297
298 static ssize_t set_port1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
299 {
300         struct usb_interface *intf = to_usb_interface(dev);
301         struct usb_cytherm *cytherm = usb_get_intfdata(intf);
302
303         unsigned char *buffer;
304         int retval;
305         int tmp;
306    
307         buffer = kmalloc(8, GFP_KERNEL);
308         if (!buffer)
309                 return 0;
310
311         tmp = simple_strtoul(buf, NULL, 10);
312    
313         if (tmp > 0xFF)
314                 tmp = 0xFF;
315         else if (tmp < 0)
316                 tmp = 0;
317    
318         retval = vendor_command(cytherm->udev, WRITE_PORT, 1,
319                                 tmp, buffer, 8);
320         if (retval)
321                 dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
322
323         kfree(buffer);
324
325         return count;
326 }
327
328 static DEVICE_ATTR(port1, S_IRUGO | S_IWUSR | S_IWGRP, show_port1, set_port1);
329
330
331
332 static int cytherm_probe(struct usb_interface *interface, 
333                          const struct usb_device_id *id)
334 {
335         struct usb_device *udev = interface_to_usbdev(interface);
336         struct usb_cytherm *dev = NULL;
337         int retval = -ENOMEM;
338
339         dev = kzalloc (sizeof(struct usb_cytherm), GFP_KERNEL);
340         if (!dev)
341                 goto error_mem;
342
343         dev->udev = usb_get_dev(udev);
344
345         usb_set_intfdata (interface, dev);
346
347         dev->brightness = 0xFF;
348
349         retval = device_create_file(&interface->dev, &dev_attr_brightness);
350         if (retval)
351                 goto error;
352         retval = device_create_file(&interface->dev, &dev_attr_temp);
353         if (retval)
354                 goto error;
355         retval = device_create_file(&interface->dev, &dev_attr_button);
356         if (retval)
357                 goto error;
358         retval = device_create_file(&interface->dev, &dev_attr_port0);
359         if (retval)
360                 goto error;
361         retval = device_create_file(&interface->dev, &dev_attr_port1);
362         if (retval)
363                 goto error;
364
365         dev_info (&interface->dev,
366                   "Cypress thermometer device now attached\n");
367         return 0;
368 error:
369         device_remove_file(&interface->dev, &dev_attr_brightness);
370         device_remove_file(&interface->dev, &dev_attr_temp);
371         device_remove_file(&interface->dev, &dev_attr_button);
372         device_remove_file(&interface->dev, &dev_attr_port0);
373         device_remove_file(&interface->dev, &dev_attr_port1);
374         usb_set_intfdata (interface, NULL);
375         usb_put_dev(dev->udev);
376         kfree(dev);
377 error_mem:
378         return retval;
379 }
380
381 static void cytherm_disconnect(struct usb_interface *interface)
382 {
383         struct usb_cytherm *dev;
384
385         dev = usb_get_intfdata (interface);
386
387         device_remove_file(&interface->dev, &dev_attr_brightness);
388         device_remove_file(&interface->dev, &dev_attr_temp);
389         device_remove_file(&interface->dev, &dev_attr_button);
390         device_remove_file(&interface->dev, &dev_attr_port0);
391         device_remove_file(&interface->dev, &dev_attr_port1);
392
393         /* first remove the files, then NULL the pointer */
394         usb_set_intfdata (interface, NULL);
395
396         usb_put_dev(dev->udev);
397
398         kfree(dev);
399
400         dev_info(&interface->dev, "Cypress thermometer now disconnected\n");
401 }
402
403 module_usb_driver(cytherm_driver);
404
405 MODULE_AUTHOR(DRIVER_AUTHOR);
406 MODULE_DESCRIPTION(DRIVER_DESC);
407 MODULE_LICENSE("GPL");