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