aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Neukum <oliver@neukum.org>2009-07-13 10:45:47 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-09-23 09:46:28 -0400
commit4d155eb5f55b879e9947c3553b33764746fb15d5 (patch)
tree137129d9acdd55b04193d5ae91bf5f1a5a850f81
parentd9bfbd167b4dac51fed4edde7f6cfc378c9aea98 (diff)
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>
-rw-r--r--drivers/usb/misc/usbsevseg.c69
1 files changed, 63 insertions, 6 deletions
diff --git a/drivers/usb/misc/usbsevseg.c b/drivers/usb/misc/usbsevseg.c
index 28a6a3a09538..3db255537e79 100644
--- a/drivers/usb/misc/usbsevseg.c
+++ b/drivers/usb/misc/usbsevseg.c
@@ -38,6 +38,7 @@ static char *display_textmodes[] = {"raw", "hex", "ascii", NULL};
38 38
39struct usb_sevsegdev { 39struct usb_sevsegdev {
40 struct usb_device *udev; 40 struct usb_device *udev;
41 struct usb_interface *intf;
41 42
42 u8 powered; 43 u8 powered;
43 u8 mode_msb; 44 u8 mode_msb;
@@ -46,6 +47,8 @@ struct usb_sevsegdev {
46 u8 textmode; 47 u8 textmode;
47 u8 text[MAXLEN]; 48 u8 text[MAXLEN];
48 u16 textlength; 49 u16 textlength;
50
51 u8 shadow_power; /* for PM */
49}; 52};
50 53
51/* sysfs_streq can't replace this completely 54/* sysfs_streq can't replace this completely
@@ -65,6 +68,12 @@ static void update_display_powered(struct usb_sevsegdev *mydev)
65{ 68{
66 int rc; 69 int rc;
67 70
71 if (!mydev->shadow_power && mydev->powered) {
72 rc = usb_autopm_get_interface(mydev->intf);
73 if (rc < 0)
74 return;
75 }
76
68 rc = usb_control_msg(mydev->udev, 77 rc = usb_control_msg(mydev->udev,
69 usb_sndctrlpipe(mydev->udev, 0), 78 usb_sndctrlpipe(mydev->udev, 0),
70 0x12, 79 0x12,
@@ -76,12 +85,18 @@ static void update_display_powered(struct usb_sevsegdev *mydev)
76 2000); 85 2000);
77 if (rc < 0) 86 if (rc < 0)
78 dev_dbg(&mydev->udev->dev, "power retval = %d\n", rc); 87 dev_dbg(&mydev->udev->dev, "power retval = %d\n", rc);
88
89 if (mydev->shadow_power && !mydev->powered)
90 usb_autopm_put_interface(mydev->intf);
79} 91}
80 92
81static void update_display_mode(struct usb_sevsegdev *mydev) 93static void update_display_mode(struct usb_sevsegdev *mydev)
82{ 94{
83 int rc; 95 int rc;
84 96
97 if(mydev->shadow_power != 1)
98 return;
99
85 rc = usb_control_msg(mydev->udev, 100 rc = usb_control_msg(mydev->udev,
86 usb_sndctrlpipe(mydev->udev, 0), 101 usb_sndctrlpipe(mydev->udev, 0),
87 0x12, 102 0x12,
@@ -96,14 +111,17 @@ static void update_display_mode(struct usb_sevsegdev *mydev)
96 dev_dbg(&mydev->udev->dev, "mode retval = %d\n", rc); 111 dev_dbg(&mydev->udev->dev, "mode retval = %d\n", rc);
97} 112}
98 113
99static void update_display_visual(struct usb_sevsegdev *mydev) 114static void update_display_visual(struct usb_sevsegdev *mydev, gfp_t mf)
100{ 115{
101 int rc; 116 int rc;
102 int i; 117 int i;
103 unsigned char *buffer; 118 unsigned char *buffer;
104 u8 decimals = 0; 119 u8 decimals = 0;
105 120
106 buffer = kzalloc(MAXLEN, GFP_KERNEL); 121 if(mydev->shadow_power != 1)
122 return;
123
124 buffer = kzalloc(MAXLEN, mf);
107 if (!buffer) { 125 if (!buffer) {
108 dev_err(&mydev->udev->dev, "out of memory\n"); 126 dev_err(&mydev->udev->dev, "out of memory\n");
109 return; 127 return;
@@ -163,7 +181,7 @@ static ssize_t set_attr_##name(struct device *dev, \
163 struct usb_sevsegdev *mydev = usb_get_intfdata(intf); \ 181 struct usb_sevsegdev *mydev = usb_get_intfdata(intf); \
164 \ 182 \
165 mydev->name = simple_strtoul(buf, NULL, 10); \ 183 mydev->name = simple_strtoul(buf, NULL, 10); \
166 update_fcn(mydev); \ 184 update_fcn(mydev); \
167 \ 185 \
168 return count; \ 186 return count; \
169} \ 187} \
@@ -194,7 +212,7 @@ static ssize_t set_attr_text(struct device *dev,
194 if (end > 0) 212 if (end > 0)
195 memcpy(mydev->text, buf, end); 213 memcpy(mydev->text, buf, end);
196 214
197 update_display_visual(mydev); 215 update_display_visual(mydev, GFP_KERNEL);
198 return count; 216 return count;
199} 217}
200 218
@@ -242,7 +260,7 @@ static ssize_t set_attr_decimals(struct device *dev,
242 if (buf[i] == '1') 260 if (buf[i] == '1')
243 mydev->decimals[end-1-i] = 1; 261 mydev->decimals[end-1-i] = 1;
244 262
245 update_display_visual(mydev); 263 update_display_visual(mydev, GFP_KERNEL);
246 264
247 return count; 265 return count;
248} 266}
@@ -286,7 +304,7 @@ static ssize_t set_attr_textmode(struct device *dev,
286 for (i = 0; display_textmodes[i]; i++) { 304 for (i = 0; display_textmodes[i]; i++) {
287 if (sysfs_streq(display_textmodes[i], buf)) { 305 if (sysfs_streq(display_textmodes[i], buf)) {
288 mydev->textmode = i; 306 mydev->textmode = i;
289 update_display_visual(mydev); 307 update_display_visual(mydev, GFP_KERNEL);
290 return count; 308 return count;
291 } 309 }
292 } 310 }
@@ -330,6 +348,7 @@ static int sevseg_probe(struct usb_interface *interface,
330 } 348 }
331 349
332 mydev->udev = usb_get_dev(udev); 350 mydev->udev = usb_get_dev(udev);
351 mydev->intf = interface;
333 usb_set_intfdata(interface, mydev); 352 usb_set_intfdata(interface, mydev);
334 353
335 /*set defaults */ 354 /*set defaults */
@@ -364,11 +383,49 @@ static void sevseg_disconnect(struct usb_interface *interface)
364 dev_info(&interface->dev, "USB 7 Segment now disconnected\n"); 383 dev_info(&interface->dev, "USB 7 Segment now disconnected\n");
365} 384}
366 385
386static int sevseg_suspend(struct usb_interface *intf, pm_message_t message)
387{
388 struct usb_sevsegdev *mydev;
389
390 mydev = usb_get_intfdata(intf);
391 mydev->shadow_power = 0;
392
393 return 0;
394}
395
396static int sevseg_resume(struct usb_interface *intf)
397{
398 struct usb_sevsegdev *mydev;
399
400 mydev = usb_get_intfdata(intf);
401 mydev->shadow_power = 1;
402 update_display_mode(mydev);
403 update_display_visual(mydev, GFP_NOIO);
404
405 return 0;
406}
407
408static int sevseg_reset_resume(struct usb_interface *intf)
409{
410 struct usb_sevsegdev *mydev;
411
412 mydev = usb_get_intfdata(intf);
413 mydev->shadow_power = 1;
414 update_display_mode(mydev);
415 update_display_visual(mydev, GFP_NOIO);
416
417 return 0;
418}
419
367static struct usb_driver sevseg_driver = { 420static struct usb_driver sevseg_driver = {
368 .name = "usbsevseg", 421 .name = "usbsevseg",
369 .probe = sevseg_probe, 422 .probe = sevseg_probe,
370 .disconnect = sevseg_disconnect, 423 .disconnect = sevseg_disconnect,
424 .suspend = sevseg_suspend,
425 .resume = sevseg_resume,
426 .reset_resume = sevseg_reset_resume,
371 .id_table = id_table, 427 .id_table = id_table,
428 .supports_autosuspend = 1,
372}; 429};
373 430
374static int __init usb_sevseg_init(void) 431static int __init usb_sevseg_init(void)