xref: /OK3568_Linux_fs/kernel/drivers/usb/misc/usbsevseg.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * USB 7 Segment Driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2008 Harrison Metzger <harrisonmetz@gmail.com>
6*4882a593Smuzhiyun  * Based on usbled.c by Greg Kroah-Hartman (greg@kroah.com)
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/errno.h>
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/string.h>
14*4882a593Smuzhiyun #include <linux/usb.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #define DRIVER_AUTHOR "Harrison Metzger <harrisonmetz@gmail.com>"
18*4882a593Smuzhiyun #define DRIVER_DESC "USB 7 Segment Driver"
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #define VENDOR_ID	0x0fc5
21*4882a593Smuzhiyun #define PRODUCT_ID	0x1227
22*4882a593Smuzhiyun #define MAXLEN		8
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun /* table of devices that work with this driver */
25*4882a593Smuzhiyun static const struct usb_device_id id_table[] = {
26*4882a593Smuzhiyun 	{ USB_DEVICE(VENDOR_ID, PRODUCT_ID) },
27*4882a593Smuzhiyun 	{ },
28*4882a593Smuzhiyun };
29*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, id_table);
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /* the different text display modes the device is capable of */
32*4882a593Smuzhiyun static const char *display_textmodes[] = {"raw", "hex", "ascii"};
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun struct usb_sevsegdev {
35*4882a593Smuzhiyun 	struct usb_device *udev;
36*4882a593Smuzhiyun 	struct usb_interface *intf;
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	u8 powered;
39*4882a593Smuzhiyun 	u8 mode_msb;
40*4882a593Smuzhiyun 	u8 mode_lsb;
41*4882a593Smuzhiyun 	u8 decimals[MAXLEN];
42*4882a593Smuzhiyun 	u8 textmode;
43*4882a593Smuzhiyun 	u8 text[MAXLEN];
44*4882a593Smuzhiyun 	u16 textlength;
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	u8 shadow_power; /* for PM */
47*4882a593Smuzhiyun 	u8 has_interface_pm;
48*4882a593Smuzhiyun };
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun /* sysfs_streq can't replace this completely
51*4882a593Smuzhiyun  * If the device was in hex mode, and the user wanted a 0,
52*4882a593Smuzhiyun  * if str commands are used, we would assume the end of string
53*4882a593Smuzhiyun  * so mem commands are used.
54*4882a593Smuzhiyun  */
my_memlen(const char * buf,size_t count)55*4882a593Smuzhiyun static inline size_t my_memlen(const char *buf, size_t count)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun 	if (count > 0 && buf[count-1] == '\n')
58*4882a593Smuzhiyun 		return count - 1;
59*4882a593Smuzhiyun 	else
60*4882a593Smuzhiyun 		return count;
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun 
update_display_powered(struct usb_sevsegdev * mydev)63*4882a593Smuzhiyun static void update_display_powered(struct usb_sevsegdev *mydev)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun 	int rc;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	if (mydev->powered && !mydev->has_interface_pm) {
68*4882a593Smuzhiyun 		rc = usb_autopm_get_interface(mydev->intf);
69*4882a593Smuzhiyun 		if (rc < 0)
70*4882a593Smuzhiyun 			return;
71*4882a593Smuzhiyun 		mydev->has_interface_pm = 1;
72*4882a593Smuzhiyun 	}
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	if (mydev->shadow_power != 1)
75*4882a593Smuzhiyun 		return;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	rc = usb_control_msg(mydev->udev,
78*4882a593Smuzhiyun 			usb_sndctrlpipe(mydev->udev, 0),
79*4882a593Smuzhiyun 			0x12,
80*4882a593Smuzhiyun 			0x48,
81*4882a593Smuzhiyun 			(80 * 0x100) + 10, /*  (power mode) */
82*4882a593Smuzhiyun 			(0x00 * 0x100) + (mydev->powered ? 1 : 0),
83*4882a593Smuzhiyun 			NULL,
84*4882a593Smuzhiyun 			0,
85*4882a593Smuzhiyun 			2000);
86*4882a593Smuzhiyun 	if (rc < 0)
87*4882a593Smuzhiyun 		dev_dbg(&mydev->udev->dev, "power retval = %d\n", rc);
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	if (!mydev->powered && mydev->has_interface_pm) {
90*4882a593Smuzhiyun 		usb_autopm_put_interface(mydev->intf);
91*4882a593Smuzhiyun 		mydev->has_interface_pm = 0;
92*4882a593Smuzhiyun 	}
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun 
update_display_mode(struct usb_sevsegdev * mydev)95*4882a593Smuzhiyun static void update_display_mode(struct usb_sevsegdev *mydev)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun 	int rc;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	if(mydev->shadow_power != 1)
100*4882a593Smuzhiyun 		return;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	rc = usb_control_msg(mydev->udev,
103*4882a593Smuzhiyun 			usb_sndctrlpipe(mydev->udev, 0),
104*4882a593Smuzhiyun 			0x12,
105*4882a593Smuzhiyun 			0x48,
106*4882a593Smuzhiyun 			(82 * 0x100) + 10, /* (set mode) */
107*4882a593Smuzhiyun 			(mydev->mode_msb * 0x100) + mydev->mode_lsb,
108*4882a593Smuzhiyun 			NULL,
109*4882a593Smuzhiyun 			0,
110*4882a593Smuzhiyun 			2000);
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	if (rc < 0)
113*4882a593Smuzhiyun 		dev_dbg(&mydev->udev->dev, "mode retval = %d\n", rc);
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun 
update_display_visual(struct usb_sevsegdev * mydev,gfp_t mf)116*4882a593Smuzhiyun static void update_display_visual(struct usb_sevsegdev *mydev, gfp_t mf)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun 	int rc;
119*4882a593Smuzhiyun 	int i;
120*4882a593Smuzhiyun 	unsigned char *buffer;
121*4882a593Smuzhiyun 	u8 decimals = 0;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	if(mydev->shadow_power != 1)
124*4882a593Smuzhiyun 		return;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	buffer = kzalloc(MAXLEN, mf);
127*4882a593Smuzhiyun 	if (!buffer)
128*4882a593Smuzhiyun 		return;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	/* The device is right to left, where as you write left to right */
131*4882a593Smuzhiyun 	for (i = 0; i < mydev->textlength; i++)
132*4882a593Smuzhiyun 		buffer[i] = mydev->text[mydev->textlength-1-i];
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	rc = usb_control_msg(mydev->udev,
135*4882a593Smuzhiyun 			usb_sndctrlpipe(mydev->udev, 0),
136*4882a593Smuzhiyun 			0x12,
137*4882a593Smuzhiyun 			0x48,
138*4882a593Smuzhiyun 			(85 * 0x100) + 10, /* (write text) */
139*4882a593Smuzhiyun 			(0 * 0x100) + mydev->textmode, /* mode  */
140*4882a593Smuzhiyun 			buffer,
141*4882a593Smuzhiyun 			mydev->textlength,
142*4882a593Smuzhiyun 			2000);
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	if (rc < 0)
145*4882a593Smuzhiyun 		dev_dbg(&mydev->udev->dev, "write retval = %d\n", rc);
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	kfree(buffer);
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	/* The device is right to left, where as you write left to right */
150*4882a593Smuzhiyun 	for (i = 0; i < sizeof(mydev->decimals); i++)
151*4882a593Smuzhiyun 		decimals |= mydev->decimals[i] << i;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	rc = usb_control_msg(mydev->udev,
154*4882a593Smuzhiyun 			usb_sndctrlpipe(mydev->udev, 0),
155*4882a593Smuzhiyun 			0x12,
156*4882a593Smuzhiyun 			0x48,
157*4882a593Smuzhiyun 			(86 * 0x100) + 10, /* (set decimal) */
158*4882a593Smuzhiyun 			(0 * 0x100) + decimals, /* decimals */
159*4882a593Smuzhiyun 			NULL,
160*4882a593Smuzhiyun 			0,
161*4882a593Smuzhiyun 			2000);
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	if (rc < 0)
164*4882a593Smuzhiyun 		dev_dbg(&mydev->udev->dev, "decimal retval = %d\n", rc);
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun #define MYDEV_ATTR_SIMPLE_UNSIGNED(name, update_fcn)		\
168*4882a593Smuzhiyun static ssize_t name##_show(struct device *dev,			\
169*4882a593Smuzhiyun 	struct device_attribute *attr, char *buf) 		\
170*4882a593Smuzhiyun {								\
171*4882a593Smuzhiyun 	struct usb_interface *intf = to_usb_interface(dev);	\
172*4882a593Smuzhiyun 	struct usb_sevsegdev *mydev = usb_get_intfdata(intf);	\
173*4882a593Smuzhiyun 								\
174*4882a593Smuzhiyun 	return sprintf(buf, "%u\n", mydev->name);		\
175*4882a593Smuzhiyun }								\
176*4882a593Smuzhiyun 								\
177*4882a593Smuzhiyun static ssize_t name##_store(struct device *dev,			\
178*4882a593Smuzhiyun 	struct device_attribute *attr, const char *buf, size_t count) \
179*4882a593Smuzhiyun {								\
180*4882a593Smuzhiyun 	struct usb_interface *intf = to_usb_interface(dev);	\
181*4882a593Smuzhiyun 	struct usb_sevsegdev *mydev = usb_get_intfdata(intf);	\
182*4882a593Smuzhiyun 								\
183*4882a593Smuzhiyun 	mydev->name = simple_strtoul(buf, NULL, 10);		\
184*4882a593Smuzhiyun 	update_fcn(mydev); 					\
185*4882a593Smuzhiyun 								\
186*4882a593Smuzhiyun 	return count;						\
187*4882a593Smuzhiyun }								\
188*4882a593Smuzhiyun static DEVICE_ATTR_RW(name);
189*4882a593Smuzhiyun 
text_show(struct device * dev,struct device_attribute * attr,char * buf)190*4882a593Smuzhiyun static ssize_t text_show(struct device *dev,
191*4882a593Smuzhiyun 	struct device_attribute *attr, char *buf)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun 	struct usb_interface *intf = to_usb_interface(dev);
194*4882a593Smuzhiyun 	struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	return snprintf(buf, mydev->textlength, "%s\n", mydev->text);
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun 
text_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)199*4882a593Smuzhiyun static ssize_t text_store(struct device *dev,
200*4882a593Smuzhiyun 	struct device_attribute *attr, const char *buf, size_t count)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun 	struct usb_interface *intf = to_usb_interface(dev);
203*4882a593Smuzhiyun 	struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
204*4882a593Smuzhiyun 	size_t end = my_memlen(buf, count);
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	if (end > sizeof(mydev->text))
207*4882a593Smuzhiyun 		return -EINVAL;
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	memset(mydev->text, 0, sizeof(mydev->text));
210*4882a593Smuzhiyun 	mydev->textlength = end;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	if (end > 0)
213*4882a593Smuzhiyun 		memcpy(mydev->text, buf, end);
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	update_display_visual(mydev, GFP_KERNEL);
216*4882a593Smuzhiyun 	return count;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun static DEVICE_ATTR_RW(text);
220*4882a593Smuzhiyun 
decimals_show(struct device * dev,struct device_attribute * attr,char * buf)221*4882a593Smuzhiyun static ssize_t decimals_show(struct device *dev,
222*4882a593Smuzhiyun 	struct device_attribute *attr, char *buf)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun 	struct usb_interface *intf = to_usb_interface(dev);
225*4882a593Smuzhiyun 	struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
226*4882a593Smuzhiyun 	int i;
227*4882a593Smuzhiyun 	int pos;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	for (i = 0; i < sizeof(mydev->decimals); i++) {
230*4882a593Smuzhiyun 		pos = sizeof(mydev->decimals) - 1 - i;
231*4882a593Smuzhiyun 		if (mydev->decimals[i] == 0)
232*4882a593Smuzhiyun 			buf[pos] = '0';
233*4882a593Smuzhiyun 		else if (mydev->decimals[i] == 1)
234*4882a593Smuzhiyun 			buf[pos] = '1';
235*4882a593Smuzhiyun 		else
236*4882a593Smuzhiyun 			buf[pos] = 'x';
237*4882a593Smuzhiyun 	}
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	buf[sizeof(mydev->decimals)] = '\n';
240*4882a593Smuzhiyun 	return sizeof(mydev->decimals) + 1;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun 
decimals_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)243*4882a593Smuzhiyun static ssize_t decimals_store(struct device *dev,
244*4882a593Smuzhiyun 	struct device_attribute *attr, const char *buf, size_t count)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun 	struct usb_interface *intf = to_usb_interface(dev);
247*4882a593Smuzhiyun 	struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
248*4882a593Smuzhiyun 	size_t end = my_memlen(buf, count);
249*4882a593Smuzhiyun 	int i;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	if (end > sizeof(mydev->decimals))
252*4882a593Smuzhiyun 		return -EINVAL;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	for (i = 0; i < end; i++)
255*4882a593Smuzhiyun 		if (buf[i] != '0' && buf[i] != '1')
256*4882a593Smuzhiyun 			return -EINVAL;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	memset(mydev->decimals, 0, sizeof(mydev->decimals));
259*4882a593Smuzhiyun 	for (i = 0; i < end; i++)
260*4882a593Smuzhiyun 		if (buf[i] == '1')
261*4882a593Smuzhiyun 			mydev->decimals[end-1-i] = 1;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	update_display_visual(mydev, GFP_KERNEL);
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	return count;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun static DEVICE_ATTR_RW(decimals);
269*4882a593Smuzhiyun 
textmode_show(struct device * dev,struct device_attribute * attr,char * buf)270*4882a593Smuzhiyun static ssize_t textmode_show(struct device *dev,
271*4882a593Smuzhiyun 	struct device_attribute *attr, char *buf)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun 	struct usb_interface *intf = to_usb_interface(dev);
274*4882a593Smuzhiyun 	struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
275*4882a593Smuzhiyun 	int i;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	buf[0] = 0;
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(display_textmodes); i++) {
280*4882a593Smuzhiyun 		if (mydev->textmode == i) {
281*4882a593Smuzhiyun 			strcat(buf, " [");
282*4882a593Smuzhiyun 			strcat(buf, display_textmodes[i]);
283*4882a593Smuzhiyun 			strcat(buf, "] ");
284*4882a593Smuzhiyun 		} else {
285*4882a593Smuzhiyun 			strcat(buf, " ");
286*4882a593Smuzhiyun 			strcat(buf, display_textmodes[i]);
287*4882a593Smuzhiyun 			strcat(buf, " ");
288*4882a593Smuzhiyun 		}
289*4882a593Smuzhiyun 	}
290*4882a593Smuzhiyun 	strcat(buf, "\n");
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	return strlen(buf);
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun 
textmode_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)296*4882a593Smuzhiyun static ssize_t textmode_store(struct device *dev,
297*4882a593Smuzhiyun 	struct device_attribute *attr, const char *buf, size_t count)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun 	struct usb_interface *intf = to_usb_interface(dev);
300*4882a593Smuzhiyun 	struct usb_sevsegdev *mydev = usb_get_intfdata(intf);
301*4882a593Smuzhiyun 	int i;
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	i = sysfs_match_string(display_textmodes, buf);
304*4882a593Smuzhiyun 	if (i < 0)
305*4882a593Smuzhiyun 		return i;
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	mydev->textmode = i;
308*4882a593Smuzhiyun 	update_display_visual(mydev, GFP_KERNEL);
309*4882a593Smuzhiyun 	return count;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun static DEVICE_ATTR_RW(textmode);
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun MYDEV_ATTR_SIMPLE_UNSIGNED(powered, update_display_powered);
316*4882a593Smuzhiyun MYDEV_ATTR_SIMPLE_UNSIGNED(mode_msb, update_display_mode);
317*4882a593Smuzhiyun MYDEV_ATTR_SIMPLE_UNSIGNED(mode_lsb, update_display_mode);
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun static struct attribute *sevseg_attrs[] = {
320*4882a593Smuzhiyun 	&dev_attr_powered.attr,
321*4882a593Smuzhiyun 	&dev_attr_text.attr,
322*4882a593Smuzhiyun 	&dev_attr_textmode.attr,
323*4882a593Smuzhiyun 	&dev_attr_decimals.attr,
324*4882a593Smuzhiyun 	&dev_attr_mode_msb.attr,
325*4882a593Smuzhiyun 	&dev_attr_mode_lsb.attr,
326*4882a593Smuzhiyun 	NULL
327*4882a593Smuzhiyun };
328*4882a593Smuzhiyun ATTRIBUTE_GROUPS(sevseg);
329*4882a593Smuzhiyun 
sevseg_probe(struct usb_interface * interface,const struct usb_device_id * id)330*4882a593Smuzhiyun static int sevseg_probe(struct usb_interface *interface,
331*4882a593Smuzhiyun 	const struct usb_device_id *id)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun 	struct usb_device *udev = interface_to_usbdev(interface);
334*4882a593Smuzhiyun 	struct usb_sevsegdev *mydev = NULL;
335*4882a593Smuzhiyun 	int rc = -ENOMEM;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	mydev = kzalloc(sizeof(struct usb_sevsegdev), GFP_KERNEL);
338*4882a593Smuzhiyun 	if (!mydev)
339*4882a593Smuzhiyun 		goto error_mem;
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	mydev->udev = usb_get_dev(udev);
342*4882a593Smuzhiyun 	mydev->intf = interface;
343*4882a593Smuzhiyun 	usb_set_intfdata(interface, mydev);
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	/* PM */
346*4882a593Smuzhiyun 	mydev->shadow_power = 1; /* currently active */
347*4882a593Smuzhiyun 	mydev->has_interface_pm = 0; /* have not issued autopm_get */
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	/*set defaults */
350*4882a593Smuzhiyun 	mydev->textmode = 0x02; /* ascii mode */
351*4882a593Smuzhiyun 	mydev->mode_msb = 0x06; /* 6 characters */
352*4882a593Smuzhiyun 	mydev->mode_lsb = 0x3f; /* scanmode for 6 chars */
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	dev_info(&interface->dev, "USB 7 Segment device now attached\n");
355*4882a593Smuzhiyun 	return 0;
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun error_mem:
358*4882a593Smuzhiyun 	return rc;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun 
sevseg_disconnect(struct usb_interface * interface)361*4882a593Smuzhiyun static void sevseg_disconnect(struct usb_interface *interface)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun 	struct usb_sevsegdev *mydev;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	mydev = usb_get_intfdata(interface);
366*4882a593Smuzhiyun 	usb_set_intfdata(interface, NULL);
367*4882a593Smuzhiyun 	usb_put_dev(mydev->udev);
368*4882a593Smuzhiyun 	kfree(mydev);
369*4882a593Smuzhiyun 	dev_info(&interface->dev, "USB 7 Segment now disconnected\n");
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun 
sevseg_suspend(struct usb_interface * intf,pm_message_t message)372*4882a593Smuzhiyun static int sevseg_suspend(struct usb_interface *intf, pm_message_t message)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun 	struct usb_sevsegdev *mydev;
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	mydev = usb_get_intfdata(intf);
377*4882a593Smuzhiyun 	mydev->shadow_power = 0;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	return 0;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun 
sevseg_resume(struct usb_interface * intf)382*4882a593Smuzhiyun static int sevseg_resume(struct usb_interface *intf)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun 	struct usb_sevsegdev *mydev;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	mydev = usb_get_intfdata(intf);
387*4882a593Smuzhiyun 	mydev->shadow_power = 1;
388*4882a593Smuzhiyun 	update_display_mode(mydev);
389*4882a593Smuzhiyun 	update_display_visual(mydev, GFP_NOIO);
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	return 0;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun 
sevseg_reset_resume(struct usb_interface * intf)394*4882a593Smuzhiyun static int sevseg_reset_resume(struct usb_interface *intf)
395*4882a593Smuzhiyun {
396*4882a593Smuzhiyun 	struct usb_sevsegdev *mydev;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	mydev = usb_get_intfdata(intf);
399*4882a593Smuzhiyun 	mydev->shadow_power = 1;
400*4882a593Smuzhiyun 	update_display_mode(mydev);
401*4882a593Smuzhiyun 	update_display_visual(mydev, GFP_NOIO);
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	return 0;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun static struct usb_driver sevseg_driver = {
407*4882a593Smuzhiyun 	.name =		"usbsevseg",
408*4882a593Smuzhiyun 	.probe =	sevseg_probe,
409*4882a593Smuzhiyun 	.disconnect =	sevseg_disconnect,
410*4882a593Smuzhiyun 	.suspend =	sevseg_suspend,
411*4882a593Smuzhiyun 	.resume =	sevseg_resume,
412*4882a593Smuzhiyun 	.reset_resume =	sevseg_reset_resume,
413*4882a593Smuzhiyun 	.id_table =	id_table,
414*4882a593Smuzhiyun 	.dev_groups =	sevseg_groups,
415*4882a593Smuzhiyun 	.supports_autosuspend = 1,
416*4882a593Smuzhiyun };
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun module_usb_driver(sevseg_driver);
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun MODULE_AUTHOR(DRIVER_AUTHOR);
421*4882a593Smuzhiyun MODULE_DESCRIPTION(DRIVER_DESC);
422*4882a593Smuzhiyun MODULE_LICENSE("GPL");
423