xref: /linux/drivers/usb/misc/usbsevseg.c (revision a1c613ae4c322ddd58d5a8539dbfba2a0380a8c0)
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  */
my_memlen(const char * buf,size_t count)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 
update_display_powered(struct usb_sevsegdev * mydev)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 
7738833cbdSAnant Thazhemadam 	rc = usb_control_msg_send(mydev->udev, 0, 0x12, 0x48,
78eb86be54SHarrison Metzger 				  (80 * 0x100) + 10, /*  (power mode) */
79eb86be54SHarrison Metzger 				  (0x00 * 0x100) + (mydev->powered ? 1 : 0),
8038833cbdSAnant Thazhemadam 				  NULL, 0, 2000, GFP_KERNEL);
81eb86be54SHarrison Metzger 	if (rc < 0)
82eb86be54SHarrison Metzger 		dev_dbg(&mydev->udev->dev, "power retval = %d\n", rc);
834d155eb5SOliver Neukum 
844c1f5c88SHarrison Metzger 	if (!mydev->powered && mydev->has_interface_pm) {
854d155eb5SOliver Neukum 		usb_autopm_put_interface(mydev->intf);
864c1f5c88SHarrison Metzger 		mydev->has_interface_pm = 0;
874c1f5c88SHarrison Metzger 	}
88eb86be54SHarrison Metzger }
89eb86be54SHarrison Metzger 
update_display_mode(struct usb_sevsegdev * mydev)90eb86be54SHarrison Metzger static void update_display_mode(struct usb_sevsegdev *mydev)
91eb86be54SHarrison Metzger {
92eb86be54SHarrison Metzger 	int rc;
93eb86be54SHarrison Metzger 
944d155eb5SOliver Neukum 	if(mydev->shadow_power != 1)
954d155eb5SOliver Neukum 		return;
964d155eb5SOliver Neukum 
9738833cbdSAnant Thazhemadam 	rc = usb_control_msg_send(mydev->udev, 0, 0x12, 0x48,
98eb86be54SHarrison Metzger 				  (82 * 0x100) + 10, /* (set mode) */
99eb86be54SHarrison Metzger 				  (mydev->mode_msb * 0x100) + mydev->mode_lsb,
10038833cbdSAnant Thazhemadam 				  NULL, 0, 2000, GFP_NOIO);
101eb86be54SHarrison Metzger 
102eb86be54SHarrison Metzger 	if (rc < 0)
103eb86be54SHarrison Metzger 		dev_dbg(&mydev->udev->dev, "mode retval = %d\n", rc);
104eb86be54SHarrison Metzger }
105eb86be54SHarrison Metzger 
update_display_visual(struct usb_sevsegdev * mydev,gfp_t mf)1064d155eb5SOliver Neukum static void update_display_visual(struct usb_sevsegdev *mydev, gfp_t mf)
107eb86be54SHarrison Metzger {
108eb86be54SHarrison Metzger 	int rc;
109eb86be54SHarrison Metzger 	int i;
11038833cbdSAnant Thazhemadam 	unsigned char buffer[MAXLEN] = {0};
111eb86be54SHarrison Metzger 	u8 decimals = 0;
112eb86be54SHarrison Metzger 
1134d155eb5SOliver Neukum 	if(mydev->shadow_power != 1)
1144d155eb5SOliver Neukum 		return;
1154d155eb5SOliver Neukum 
116eb86be54SHarrison Metzger 	/* The device is right to left, where as you write left to right */
117eb86be54SHarrison Metzger 	for (i = 0; i < mydev->textlength; i++)
118eb86be54SHarrison Metzger 		buffer[i] = mydev->text[mydev->textlength-1-i];
119eb86be54SHarrison Metzger 
12038833cbdSAnant Thazhemadam 	rc = usb_control_msg_send(mydev->udev, 0, 0x12, 0x48,
121eb86be54SHarrison Metzger 				  (85 * 0x100) + 10, /* (write text) */
122eb86be54SHarrison Metzger 				  (0 * 0x100) + mydev->textmode, /* mode  */
12338833cbdSAnant Thazhemadam 				  &buffer, mydev->textlength, 2000, mf);
124eb86be54SHarrison Metzger 
125eb86be54SHarrison Metzger 	if (rc < 0)
126eb86be54SHarrison Metzger 		dev_dbg(&mydev->udev->dev, "write retval = %d\n", rc);
127eb86be54SHarrison Metzger 
128eb86be54SHarrison Metzger 	/* The device is right to left, where as you write left to right */
129eb86be54SHarrison Metzger 	for (i = 0; i < sizeof(mydev->decimals); i++)
130eb86be54SHarrison Metzger 		decimals |= mydev->decimals[i] << i;
131eb86be54SHarrison Metzger 
13238833cbdSAnant Thazhemadam 	rc = usb_control_msg_send(mydev->udev, 0, 0x12, 0x48,
133eb86be54SHarrison Metzger 				  (86 * 0x100) + 10, /* (set decimal) */
134eb86be54SHarrison Metzger 				  (0 * 0x100) + decimals, /* decimals */
13538833cbdSAnant Thazhemadam 				  NULL, 0, 2000, mf);
136eb86be54SHarrison Metzger 
137eb86be54SHarrison Metzger 	if (rc < 0)
138eb86be54SHarrison Metzger 		dev_dbg(&mydev->udev->dev, "decimal retval = %d\n", rc);
139eb86be54SHarrison Metzger }
140eb86be54SHarrison Metzger 
141eb86be54SHarrison Metzger #define MYDEV_ATTR_SIMPLE_UNSIGNED(name, update_fcn)		\
142a86856dbSGreg Kroah-Hartman static ssize_t name##_show(struct device *dev,			\
143eb86be54SHarrison Metzger 	struct device_attribute *attr, char *buf) 		\
144eb86be54SHarrison Metzger {								\
145eb86be54SHarrison Metzger 	struct usb_interface *intf = to_usb_interface(dev);	\
146eb86be54SHarrison Metzger 	struct usb_sevsegdev *mydev = usb_get_intfdata(intf);	\
147eb86be54SHarrison Metzger 								\
148eb86be54SHarrison Metzger 	return sprintf(buf, "%u\n", mydev->name);		\
149eb86be54SHarrison Metzger }								\
150eb86be54SHarrison Metzger 								\
151a86856dbSGreg Kroah-Hartman static ssize_t name##_store(struct device *dev,			\
152eb86be54SHarrison Metzger 	struct device_attribute *attr, const char *buf, size_t count) \
153eb86be54SHarrison Metzger {								\
154eb86be54SHarrison Metzger 	struct usb_interface *intf = to_usb_interface(dev);	\
155eb86be54SHarrison Metzger 	struct usb_sevsegdev *mydev = usb_get_intfdata(intf);	\
156eb86be54SHarrison Metzger 								\
157eb86be54SHarrison Metzger 	mydev->name = simple_strtoul(buf, NULL, 10);		\
158eb86be54SHarrison Metzger 	update_fcn(mydev); 					\
159eb86be54SHarrison Metzger 								\
160eb86be54SHarrison Metzger 	return count;						\
161eb86be54SHarrison Metzger }								\
162a86856dbSGreg Kroah-Hartman static DEVICE_ATTR_RW(name);
163eb86be54SHarrison Metzger 
text_show(struct device * dev,struct device_attribute * attr,char * buf)164ed5bd7a4SGreg Kroah-Hartman static ssize_t text_show(struct device *dev,
165eb86be54SHarrison Metzger 	struct device_attribute *attr, char *buf)
166eb86be54SHarrison Metzger {
167eb86be54SHarrison Metzger 	struct usb_interface *intf = to_usb_interface(dev);
168eb86be54SHarrison Metzger 	struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
169eb86be54SHarrison Metzger 
170e0c6b1f3SXuezhi Zhang 	return sysfs_emit(buf, "%s\n", mydev->text);
171eb86be54SHarrison Metzger }
172eb86be54SHarrison Metzger 
text_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)173ed5bd7a4SGreg Kroah-Hartman static ssize_t text_store(struct device *dev,
174eb86be54SHarrison Metzger 	struct device_attribute *attr, const char *buf, size_t count)
175eb86be54SHarrison Metzger {
176eb86be54SHarrison Metzger 	struct usb_interface *intf = to_usb_interface(dev);
177eb86be54SHarrison Metzger 	struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
178eb86be54SHarrison Metzger 	size_t end = my_memlen(buf, count);
179eb86be54SHarrison Metzger 
180eb86be54SHarrison Metzger 	if (end > sizeof(mydev->text))
181eb86be54SHarrison Metzger 		return -EINVAL;
182eb86be54SHarrison Metzger 
183eb86be54SHarrison Metzger 	memset(mydev->text, 0, sizeof(mydev->text));
184eb86be54SHarrison Metzger 	mydev->textlength = end;
185eb86be54SHarrison Metzger 
186eb86be54SHarrison Metzger 	if (end > 0)
187eb86be54SHarrison Metzger 		memcpy(mydev->text, buf, end);
188eb86be54SHarrison Metzger 
1894d155eb5SOliver Neukum 	update_display_visual(mydev, GFP_KERNEL);
190eb86be54SHarrison Metzger 	return count;
191eb86be54SHarrison Metzger }
192eb86be54SHarrison Metzger 
193ed5bd7a4SGreg Kroah-Hartman static DEVICE_ATTR_RW(text);
194eb86be54SHarrison Metzger 
decimals_show(struct device * dev,struct device_attribute * attr,char * buf)195ed5bd7a4SGreg Kroah-Hartman static ssize_t decimals_show(struct device *dev,
196eb86be54SHarrison Metzger 	struct device_attribute *attr, char *buf)
197eb86be54SHarrison Metzger {
198eb86be54SHarrison Metzger 	struct usb_interface *intf = to_usb_interface(dev);
199eb86be54SHarrison Metzger 	struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
200eb86be54SHarrison Metzger 	int i;
201eb86be54SHarrison Metzger 	int pos;
202eb86be54SHarrison Metzger 
203eb86be54SHarrison Metzger 	for (i = 0; i < sizeof(mydev->decimals); i++) {
204eb86be54SHarrison Metzger 		pos = sizeof(mydev->decimals) - 1 - i;
205eb86be54SHarrison Metzger 		if (mydev->decimals[i] == 0)
206eb86be54SHarrison Metzger 			buf[pos] = '0';
207eb86be54SHarrison Metzger 		else if (mydev->decimals[i] == 1)
208eb86be54SHarrison Metzger 			buf[pos] = '1';
209eb86be54SHarrison Metzger 		else
210eb86be54SHarrison Metzger 			buf[pos] = 'x';
211eb86be54SHarrison Metzger 	}
212eb86be54SHarrison Metzger 
213eb86be54SHarrison Metzger 	buf[sizeof(mydev->decimals)] = '\n';
214eb86be54SHarrison Metzger 	return sizeof(mydev->decimals) + 1;
215eb86be54SHarrison Metzger }
216eb86be54SHarrison Metzger 
decimals_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)217ed5bd7a4SGreg Kroah-Hartman static ssize_t decimals_store(struct device *dev,
218eb86be54SHarrison Metzger 	struct device_attribute *attr, const char *buf, size_t count)
219eb86be54SHarrison Metzger {
220eb86be54SHarrison Metzger 	struct usb_interface *intf = to_usb_interface(dev);
221eb86be54SHarrison Metzger 	struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
222eb86be54SHarrison Metzger 	size_t end = my_memlen(buf, count);
223eb86be54SHarrison Metzger 	int i;
224eb86be54SHarrison Metzger 
225eb86be54SHarrison Metzger 	if (end > sizeof(mydev->decimals))
226eb86be54SHarrison Metzger 		return -EINVAL;
227eb86be54SHarrison Metzger 
228eb86be54SHarrison Metzger 	for (i = 0; i < end; i++)
229eb86be54SHarrison Metzger 		if (buf[i] != '0' && buf[i] != '1')
230eb86be54SHarrison Metzger 			return -EINVAL;
231eb86be54SHarrison Metzger 
232eb86be54SHarrison Metzger 	memset(mydev->decimals, 0, sizeof(mydev->decimals));
233eb86be54SHarrison Metzger 	for (i = 0; i < end; i++)
234eb86be54SHarrison Metzger 		if (buf[i] == '1')
235eb86be54SHarrison Metzger 			mydev->decimals[end-1-i] = 1;
236eb86be54SHarrison Metzger 
2374d155eb5SOliver Neukum 	update_display_visual(mydev, GFP_KERNEL);
238eb86be54SHarrison Metzger 
239eb86be54SHarrison Metzger 	return count;
240eb86be54SHarrison Metzger }
241eb86be54SHarrison Metzger 
242ed5bd7a4SGreg Kroah-Hartman static DEVICE_ATTR_RW(decimals);
243eb86be54SHarrison Metzger 
textmode_show(struct device * dev,struct device_attribute * attr,char * buf)244ed5bd7a4SGreg Kroah-Hartman static ssize_t textmode_show(struct device *dev,
245eb86be54SHarrison Metzger 	struct device_attribute *attr, char *buf)
246eb86be54SHarrison Metzger {
247eb86be54SHarrison Metzger 	struct usb_interface *intf = to_usb_interface(dev);
248eb86be54SHarrison Metzger 	struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
249eb86be54SHarrison Metzger 	int i;
250eb86be54SHarrison Metzger 
251eb86be54SHarrison Metzger 	buf[0] = 0;
252eb86be54SHarrison Metzger 
2530bd08fc8SAndy Shevchenko 	for (i = 0; i < ARRAY_SIZE(display_textmodes); i++) {
254eb86be54SHarrison Metzger 		if (mydev->textmode == i) {
255eb86be54SHarrison Metzger 			strcat(buf, " [");
256eb86be54SHarrison Metzger 			strcat(buf, display_textmodes[i]);
257eb86be54SHarrison Metzger 			strcat(buf, "] ");
258eb86be54SHarrison Metzger 		} else {
259eb86be54SHarrison Metzger 			strcat(buf, " ");
260eb86be54SHarrison Metzger 			strcat(buf, display_textmodes[i]);
261eb86be54SHarrison Metzger 			strcat(buf, " ");
262eb86be54SHarrison Metzger 		}
263eb86be54SHarrison Metzger 	}
264eb86be54SHarrison Metzger 	strcat(buf, "\n");
265eb86be54SHarrison Metzger 
266eb86be54SHarrison Metzger 
267eb86be54SHarrison Metzger 	return strlen(buf);
268eb86be54SHarrison Metzger }
269eb86be54SHarrison Metzger 
textmode_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)270ed5bd7a4SGreg Kroah-Hartman static ssize_t textmode_store(struct device *dev,
271eb86be54SHarrison Metzger 	struct device_attribute *attr, const char *buf, size_t count)
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 
2770bd08fc8SAndy Shevchenko 	i = sysfs_match_string(display_textmodes, buf);
2780bd08fc8SAndy Shevchenko 	if (i < 0)
2790bd08fc8SAndy Shevchenko 		return i;
2800bd08fc8SAndy Shevchenko 
281eb86be54SHarrison Metzger 	mydev->textmode = i;
2824d155eb5SOliver Neukum 	update_display_visual(mydev, GFP_KERNEL);
283eb86be54SHarrison Metzger 	return count;
284eb86be54SHarrison Metzger }
285eb86be54SHarrison Metzger 
286ed5bd7a4SGreg Kroah-Hartman static DEVICE_ATTR_RW(textmode);
287eb86be54SHarrison Metzger 
288eb86be54SHarrison Metzger 
289eb86be54SHarrison Metzger MYDEV_ATTR_SIMPLE_UNSIGNED(powered, update_display_powered);
290eb86be54SHarrison Metzger MYDEV_ATTR_SIMPLE_UNSIGNED(mode_msb, update_display_mode);
291eb86be54SHarrison Metzger MYDEV_ATTR_SIMPLE_UNSIGNED(mode_lsb, update_display_mode);
292eb86be54SHarrison Metzger 
293a21350feSGreg Kroah-Hartman static struct attribute *sevseg_attrs[] = {
294eb86be54SHarrison Metzger 	&dev_attr_powered.attr,
295eb86be54SHarrison Metzger 	&dev_attr_text.attr,
296eb86be54SHarrison Metzger 	&dev_attr_textmode.attr,
297eb86be54SHarrison Metzger 	&dev_attr_decimals.attr,
298eb86be54SHarrison Metzger 	&dev_attr_mode_msb.attr,
299eb86be54SHarrison Metzger 	&dev_attr_mode_lsb.attr,
300eb86be54SHarrison Metzger 	NULL
301eb86be54SHarrison Metzger };
302a21350feSGreg Kroah-Hartman ATTRIBUTE_GROUPS(sevseg);
303eb86be54SHarrison Metzger 
sevseg_probe(struct usb_interface * interface,const struct usb_device_id * id)304eb86be54SHarrison Metzger static int sevseg_probe(struct usb_interface *interface,
305eb86be54SHarrison Metzger 	const struct usb_device_id *id)
306eb86be54SHarrison Metzger {
307eb86be54SHarrison Metzger 	struct usb_device *udev = interface_to_usbdev(interface);
308*f87ba66aSRuan Jinjie 	struct usb_sevsegdev *mydev;
309eb86be54SHarrison Metzger 	int rc = -ENOMEM;
310eb86be54SHarrison Metzger 
311eb86be54SHarrison Metzger 	mydev = kzalloc(sizeof(struct usb_sevsegdev), GFP_KERNEL);
312bcf0848dSWolfram Sang 	if (!mydev)
313eb86be54SHarrison Metzger 		goto error_mem;
314eb86be54SHarrison Metzger 
315eb86be54SHarrison Metzger 	mydev->udev = usb_get_dev(udev);
3164d155eb5SOliver Neukum 	mydev->intf = interface;
317eb86be54SHarrison Metzger 	usb_set_intfdata(interface, mydev);
318eb86be54SHarrison Metzger 
3194c1f5c88SHarrison Metzger 	/* PM */
3204c1f5c88SHarrison Metzger 	mydev->shadow_power = 1; /* currently active */
3214c1f5c88SHarrison Metzger 	mydev->has_interface_pm = 0; /* have not issued autopm_get */
3224c1f5c88SHarrison Metzger 
323eb86be54SHarrison Metzger 	/*set defaults */
324eb86be54SHarrison Metzger 	mydev->textmode = 0x02; /* ascii mode */
325eb86be54SHarrison Metzger 	mydev->mode_msb = 0x06; /* 6 characters */
326eb86be54SHarrison Metzger 	mydev->mode_lsb = 0x3f; /* scanmode for 6 chars */
327eb86be54SHarrison Metzger 
328eb86be54SHarrison Metzger 	dev_info(&interface->dev, "USB 7 Segment device now attached\n");
329eb86be54SHarrison Metzger 	return 0;
330eb86be54SHarrison Metzger 
331eb86be54SHarrison Metzger error_mem:
332eb86be54SHarrison Metzger 	return rc;
333eb86be54SHarrison Metzger }
334eb86be54SHarrison Metzger 
sevseg_disconnect(struct usb_interface * interface)335eb86be54SHarrison Metzger static void sevseg_disconnect(struct usb_interface *interface)
336eb86be54SHarrison Metzger {
337eb86be54SHarrison Metzger 	struct usb_sevsegdev *mydev;
338eb86be54SHarrison Metzger 
339eb86be54SHarrison Metzger 	mydev = usb_get_intfdata(interface);
340eb86be54SHarrison Metzger 	usb_set_intfdata(interface, NULL);
341eb86be54SHarrison Metzger 	usb_put_dev(mydev->udev);
342eb86be54SHarrison Metzger 	kfree(mydev);
343eb86be54SHarrison Metzger 	dev_info(&interface->dev, "USB 7 Segment now disconnected\n");
344eb86be54SHarrison Metzger }
345eb86be54SHarrison Metzger 
sevseg_suspend(struct usb_interface * intf,pm_message_t message)3464d155eb5SOliver Neukum static int sevseg_suspend(struct usb_interface *intf, pm_message_t message)
3474d155eb5SOliver Neukum {
3484d155eb5SOliver Neukum 	struct usb_sevsegdev *mydev;
3494d155eb5SOliver Neukum 
3504d155eb5SOliver Neukum 	mydev = usb_get_intfdata(intf);
3514d155eb5SOliver Neukum 	mydev->shadow_power = 0;
3524d155eb5SOliver Neukum 
3534d155eb5SOliver Neukum 	return 0;
3544d155eb5SOliver Neukum }
3554d155eb5SOliver Neukum 
sevseg_resume(struct usb_interface * intf)3564d155eb5SOliver Neukum static int sevseg_resume(struct usb_interface *intf)
3574d155eb5SOliver Neukum {
3584d155eb5SOliver Neukum 	struct usb_sevsegdev *mydev;
3594d155eb5SOliver Neukum 
3604d155eb5SOliver Neukum 	mydev = usb_get_intfdata(intf);
3614d155eb5SOliver Neukum 	mydev->shadow_power = 1;
3624d155eb5SOliver Neukum 	update_display_mode(mydev);
3634d155eb5SOliver Neukum 	update_display_visual(mydev, GFP_NOIO);
3644d155eb5SOliver Neukum 
3654d155eb5SOliver Neukum 	return 0;
3664d155eb5SOliver Neukum }
3674d155eb5SOliver Neukum 
sevseg_reset_resume(struct usb_interface * intf)3684d155eb5SOliver Neukum static int sevseg_reset_resume(struct usb_interface *intf)
3694d155eb5SOliver Neukum {
3704d155eb5SOliver Neukum 	struct usb_sevsegdev *mydev;
3714d155eb5SOliver Neukum 
3724d155eb5SOliver Neukum 	mydev = usb_get_intfdata(intf);
3734d155eb5SOliver Neukum 	mydev->shadow_power = 1;
3744d155eb5SOliver Neukum 	update_display_mode(mydev);
3754d155eb5SOliver Neukum 	update_display_visual(mydev, GFP_NOIO);
3764d155eb5SOliver Neukum 
3774d155eb5SOliver Neukum 	return 0;
3784d155eb5SOliver Neukum }
3794d155eb5SOliver Neukum 
380eb86be54SHarrison Metzger static struct usb_driver sevseg_driver = {
381eb86be54SHarrison Metzger 	.name =		"usbsevseg",
382eb86be54SHarrison Metzger 	.probe =	sevseg_probe,
383eb86be54SHarrison Metzger 	.disconnect =	sevseg_disconnect,
3844d155eb5SOliver Neukum 	.suspend =	sevseg_suspend,
3854d155eb5SOliver Neukum 	.resume =	sevseg_resume,
3864d155eb5SOliver Neukum 	.reset_resume =	sevseg_reset_resume,
387eb86be54SHarrison Metzger 	.id_table =	id_table,
388a21350feSGreg Kroah-Hartman 	.dev_groups =	sevseg_groups,
3894d155eb5SOliver Neukum 	.supports_autosuspend = 1,
390eb86be54SHarrison Metzger };
391eb86be54SHarrison Metzger 
39265db4305SGreg Kroah-Hartman module_usb_driver(sevseg_driver);
393eb86be54SHarrison Metzger 
394eb86be54SHarrison Metzger MODULE_AUTHOR(DRIVER_AUTHOR);
395eb86be54SHarrison Metzger MODULE_DESCRIPTION(DRIVER_DESC);
396eb86be54SHarrison Metzger MODULE_LICENSE("GPL");
397