v2.4.9.9 -> v2.4.9.10
[opensuse:kernel.git] / 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