File: /usr/src/linux/drivers/usb/serial/omninet.c

1     /*
2      * USB ZyXEL omni.net LCD PLUS driver
3      *
4      *	This program is free software; you can redistribute it and/or modify
5      *	it under the terms of the GNU General Public License as published by
6      *	the Free Software Foundation; either version 2 of the License, or
7      *	(at your option) any later version.
8      *
9      * See Documentation/usb/usb-serial.txt for more information on using this driver
10      *
11      * Please report both successes and troubles to the author at omninet@kroah.com
12      * 
13      * (05/30/2001) gkh
14      *	switched from using spinlock to a semaphore, which fixes lots of problems.
15      *
16      * (04/08/2001) gb
17      *	Identify version on module load.
18      *
19      * (11/01/2000) Adam J. Richter
20      *	usb_device_id table support
21      * 
22      * (10/05/2000) gkh
23      *	Fixed bug with urb->dev not being set properly, now that the usb
24      *	core needs it.
25      * 
26      * (08/28/2000) gkh
27      *	Added locks for SMP safeness.
28      *	Fixed MOD_INC and MOD_DEC logic and the ability to open a port more 
29      *	than once.
30      *	Fixed potential race in omninet_write_bulk_callback
31      *
32      * (07/19/2000) gkh
33      *	Added module_init and module_exit functions to handle the fact that this
34      *	driver is a loadable module now.
35      *
36      */
37     
38     #include <linux/config.h>
39     #include <linux/kernel.h>
40     #include <linux/sched.h>
41     #include <linux/signal.h>
42     #include <linux/errno.h>
43     #include <linux/poll.h>
44     #include <linux/init.h>
45     #include <linux/slab.h>
46     #include <linux/fcntl.h>
47     #include <linux/tty.h>
48     #include <linux/tty_driver.h>
49     #include <linux/tty_flip.h>
50     #include <linux/module.h>
51     #include <linux/spinlock.h>
52     #include <linux/usb.h>
53     
54     #ifdef CONFIG_USB_SERIAL_DEBUG
55     	static int debug = 1;
56     #else
57     	static int debug;
58     #endif
59     
60     #include "usb-serial.h"
61     
62     
63     /*
64      * Version Information
65      */
66     #define DRIVER_VERSION "v1.1"
67     #define DRIVER_AUTHOR "Anonymous"
68     #define DRIVER_DESC "USB ZyXEL omni.net LCD PLUS Driver"
69     
70     #define ZYXEL_VENDOR_ID		0x0586
71     #define ZYXEL_OMNINET_ID	0x1000
72     
73     /* function prototypes */
74     static int  omninet_open		(struct usb_serial_port *port, struct file *filp);
75     static void omninet_close		(struct usb_serial_port *port, struct file *filp);
76     static void omninet_read_bulk_callback	(struct urb *urb);
77     static void omninet_write_bulk_callback	(struct urb *urb);
78     static int  omninet_write		(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
79     static int  omninet_write_room		(struct usb_serial_port *port);
80     static void omninet_shutdown		(struct usb_serial *serial);
81     
82     static __devinitdata struct usb_device_id id_table [] = {
83     	{ USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) },
84     	{ }						/* Terminating entry */
85     };
86     
87     MODULE_DEVICE_TABLE (usb, id_table);
88     
89     
90     struct usb_serial_device_type zyxel_omninet_device = {
91     	name:			"ZyXEL - omni.net lcd plus usb",
92     	id_table:		id_table,
93     	needs_interrupt_in:	MUST_HAVE,
94     	needs_bulk_in:		MUST_HAVE,
95     	needs_bulk_out:		MUST_HAVE,
96     	num_interrupt_in:	1,
97     	num_bulk_in:		1,
98     	num_bulk_out:		2,
99     	num_ports:		1,
100     	open:			omninet_open,
101     	close:			omninet_close,
102     	write:			omninet_write,
103     	write_room:		omninet_write_room,
104     	read_bulk_callback:	omninet_read_bulk_callback,
105     	write_bulk_callback:	omninet_write_bulk_callback,
106     	shutdown:		omninet_shutdown,
107     };
108     
109     
110     /* The protocol.
111      *
112      * The omni.net always exchange 64 bytes of data with the host. The first
113      * four bytes are the control header, you can see it in the above structure.
114      *
115      * oh_seq is a sequence number. Don't know if/how it's used.
116      * oh_len is the length of the data bytes in the packet.
117      * oh_xxx Bit-mapped, related to handshaking and status info.
118      *	I normally set it to 0x03 in trasmitted frames.
119      *	7: Active when the TA is in a CONNECTed state.
120      *	6: unknown
121      *	5: handshaking, unknown
122      *	4: handshaking, unknown
123      *	3: unknown, usually 0
124      *	2: unknown, usually 0
125      *	1: handshaking, unknown, usually set to 1 in trasmitted frames
126      *	0: handshaking, unknown, usually set to 1 in trasmitted frames
127      * oh_pad Probably a pad byte.
128      *
129      * After the header you will find data bytes if oh_len was greater than zero.
130      *
131      */
132     
133     struct omninet_header
134     {
135     	__u8	oh_seq;
136     	__u8	oh_len;
137     	__u8	oh_xxx;
138     	__u8	oh_pad;
139     };
140     
141     struct omninet_data
142     {
143     	__u8	od_outseq;	// Sequence number for bulk_out URBs
144     };
145     
146     static int omninet_open (struct usb_serial_port *port, struct file *filp)
147     {
148     	struct usb_serial	*serial;
149     	struct usb_serial_port	*wport;
150     	struct omninet_data	*od;
151     	int			result = 0;
152     
153     	if (port_paranoia_check (port, __FUNCTION__))
154     		return -ENODEV;
155     
156     	dbg(__FUNCTION__ " - port %d", port->number);
157     
158     	serial = get_usb_serial (port, __FUNCTION__);
159     	if (!serial)
160     		return -ENODEV;
161     
162     	down (&port->sem);
163     
164     	MOD_INC_USE_COUNT;
165     	++port->open_count;
166     
167     	if (!port->active) {
168     		port->active = 1;
169     
170     		od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
171     		if( !od ) {
172     			err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct omninet_data));
173     			--port->open_count;
174     			port->active = 0;
175     			up (&port->sem);
176     			MOD_DEC_USE_COUNT;
177     			return -ENOMEM;
178     		}
179     
180     		port->private = od;
181     		wport = &serial->port[1];
182     		wport->tty = port->tty;
183     
184     		/* Start reading from the device */
185     		FILL_BULK_URB(port->read_urb, serial->dev, 
186     			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
187     			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
188     			      omninet_read_bulk_callback, port);
189     		result = usb_submit_urb(port->read_urb);
190     		if (result)
191     			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
192     	}
193     
194     	up (&port->sem);
195     
196     	return result;
197     }
198     
199     static void omninet_close (struct usb_serial_port *port, struct file * filp)
200     {
201     	struct usb_serial 	*serial;
202     	struct usb_serial_port 	*wport;
203     	struct omninet_data 	*od;
204     
205     	if (port_paranoia_check (port, __FUNCTION__))
206     		return;
207     
208     	dbg(__FUNCTION__ " - port %d", port->number);
209     
210     	serial = get_usb_serial (port, __FUNCTION__);
211     	if (!serial)
212     		return;
213     
214     	down (&port->sem);
215     
216     	--port->open_count;
217     
218     	if (port->open_count <= 0) {
219     		od = (struct omninet_data *)port->private;
220     		wport = &serial->port[1];
221     
222     		usb_unlink_urb (wport->write_urb);
223     		usb_unlink_urb (port->read_urb);
224     
225     		port->active = 0;
226     		port->open_count = 0;
227     		if (od)
228     			kfree(od);
229     	}
230     
231     	up (&port->sem);
232     	MOD_DEC_USE_COUNT;
233     }
234     
235     
236     #define OMNINET_DATAOFFSET	0x04
237     #define OMNINET_HEADERLEN	sizeof(struct omninet_header)
238     #define OMNINET_BULKOUTSIZE 	(64 - OMNINET_HEADERLEN)
239     
240     static void omninet_read_bulk_callback (struct urb *urb)
241     {
242     	struct usb_serial_port 	*port 	= (struct usb_serial_port *)urb->context;
243     	struct usb_serial	*serial = get_usb_serial (port, __FUNCTION__);
244     
245     	unsigned char 		*data 	= urb->transfer_buffer;
246     	struct omninet_header 	*header = (struct omninet_header *) &data[0];
247     
248     	int i;
249     	int result;
250     
251     //	dbg("omninet_read_bulk_callback");
252     
253     	if (!serial) {
254     		dbg(__FUNCTION__ " - bad serial pointer, exiting");
255     		return;
256     	}
257     
258     	if (urb->status) {
259     		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
260     		return;
261     	}
262     
263     	if ((debug) && (header->oh_xxx != 0x30)) {
264     		if (urb->actual_length) {
265     			printk (KERN_DEBUG __FILE__ ": omninet_read %d: ", header->oh_len);
266     			for (i = 0; i < (header->oh_len + OMNINET_HEADERLEN); i++) {
267     				printk ("%.2x ", data[i]);
268     			}
269     			printk ("\n");
270     		}
271     	}
272     
273     	if (urb->actual_length && header->oh_len) {
274     		for (i = 0; i < header->oh_len; i++) {
275     			 tty_insert_flip_char(port->tty, data[OMNINET_DATAOFFSET + i], 0);
276     	  	}
277     	  	tty_flip_buffer_push(port->tty);
278     	}
279     
280     	/* Continue trying to always read  */
281     	FILL_BULK_URB(urb, serial->dev, 
282     		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
283     		      urb->transfer_buffer, urb->transfer_buffer_length,
284     		      omninet_read_bulk_callback, port);
285     	result = usb_submit_urb(urb);
286     	if (result)
287     		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
288     
289     	return;
290     }
291     
292     static int omninet_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
293     {
294     	struct usb_serial 	*serial	= port->serial;
295     	struct usb_serial_port 	*wport	= &serial->port[1];
296     
297     	struct omninet_data 	*od 	= (struct omninet_data   *) port->private;
298     	struct omninet_header	*header = (struct omninet_header *) wport->write_urb->transfer_buffer;
299     
300     	int			result;
301     
302     //	dbg("omninet_write port %d", port->number);
303     
304     	if (count == 0) {
305     		dbg(__FUNCTION__" - write request of 0 bytes");
306     		return (0);
307     	}
308     	if (wport->write_urb->status == -EINPROGRESS) {
309     		dbg (__FUNCTION__" - already writing");
310     		return (0);
311     	}
312     
313     	count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
314     
315     	if (from_user) {
316     		if (copy_from_user(wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count) != 0) {
317     			result = -EFAULT;
318     			goto exit;
319     		}
320     	}
321     	else {
322     		memcpy (wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count);
323     	}
324     
325     	usb_serial_debug_data (__FILE__, __FUNCTION__, count, wport->write_urb->transfer_buffer);
326     
327     	header->oh_seq 	= od->od_outseq++;
328     	header->oh_len 	= count;
329     	header->oh_xxx  = 0x03;
330     	header->oh_pad 	= 0x00;
331     
332     	/* send the data out the bulk port, always 64 bytes */
333     	wport->write_urb->transfer_buffer_length = 64;
334     
335     	wport->write_urb->dev = serial->dev;
336     	result = usb_submit_urb(wport->write_urb);
337     	if (result)
338     		err(__FUNCTION__ " - failed submitting write urb, error %d", result);
339     	else
340     		result = count;
341     
342     exit:	
343     	return result;
344     }
345     
346     
347     static int omninet_write_room (struct usb_serial_port *port)
348     {
349     	struct usb_serial 	*serial = port->serial;
350     	struct usb_serial_port 	*wport 	= &serial->port[1];
351     
352     	int room = 0; // Default: no room
353     
354     	if (wport->write_urb->status != -EINPROGRESS)
355     		room = wport->bulk_out_size - OMNINET_HEADERLEN;
356     
357     //	dbg("omninet_write_room returns %d", room);
358     
359     	return (room);
360     }
361     
362     static void omninet_write_bulk_callback (struct urb *urb)
363     {
364     /*	struct omninet_header	*header = (struct omninet_header  *) urb->transfer_buffer; */
365     	struct usb_serial_port 	*port   = (struct usb_serial_port *) urb->context;
366     	struct usb_serial 	*serial;
367     
368     //	dbg("omninet_write_bulk_callback, port %0x\n", port);
369     
370     
371     	if (port_paranoia_check (port, __FUNCTION__)) {
372     		return;
373     	}
374     
375     	serial = port->serial;
376     	if (serial_paranoia_check (serial, __FUNCTION__)) {
377     		return;
378     	}
379     
380     	if (urb->status) {
381     		dbg(__FUNCTION__" - nonzero write bulk status received: %d", urb->status);
382     		return;
383     	}
384     
385     	queue_task(&port->tqueue, &tq_immediate);
386     	mark_bh(IMMEDIATE_BH);
387     
388     //	dbg("omninet_write_bulk_callback, tty %0x\n", tty);
389     
390     	return;
391     }
392     
393     
394     static void omninet_shutdown (struct usb_serial *serial)
395     {
396     	dbg (__FUNCTION__);
397     
398     	while (serial->port[0].open_count > 0) {
399     		omninet_close (&serial->port[0], NULL);
400     	}
401     }
402     
403     
404     static int __init omninet_init (void)
405     {
406     	usb_serial_register (&zyxel_omninet_device);
407     	info(DRIVER_VERSION ":" DRIVER_DESC);
408     	return 0;
409     }
410     
411     
412     static void __exit omninet_exit (void)
413     {
414     	usb_serial_deregister (&zyxel_omninet_device);
415     }
416     
417     
418     module_init(omninet_init);
419     module_exit(omninet_exit);
420     
421     MODULE_AUTHOR( DRIVER_AUTHOR );
422     MODULE_DESCRIPTION( DRIVER_DESC );
423     MODULE_LICENSE("GPL");
424     
425     MODULE_PARM(debug, "i");
426     MODULE_PARM_DESC(debug, "Debug enabled or not");
427     
428