xref: /OK3568_Linux_fs/kernel/drivers/usb/misc/adutux.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * adutux - driver for ADU devices from Ontrak Control Systems
4*4882a593Smuzhiyun  * This is an experimental driver. Use at your own risk.
5*4882a593Smuzhiyun  * This driver is not supported by Ontrak Control Systems.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Copyright (c) 2003 John Homppi (SCO, leave this notice here)
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * derived from the Lego USB Tower driver 0.56:
10*4882a593Smuzhiyun  * Copyright (c) 2003 David Glance <davidgsf@sourceforge.net>
11*4882a593Smuzhiyun  *               2001 Juergen Stuber <stuber@loria.fr>
12*4882a593Smuzhiyun  * that was derived from USB Skeleton driver - 0.5
13*4882a593Smuzhiyun  * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  */
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include <linux/kernel.h>
20*4882a593Smuzhiyun #include <linux/sched/signal.h>
21*4882a593Smuzhiyun #include <linux/errno.h>
22*4882a593Smuzhiyun #include <linux/slab.h>
23*4882a593Smuzhiyun #include <linux/module.h>
24*4882a593Smuzhiyun #include <linux/usb.h>
25*4882a593Smuzhiyun #include <linux/mutex.h>
26*4882a593Smuzhiyun #include <linux/uaccess.h>
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #define DRIVER_AUTHOR "John Homppi"
29*4882a593Smuzhiyun #define DRIVER_DESC "adutux (see www.ontrak.net)"
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /* Define these values to match your device */
32*4882a593Smuzhiyun #define ADU_VENDOR_ID 0x0a07
33*4882a593Smuzhiyun #define ADU_PRODUCT_ID 0x0064
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun /* table of devices that work with this driver */
36*4882a593Smuzhiyun static const struct usb_device_id device_table[] = {
37*4882a593Smuzhiyun 	{ USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID) },		/* ADU100 */
38*4882a593Smuzhiyun 	{ USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+20) },	/* ADU120 */
39*4882a593Smuzhiyun 	{ USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+30) },	/* ADU130 */
40*4882a593Smuzhiyun 	{ USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+100) },	/* ADU200 */
41*4882a593Smuzhiyun 	{ USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+108) },	/* ADU208 */
42*4882a593Smuzhiyun 	{ USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+118) },	/* ADU218 */
43*4882a593Smuzhiyun 	{ } /* Terminating entry */
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, device_table);
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun #ifdef CONFIG_USB_DYNAMIC_MINORS
49*4882a593Smuzhiyun #define ADU_MINOR_BASE	0
50*4882a593Smuzhiyun #else
51*4882a593Smuzhiyun #define ADU_MINOR_BASE	67
52*4882a593Smuzhiyun #endif
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun /* we can have up to this number of device plugged in at once */
55*4882a593Smuzhiyun #define MAX_DEVICES	16
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun #define COMMAND_TIMEOUT	(2*HZ)
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun /*
60*4882a593Smuzhiyun  * The locking scheme is a vanilla 3-lock:
61*4882a593Smuzhiyun  *   adu_device.buflock: A spinlock, covers what IRQs touch.
62*4882a593Smuzhiyun  *   adutux_mutex:       A Static lock to cover open_count. It would also cover
63*4882a593Smuzhiyun  *                       any globals, but we don't have them in 2.6.
64*4882a593Smuzhiyun  *   adu_device.mtx:     A mutex to hold across sleepers like copy_from_user.
65*4882a593Smuzhiyun  *                       It covers all of adu_device, except the open_count
66*4882a593Smuzhiyun  *                       and what .buflock covers.
67*4882a593Smuzhiyun  */
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun /* Structure to hold all of our device specific stuff */
70*4882a593Smuzhiyun struct adu_device {
71*4882a593Smuzhiyun 	struct mutex		mtx;
72*4882a593Smuzhiyun 	struct usb_device *udev; /* save off the usb device pointer */
73*4882a593Smuzhiyun 	struct usb_interface *interface;
74*4882a593Smuzhiyun 	unsigned int		minor; /* the starting minor number for this device */
75*4882a593Smuzhiyun 	char			serial_number[8];
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	int			open_count; /* number of times this port has been opened */
78*4882a593Smuzhiyun 	unsigned long		disconnected:1;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	char		*read_buffer_primary;
81*4882a593Smuzhiyun 	int			read_buffer_length;
82*4882a593Smuzhiyun 	char		*read_buffer_secondary;
83*4882a593Smuzhiyun 	int			secondary_head;
84*4882a593Smuzhiyun 	int			secondary_tail;
85*4882a593Smuzhiyun 	spinlock_t		buflock;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	wait_queue_head_t	read_wait;
88*4882a593Smuzhiyun 	wait_queue_head_t	write_wait;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	char		*interrupt_in_buffer;
91*4882a593Smuzhiyun 	struct usb_endpoint_descriptor *interrupt_in_endpoint;
92*4882a593Smuzhiyun 	struct urb	*interrupt_in_urb;
93*4882a593Smuzhiyun 	int			read_urb_finished;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	char		*interrupt_out_buffer;
96*4882a593Smuzhiyun 	struct usb_endpoint_descriptor *interrupt_out_endpoint;
97*4882a593Smuzhiyun 	struct urb	*interrupt_out_urb;
98*4882a593Smuzhiyun 	int			out_urb_finished;
99*4882a593Smuzhiyun };
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun static DEFINE_MUTEX(adutux_mutex);
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun static struct usb_driver adu_driver;
104*4882a593Smuzhiyun 
adu_debug_data(struct device * dev,const char * function,int size,const unsigned char * data)105*4882a593Smuzhiyun static inline void adu_debug_data(struct device *dev, const char *function,
106*4882a593Smuzhiyun 				  int size, const unsigned char *data)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	dev_dbg(dev, "%s - length = %d, data = %*ph\n",
109*4882a593Smuzhiyun 		function, size, size, data);
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun /*
113*4882a593Smuzhiyun  * adu_abort_transfers
114*4882a593Smuzhiyun  *      aborts transfers and frees associated data structures
115*4882a593Smuzhiyun  */
adu_abort_transfers(struct adu_device * dev)116*4882a593Smuzhiyun static void adu_abort_transfers(struct adu_device *dev)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun 	unsigned long flags;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	if (dev->disconnected)
121*4882a593Smuzhiyun 		return;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	/* shutdown transfer */
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	/* XXX Anchor these instead */
126*4882a593Smuzhiyun 	spin_lock_irqsave(&dev->buflock, flags);
127*4882a593Smuzhiyun 	if (!dev->read_urb_finished) {
128*4882a593Smuzhiyun 		spin_unlock_irqrestore(&dev->buflock, flags);
129*4882a593Smuzhiyun 		usb_kill_urb(dev->interrupt_in_urb);
130*4882a593Smuzhiyun 	} else
131*4882a593Smuzhiyun 		spin_unlock_irqrestore(&dev->buflock, flags);
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	spin_lock_irqsave(&dev->buflock, flags);
134*4882a593Smuzhiyun 	if (!dev->out_urb_finished) {
135*4882a593Smuzhiyun 		spin_unlock_irqrestore(&dev->buflock, flags);
136*4882a593Smuzhiyun 		wait_event_timeout(dev->write_wait, dev->out_urb_finished,
137*4882a593Smuzhiyun 			COMMAND_TIMEOUT);
138*4882a593Smuzhiyun 		usb_kill_urb(dev->interrupt_out_urb);
139*4882a593Smuzhiyun 	} else
140*4882a593Smuzhiyun 		spin_unlock_irqrestore(&dev->buflock, flags);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun 
adu_delete(struct adu_device * dev)143*4882a593Smuzhiyun static void adu_delete(struct adu_device *dev)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun 	/* free data structures */
146*4882a593Smuzhiyun 	usb_free_urb(dev->interrupt_in_urb);
147*4882a593Smuzhiyun 	usb_free_urb(dev->interrupt_out_urb);
148*4882a593Smuzhiyun 	kfree(dev->read_buffer_primary);
149*4882a593Smuzhiyun 	kfree(dev->read_buffer_secondary);
150*4882a593Smuzhiyun 	kfree(dev->interrupt_in_buffer);
151*4882a593Smuzhiyun 	kfree(dev->interrupt_out_buffer);
152*4882a593Smuzhiyun 	usb_put_dev(dev->udev);
153*4882a593Smuzhiyun 	kfree(dev);
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
adu_interrupt_in_callback(struct urb * urb)156*4882a593Smuzhiyun static void adu_interrupt_in_callback(struct urb *urb)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	struct adu_device *dev = urb->context;
159*4882a593Smuzhiyun 	int status = urb->status;
160*4882a593Smuzhiyun 	unsigned long flags;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	adu_debug_data(&dev->udev->dev, __func__,
163*4882a593Smuzhiyun 		       urb->actual_length, urb->transfer_buffer);
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	spin_lock_irqsave(&dev->buflock, flags);
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	if (status != 0) {
168*4882a593Smuzhiyun 		if ((status != -ENOENT) && (status != -ECONNRESET) &&
169*4882a593Smuzhiyun 			(status != -ESHUTDOWN)) {
170*4882a593Smuzhiyun 			dev_dbg(&dev->udev->dev,
171*4882a593Smuzhiyun 				"%s : nonzero status received: %d\n",
172*4882a593Smuzhiyun 				__func__, status);
173*4882a593Smuzhiyun 		}
174*4882a593Smuzhiyun 		goto exit;
175*4882a593Smuzhiyun 	}
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	if (urb->actual_length > 0 && dev->interrupt_in_buffer[0] != 0x00) {
178*4882a593Smuzhiyun 		if (dev->read_buffer_length <
179*4882a593Smuzhiyun 		    (4 * usb_endpoint_maxp(dev->interrupt_in_endpoint)) -
180*4882a593Smuzhiyun 		     (urb->actual_length)) {
181*4882a593Smuzhiyun 			memcpy (dev->read_buffer_primary +
182*4882a593Smuzhiyun 				dev->read_buffer_length,
183*4882a593Smuzhiyun 				dev->interrupt_in_buffer, urb->actual_length);
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 			dev->read_buffer_length += urb->actual_length;
186*4882a593Smuzhiyun 			dev_dbg(&dev->udev->dev,"%s reading  %d\n", __func__,
187*4882a593Smuzhiyun 				urb->actual_length);
188*4882a593Smuzhiyun 		} else {
189*4882a593Smuzhiyun 			dev_dbg(&dev->udev->dev,"%s : read_buffer overflow\n",
190*4882a593Smuzhiyun 				__func__);
191*4882a593Smuzhiyun 		}
192*4882a593Smuzhiyun 	}
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun exit:
195*4882a593Smuzhiyun 	dev->read_urb_finished = 1;
196*4882a593Smuzhiyun 	spin_unlock_irqrestore(&dev->buflock, flags);
197*4882a593Smuzhiyun 	/* always wake up so we recover from errors */
198*4882a593Smuzhiyun 	wake_up_interruptible(&dev->read_wait);
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
adu_interrupt_out_callback(struct urb * urb)201*4882a593Smuzhiyun static void adu_interrupt_out_callback(struct urb *urb)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun 	struct adu_device *dev = urb->context;
204*4882a593Smuzhiyun 	int status = urb->status;
205*4882a593Smuzhiyun 	unsigned long flags;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	adu_debug_data(&dev->udev->dev, __func__,
208*4882a593Smuzhiyun 		       urb->actual_length, urb->transfer_buffer);
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	if (status != 0) {
211*4882a593Smuzhiyun 		if ((status != -ENOENT) &&
212*4882a593Smuzhiyun 		    (status != -ESHUTDOWN) &&
213*4882a593Smuzhiyun 		    (status != -ECONNRESET)) {
214*4882a593Smuzhiyun 			dev_dbg(&dev->udev->dev,
215*4882a593Smuzhiyun 				"%s :nonzero status received: %d\n", __func__,
216*4882a593Smuzhiyun 				status);
217*4882a593Smuzhiyun 		}
218*4882a593Smuzhiyun 		return;
219*4882a593Smuzhiyun 	}
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	spin_lock_irqsave(&dev->buflock, flags);
222*4882a593Smuzhiyun 	dev->out_urb_finished = 1;
223*4882a593Smuzhiyun 	wake_up(&dev->write_wait);
224*4882a593Smuzhiyun 	spin_unlock_irqrestore(&dev->buflock, flags);
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun 
adu_open(struct inode * inode,struct file * file)227*4882a593Smuzhiyun static int adu_open(struct inode *inode, struct file *file)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun 	struct adu_device *dev = NULL;
230*4882a593Smuzhiyun 	struct usb_interface *interface;
231*4882a593Smuzhiyun 	int subminor;
232*4882a593Smuzhiyun 	int retval;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	subminor = iminor(inode);
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	retval = mutex_lock_interruptible(&adutux_mutex);
237*4882a593Smuzhiyun 	if (retval)
238*4882a593Smuzhiyun 		goto exit_no_lock;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	interface = usb_find_interface(&adu_driver, subminor);
241*4882a593Smuzhiyun 	if (!interface) {
242*4882a593Smuzhiyun 		pr_err("%s - error, can't find device for minor %d\n",
243*4882a593Smuzhiyun 		       __func__, subminor);
244*4882a593Smuzhiyun 		retval = -ENODEV;
245*4882a593Smuzhiyun 		goto exit_no_device;
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	dev = usb_get_intfdata(interface);
249*4882a593Smuzhiyun 	if (!dev) {
250*4882a593Smuzhiyun 		retval = -ENODEV;
251*4882a593Smuzhiyun 		goto exit_no_device;
252*4882a593Smuzhiyun 	}
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	/* check that nobody else is using the device */
255*4882a593Smuzhiyun 	if (dev->open_count) {
256*4882a593Smuzhiyun 		retval = -EBUSY;
257*4882a593Smuzhiyun 		goto exit_no_device;
258*4882a593Smuzhiyun 	}
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	++dev->open_count;
261*4882a593Smuzhiyun 	dev_dbg(&dev->udev->dev, "%s: open count %d\n", __func__,
262*4882a593Smuzhiyun 		dev->open_count);
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	/* save device in the file's private structure */
265*4882a593Smuzhiyun 	file->private_data = dev;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	/* initialize in direction */
268*4882a593Smuzhiyun 	dev->read_buffer_length = 0;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	/* fixup first read by having urb waiting for it */
271*4882a593Smuzhiyun 	usb_fill_int_urb(dev->interrupt_in_urb, dev->udev,
272*4882a593Smuzhiyun 			 usb_rcvintpipe(dev->udev,
273*4882a593Smuzhiyun 					dev->interrupt_in_endpoint->bEndpointAddress),
274*4882a593Smuzhiyun 			 dev->interrupt_in_buffer,
275*4882a593Smuzhiyun 			 usb_endpoint_maxp(dev->interrupt_in_endpoint),
276*4882a593Smuzhiyun 			 adu_interrupt_in_callback, dev,
277*4882a593Smuzhiyun 			 dev->interrupt_in_endpoint->bInterval);
278*4882a593Smuzhiyun 	dev->read_urb_finished = 0;
279*4882a593Smuzhiyun 	if (usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL))
280*4882a593Smuzhiyun 		dev->read_urb_finished = 1;
281*4882a593Smuzhiyun 	/* we ignore failure */
282*4882a593Smuzhiyun 	/* end of fixup for first read */
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	/* initialize out direction */
285*4882a593Smuzhiyun 	dev->out_urb_finished = 1;
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	retval = 0;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun exit_no_device:
290*4882a593Smuzhiyun 	mutex_unlock(&adutux_mutex);
291*4882a593Smuzhiyun exit_no_lock:
292*4882a593Smuzhiyun 	return retval;
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun 
adu_release_internal(struct adu_device * dev)295*4882a593Smuzhiyun static void adu_release_internal(struct adu_device *dev)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun 	/* decrement our usage count for the device */
298*4882a593Smuzhiyun 	--dev->open_count;
299*4882a593Smuzhiyun 	dev_dbg(&dev->udev->dev, "%s : open count %d\n", __func__,
300*4882a593Smuzhiyun 		dev->open_count);
301*4882a593Smuzhiyun 	if (dev->open_count <= 0) {
302*4882a593Smuzhiyun 		adu_abort_transfers(dev);
303*4882a593Smuzhiyun 		dev->open_count = 0;
304*4882a593Smuzhiyun 	}
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun 
adu_release(struct inode * inode,struct file * file)307*4882a593Smuzhiyun static int adu_release(struct inode *inode, struct file *file)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun 	struct adu_device *dev;
310*4882a593Smuzhiyun 	int retval = 0;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	if (file == NULL) {
313*4882a593Smuzhiyun 		retval = -ENODEV;
314*4882a593Smuzhiyun 		goto exit;
315*4882a593Smuzhiyun 	}
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	dev = file->private_data;
318*4882a593Smuzhiyun 	if (dev == NULL) {
319*4882a593Smuzhiyun 		retval = -ENODEV;
320*4882a593Smuzhiyun 		goto exit;
321*4882a593Smuzhiyun 	}
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	mutex_lock(&adutux_mutex); /* not interruptible */
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	if (dev->open_count <= 0) {
326*4882a593Smuzhiyun 		dev_dbg(&dev->udev->dev, "%s : device not opened\n", __func__);
327*4882a593Smuzhiyun 		retval = -ENODEV;
328*4882a593Smuzhiyun 		goto unlock;
329*4882a593Smuzhiyun 	}
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	adu_release_internal(dev);
332*4882a593Smuzhiyun 	if (dev->disconnected) {
333*4882a593Smuzhiyun 		/* the device was unplugged before the file was released */
334*4882a593Smuzhiyun 		if (!dev->open_count)	/* ... and we're the last user */
335*4882a593Smuzhiyun 			adu_delete(dev);
336*4882a593Smuzhiyun 	}
337*4882a593Smuzhiyun unlock:
338*4882a593Smuzhiyun 	mutex_unlock(&adutux_mutex);
339*4882a593Smuzhiyun exit:
340*4882a593Smuzhiyun 	return retval;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun 
adu_read(struct file * file,__user char * buffer,size_t count,loff_t * ppos)343*4882a593Smuzhiyun static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
344*4882a593Smuzhiyun 			loff_t *ppos)
345*4882a593Smuzhiyun {
346*4882a593Smuzhiyun 	struct adu_device *dev;
347*4882a593Smuzhiyun 	size_t bytes_read = 0;
348*4882a593Smuzhiyun 	size_t bytes_to_read = count;
349*4882a593Smuzhiyun 	int retval = 0;
350*4882a593Smuzhiyun 	int timeout = 0;
351*4882a593Smuzhiyun 	int should_submit = 0;
352*4882a593Smuzhiyun 	unsigned long flags;
353*4882a593Smuzhiyun 	DECLARE_WAITQUEUE(wait, current);
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	dev = file->private_data;
356*4882a593Smuzhiyun 	if (mutex_lock_interruptible(&dev->mtx))
357*4882a593Smuzhiyun 		return -ERESTARTSYS;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	/* verify that the device wasn't unplugged */
360*4882a593Smuzhiyun 	if (dev->disconnected) {
361*4882a593Smuzhiyun 		retval = -ENODEV;
362*4882a593Smuzhiyun 		pr_err("No device or device unplugged %d\n", retval);
363*4882a593Smuzhiyun 		goto exit;
364*4882a593Smuzhiyun 	}
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	/* verify that some data was requested */
367*4882a593Smuzhiyun 	if (count == 0) {
368*4882a593Smuzhiyun 		dev_dbg(&dev->udev->dev, "%s : read request of 0 bytes\n",
369*4882a593Smuzhiyun 			__func__);
370*4882a593Smuzhiyun 		goto exit;
371*4882a593Smuzhiyun 	}
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	timeout = COMMAND_TIMEOUT;
374*4882a593Smuzhiyun 	dev_dbg(&dev->udev->dev, "%s : about to start looping\n", __func__);
375*4882a593Smuzhiyun 	while (bytes_to_read) {
376*4882a593Smuzhiyun 		size_t data_in_secondary = dev->secondary_tail - dev->secondary_head;
377*4882a593Smuzhiyun 		dev_dbg(&dev->udev->dev,
378*4882a593Smuzhiyun 			"%s : while, data_in_secondary=%zu, status=%d\n",
379*4882a593Smuzhiyun 			__func__, data_in_secondary,
380*4882a593Smuzhiyun 			dev->interrupt_in_urb->status);
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 		if (data_in_secondary) {
383*4882a593Smuzhiyun 			/* drain secondary buffer */
384*4882a593Smuzhiyun 			size_t amount = min(bytes_to_read, data_in_secondary);
385*4882a593Smuzhiyun 			if (copy_to_user(buffer, dev->read_buffer_secondary+dev->secondary_head, amount)) {
386*4882a593Smuzhiyun 				retval = -EFAULT;
387*4882a593Smuzhiyun 				goto exit;
388*4882a593Smuzhiyun 			}
389*4882a593Smuzhiyun 			dev->secondary_head += amount;
390*4882a593Smuzhiyun 			bytes_read += amount;
391*4882a593Smuzhiyun 			bytes_to_read -= amount;
392*4882a593Smuzhiyun 		} else {
393*4882a593Smuzhiyun 			/* we check the primary buffer */
394*4882a593Smuzhiyun 			spin_lock_irqsave (&dev->buflock, flags);
395*4882a593Smuzhiyun 			if (dev->read_buffer_length) {
396*4882a593Smuzhiyun 				/* we secure access to the primary */
397*4882a593Smuzhiyun 				char *tmp;
398*4882a593Smuzhiyun 				dev_dbg(&dev->udev->dev,
399*4882a593Smuzhiyun 					"%s : swap, read_buffer_length = %d\n",
400*4882a593Smuzhiyun 					__func__, dev->read_buffer_length);
401*4882a593Smuzhiyun 				tmp = dev->read_buffer_secondary;
402*4882a593Smuzhiyun 				dev->read_buffer_secondary = dev->read_buffer_primary;
403*4882a593Smuzhiyun 				dev->read_buffer_primary = tmp;
404*4882a593Smuzhiyun 				dev->secondary_head = 0;
405*4882a593Smuzhiyun 				dev->secondary_tail = dev->read_buffer_length;
406*4882a593Smuzhiyun 				dev->read_buffer_length = 0;
407*4882a593Smuzhiyun 				spin_unlock_irqrestore(&dev->buflock, flags);
408*4882a593Smuzhiyun 				/* we have a free buffer so use it */
409*4882a593Smuzhiyun 				should_submit = 1;
410*4882a593Smuzhiyun 			} else {
411*4882a593Smuzhiyun 				/* even the primary was empty - we may need to do IO */
412*4882a593Smuzhiyun 				if (!dev->read_urb_finished) {
413*4882a593Smuzhiyun 					/* somebody is doing IO */
414*4882a593Smuzhiyun 					spin_unlock_irqrestore(&dev->buflock, flags);
415*4882a593Smuzhiyun 					dev_dbg(&dev->udev->dev,
416*4882a593Smuzhiyun 						"%s : submitted already\n",
417*4882a593Smuzhiyun 						__func__);
418*4882a593Smuzhiyun 				} else {
419*4882a593Smuzhiyun 					/* we must initiate input */
420*4882a593Smuzhiyun 					dev_dbg(&dev->udev->dev,
421*4882a593Smuzhiyun 						"%s : initiate input\n",
422*4882a593Smuzhiyun 						__func__);
423*4882a593Smuzhiyun 					dev->read_urb_finished = 0;
424*4882a593Smuzhiyun 					spin_unlock_irqrestore(&dev->buflock, flags);
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 					usb_fill_int_urb(dev->interrupt_in_urb, dev->udev,
427*4882a593Smuzhiyun 							usb_rcvintpipe(dev->udev,
428*4882a593Smuzhiyun 								dev->interrupt_in_endpoint->bEndpointAddress),
429*4882a593Smuzhiyun 							 dev->interrupt_in_buffer,
430*4882a593Smuzhiyun 							 usb_endpoint_maxp(dev->interrupt_in_endpoint),
431*4882a593Smuzhiyun 							 adu_interrupt_in_callback,
432*4882a593Smuzhiyun 							 dev,
433*4882a593Smuzhiyun 							 dev->interrupt_in_endpoint->bInterval);
434*4882a593Smuzhiyun 					retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
435*4882a593Smuzhiyun 					if (retval) {
436*4882a593Smuzhiyun 						dev->read_urb_finished = 1;
437*4882a593Smuzhiyun 						if (retval == -ENOMEM) {
438*4882a593Smuzhiyun 							retval = bytes_read ? bytes_read : -ENOMEM;
439*4882a593Smuzhiyun 						}
440*4882a593Smuzhiyun 						dev_dbg(&dev->udev->dev,
441*4882a593Smuzhiyun 							"%s : submit failed\n",
442*4882a593Smuzhiyun 							__func__);
443*4882a593Smuzhiyun 						goto exit;
444*4882a593Smuzhiyun 					}
445*4882a593Smuzhiyun 				}
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 				/* we wait for I/O to complete */
448*4882a593Smuzhiyun 				set_current_state(TASK_INTERRUPTIBLE);
449*4882a593Smuzhiyun 				add_wait_queue(&dev->read_wait, &wait);
450*4882a593Smuzhiyun 				spin_lock_irqsave(&dev->buflock, flags);
451*4882a593Smuzhiyun 				if (!dev->read_urb_finished) {
452*4882a593Smuzhiyun 					spin_unlock_irqrestore(&dev->buflock, flags);
453*4882a593Smuzhiyun 					timeout = schedule_timeout(COMMAND_TIMEOUT);
454*4882a593Smuzhiyun 				} else {
455*4882a593Smuzhiyun 					spin_unlock_irqrestore(&dev->buflock, flags);
456*4882a593Smuzhiyun 					set_current_state(TASK_RUNNING);
457*4882a593Smuzhiyun 				}
458*4882a593Smuzhiyun 				remove_wait_queue(&dev->read_wait, &wait);
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 				if (timeout <= 0) {
461*4882a593Smuzhiyun 					dev_dbg(&dev->udev->dev,
462*4882a593Smuzhiyun 						"%s : timeout\n", __func__);
463*4882a593Smuzhiyun 					retval = bytes_read ? bytes_read : -ETIMEDOUT;
464*4882a593Smuzhiyun 					goto exit;
465*4882a593Smuzhiyun 				}
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 				if (signal_pending(current)) {
468*4882a593Smuzhiyun 					dev_dbg(&dev->udev->dev,
469*4882a593Smuzhiyun 						"%s : signal pending\n",
470*4882a593Smuzhiyun 						__func__);
471*4882a593Smuzhiyun 					retval = bytes_read ? bytes_read : -EINTR;
472*4882a593Smuzhiyun 					goto exit;
473*4882a593Smuzhiyun 				}
474*4882a593Smuzhiyun 			}
475*4882a593Smuzhiyun 		}
476*4882a593Smuzhiyun 	}
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	retval = bytes_read;
479*4882a593Smuzhiyun 	/* if the primary buffer is empty then use it */
480*4882a593Smuzhiyun 	spin_lock_irqsave(&dev->buflock, flags);
481*4882a593Smuzhiyun 	if (should_submit && dev->read_urb_finished) {
482*4882a593Smuzhiyun 		dev->read_urb_finished = 0;
483*4882a593Smuzhiyun 		spin_unlock_irqrestore(&dev->buflock, flags);
484*4882a593Smuzhiyun 		usb_fill_int_urb(dev->interrupt_in_urb, dev->udev,
485*4882a593Smuzhiyun 				 usb_rcvintpipe(dev->udev,
486*4882a593Smuzhiyun 					dev->interrupt_in_endpoint->bEndpointAddress),
487*4882a593Smuzhiyun 				dev->interrupt_in_buffer,
488*4882a593Smuzhiyun 				usb_endpoint_maxp(dev->interrupt_in_endpoint),
489*4882a593Smuzhiyun 				adu_interrupt_in_callback,
490*4882a593Smuzhiyun 				dev,
491*4882a593Smuzhiyun 				dev->interrupt_in_endpoint->bInterval);
492*4882a593Smuzhiyun 		if (usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL) != 0)
493*4882a593Smuzhiyun 			dev->read_urb_finished = 1;
494*4882a593Smuzhiyun 		/* we ignore failure */
495*4882a593Smuzhiyun 	} else {
496*4882a593Smuzhiyun 		spin_unlock_irqrestore(&dev->buflock, flags);
497*4882a593Smuzhiyun 	}
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun exit:
500*4882a593Smuzhiyun 	/* unlock the device */
501*4882a593Smuzhiyun 	mutex_unlock(&dev->mtx);
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	return retval;
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun 
adu_write(struct file * file,const __user char * buffer,size_t count,loff_t * ppos)506*4882a593Smuzhiyun static ssize_t adu_write(struct file *file, const __user char *buffer,
507*4882a593Smuzhiyun 			 size_t count, loff_t *ppos)
508*4882a593Smuzhiyun {
509*4882a593Smuzhiyun 	DECLARE_WAITQUEUE(waita, current);
510*4882a593Smuzhiyun 	struct adu_device *dev;
511*4882a593Smuzhiyun 	size_t bytes_written = 0;
512*4882a593Smuzhiyun 	size_t bytes_to_write;
513*4882a593Smuzhiyun 	size_t buffer_size;
514*4882a593Smuzhiyun 	unsigned long flags;
515*4882a593Smuzhiyun 	int retval;
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	dev = file->private_data;
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	retval = mutex_lock_interruptible(&dev->mtx);
520*4882a593Smuzhiyun 	if (retval)
521*4882a593Smuzhiyun 		goto exit_nolock;
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	/* verify that the device wasn't unplugged */
524*4882a593Smuzhiyun 	if (dev->disconnected) {
525*4882a593Smuzhiyun 		retval = -ENODEV;
526*4882a593Smuzhiyun 		pr_err("No device or device unplugged %d\n", retval);
527*4882a593Smuzhiyun 		goto exit;
528*4882a593Smuzhiyun 	}
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	/* verify that we actually have some data to write */
531*4882a593Smuzhiyun 	if (count == 0) {
532*4882a593Smuzhiyun 		dev_dbg(&dev->udev->dev, "%s : write request of 0 bytes\n",
533*4882a593Smuzhiyun 			__func__);
534*4882a593Smuzhiyun 		goto exit;
535*4882a593Smuzhiyun 	}
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	while (count > 0) {
538*4882a593Smuzhiyun 		add_wait_queue(&dev->write_wait, &waita);
539*4882a593Smuzhiyun 		set_current_state(TASK_INTERRUPTIBLE);
540*4882a593Smuzhiyun 		spin_lock_irqsave(&dev->buflock, flags);
541*4882a593Smuzhiyun 		if (!dev->out_urb_finished) {
542*4882a593Smuzhiyun 			spin_unlock_irqrestore(&dev->buflock, flags);
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 			mutex_unlock(&dev->mtx);
545*4882a593Smuzhiyun 			if (signal_pending(current)) {
546*4882a593Smuzhiyun 				dev_dbg(&dev->udev->dev, "%s : interrupted\n",
547*4882a593Smuzhiyun 					__func__);
548*4882a593Smuzhiyun 				set_current_state(TASK_RUNNING);
549*4882a593Smuzhiyun 				retval = -EINTR;
550*4882a593Smuzhiyun 				goto exit_onqueue;
551*4882a593Smuzhiyun 			}
552*4882a593Smuzhiyun 			if (schedule_timeout(COMMAND_TIMEOUT) == 0) {
553*4882a593Smuzhiyun 				dev_dbg(&dev->udev->dev,
554*4882a593Smuzhiyun 					"%s - command timed out.\n", __func__);
555*4882a593Smuzhiyun 				retval = -ETIMEDOUT;
556*4882a593Smuzhiyun 				goto exit_onqueue;
557*4882a593Smuzhiyun 			}
558*4882a593Smuzhiyun 			remove_wait_queue(&dev->write_wait, &waita);
559*4882a593Smuzhiyun 			retval = mutex_lock_interruptible(&dev->mtx);
560*4882a593Smuzhiyun 			if (retval) {
561*4882a593Smuzhiyun 				retval = bytes_written ? bytes_written : retval;
562*4882a593Smuzhiyun 				goto exit_nolock;
563*4882a593Smuzhiyun 			}
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 			dev_dbg(&dev->udev->dev,
566*4882a593Smuzhiyun 				"%s : in progress, count = %zd\n",
567*4882a593Smuzhiyun 				__func__, count);
568*4882a593Smuzhiyun 		} else {
569*4882a593Smuzhiyun 			spin_unlock_irqrestore(&dev->buflock, flags);
570*4882a593Smuzhiyun 			set_current_state(TASK_RUNNING);
571*4882a593Smuzhiyun 			remove_wait_queue(&dev->write_wait, &waita);
572*4882a593Smuzhiyun 			dev_dbg(&dev->udev->dev, "%s : sending, count = %zd\n",
573*4882a593Smuzhiyun 				__func__, count);
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 			/* write the data into interrupt_out_buffer from userspace */
576*4882a593Smuzhiyun 			buffer_size = usb_endpoint_maxp(dev->interrupt_out_endpoint);
577*4882a593Smuzhiyun 			bytes_to_write = count > buffer_size ? buffer_size : count;
578*4882a593Smuzhiyun 			dev_dbg(&dev->udev->dev,
579*4882a593Smuzhiyun 				"%s : buffer_size = %zd, count = %zd, bytes_to_write = %zd\n",
580*4882a593Smuzhiyun 				__func__, buffer_size, count, bytes_to_write);
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 			if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write) != 0) {
583*4882a593Smuzhiyun 				retval = -EFAULT;
584*4882a593Smuzhiyun 				goto exit;
585*4882a593Smuzhiyun 			}
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 			/* send off the urb */
588*4882a593Smuzhiyun 			usb_fill_int_urb(
589*4882a593Smuzhiyun 				dev->interrupt_out_urb,
590*4882a593Smuzhiyun 				dev->udev,
591*4882a593Smuzhiyun 				usb_sndintpipe(dev->udev, dev->interrupt_out_endpoint->bEndpointAddress),
592*4882a593Smuzhiyun 				dev->interrupt_out_buffer,
593*4882a593Smuzhiyun 				bytes_to_write,
594*4882a593Smuzhiyun 				adu_interrupt_out_callback,
595*4882a593Smuzhiyun 				dev,
596*4882a593Smuzhiyun 				dev->interrupt_out_endpoint->bInterval);
597*4882a593Smuzhiyun 			dev->interrupt_out_urb->actual_length = bytes_to_write;
598*4882a593Smuzhiyun 			dev->out_urb_finished = 0;
599*4882a593Smuzhiyun 			retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
600*4882a593Smuzhiyun 			if (retval < 0) {
601*4882a593Smuzhiyun 				dev->out_urb_finished = 1;
602*4882a593Smuzhiyun 				dev_err(&dev->udev->dev, "Couldn't submit "
603*4882a593Smuzhiyun 					"interrupt_out_urb %d\n", retval);
604*4882a593Smuzhiyun 				goto exit;
605*4882a593Smuzhiyun 			}
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 			buffer += bytes_to_write;
608*4882a593Smuzhiyun 			count -= bytes_to_write;
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 			bytes_written += bytes_to_write;
611*4882a593Smuzhiyun 		}
612*4882a593Smuzhiyun 	}
613*4882a593Smuzhiyun 	mutex_unlock(&dev->mtx);
614*4882a593Smuzhiyun 	return bytes_written;
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun exit:
617*4882a593Smuzhiyun 	mutex_unlock(&dev->mtx);
618*4882a593Smuzhiyun exit_nolock:
619*4882a593Smuzhiyun 	return retval;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun exit_onqueue:
622*4882a593Smuzhiyun 	remove_wait_queue(&dev->write_wait, &waita);
623*4882a593Smuzhiyun 	return retval;
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun /* file operations needed when we register this driver */
627*4882a593Smuzhiyun static const struct file_operations adu_fops = {
628*4882a593Smuzhiyun 	.owner = THIS_MODULE,
629*4882a593Smuzhiyun 	.read  = adu_read,
630*4882a593Smuzhiyun 	.write = adu_write,
631*4882a593Smuzhiyun 	.open = adu_open,
632*4882a593Smuzhiyun 	.release = adu_release,
633*4882a593Smuzhiyun 	.llseek = noop_llseek,
634*4882a593Smuzhiyun };
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun /*
637*4882a593Smuzhiyun  * usb class driver info in order to get a minor number from the usb core,
638*4882a593Smuzhiyun  * and to have the device registered with devfs and the driver core
639*4882a593Smuzhiyun  */
640*4882a593Smuzhiyun static struct usb_class_driver adu_class = {
641*4882a593Smuzhiyun 	.name = "usb/adutux%d",
642*4882a593Smuzhiyun 	.fops = &adu_fops,
643*4882a593Smuzhiyun 	.minor_base = ADU_MINOR_BASE,
644*4882a593Smuzhiyun };
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun /*
647*4882a593Smuzhiyun  * adu_probe
648*4882a593Smuzhiyun  *
649*4882a593Smuzhiyun  * Called by the usb core when a new device is connected that it thinks
650*4882a593Smuzhiyun  * this driver might be interested in.
651*4882a593Smuzhiyun  */
adu_probe(struct usb_interface * interface,const struct usb_device_id * id)652*4882a593Smuzhiyun static int adu_probe(struct usb_interface *interface,
653*4882a593Smuzhiyun 		     const struct usb_device_id *id)
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun 	struct usb_device *udev = interface_to_usbdev(interface);
656*4882a593Smuzhiyun 	struct adu_device *dev = NULL;
657*4882a593Smuzhiyun 	int retval = -ENOMEM;
658*4882a593Smuzhiyun 	int in_end_size;
659*4882a593Smuzhiyun 	int out_end_size;
660*4882a593Smuzhiyun 	int res;
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	/* allocate memory for our device state and initialize it */
663*4882a593Smuzhiyun 	dev = kzalloc(sizeof(struct adu_device), GFP_KERNEL);
664*4882a593Smuzhiyun 	if (!dev)
665*4882a593Smuzhiyun 		return -ENOMEM;
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	mutex_init(&dev->mtx);
668*4882a593Smuzhiyun 	spin_lock_init(&dev->buflock);
669*4882a593Smuzhiyun 	dev->udev = usb_get_dev(udev);
670*4882a593Smuzhiyun 	init_waitqueue_head(&dev->read_wait);
671*4882a593Smuzhiyun 	init_waitqueue_head(&dev->write_wait);
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun 	res = usb_find_common_endpoints_reverse(interface->cur_altsetting,
674*4882a593Smuzhiyun 			NULL, NULL,
675*4882a593Smuzhiyun 			&dev->interrupt_in_endpoint,
676*4882a593Smuzhiyun 			&dev->interrupt_out_endpoint);
677*4882a593Smuzhiyun 	if (res) {
678*4882a593Smuzhiyun 		dev_err(&interface->dev, "interrupt endpoints not found\n");
679*4882a593Smuzhiyun 		retval = res;
680*4882a593Smuzhiyun 		goto error;
681*4882a593Smuzhiyun 	}
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	in_end_size = usb_endpoint_maxp(dev->interrupt_in_endpoint);
684*4882a593Smuzhiyun 	out_end_size = usb_endpoint_maxp(dev->interrupt_out_endpoint);
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	dev->read_buffer_primary = kmalloc((4 * in_end_size), GFP_KERNEL);
687*4882a593Smuzhiyun 	if (!dev->read_buffer_primary)
688*4882a593Smuzhiyun 		goto error;
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun 	/* debug code prime the buffer */
691*4882a593Smuzhiyun 	memset(dev->read_buffer_primary, 'a', in_end_size);
692*4882a593Smuzhiyun 	memset(dev->read_buffer_primary + in_end_size, 'b', in_end_size);
693*4882a593Smuzhiyun 	memset(dev->read_buffer_primary + (2 * in_end_size), 'c', in_end_size);
694*4882a593Smuzhiyun 	memset(dev->read_buffer_primary + (3 * in_end_size), 'd', in_end_size);
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	dev->read_buffer_secondary = kmalloc((4 * in_end_size), GFP_KERNEL);
697*4882a593Smuzhiyun 	if (!dev->read_buffer_secondary)
698*4882a593Smuzhiyun 		goto error;
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 	/* debug code prime the buffer */
701*4882a593Smuzhiyun 	memset(dev->read_buffer_secondary, 'e', in_end_size);
702*4882a593Smuzhiyun 	memset(dev->read_buffer_secondary + in_end_size, 'f', in_end_size);
703*4882a593Smuzhiyun 	memset(dev->read_buffer_secondary + (2 * in_end_size), 'g', in_end_size);
704*4882a593Smuzhiyun 	memset(dev->read_buffer_secondary + (3 * in_end_size), 'h', in_end_size);
705*4882a593Smuzhiyun 
706*4882a593Smuzhiyun 	dev->interrupt_in_buffer = kmalloc(in_end_size, GFP_KERNEL);
707*4882a593Smuzhiyun 	if (!dev->interrupt_in_buffer)
708*4882a593Smuzhiyun 		goto error;
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	/* debug code prime the buffer */
711*4882a593Smuzhiyun 	memset(dev->interrupt_in_buffer, 'i', in_end_size);
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 	dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
714*4882a593Smuzhiyun 	if (!dev->interrupt_in_urb)
715*4882a593Smuzhiyun 		goto error;
716*4882a593Smuzhiyun 	dev->interrupt_out_buffer = kmalloc(out_end_size, GFP_KERNEL);
717*4882a593Smuzhiyun 	if (!dev->interrupt_out_buffer)
718*4882a593Smuzhiyun 		goto error;
719*4882a593Smuzhiyun 	dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
720*4882a593Smuzhiyun 	if (!dev->interrupt_out_urb)
721*4882a593Smuzhiyun 		goto error;
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	if (!usb_string(udev, udev->descriptor.iSerialNumber, dev->serial_number,
724*4882a593Smuzhiyun 			sizeof(dev->serial_number))) {
725*4882a593Smuzhiyun 		dev_err(&interface->dev, "Could not retrieve serial number\n");
726*4882a593Smuzhiyun 		retval = -EIO;
727*4882a593Smuzhiyun 		goto error;
728*4882a593Smuzhiyun 	}
729*4882a593Smuzhiyun 	dev_dbg(&interface->dev,"serial_number=%s", dev->serial_number);
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	/* we can register the device now, as it is ready */
732*4882a593Smuzhiyun 	usb_set_intfdata(interface, dev);
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	retval = usb_register_dev(interface, &adu_class);
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 	if (retval) {
737*4882a593Smuzhiyun 		/* something prevented us from registering this driver */
738*4882a593Smuzhiyun 		dev_err(&interface->dev, "Not able to get a minor for this device.\n");
739*4882a593Smuzhiyun 		usb_set_intfdata(interface, NULL);
740*4882a593Smuzhiyun 		goto error;
741*4882a593Smuzhiyun 	}
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	dev->minor = interface->minor;
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun 	/* let the user know what node this device is now attached to */
746*4882a593Smuzhiyun 	dev_info(&interface->dev, "ADU%d %s now attached to /dev/usb/adutux%d\n",
747*4882a593Smuzhiyun 		 le16_to_cpu(udev->descriptor.idProduct), dev->serial_number,
748*4882a593Smuzhiyun 		 (dev->minor - ADU_MINOR_BASE));
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun 	return 0;
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun error:
753*4882a593Smuzhiyun 	adu_delete(dev);
754*4882a593Smuzhiyun 	return retval;
755*4882a593Smuzhiyun }
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun /*
758*4882a593Smuzhiyun  * adu_disconnect
759*4882a593Smuzhiyun  *
760*4882a593Smuzhiyun  * Called by the usb core when the device is removed from the system.
761*4882a593Smuzhiyun  */
adu_disconnect(struct usb_interface * interface)762*4882a593Smuzhiyun static void adu_disconnect(struct usb_interface *interface)
763*4882a593Smuzhiyun {
764*4882a593Smuzhiyun 	struct adu_device *dev;
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 	dev = usb_get_intfdata(interface);
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun 	usb_deregister_dev(interface, &adu_class);
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 	usb_poison_urb(dev->interrupt_in_urb);
771*4882a593Smuzhiyun 	usb_poison_urb(dev->interrupt_out_urb);
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	mutex_lock(&adutux_mutex);
774*4882a593Smuzhiyun 	usb_set_intfdata(interface, NULL);
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 	mutex_lock(&dev->mtx);	/* not interruptible */
777*4882a593Smuzhiyun 	dev->disconnected = 1;
778*4882a593Smuzhiyun 	mutex_unlock(&dev->mtx);
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	/* if the device is not opened, then we clean up right now */
781*4882a593Smuzhiyun 	if (!dev->open_count)
782*4882a593Smuzhiyun 		adu_delete(dev);
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 	mutex_unlock(&adutux_mutex);
785*4882a593Smuzhiyun }
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun /* usb specific object needed to register this driver with the usb subsystem */
788*4882a593Smuzhiyun static struct usb_driver adu_driver = {
789*4882a593Smuzhiyun 	.name = "adutux",
790*4882a593Smuzhiyun 	.probe = adu_probe,
791*4882a593Smuzhiyun 	.disconnect = adu_disconnect,
792*4882a593Smuzhiyun 	.id_table = device_table,
793*4882a593Smuzhiyun };
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun module_usb_driver(adu_driver);
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun MODULE_AUTHOR(DRIVER_AUTHOR);
798*4882a593Smuzhiyun MODULE_DESCRIPTION(DRIVER_DESC);
799*4882a593Smuzhiyun MODULE_LICENSE("GPL");
800