Import 2.3.46pre3
[davej-history.git] / drivers / usb / plusb.c
blob0cac10898c72d22a8e8acd3a96a89efc0c2a5dc6
1 /*****************************************************************************/
3 /*
4 * plusb.c -- prolific pl-2302 driver.
6 * Copyright (C) 2000 Deti Fliegl (deti@fliegl.de)
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * $Id: plusb.c,v 1.18 2000/02/14 10:38:58 fliegl Exp $
28 /*****************************************************************************/
30 #include <linux/module.h>
31 #include <linux/socket.h>
32 #include <linux/miscdevice.h>
33 #include <linux/list.h>
34 #include <linux/vmalloc.h>
35 #include <linux/slab.h>
36 #include <linux/init.h>
37 #include <asm/uaccess.h>
38 #include <asm/atomic.h>
39 #include <linux/delay.h>
40 #include <linux/netdevice.h>
41 #include <linux/etherdevice.h>
42 #include <linux/skbuff.h>
44 //#define DEBUG
46 #include "usb.h"
47 #include "plusb.h"
49 /* --------------------------------------------------------------------- */
51 #define NRPLUSB 4
53 /*-------------------------------------------------------------------*/
55 static plusb_t plusb[NRPLUSB];
57 /* --------------------------------------------------------------------- */
58 static int plusb_add_buf_tail (plusb_t *s, struct list_head *dst, struct list_head *src)
60 unsigned long flags;
61 struct list_head *tmp;
62 int ret = 0;
64 spin_lock_irqsave (&s->lock, flags);
66 if (list_empty (src)) {
67 // no elements in source buffer
68 ret = -1;
69 goto err;
71 tmp = src->next;
72 list_del (tmp);
73 list_add_tail (tmp, dst);
75 err: spin_unlock_irqrestore (&s->lock, flags);
76 return ret;
78 /*-------------------------------------------------------------------*/
80 static int plusb_my_bulk(plusb_t *s, int pipe, void *data, int size, int *actual_length)
82 int ret;
84 dbg("plusb_my_bulk: len:%d",size);
86 ret=usb_bulk_msg(s->usbdev, pipe, data, size, actual_length, 500);
87 if(ret<0) {
88 err("plusb: usb_bulk_msg failed(%d)",ret);
91 if( ret == -EPIPE ) {
92 warn("CLEAR_FEATURE request to remove STALL condition.");
93 if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe)))
94 err("request failed");
97 dbg("plusb_my_bulk: finished act: %d", *actual_length);
98 return ret;
101 /* --------------------------------------------------------------------- */
103 static void plusb_bh(void *context)
105 plusb_t *s=context;
106 struct net_device_stats *stats=&s->net_stats;
107 int ret=0;
108 int actual_length;
109 skb_list_t *skb_list;
110 struct sk_buff *skb;
112 dbg("plusb_bh: i:%d",in_interrupt());
114 while(!list_empty(&s->tx_skb_list)) {
116 if(!(s->status&_PLUSB_TXOK))
117 break;
119 skb_list = list_entry (s->tx_skb_list.next, skb_list_t, skb_list);
120 if(!skb_list->state) {
121 dbg("plusb_bh: not yet ready");
122 schedule();
123 continue;
126 skb=skb_list->skb;
127 ret=plusb_my_bulk(s, usb_sndbulkpipe (s->usbdev, _PLUSB_BULKOUTPIPE),
128 skb->data, skb->len, &actual_length);
130 if(ret || skb->len != actual_length ||!(skb->len%64)) {
131 plusb_my_bulk(s, usb_sndbulkpipe (s->usbdev, _PLUSB_BULKOUTPIPE),
132 NULL, 0, &actual_length);
135 if(!ret) {
136 stats->tx_packets++;
137 stats->tx_bytes+=skb->len;
139 else {
140 stats->tx_errors++;
141 stats->tx_aborted_errors++;
144 dbg("plusb_bh: dev_kfree_skb");
146 dev_kfree_skb(skb);
147 skb_list->state=0;
148 plusb_add_buf_tail (s, &s->free_skb_list, &s->tx_skb_list);
151 dbg("plusb_bh: finished");
152 s->in_bh=0;
155 /* --------------------------------------------------------------------- */
157 static int plusb_net_xmit(struct sk_buff *skb, struct net_device *dev)
159 plusb_t *s=dev->priv;
160 skb_list_t *skb_list;
161 int ret=NET_XMIT_SUCCESS;
163 dbg("plusb_net_xmit: len:%d i:%d",skb->len,in_interrupt());
165 if(!s->connected || list_empty(&s->free_skb_list)) {
166 ret=NET_XMIT_CN;
167 goto lab;
170 plusb_add_buf_tail (s, &s->tx_skb_list, &s->free_skb_list);
171 skb_list = list_entry (s->tx_skb_list.prev, skb_list_t, skb_list);
172 skb_list->skb=skb;
173 skb_list->state=1;
175 lab:
176 if(s->in_bh)
177 return ret;
179 dbg("plusb_net_xmit: queue_task");
181 s->in_bh=1;
182 queue_task(&s->bh, &tq_scheduler);
184 dbg("plusb_net_xmit: finished");
185 return ret;
189 /* --------------------------------------------------------------------- */
191 static void plusb_bulk_complete(urb_t *purb)
193 plusb_t *s=purb->context;
195 dbg("plusb_bulk_complete: status:%d length:%d",purb->status,purb->actual_length);
196 if(!s->connected)
197 return;
199 if( !purb->status) {
200 struct sk_buff *skb;
201 unsigned char *dst;
202 int len=purb->transfer_buffer_length;
203 struct net_device_stats *stats=&s->net_stats;
205 skb=dev_alloc_skb(len);
207 if(!skb) {
208 err("plusb_bulk_complete: dev_alloc_skb(%d)=NULL, dropping frame",len);
209 stats->rx_dropped++;
210 return;
213 dst=(char *)skb_put(skb, len);
214 memcpy( dst, purb->transfer_buffer, len);
216 skb->dev=&s->net_dev;
217 skb->protocol=eth_type_trans(skb, skb->dev);
218 stats->rx_packets++;
219 stats->rx_bytes+=len;
220 netif_rx(skb);
222 else
223 purb->status=0;
226 /* --------------------------------------------------------------------- */
228 static void plusb_int_complete(urb_t *purb)
230 plusb_t *s=purb->context;
231 s->status=((unsigned char*)purb->transfer_buffer)[0]&255;
232 #if 0
233 if((s->status&0x3f)!=0x20) {
234 warn("invalid device status %02X", s->status);
235 return;
237 #endif
238 if(!s->connected)
239 return;
241 if(s->status&_PLUSB_RXD) {
242 int ret;
244 if(s->bulkurb->status) {
245 err("plusb_int_complete: URB still in use");
246 return;
249 ret=usb_submit_urb(s->bulkurb);
250 if(ret && ret!=-EBUSY) {
251 err("plusb_int_complete: usb_submit_urb failed");
255 if(purb->status || s->status!=160)
256 dbg("status: %p %d buf: %02X", purb->dev, purb->status, s->status);
259 /* --------------------------------------------------------------------- */
261 static void plusb_free_all(plusb_t *s)
263 struct list_head *skb;
264 skb_list_t *skb_list;
266 dbg("plusb_free_all");
267 run_task_queue(&tq_immediate);
269 if(s->inturb) {
270 dbg("unlink inturb");
271 usb_unlink_urb(s->inturb);
274 if(s->inturb && s->inturb->transfer_buffer) {
275 dbg("kfree inturb->transfer_buffer");
276 kfree(s->inturb->transfer_buffer);
277 s->inturb->transfer_buffer=NULL;
280 if(s->inturb) {
281 dbg("free_urb inturb");
282 usb_free_urb(s->inturb);
283 s->inturb=NULL;
286 if(s->bulkurb) {
287 dbg("unlink bulkurb");
288 usb_unlink_urb(s->bulkurb);
291 if(s->bulkurb && s->bulkurb->transfer_buffer) {
292 dbg("kfree bulkurb->transfer_buffer");
293 kfree(s->bulkurb->transfer_buffer);
294 s->bulkurb->transfer_buffer=NULL;
296 if(s->bulkurb) {
297 dbg("free_urb bulkurb");
298 usb_free_urb(s->bulkurb);
299 s->bulkurb=NULL;
302 while(!list_empty(&s->free_skb_list)) {
303 skb=s->free_skb_list.next;
304 list_del(skb);
305 skb_list = list_entry (skb, skb_list_t, skb_list);
306 kfree(skb_list);
309 while(!list_empty(&s->tx_skb_list)) {
310 skb=s->tx_skb_list.next;
311 list_del(skb);
312 skb_list = list_entry (skb, skb_list_t, skb_list);
313 kfree(skb_list);
315 dbg("plusb_free_all: finished");
318 /*-------------------------------------------------------------------*/
320 static int plusb_alloc(plusb_t *s)
322 int i;
323 skb_list_t *skb;
325 dbg("plusb_alloc");
327 for(i=0 ; i < _SKB_NUM ; i++) {
328 skb=kmalloc(sizeof(skb_list_t), GFP_KERNEL);
329 if(!skb) {
330 err("kmalloc for skb_list failed");
331 goto reject;
333 memset(skb, 0, sizeof(skb_list_t));
334 list_add(&skb->skb_list, &s->free_skb_list);
337 dbg("inturb allocation:");
338 s->inturb=usb_alloc_urb(0);
339 if(!s->inturb) {
340 err("alloc_urb failed");
341 goto reject;
344 dbg("bulkurb allocation:");
345 s->bulkurb=usb_alloc_urb(0);
346 if(!s->bulkurb) {
347 err("alloc_urb failed");
348 goto reject;
351 dbg("bulkurb/inturb init:");
352 s->inturb->dev=s->usbdev;
353 s->inturb->pipe=usb_rcvintpipe (s->usbdev, _PLUSB_INTPIPE);
354 s->inturb->transfer_buffer=kmalloc(64, GFP_KERNEL);
355 if(!s->inturb->transfer_buffer) {
356 err("kmalloc failed");
357 goto reject;
360 s->inturb->transfer_buffer_length=1;
361 s->inturb->complete=plusb_int_complete;
362 s->inturb->context=s;
363 s->inturb->interval=10;
365 dbg("inturb submission:");
366 if(usb_submit_urb(s->inturb)<0) {
367 err("usb_submit_urb failed");
368 goto reject;
371 dbg("bulkurb init:");
372 s->bulkurb->dev=s->usbdev;
373 s->bulkurb->pipe=usb_rcvbulkpipe (s->usbdev, _PLUSB_BULKINPIPE);
374 s->bulkurb->transfer_buffer=kmalloc(_BULK_DATA_LEN, GFP_KERNEL);
375 if(!s->bulkurb->transfer_buffer) {
376 err("kmalloc failed");
377 goto reject;
380 s->bulkurb->transfer_buffer_length=_BULK_DATA_LEN;
381 s->bulkurb->complete=plusb_bulk_complete;
382 s->bulkurb->context=s;
384 dbg("plusb_alloc: finished");
386 return 0;
388 reject:
389 dbg("plusb_alloc: failed");
391 plusb_free_all(s);
392 return -ENOMEM;
395 /*-------------------------------------------------------------------*/
397 static int plusb_net_open(struct net_device *dev)
399 plusb_t *s=dev->priv;
401 dbg("plusb_net_open");
403 if(plusb_alloc(s))
404 return -ENOMEM;
406 s->opened=1;
407 MOD_INC_USE_COUNT;
409 dbg("plusb_net_open: success");
411 return 0;
415 /* --------------------------------------------------------------------- */
417 static int plusb_net_stop(struct net_device *dev)
419 plusb_t *s=dev->priv;
421 dbg("plusb_net_stop");
423 plusb_free_all(s);
424 s->opened=0;
425 MOD_DEC_USE_COUNT;
426 dbg("plusb_net_stop:finished");
427 return 0;
430 /* --------------------------------------------------------------------- */
432 static struct net_device_stats *plusb_net_get_stats(struct net_device *dev)
434 plusb_t *s=dev->priv;
436 dbg("net_device_stats");
438 return &s->net_stats;
441 /* --------------------------------------------------------------------- */
443 static plusb_t *plusb_find_struct (void)
445 int u;
447 for (u = 0; u < NRPLUSB; u++) {
448 plusb_t *s = &plusb[u];
449 if (!s->connected)
450 return s;
452 return NULL;
455 /* --------------------------------------------------------------------- */
457 static void plusb_disconnect (struct usb_device *usbdev, void *ptr)
459 plusb_t *s = ptr;
461 dbg("plusb_disconnect");
462 s->connected = 0;
464 plusb_free_all(s);
466 if(!s->opened && s->net_dev.name) {
467 dbg("unregistering netdev: %s",s->net_dev.name);
468 unregister_netdev(&s->net_dev);
469 kfree(s->net_dev.name);
470 s->net_dev.name=NULL;
473 dbg("plusb_disconnect: finished");
474 MOD_DEC_USE_COUNT;
477 /* --------------------------------------------------------------------- */
479 int plusb_net_init(struct net_device *dev)
481 dbg("plusb_net_init");
483 dev->open=plusb_net_open;
484 dev->stop=plusb_net_stop;
485 dev->hard_start_xmit=plusb_net_xmit;
486 dev->get_stats = plusb_net_get_stats;
487 ether_setup(dev);
488 dev->tx_queue_len = 0;
489 dev->flags = IFF_POINTOPOINT|IFF_NOARP;
492 dbg("plusb_net_init: finished");
493 return 0;
496 /* --------------------------------------------------------------------- */
498 static void *plusb_probe (struct usb_device *usbdev, unsigned int ifnum)
500 plusb_t *s;
502 dbg("plusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d",
503 usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, ifnum);
505 if (usbdev->descriptor.idVendor != 0x067b || usbdev->descriptor.idProduct != 0x1)
506 return NULL;
508 /* We don't handle multiple configurations */
509 if (usbdev->descriptor.bNumConfigurations != 1)
510 return NULL;
512 s = plusb_find_struct ();
513 if (!s)
514 return NULL;
516 s->usbdev = usbdev;
518 if (usb_set_configuration (s->usbdev, usbdev->config[0].bConfigurationValue) < 0) {
519 err("set_configuration failed");
520 return NULL;
523 if (usb_set_interface (s->usbdev, 0, 0) < 0) {
524 err("set_interface failed");
525 return NULL;
528 if(!s->net_dev.name) {
529 s->net_dev.name=kmalloc(16, GFP_KERNEL);
531 if(!s->net_dev.name || dev_alloc_name(&s->net_dev,"plusb%d")<0) {
532 err("alloc name failed\n");
533 return NULL;
536 s->net_dev.init=plusb_net_init;
537 s->net_dev.priv=s;
538 if(!register_netdev(&s->net_dev))
539 info("registered: %s", s->net_dev.name);
540 else {
541 err("register_netdev failed");
542 kfree(s->net_dev.name);
543 s->net_dev.name=NULL;
547 s->connected = 1;
549 if(s->opened) {
550 dbg("net device already allocated, restarting USB transfers");
551 plusb_alloc(s);
554 info("bound to interface: %d dev: %p", ifnum, usbdev);
555 MOD_INC_USE_COUNT;
556 return s;
558 /* --------------------------------------------------------------------- */
560 static struct usb_driver plusb_driver =
562 name: "plusb",
563 probe: plusb_probe,
564 disconnect: plusb_disconnect,
567 /* --------------------------------------------------------------------- */
569 int __init plusb_init (void)
571 unsigned u;
572 dbg("plusb_init");
574 /* initialize struct */
575 for (u = 0; u < NRPLUSB; u++) {
576 plusb_t *s = &plusb[u];
577 memset (s, 0, sizeof (plusb_t));
578 s->bh.routine = (void (*)(void *))plusb_bh;
579 s->bh.data = s;
580 INIT_LIST_HEAD (&s->tx_skb_list);
581 INIT_LIST_HEAD (&s->free_skb_list);
582 spin_lock_init (&s->lock);
585 /* register misc device */
586 usb_register (&plusb_driver);
588 dbg("plusb_init: driver registered");
590 return 0;
593 /* --------------------------------------------------------------------- */
595 void __exit plusb_cleanup (void)
597 unsigned u;
599 dbg("plusb_cleanup");
600 for (u = 0; u < NRPLUSB; u++) {
601 plusb_t *s = &plusb[u];
602 if(s->net_dev.name) {
603 dbg("unregistering netdev: %s",s->net_dev.name);
604 unregister_netdev(&s->net_dev);
605 kfree(s->net_dev.name);
606 s->net_dev.name=NULL;
609 usb_deregister (&plusb_driver);
610 dbg("plusb_cleanup: finished");
613 /* --------------------------------------------------------------------- */
615 #ifdef MODULE
616 MODULE_AUTHOR ("Deti Fliegl, deti@fliegl.de");
617 MODULE_DESCRIPTION ("PL-2302 USB Interface Driver for Linux (c)2000");
619 /* --------------------------------------------------------------------- */
620 int __init init_module (void)
622 return plusb_init ();
624 /* --------------------------------------------------------------------- */
625 void __exit cleanup_module (void)
627 plusb_cleanup ();
630 #endif
632 /* --------------------------------------------------------------------- */