original comment: +Wilson03172004,marked due to this pci host does not support MWI
[linux-2.4.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/errno.h>
41 #include <linux/init.h>
42 #include <linux/slab.h>
43 #include <linux/tty.h>
44 #include <linux/tty_driver.h>
45 #include <linux/tty_flip.h>
46 #include <linux/module.h>
47 #include <linux/spinlock.h>
48 #include <asm/uaccess.h>
49 #include <linux/usb.h>
50
51 #ifdef CONFIG_USB_SERIAL_DEBUG
52         static int debug = 1;
53 #else
54         static int debug;
55 #endif
56
57 #include "usb-serial.h"
58
59
60 /*
61  * Version Information
62  */
63 #define DRIVER_VERSION "v1.1"
64 #define DRIVER_AUTHOR "Anonymous"
65 #define DRIVER_DESC "USB ZyXEL omni.net LCD PLUS Driver"
66
67 #define ZYXEL_VENDOR_ID         0x0586
68 #define ZYXEL_OMNINET_ID        0x1000
69
70 /* function prototypes */
71 static int  omninet_open                (struct usb_serial_port *port, struct file *filp);
72 static void omninet_close               (struct usb_serial_port *port, struct file *filp);
73 static void omninet_read_bulk_callback  (struct urb *urb);
74 static void omninet_write_bulk_callback (struct urb *urb);
75 static int  omninet_write               (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
76 static int  omninet_write_room          (struct usb_serial_port *port);
77 static void omninet_shutdown            (struct usb_serial *serial);
78
79 static struct usb_device_id id_table [] = {
80         { USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) },
81         { }                                             /* Terminating entry */
82 };
83
84 MODULE_DEVICE_TABLE (usb, id_table);
85
86
87 static struct usb_serial_device_type zyxel_omninet_device = {
88         .owner =                THIS_MODULE,
89         .name =                 "ZyXEL - omni.net lcd plus usb",
90         .id_table =             id_table,
91         .num_interrupt_in =     1,
92         .num_bulk_in =          1,
93         .num_bulk_out =         2,
94         .num_ports =            1,
95         .open =                 omninet_open,
96         .close =                omninet_close,
97         .write =                omninet_write,
98         .write_room =           omninet_write_room,
99         .read_bulk_callback =   omninet_read_bulk_callback,
100         .write_bulk_callback =  omninet_write_bulk_callback,
101         .shutdown =             omninet_shutdown,
102 };
103
104
105 /* The protocol.
106  *
107  * The omni.net always exchange 64 bytes of data with the host. The first
108  * four bytes are the control header, you can see it in the above structure.
109  *
110  * oh_seq is a sequence number. Don't know if/how it's used.
111  * oh_len is the length of the data bytes in the packet.
112  * oh_xxx Bit-mapped, related to handshaking and status info.
113  *      I normally set it to 0x03 in trasmitted frames.
114  *      7: Active when the TA is in a CONNECTed state.
115  *      6: unknown
116  *      5: handshaking, unknown
117  *      4: handshaking, unknown
118  *      3: unknown, usually 0
119  *      2: unknown, usually 0
120  *      1: handshaking, unknown, usually set to 1 in trasmitted frames
121  *      0: handshaking, unknown, usually set to 1 in trasmitted frames
122  * oh_pad Probably a pad byte.
123  *
124  * After the header you will find data bytes if oh_len was greater than zero.
125  *
126  */
127
128 struct omninet_header
129 {
130         __u8    oh_seq;
131         __u8    oh_len;
132         __u8    oh_xxx;
133         __u8    oh_pad;
134 };
135
136 struct omninet_data
137 {
138         __u8    od_outseq;      // Sequence number for bulk_out URBs
139 };
140
141 static int omninet_open (struct usb_serial_port *port, struct file *filp)
142 {
143         struct usb_serial       *serial;
144         struct usb_serial_port  *wport;
145         struct omninet_data     *od;
146         int                     result = 0;
147
148         if (port_paranoia_check (port, __FUNCTION__))
149                 return -ENODEV;
150
151         dbg("%s - port %d", __FUNCTION__, port->number);
152
153         serial = get_usb_serial (port, __FUNCTION__);
154         if (!serial)
155                 return -ENODEV;
156
157         od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
158         if( !od ) {
159                 err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct omninet_data));
160                 return -ENOMEM;
161         }
162
163         port->private = od;
164         wport = &serial->port[1];
165         wport->tty = port->tty;
166
167         /* Start reading from the device */
168         FILL_BULK_URB(port->read_urb, serial->dev, 
169                       usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
170                       port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
171                       omninet_read_bulk_callback, port);
172         result = usb_submit_urb(port->read_urb);
173         if (result)
174                 err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
175
176         return result;
177 }
178
179 static void omninet_close (struct usb_serial_port *port, struct file * filp)
180 {
181         struct usb_serial       *serial;
182         struct usb_serial_port  *wport;
183         struct omninet_data     *od;
184
185         if (port_paranoia_check (port, __FUNCTION__))
186                 return;
187
188         dbg("%s - port %d", __FUNCTION__, port->number);
189
190         serial = get_usb_serial (port, __FUNCTION__);
191         if (!serial)
192                 return;
193
194         if (serial->dev) {
195                 wport = &serial->port[1];
196                 usb_unlink_urb (wport->write_urb);
197                 usb_unlink_urb (port->read_urb);
198         }
199
200         od = (struct omninet_data *)port->private;
201         if (od)
202                 kfree(od);
203 }
204
205
206 #define OMNINET_DATAOFFSET      0x04
207 #define OMNINET_HEADERLEN       sizeof(struct omninet_header)
208 #define OMNINET_BULKOUTSIZE     (64 - OMNINET_HEADERLEN)
209
210 static void omninet_read_bulk_callback (struct urb *urb)
211 {
212         struct usb_serial_port  *port   = (struct usb_serial_port *)urb->context;
213         struct usb_serial       *serial = get_usb_serial (port, __FUNCTION__);
214
215         unsigned char           *data   = urb->transfer_buffer;
216         struct omninet_header   *header = (struct omninet_header *) &data[0];
217
218         int i;
219         int result;
220
221 //      dbg("omninet_read_bulk_callback");
222
223         if (!serial) {
224                 dbg("%s - bad serial pointer, exiting", __FUNCTION__);
225                 return;
226         }
227
228         if (urb->status) {
229                 dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
230                 return;
231         }
232
233         if ((debug) && (header->oh_xxx != 0x30)) {
234                 if (urb->actual_length) {
235                         printk (KERN_DEBUG __FILE__ ": omninet_read %d: ", header->oh_len);
236                         for (i = 0; i < (header->oh_len + OMNINET_HEADERLEN); i++) {
237                                 printk ("%.2x ", data[i]);
238                         }
239                         printk ("\n");
240                 }
241         }
242
243         if (urb->actual_length && header->oh_len) {
244                 for (i = 0; i < header->oh_len; i++) {
245                          tty_insert_flip_char(port->tty, data[OMNINET_DATAOFFSET + i], 0);
246                 }
247                 tty_flip_buffer_push(port->tty);
248         }
249
250         /* Continue trying to always read  */
251         FILL_BULK_URB(urb, serial->dev, 
252                       usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
253                       urb->transfer_buffer, urb->transfer_buffer_length,
254                       omninet_read_bulk_callback, port);
255         result = usb_submit_urb(urb);
256         if (result)
257                 err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
258
259         return;
260 }
261
262 static int omninet_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
263 {
264         struct usb_serial       *serial = port->serial;
265         struct usb_serial_port  *wport  = &serial->port[1];
266
267         struct omninet_data     *od     = (struct omninet_data   *) port->private;
268         struct omninet_header   *header = (struct omninet_header *) wport->write_urb->transfer_buffer;
269
270         int                     result;
271
272 //      dbg("omninet_write port %d", port->number);
273
274         if (count == 0) {
275                 dbg("%s - write request of 0 bytes", __FUNCTION__);
276                 return (0);
277         }
278         if (wport->write_urb->status == -EINPROGRESS) {
279                 dbg("%s - already writing", __FUNCTION__);
280                 return (0);
281         }
282
283         count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
284
285         if (from_user) {
286                 if (copy_from_user(wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count) != 0) {
287                         result = -EFAULT;
288                         goto exit;
289                 }
290         }
291         else {
292                 memcpy (wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count);
293         }
294
295         usb_serial_debug_data (__FILE__, __FUNCTION__, count, wport->write_urb->transfer_buffer);
296
297         header->oh_seq  = od->od_outseq++;
298         header->oh_len  = count;
299         header->oh_xxx  = 0x03;
300         header->oh_pad  = 0x00;
301
302         /* send the data out the bulk port, always 64 bytes */
303         wport->write_urb->transfer_buffer_length = 64;
304
305         wport->write_urb->dev = serial->dev;
306         result = usb_submit_urb(wport->write_urb);
307         if (result)
308                 err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
309         else
310                 result = count;
311
312 exit:   
313         return result;
314 }
315
316
317 static int omninet_write_room (struct usb_serial_port *port)
318 {
319         struct usb_serial       *serial = port->serial;
320         struct usb_serial_port  *wport  = &serial->port[1];
321
322         int room = 0; // Default: no room
323
324         if (wport->write_urb->status != -EINPROGRESS)
325                 room = wport->bulk_out_size - OMNINET_HEADERLEN;
326
327 //      dbg("omninet_write_room returns %d", room);
328
329         return (room);
330 }
331
332 static void omninet_write_bulk_callback (struct urb *urb)
333 {
334 /*      struct omninet_header   *header = (struct omninet_header  *) urb->transfer_buffer; */
335         struct usb_serial_port  *port   = (struct usb_serial_port *) urb->context;
336         struct usb_serial       *serial;
337
338 //      dbg("omninet_write_bulk_callback, port %0x\n", port);
339
340
341         if (port_paranoia_check (port, __FUNCTION__)) {
342                 return;
343         }
344
345         serial = port->serial;
346         if (serial_paranoia_check (serial, __FUNCTION__)) {
347                 return;
348         }
349
350         if (urb->status) {
351                 dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
352                 return;
353         }
354
355         queue_task(&port->tqueue, &tq_immediate);
356         mark_bh(IMMEDIATE_BH);
357
358 //      dbg("omninet_write_bulk_callback, tty %0x\n", tty);
359
360         return;
361 }
362
363
364 static void omninet_shutdown (struct usb_serial *serial)
365 {
366         dbg ("%s", __FUNCTION__);
367 }
368
369
370 static int __init omninet_init (void)
371 {
372         usb_serial_register (&zyxel_omninet_device);
373         info(DRIVER_VERSION ":" DRIVER_DESC);
374         return 0;
375 }
376
377
378 static void __exit omninet_exit (void)
379 {
380         usb_serial_deregister (&zyxel_omninet_device);
381 }
382
383
384 module_init(omninet_init);
385 module_exit(omninet_exit);
386
387 MODULE_AUTHOR( DRIVER_AUTHOR );
388 MODULE_DESCRIPTION( DRIVER_DESC );
389 MODULE_LICENSE("GPL");
390
391 MODULE_PARM(debug, "i");
392 MODULE_PARM_DESC(debug, "Debug enabled or not");
393