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

USB: full autosuspend and power management support for usbsevseg

This patch adds to the usbsevseg driver:

- suspend/resume support
- reset_resume support
- autosuspend using the display's power state to determine idleness

Signed-off-by: Oliver Neukum <oliver@neukum.org>
Signed-off-by: Harrison Metzger <harrisonmetz@gmail.com>

authored by

Oliver Neukum and committed by
Greg Kroah-Hartman
4d155eb5 d9bfbd16

+63 -6
+63 -6
drivers/usb/misc/usbsevseg.c
··· 38 38 39 39 struct usb_sevsegdev { 40 40 struct usb_device *udev; 41 + struct usb_interface *intf; 41 42 42 43 u8 powered; 43 44 u8 mode_msb; ··· 47 46 u8 textmode; 48 47 u8 text[MAXLEN]; 49 48 u16 textlength; 49 + 50 + u8 shadow_power; /* for PM */ 50 51 }; 51 52 52 53 /* sysfs_streq can't replace this completely ··· 68 65 { 69 66 int rc; 70 67 68 + if (!mydev->shadow_power && mydev->powered) { 69 + rc = usb_autopm_get_interface(mydev->intf); 70 + if (rc < 0) 71 + return; 72 + } 73 + 71 74 rc = usb_control_msg(mydev->udev, 72 75 usb_sndctrlpipe(mydev->udev, 0), 73 76 0x12, ··· 85 76 2000); 86 77 if (rc < 0) 87 78 dev_dbg(&mydev->udev->dev, "power retval = %d\n", rc); 79 + 80 + if (mydev->shadow_power && !mydev->powered) 81 + usb_autopm_put_interface(mydev->intf); 88 82 } 89 83 90 84 static void update_display_mode(struct usb_sevsegdev *mydev) 91 85 { 92 86 int rc; 87 + 88 + if(mydev->shadow_power != 1) 89 + return; 93 90 94 91 rc = usb_control_msg(mydev->udev, 95 92 usb_sndctrlpipe(mydev->udev, 0), ··· 111 96 dev_dbg(&mydev->udev->dev, "mode retval = %d\n", rc); 112 97 } 113 98 114 - static void update_display_visual(struct usb_sevsegdev *mydev) 99 + static void update_display_visual(struct usb_sevsegdev *mydev, gfp_t mf) 115 100 { 116 101 int rc; 117 102 int i; 118 103 unsigned char *buffer; 119 104 u8 decimals = 0; 120 105 121 - buffer = kzalloc(MAXLEN, GFP_KERNEL); 106 + if(mydev->shadow_power != 1) 107 + return; 108 + 109 + buffer = kzalloc(MAXLEN, mf); 122 110 if (!buffer) { 123 111 dev_err(&mydev->udev->dev, "out of memory\n"); 124 112 return; ··· 181 163 struct usb_sevsegdev *mydev = usb_get_intfdata(intf); \ 182 164 \ 183 165 mydev->name = simple_strtoul(buf, NULL, 10); \ 184 - update_fcn(mydev); \ 166 + update_fcn(mydev); \ 185 167 \ 186 168 return count; \ 187 169 } \ ··· 212 194 if (end > 0) 213 195 memcpy(mydev->text, buf, end); 214 196 215 - update_display_visual(mydev); 197 + update_display_visual(mydev, GFP_KERNEL); 216 198 return count; 217 199 } 218 200 ··· 260 242 if (buf[i] == '1') 261 243 mydev->decimals[end-1-i] = 1; 262 244 263 - update_display_visual(mydev); 245 + update_display_visual(mydev, GFP_KERNEL); 264 246 265 247 return count; 266 248 } ··· 304 286 for (i = 0; display_textmodes[i]; i++) { 305 287 if (sysfs_streq(display_textmodes[i], buf)) { 306 288 mydev->textmode = i; 307 - update_display_visual(mydev); 289 + update_display_visual(mydev, GFP_KERNEL); 308 290 return count; 309 291 } 310 292 } ··· 348 330 } 349 331 350 332 mydev->udev = usb_get_dev(udev); 333 + mydev->intf = interface; 351 334 usb_set_intfdata(interface, mydev); 352 335 353 336 /*set defaults */ ··· 383 364 dev_info(&interface->dev, "USB 7 Segment now disconnected\n"); 384 365 } 385 366 367 + static int sevseg_suspend(struct usb_interface *intf, pm_message_t message) 368 + { 369 + struct usb_sevsegdev *mydev; 370 + 371 + mydev = usb_get_intfdata(intf); 372 + mydev->shadow_power = 0; 373 + 374 + return 0; 375 + } 376 + 377 + static int sevseg_resume(struct usb_interface *intf) 378 + { 379 + struct usb_sevsegdev *mydev; 380 + 381 + mydev = usb_get_intfdata(intf); 382 + mydev->shadow_power = 1; 383 + update_display_mode(mydev); 384 + update_display_visual(mydev, GFP_NOIO); 385 + 386 + return 0; 387 + } 388 + 389 + static int sevseg_reset_resume(struct usb_interface *intf) 390 + { 391 + struct usb_sevsegdev *mydev; 392 + 393 + mydev = usb_get_intfdata(intf); 394 + mydev->shadow_power = 1; 395 + update_display_mode(mydev); 396 + update_display_visual(mydev, GFP_NOIO); 397 + 398 + return 0; 399 + } 400 + 386 401 static struct usb_driver sevseg_driver = { 387 402 .name = "usbsevseg", 388 403 .probe = sevseg_probe, 389 404 .disconnect = sevseg_disconnect, 405 + .suspend = sevseg_suspend, 406 + .resume = sevseg_resume, 407 + .reset_resume = sevseg_reset_resume, 390 408 .id_table = id_table, 409 + .supports_autosuspend = 1, 391 410 }; 392 411 393 412 static int __init usb_sevseg_init(void)