Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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