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