linux/drivers/usb/misc/cytherm.c
<<
>>
Prefs
   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
  30static const struct usb_device_id id_table[] = {
  31        { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
  32        { }
  33};
  34MODULE_DEVICE_TABLE (usb, id_table);
  35
  36/* Structure to hold all of our device specific stuff */
  37struct 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 */
  45static int cytherm_probe(struct usb_interface *interface, 
  46                         const struct usb_device_id *id);
  47static void cytherm_disconnect(struct usb_interface *interface);
  48
  49
  50/* usb specific object needed to register this driver with the usb subsystem */
  51static 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 */
  69static 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
  86static 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
  94static 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
 130static 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
 137static 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
 171static ssize_t set_temp(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 172{
 173        return count;
 174}
 175
 176static DEVICE_ATTR(temp, S_IRUGO, show_temp, set_temp);
 177
 178
 179#define BUTTON 0x7a
 180
 181static 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
 210static ssize_t set_button(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 211{
 212        return count;
 213}
 214
 215static DEVICE_ATTR(button, S_IRUGO, show_button, set_button);
 216
 217
 218static 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
 242static 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
 272static DEVICE_ATTR(port0, S_IRUGO | S_IWUSR | S_IWGRP, show_port0, set_port0);
 273
 274static 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
 298static 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
 328static DEVICE_ATTR(port1, S_IRUGO | S_IWUSR | S_IWGRP, show_port1, set_port1);
 329
 330
 331
 332static 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;
 368error:
 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);
 377error_mem:
 378        return retval;
 379}
 380
 381static 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
 403module_usb_driver(cytherm_driver);
 404
 405MODULE_AUTHOR(DRIVER_AUTHOR);
 406MODULE_DESCRIPTION(DRIVER_DESC);
 407MODULE_LICENSE("GPL");
 408