15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2eb86be54SHarrison Metzger /* 3eb86be54SHarrison Metzger * USB 7 Segment Driver 4eb86be54SHarrison Metzger * 5eb86be54SHarrison Metzger * Copyright (C) 2008 Harrison Metzger <harrisonmetz@gmail.com> 6eb86be54SHarrison Metzger * Based on usbled.c by Greg Kroah-Hartman (greg@kroah.com) 7eb86be54SHarrison Metzger */ 8eb86be54SHarrison Metzger 9eb86be54SHarrison Metzger #include <linux/kernel.h> 10eb86be54SHarrison Metzger #include <linux/errno.h> 11eb86be54SHarrison Metzger #include <linux/slab.h> 12eb86be54SHarrison Metzger #include <linux/module.h> 13eb86be54SHarrison Metzger #include <linux/string.h> 14eb86be54SHarrison Metzger #include <linux/usb.h> 15eb86be54SHarrison Metzger 16eb86be54SHarrison Metzger 17eb86be54SHarrison Metzger #define DRIVER_AUTHOR "Harrison Metzger <harrisonmetz@gmail.com>" 18eb86be54SHarrison Metzger #define DRIVER_DESC "USB 7 Segment Driver" 19eb86be54SHarrison Metzger 20eb86be54SHarrison Metzger #define VENDOR_ID 0x0fc5 21eb86be54SHarrison Metzger #define PRODUCT_ID 0x1227 221097ccebSHarrison Metzger #define MAXLEN 8 23eb86be54SHarrison Metzger 24eb86be54SHarrison Metzger /* table of devices that work with this driver */ 2533b9e162SNémeth Márton static const struct usb_device_id id_table[] = { 26eb86be54SHarrison Metzger { USB_DEVICE(VENDOR_ID, PRODUCT_ID) }, 27eb86be54SHarrison Metzger { }, 28eb86be54SHarrison Metzger }; 29eb86be54SHarrison Metzger MODULE_DEVICE_TABLE(usb, id_table); 30eb86be54SHarrison Metzger 31eb86be54SHarrison Metzger /* the different text display modes the device is capable of */ 320bd08fc8SAndy Shevchenko static const char *display_textmodes[] = {"raw", "hex", "ascii"}; 33eb86be54SHarrison Metzger 34eb86be54SHarrison Metzger struct usb_sevsegdev { 35eb86be54SHarrison Metzger struct usb_device *udev; 364d155eb5SOliver Neukum struct usb_interface *intf; 37eb86be54SHarrison Metzger 38eb86be54SHarrison Metzger u8 powered; 39eb86be54SHarrison Metzger u8 mode_msb; 40eb86be54SHarrison Metzger u8 mode_lsb; 41eb86be54SHarrison Metzger u8 decimals[MAXLEN]; 42eb86be54SHarrison Metzger u8 textmode; 43eb86be54SHarrison Metzger u8 text[MAXLEN]; 44eb86be54SHarrison Metzger u16 textlength; 454d155eb5SOliver Neukum 464d155eb5SOliver Neukum u8 shadow_power; /* for PM */ 474c1f5c88SHarrison Metzger u8 has_interface_pm; 48eb86be54SHarrison Metzger }; 49eb86be54SHarrison Metzger 50eb86be54SHarrison Metzger /* sysfs_streq can't replace this completely 51eb86be54SHarrison Metzger * If the device was in hex mode, and the user wanted a 0, 52eb86be54SHarrison Metzger * if str commands are used, we would assume the end of string 53eb86be54SHarrison Metzger * so mem commands are used. 54eb86be54SHarrison Metzger */ 55ff4708e6SRashika Kheria static inline size_t my_memlen(const char *buf, size_t count) 56eb86be54SHarrison Metzger { 57eb86be54SHarrison Metzger if (count > 0 && buf[count-1] == '\n') 58eb86be54SHarrison Metzger return count - 1; 59eb86be54SHarrison Metzger else 60eb86be54SHarrison Metzger return count; 61eb86be54SHarrison Metzger } 62eb86be54SHarrison Metzger 63eb86be54SHarrison Metzger static void update_display_powered(struct usb_sevsegdev *mydev) 64eb86be54SHarrison Metzger { 65eb86be54SHarrison Metzger int rc; 66eb86be54SHarrison Metzger 674c1f5c88SHarrison Metzger if (mydev->powered && !mydev->has_interface_pm) { 684d155eb5SOliver Neukum rc = usb_autopm_get_interface(mydev->intf); 694d155eb5SOliver Neukum if (rc < 0) 704d155eb5SOliver Neukum return; 714c1f5c88SHarrison Metzger mydev->has_interface_pm = 1; 724d155eb5SOliver Neukum } 734d155eb5SOliver Neukum 744c1f5c88SHarrison Metzger if (mydev->shadow_power != 1) 754c1f5c88SHarrison Metzger return; 764c1f5c88SHarrison Metzger 77eb86be54SHarrison Metzger rc = usb_control_msg(mydev->udev, 78eb86be54SHarrison Metzger usb_sndctrlpipe(mydev->udev, 0), 79eb86be54SHarrison Metzger 0x12, 80eb86be54SHarrison Metzger 0x48, 81eb86be54SHarrison Metzger (80 * 0x100) + 10, /* (power mode) */ 82eb86be54SHarrison Metzger (0x00 * 0x100) + (mydev->powered ? 1 : 0), 83eb86be54SHarrison Metzger NULL, 84eb86be54SHarrison Metzger 0, 85eb86be54SHarrison Metzger 2000); 86eb86be54SHarrison Metzger if (rc < 0) 87eb86be54SHarrison Metzger dev_dbg(&mydev->udev->dev, "power retval = %d\n", rc); 884d155eb5SOliver Neukum 894c1f5c88SHarrison Metzger if (!mydev->powered && mydev->has_interface_pm) { 904d155eb5SOliver Neukum usb_autopm_put_interface(mydev->intf); 914c1f5c88SHarrison Metzger mydev->has_interface_pm = 0; 924c1f5c88SHarrison Metzger } 93eb86be54SHarrison Metzger } 94eb86be54SHarrison Metzger 95eb86be54SHarrison Metzger static void update_display_mode(struct usb_sevsegdev *mydev) 96eb86be54SHarrison Metzger { 97eb86be54SHarrison Metzger int rc; 98eb86be54SHarrison Metzger 994d155eb5SOliver Neukum if(mydev->shadow_power != 1) 1004d155eb5SOliver Neukum return; 1014d155eb5SOliver Neukum 102eb86be54SHarrison Metzger rc = usb_control_msg(mydev->udev, 103eb86be54SHarrison Metzger usb_sndctrlpipe(mydev->udev, 0), 104eb86be54SHarrison Metzger 0x12, 105eb86be54SHarrison Metzger 0x48, 106eb86be54SHarrison Metzger (82 * 0x100) + 10, /* (set mode) */ 107eb86be54SHarrison Metzger (mydev->mode_msb * 0x100) + mydev->mode_lsb, 108eb86be54SHarrison Metzger NULL, 109eb86be54SHarrison Metzger 0, 110eb86be54SHarrison Metzger 2000); 111eb86be54SHarrison Metzger 112eb86be54SHarrison Metzger if (rc < 0) 113eb86be54SHarrison Metzger dev_dbg(&mydev->udev->dev, "mode retval = %d\n", rc); 114eb86be54SHarrison Metzger } 115eb86be54SHarrison Metzger 1164d155eb5SOliver Neukum static void update_display_visual(struct usb_sevsegdev *mydev, gfp_t mf) 117eb86be54SHarrison Metzger { 118eb86be54SHarrison Metzger int rc; 119eb86be54SHarrison Metzger int i; 120eb86be54SHarrison Metzger unsigned char *buffer; 121eb86be54SHarrison Metzger u8 decimals = 0; 122eb86be54SHarrison Metzger 1234d155eb5SOliver Neukum if(mydev->shadow_power != 1) 1244d155eb5SOliver Neukum return; 1254d155eb5SOliver Neukum 1264d155eb5SOliver Neukum buffer = kzalloc(MAXLEN, mf); 127bcf0848dSWolfram Sang if (!buffer) 128eb86be54SHarrison Metzger return; 129eb86be54SHarrison Metzger 130eb86be54SHarrison Metzger /* The device is right to left, where as you write left to right */ 131eb86be54SHarrison Metzger for (i = 0; i < mydev->textlength; i++) 132eb86be54SHarrison Metzger buffer[i] = mydev->text[mydev->textlength-1-i]; 133eb86be54SHarrison Metzger 134eb86be54SHarrison Metzger rc = usb_control_msg(mydev->udev, 135eb86be54SHarrison Metzger usb_sndctrlpipe(mydev->udev, 0), 136eb86be54SHarrison Metzger 0x12, 137eb86be54SHarrison Metzger 0x48, 138eb86be54SHarrison Metzger (85 * 0x100) + 10, /* (write text) */ 139eb86be54SHarrison Metzger (0 * 0x100) + mydev->textmode, /* mode */ 140eb86be54SHarrison Metzger buffer, 141eb86be54SHarrison Metzger mydev->textlength, 142eb86be54SHarrison Metzger 2000); 143eb86be54SHarrison Metzger 144eb86be54SHarrison Metzger if (rc < 0) 145eb86be54SHarrison Metzger dev_dbg(&mydev->udev->dev, "write retval = %d\n", rc); 146eb86be54SHarrison Metzger 147eb86be54SHarrison Metzger kfree(buffer); 148eb86be54SHarrison Metzger 149eb86be54SHarrison Metzger /* The device is right to left, where as you write left to right */ 150eb86be54SHarrison Metzger for (i = 0; i < sizeof(mydev->decimals); i++) 151eb86be54SHarrison Metzger decimals |= mydev->decimals[i] << i; 152eb86be54SHarrison Metzger 153eb86be54SHarrison Metzger rc = usb_control_msg(mydev->udev, 154eb86be54SHarrison Metzger usb_sndctrlpipe(mydev->udev, 0), 155eb86be54SHarrison Metzger 0x12, 156eb86be54SHarrison Metzger 0x48, 157eb86be54SHarrison Metzger (86 * 0x100) + 10, /* (set decimal) */ 158eb86be54SHarrison Metzger (0 * 0x100) + decimals, /* decimals */ 159eb86be54SHarrison Metzger NULL, 160eb86be54SHarrison Metzger 0, 161eb86be54SHarrison Metzger 2000); 162eb86be54SHarrison Metzger 163eb86be54SHarrison Metzger if (rc < 0) 164eb86be54SHarrison Metzger dev_dbg(&mydev->udev->dev, "decimal retval = %d\n", rc); 165eb86be54SHarrison Metzger } 166eb86be54SHarrison Metzger 167eb86be54SHarrison Metzger #define MYDEV_ATTR_SIMPLE_UNSIGNED(name, update_fcn) \ 168*a86856dbSGreg Kroah-Hartman static ssize_t name##_show(struct device *dev, \ 169eb86be54SHarrison Metzger struct device_attribute *attr, char *buf) \ 170eb86be54SHarrison Metzger { \ 171eb86be54SHarrison Metzger struct usb_interface *intf = to_usb_interface(dev); \ 172eb86be54SHarrison Metzger struct usb_sevsegdev *mydev = usb_get_intfdata(intf); \ 173eb86be54SHarrison Metzger \ 174eb86be54SHarrison Metzger return sprintf(buf, "%u\n", mydev->name); \ 175eb86be54SHarrison Metzger } \ 176eb86be54SHarrison Metzger \ 177*a86856dbSGreg Kroah-Hartman static ssize_t name##_store(struct device *dev, \ 178eb86be54SHarrison Metzger struct device_attribute *attr, const char *buf, size_t count) \ 179eb86be54SHarrison Metzger { \ 180eb86be54SHarrison Metzger struct usb_interface *intf = to_usb_interface(dev); \ 181eb86be54SHarrison Metzger struct usb_sevsegdev *mydev = usb_get_intfdata(intf); \ 182eb86be54SHarrison Metzger \ 183eb86be54SHarrison Metzger mydev->name = simple_strtoul(buf, NULL, 10); \ 184eb86be54SHarrison Metzger update_fcn(mydev); \ 185eb86be54SHarrison Metzger \ 186eb86be54SHarrison Metzger return count; \ 187eb86be54SHarrison Metzger } \ 188*a86856dbSGreg Kroah-Hartman static DEVICE_ATTR_RW(name); 189eb86be54SHarrison Metzger 190ed5bd7a4SGreg Kroah-Hartman static ssize_t text_show(struct device *dev, 191eb86be54SHarrison Metzger struct device_attribute *attr, char *buf) 192eb86be54SHarrison Metzger { 193eb86be54SHarrison Metzger struct usb_interface *intf = to_usb_interface(dev); 194eb86be54SHarrison Metzger struct usb_sevsegdev *mydev = usb_get_intfdata(intf); 195eb86be54SHarrison Metzger 196eb86be54SHarrison Metzger return snprintf(buf, mydev->textlength, "%s\n", mydev->text); 197eb86be54SHarrison Metzger } 198eb86be54SHarrison Metzger 199ed5bd7a4SGreg Kroah-Hartman static ssize_t text_store(struct device *dev, 200eb86be54SHarrison Metzger struct device_attribute *attr, const char *buf, size_t count) 201eb86be54SHarrison Metzger { 202eb86be54SHarrison Metzger struct usb_interface *intf = to_usb_interface(dev); 203eb86be54SHarrison Metzger struct usb_sevsegdev *mydev = usb_get_intfdata(intf); 204eb86be54SHarrison Metzger size_t end = my_memlen(buf, count); 205eb86be54SHarrison Metzger 206eb86be54SHarrison Metzger if (end > sizeof(mydev->text)) 207eb86be54SHarrison Metzger return -EINVAL; 208eb86be54SHarrison Metzger 209eb86be54SHarrison Metzger memset(mydev->text, 0, sizeof(mydev->text)); 210eb86be54SHarrison Metzger mydev->textlength = end; 211eb86be54SHarrison Metzger 212eb86be54SHarrison Metzger if (end > 0) 213eb86be54SHarrison Metzger memcpy(mydev->text, buf, end); 214eb86be54SHarrison Metzger 2154d155eb5SOliver Neukum update_display_visual(mydev, GFP_KERNEL); 216eb86be54SHarrison Metzger return count; 217eb86be54SHarrison Metzger } 218eb86be54SHarrison Metzger 219ed5bd7a4SGreg Kroah-Hartman static DEVICE_ATTR_RW(text); 220eb86be54SHarrison Metzger 221ed5bd7a4SGreg Kroah-Hartman static ssize_t decimals_show(struct device *dev, 222eb86be54SHarrison Metzger struct device_attribute *attr, char *buf) 223eb86be54SHarrison Metzger { 224eb86be54SHarrison Metzger struct usb_interface *intf = to_usb_interface(dev); 225eb86be54SHarrison Metzger struct usb_sevsegdev *mydev = usb_get_intfdata(intf); 226eb86be54SHarrison Metzger int i; 227eb86be54SHarrison Metzger int pos; 228eb86be54SHarrison Metzger 229eb86be54SHarrison Metzger for (i = 0; i < sizeof(mydev->decimals); i++) { 230eb86be54SHarrison Metzger pos = sizeof(mydev->decimals) - 1 - i; 231eb86be54SHarrison Metzger if (mydev->decimals[i] == 0) 232eb86be54SHarrison Metzger buf[pos] = '0'; 233eb86be54SHarrison Metzger else if (mydev->decimals[i] == 1) 234eb86be54SHarrison Metzger buf[pos] = '1'; 235eb86be54SHarrison Metzger else 236eb86be54SHarrison Metzger buf[pos] = 'x'; 237eb86be54SHarrison Metzger } 238eb86be54SHarrison Metzger 239eb86be54SHarrison Metzger buf[sizeof(mydev->decimals)] = '\n'; 240eb86be54SHarrison Metzger return sizeof(mydev->decimals) + 1; 241eb86be54SHarrison Metzger } 242eb86be54SHarrison Metzger 243ed5bd7a4SGreg Kroah-Hartman static ssize_t decimals_store(struct device *dev, 244eb86be54SHarrison Metzger struct device_attribute *attr, const char *buf, size_t count) 245eb86be54SHarrison Metzger { 246eb86be54SHarrison Metzger struct usb_interface *intf = to_usb_interface(dev); 247eb86be54SHarrison Metzger struct usb_sevsegdev *mydev = usb_get_intfdata(intf); 248eb86be54SHarrison Metzger size_t end = my_memlen(buf, count); 249eb86be54SHarrison Metzger int i; 250eb86be54SHarrison Metzger 251eb86be54SHarrison Metzger if (end > sizeof(mydev->decimals)) 252eb86be54SHarrison Metzger return -EINVAL; 253eb86be54SHarrison Metzger 254eb86be54SHarrison Metzger for (i = 0; i < end; i++) 255eb86be54SHarrison Metzger if (buf[i] != '0' && buf[i] != '1') 256eb86be54SHarrison Metzger return -EINVAL; 257eb86be54SHarrison Metzger 258eb86be54SHarrison Metzger memset(mydev->decimals, 0, sizeof(mydev->decimals)); 259eb86be54SHarrison Metzger for (i = 0; i < end; i++) 260eb86be54SHarrison Metzger if (buf[i] == '1') 261eb86be54SHarrison Metzger mydev->decimals[end-1-i] = 1; 262eb86be54SHarrison Metzger 2634d155eb5SOliver Neukum update_display_visual(mydev, GFP_KERNEL); 264eb86be54SHarrison Metzger 265eb86be54SHarrison Metzger return count; 266eb86be54SHarrison Metzger } 267eb86be54SHarrison Metzger 268ed5bd7a4SGreg Kroah-Hartman static DEVICE_ATTR_RW(decimals); 269eb86be54SHarrison Metzger 270ed5bd7a4SGreg Kroah-Hartman static ssize_t textmode_show(struct device *dev, 271eb86be54SHarrison Metzger struct device_attribute *attr, char *buf) 272eb86be54SHarrison Metzger { 273eb86be54SHarrison Metzger struct usb_interface *intf = to_usb_interface(dev); 274eb86be54SHarrison Metzger struct usb_sevsegdev *mydev = usb_get_intfdata(intf); 275eb86be54SHarrison Metzger int i; 276eb86be54SHarrison Metzger 277eb86be54SHarrison Metzger buf[0] = 0; 278eb86be54SHarrison Metzger 2790bd08fc8SAndy Shevchenko for (i = 0; i < ARRAY_SIZE(display_textmodes); i++) { 280eb86be54SHarrison Metzger if (mydev->textmode == i) { 281eb86be54SHarrison Metzger strcat(buf, " ["); 282eb86be54SHarrison Metzger strcat(buf, display_textmodes[i]); 283eb86be54SHarrison Metzger strcat(buf, "] "); 284eb86be54SHarrison Metzger } else { 285eb86be54SHarrison Metzger strcat(buf, " "); 286eb86be54SHarrison Metzger strcat(buf, display_textmodes[i]); 287eb86be54SHarrison Metzger strcat(buf, " "); 288eb86be54SHarrison Metzger } 289eb86be54SHarrison Metzger } 290eb86be54SHarrison Metzger strcat(buf, "\n"); 291eb86be54SHarrison Metzger 292eb86be54SHarrison Metzger 293eb86be54SHarrison Metzger return strlen(buf); 294eb86be54SHarrison Metzger } 295eb86be54SHarrison Metzger 296ed5bd7a4SGreg Kroah-Hartman static ssize_t textmode_store(struct device *dev, 297eb86be54SHarrison Metzger struct device_attribute *attr, const char *buf, size_t count) 298eb86be54SHarrison Metzger { 299eb86be54SHarrison Metzger struct usb_interface *intf = to_usb_interface(dev); 300eb86be54SHarrison Metzger struct usb_sevsegdev *mydev = usb_get_intfdata(intf); 301eb86be54SHarrison Metzger int i; 302eb86be54SHarrison Metzger 3030bd08fc8SAndy Shevchenko i = sysfs_match_string(display_textmodes, buf); 3040bd08fc8SAndy Shevchenko if (i < 0) 3050bd08fc8SAndy Shevchenko return i; 3060bd08fc8SAndy Shevchenko 307eb86be54SHarrison Metzger mydev->textmode = i; 3084d155eb5SOliver Neukum update_display_visual(mydev, GFP_KERNEL); 309eb86be54SHarrison Metzger return count; 310eb86be54SHarrison Metzger } 311eb86be54SHarrison Metzger 312ed5bd7a4SGreg Kroah-Hartman static DEVICE_ATTR_RW(textmode); 313eb86be54SHarrison Metzger 314eb86be54SHarrison Metzger 315eb86be54SHarrison Metzger MYDEV_ATTR_SIMPLE_UNSIGNED(powered, update_display_powered); 316eb86be54SHarrison Metzger MYDEV_ATTR_SIMPLE_UNSIGNED(mode_msb, update_display_mode); 317eb86be54SHarrison Metzger MYDEV_ATTR_SIMPLE_UNSIGNED(mode_lsb, update_display_mode); 318eb86be54SHarrison Metzger 319eb86be54SHarrison Metzger static struct attribute *dev_attrs[] = { 320eb86be54SHarrison Metzger &dev_attr_powered.attr, 321eb86be54SHarrison Metzger &dev_attr_text.attr, 322eb86be54SHarrison Metzger &dev_attr_textmode.attr, 323eb86be54SHarrison Metzger &dev_attr_decimals.attr, 324eb86be54SHarrison Metzger &dev_attr_mode_msb.attr, 325eb86be54SHarrison Metzger &dev_attr_mode_lsb.attr, 326eb86be54SHarrison Metzger NULL 327eb86be54SHarrison Metzger }; 328eb86be54SHarrison Metzger 329cc122789SArvind Yadav static const struct attribute_group dev_attr_grp = { 330eb86be54SHarrison Metzger .attrs = dev_attrs, 331eb86be54SHarrison Metzger }; 332eb86be54SHarrison Metzger 333eb86be54SHarrison Metzger static int sevseg_probe(struct usb_interface *interface, 334eb86be54SHarrison Metzger const struct usb_device_id *id) 335eb86be54SHarrison Metzger { 336eb86be54SHarrison Metzger struct usb_device *udev = interface_to_usbdev(interface); 337eb86be54SHarrison Metzger struct usb_sevsegdev *mydev = NULL; 338eb86be54SHarrison Metzger int rc = -ENOMEM; 339eb86be54SHarrison Metzger 340eb86be54SHarrison Metzger mydev = kzalloc(sizeof(struct usb_sevsegdev), GFP_KERNEL); 341bcf0848dSWolfram Sang if (!mydev) 342eb86be54SHarrison Metzger goto error_mem; 343eb86be54SHarrison Metzger 344eb86be54SHarrison Metzger mydev->udev = usb_get_dev(udev); 3454d155eb5SOliver Neukum mydev->intf = interface; 346eb86be54SHarrison Metzger usb_set_intfdata(interface, mydev); 347eb86be54SHarrison Metzger 3484c1f5c88SHarrison Metzger /* PM */ 3494c1f5c88SHarrison Metzger mydev->shadow_power = 1; /* currently active */ 3504c1f5c88SHarrison Metzger mydev->has_interface_pm = 0; /* have not issued autopm_get */ 3514c1f5c88SHarrison Metzger 352eb86be54SHarrison Metzger /*set defaults */ 353eb86be54SHarrison Metzger mydev->textmode = 0x02; /* ascii mode */ 354eb86be54SHarrison Metzger mydev->mode_msb = 0x06; /* 6 characters */ 355eb86be54SHarrison Metzger mydev->mode_lsb = 0x3f; /* scanmode for 6 chars */ 356eb86be54SHarrison Metzger 357eb86be54SHarrison Metzger rc = sysfs_create_group(&interface->dev.kobj, &dev_attr_grp); 358eb86be54SHarrison Metzger if (rc) 359eb86be54SHarrison Metzger goto error; 360eb86be54SHarrison Metzger 361eb86be54SHarrison Metzger dev_info(&interface->dev, "USB 7 Segment device now attached\n"); 362eb86be54SHarrison Metzger return 0; 363eb86be54SHarrison Metzger 364eb86be54SHarrison Metzger error: 365eb86be54SHarrison Metzger usb_set_intfdata(interface, NULL); 366eb86be54SHarrison Metzger usb_put_dev(mydev->udev); 367eb86be54SHarrison Metzger kfree(mydev); 368eb86be54SHarrison Metzger error_mem: 369eb86be54SHarrison Metzger return rc; 370eb86be54SHarrison Metzger } 371eb86be54SHarrison Metzger 372eb86be54SHarrison Metzger static void sevseg_disconnect(struct usb_interface *interface) 373eb86be54SHarrison Metzger { 374eb86be54SHarrison Metzger struct usb_sevsegdev *mydev; 375eb86be54SHarrison Metzger 376eb86be54SHarrison Metzger mydev = usb_get_intfdata(interface); 377eb86be54SHarrison Metzger sysfs_remove_group(&interface->dev.kobj, &dev_attr_grp); 378eb86be54SHarrison Metzger usb_set_intfdata(interface, NULL); 379eb86be54SHarrison Metzger usb_put_dev(mydev->udev); 380eb86be54SHarrison Metzger kfree(mydev); 381eb86be54SHarrison Metzger dev_info(&interface->dev, "USB 7 Segment now disconnected\n"); 382eb86be54SHarrison Metzger } 383eb86be54SHarrison Metzger 3844d155eb5SOliver Neukum static int sevseg_suspend(struct usb_interface *intf, pm_message_t message) 3854d155eb5SOliver Neukum { 3864d155eb5SOliver Neukum struct usb_sevsegdev *mydev; 3874d155eb5SOliver Neukum 3884d155eb5SOliver Neukum mydev = usb_get_intfdata(intf); 3894d155eb5SOliver Neukum mydev->shadow_power = 0; 3904d155eb5SOliver Neukum 3914d155eb5SOliver Neukum return 0; 3924d155eb5SOliver Neukum } 3934d155eb5SOliver Neukum 3944d155eb5SOliver Neukum static int sevseg_resume(struct usb_interface *intf) 3954d155eb5SOliver Neukum { 3964d155eb5SOliver Neukum struct usb_sevsegdev *mydev; 3974d155eb5SOliver Neukum 3984d155eb5SOliver Neukum mydev = usb_get_intfdata(intf); 3994d155eb5SOliver Neukum mydev->shadow_power = 1; 4004d155eb5SOliver Neukum update_display_mode(mydev); 4014d155eb5SOliver Neukum update_display_visual(mydev, GFP_NOIO); 4024d155eb5SOliver Neukum 4034d155eb5SOliver Neukum return 0; 4044d155eb5SOliver Neukum } 4054d155eb5SOliver Neukum 4064d155eb5SOliver Neukum static int sevseg_reset_resume(struct usb_interface *intf) 4074d155eb5SOliver Neukum { 4084d155eb5SOliver Neukum struct usb_sevsegdev *mydev; 4094d155eb5SOliver Neukum 4104d155eb5SOliver Neukum mydev = usb_get_intfdata(intf); 4114d155eb5SOliver Neukum mydev->shadow_power = 1; 4124d155eb5SOliver Neukum update_display_mode(mydev); 4134d155eb5SOliver Neukum update_display_visual(mydev, GFP_NOIO); 4144d155eb5SOliver Neukum 4154d155eb5SOliver Neukum return 0; 4164d155eb5SOliver Neukum } 4174d155eb5SOliver Neukum 418eb86be54SHarrison Metzger static struct usb_driver sevseg_driver = { 419eb86be54SHarrison Metzger .name = "usbsevseg", 420eb86be54SHarrison Metzger .probe = sevseg_probe, 421eb86be54SHarrison Metzger .disconnect = sevseg_disconnect, 4224d155eb5SOliver Neukum .suspend = sevseg_suspend, 4234d155eb5SOliver Neukum .resume = sevseg_resume, 4244d155eb5SOliver Neukum .reset_resume = sevseg_reset_resume, 425eb86be54SHarrison Metzger .id_table = id_table, 4264d155eb5SOliver Neukum .supports_autosuspend = 1, 427eb86be54SHarrison Metzger }; 428eb86be54SHarrison Metzger 42965db4305SGreg Kroah-Hartman module_usb_driver(sevseg_driver); 430eb86be54SHarrison Metzger 431eb86be54SHarrison Metzger MODULE_AUTHOR(DRIVER_AUTHOR); 432eb86be54SHarrison Metzger MODULE_DESCRIPTION(DRIVER_DESC); 433eb86be54SHarrison Metzger MODULE_LICENSE("GPL"); 434