xref: /linux/drivers/usb/misc/usbsevseg.c (revision a86856dbee984b2d107609e8b133e8ba0aa90b26)
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