OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [usb/] [acm.c] - Blame information for rev 1275

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * acm.c  Version 0.21
3
 *
4
 * Copyright (c) 1999 Armin Fuerst      <fuerst@in.tum.de>
5
 * Copyright (c) 1999 Pavel Machek      <pavel@suse.cz>
6
 * Copyright (c) 1999 Johannes Erdfelt  <johannes@erdfelt.com>
7
 * Copyright (c) 2000 Vojtech Pavlik    <vojtech@suse.cz>
8
 *
9
 * USB Abstract Control Model driver for USB modems and ISDN adapters
10
 *
11
 * Sponsored by SuSE
12
 *
13
 * ChangeLog:
14
 *      v0.9  - thorough cleaning, URBification, almost a rewrite
15
 *      v0.10 - some more cleanups
16
 *      v0.11 - fixed flow control, read error doesn't stop reads
17
 *      v0.12 - added TIOCM ioctls, added break handling, made struct acm kmalloced
18
 *      v0.13 - added termios, added hangup
19
 *      v0.14 - sized down struct acm
20
 *      v0.15 - fixed flow control again - characters could be lost
21
 *      v0.16 - added code for modems with swapped data and control interfaces
22
 *      v0.17 - added new style probing
23
 *      v0.18 - fixed new style probing for devices with more configurations
24
 *      v0.19 - fixed CLOCAL handling (thanks to Richard Shih-Ping Chan)
25
 *      v0.20 - switched to probing on interface (rather than device) class
26
 *      v0.21 - revert to probing on device for devices with multiple configs
27
 */
28
 
29
/*
30
 * This program is free software; you can redistribute it and/or modify
31
 * it under the terms of the GNU General Public License as published by
32
 * the Free Software Foundation; either version 2 of the License, or
33
 * (at your option) any later version.
34
 *
35
 * This program is distributed in the hope that it will be useful,
36
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38
 * GNU General Public License for more details.
39
 *
40
 * You should have received a copy of the GNU General Public License
41
 * along with this program; if not, write to the Free Software
42
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
43
 */
44
 
45
#include <linux/kernel.h>
46
#include <linux/sched.h>
47
#include <linux/signal.h>
48
#include <linux/errno.h>
49
#include <linux/poll.h>
50
#include <linux/init.h>
51
#include <linux/slab.h>
52
#include <linux/fcntl.h>
53
#include <linux/tty.h>
54
#include <linux/tty_driver.h>
55
#include <linux/tty_flip.h>
56
#include <linux/module.h>
57
#include <linux/smp_lock.h>
58
#undef DEBUG
59
#include <linux/usb.h>
60
 
61
/*
62
 * Version Information
63
 */
64
#define DRIVER_VERSION "v0.21"
65
#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik"
66
#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
67
 
68
/*
69
 * CMSPAR, some architectures can't have space and mark parity.
70
 */
71
 
72
#ifndef CMSPAR
73
#define CMSPAR                  0
74
#endif
75
 
76
/*
77
 * Major and minor numbers.
78
 */
79
 
80
#define ACM_TTY_MAJOR           166
81
#define ACM_TTY_MINORS          32
82
 
83
/*
84
 * Requests.
85
 */
86
 
87
#define USB_RT_ACM              (USB_TYPE_CLASS | USB_RECIP_INTERFACE)
88
 
89
#define ACM_REQ_COMMAND         0x00
90
#define ACM_REQ_RESPONSE        0x01
91
#define ACM_REQ_SET_FEATURE     0x02
92
#define ACM_REQ_GET_FEATURE     0x03
93
#define ACM_REQ_CLEAR_FEATURE   0x04
94
 
95
#define ACM_REQ_SET_LINE        0x20
96
#define ACM_REQ_GET_LINE        0x21
97
#define ACM_REQ_SET_CONTROL     0x22
98
#define ACM_REQ_SEND_BREAK      0x23
99
 
100
/*
101
 * IRQs.
102
 */
103
 
104
#define ACM_IRQ_NETWORK         0x00
105
#define ACM_IRQ_LINE_STATE      0x20
106
 
107
/*
108
 * Output control lines.
109
 */
110
 
111
#define ACM_CTRL_DTR            0x01
112
#define ACM_CTRL_RTS            0x02
113
 
114
/*
115
 * Input control lines and line errors.
116
 */
117
 
118
#define ACM_CTRL_DCD            0x01
119
#define ACM_CTRL_DSR            0x02
120
#define ACM_CTRL_BRK            0x04
121
#define ACM_CTRL_RI             0x08
122
 
123
#define ACM_CTRL_FRAMING        0x10
124
#define ACM_CTRL_PARITY         0x20
125
#define ACM_CTRL_OVERRUN        0x40
126
 
127
/*
128
 * Line speed and caracter encoding.
129
 */
130
 
131
struct acm_line {
132
        __u32 speed;
133
        __u8 stopbits;
134
        __u8 parity;
135
        __u8 databits;
136
} __attribute__ ((packed));
137
 
138
/*
139
 * Internal driver structures.
140
 */
141
 
142
struct acm {
143
        struct usb_device *dev;                         /* the coresponding usb device */
144
        struct usb_interface *iface;                    /* the interfaces - +0 control +1 data */
145
        struct tty_struct *tty;                         /* the coresponding tty */
146
        struct urb ctrlurb, readurb, writeurb;          /* urbs */
147
        struct acm_line line;                           /* line coding (bits, stop, parity) */
148
        struct tq_struct tqueue;                        /* task queue for line discipline waking up */
149
        unsigned int ctrlin;                            /* input control lines (DCD, DSR, RI, break, overruns) */
150
        unsigned int ctrlout;                           /* output control lines (DTR, RTS) */
151
        unsigned int writesize;                         /* max packet size for the output bulk endpoint */
152
        unsigned int used;                              /* someone has this acm's device open */
153
        unsigned int minor;                             /* acm minor number */
154
        unsigned char throttle;                         /* throttled by tty layer */
155
        unsigned char clocal;                           /* termios CLOCAL */
156
};
157
 
158
static struct usb_driver acm_driver;
159
static struct tty_driver acm_tty_driver;
160
static struct acm *acm_table[ACM_TTY_MINORS];
161
 
162
#define ACM_READY(acm)  (acm && acm->dev && acm->used)
163
 
164
/*
165
 * Functions for ACM control messages.
166
 */
167
 
168
static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len)
169
{
170
        int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
171
                request, USB_RT_ACM, value, acm->iface[0].altsetting[0].bInterfaceNumber, buf, len, HZ * 5);
172
        dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
173
        return retval < 0 ? retval : 0;
174
}
175
 
176
#define acm_set_control(acm, control)   acm_ctrl_msg(acm, ACM_REQ_SET_CONTROL, control, NULL, 0)
177
#define acm_set_line(acm, line)         acm_ctrl_msg(acm, ACM_REQ_SET_LINE, 0, line, sizeof(struct acm_line))
178
#define acm_send_break(acm, ms)         acm_ctrl_msg(acm, ACM_REQ_SEND_BREAK, ms, NULL, 0)
179
 
180
/*
181
 * Interrupt handler for various ACM control events
182
 */
183
 
184
static void acm_ctrl_irq(struct urb *urb)
185
{
186
        struct acm *acm = urb->context;
187
        struct usb_ctrlrequest *dr = urb->transfer_buffer;
188
        unsigned char *data = (unsigned char *)(dr + 1);
189
        int newctrl;
190
 
191
        if (!ACM_READY(acm)) return;
192
 
193
        if (urb->status < 0) {
194
                dbg("nonzero ctrl irq status received: %d", urb->status);
195
                return;
196
        }
197
 
198
        switch (dr->bRequest) {
199
 
200
                case ACM_IRQ_NETWORK:
201
 
202
                        dbg("%s network", data[0] ? "connected to" : "disconnected from");
203
                        return;
204
 
205
                case ACM_IRQ_LINE_STATE:
206
 
207
                        newctrl = le16_to_cpup((__u16 *) data);
208
 
209
                        if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
210
                                dbg("calling hangup");
211
                                tty_hangup(acm->tty);
212
                        }
213
 
214
                        acm->ctrlin = newctrl;
215
 
216
                        dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
217
                                acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
218
                                acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', acm->ctrlin & ACM_CTRL_RI  ? '+' : '-',
219
                                acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-',     acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
220
                                acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
221
 
222
                        return;
223
 
224
                default:
225
                        dbg("unknown control event received: request %d index %d len %d data0 %d data1 %d",
226
                                dr->bRequest, dr->wIndex, dr->wLength, data[0], data[1]);
227
                        return;
228
        }
229
}
230
 
231
static void acm_read_bulk(struct urb *urb)
232
{
233
        struct acm *acm = urb->context;
234
        struct tty_struct *tty = acm->tty;
235
        unsigned char *data = urb->transfer_buffer;
236
        int i = 0;
237
 
238
        if (!ACM_READY(acm)) return;
239
 
240
        if (urb->status)
241
                dbg("nonzero read bulk status received: %d", urb->status);
242
 
243
        if (!urb->status && !acm->throttle)  {
244
                for (i = 0; i < urb->actual_length && !acm->throttle; i++) {
245
                        /* if we insert more than TTY_FLIPBUF_SIZE characters,
246
                         * we drop them. */
247
                        if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
248
                                tty_flip_buffer_push(tty);
249
                        }
250
                        tty_insert_flip_char(tty, data[i], 0);
251
                }
252
                tty_flip_buffer_push(tty);
253
        }
254
 
255
        if (acm->throttle) {
256
                memmove(data, data + i, urb->actual_length - i);
257
                urb->actual_length -= i;
258
                return;
259
        }
260
 
261
        urb->actual_length = 0;
262
        urb->dev = acm->dev;
263
 
264
        if (usb_submit_urb(urb))
265
                dbg("failed resubmitting read urb");
266
}
267
 
268
static void acm_write_bulk(struct urb *urb)
269
{
270
        struct acm *acm = (struct acm *)urb->context;
271
 
272
        if (!ACM_READY(acm)) return;
273
 
274
        if (urb->status)
275
                dbg("nonzero write bulk status received: %d", urb->status);
276
 
277
        queue_task(&acm->tqueue, &tq_immediate);
278
        mark_bh(IMMEDIATE_BH);
279
}
280
 
281
static void acm_softint(void *private)
282
{
283
        struct acm *acm = private;
284
        struct tty_struct *tty = acm->tty;
285
 
286
        if (!ACM_READY(acm)) return;
287
 
288
        if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
289
                (tty->ldisc.write_wakeup)(tty);
290
 
291
        wake_up_interruptible(&tty->write_wait);
292
}
293
 
294
/*
295
 * TTY handlers
296
 */
297
 
298
static int acm_tty_open(struct tty_struct *tty, struct file *filp)
299
{
300
        struct acm *acm = acm_table[MINOR(tty->device)];
301
 
302
        if (!acm || !acm->dev) return -EINVAL;
303
 
304
        tty->driver_data = acm;
305
        acm->tty = tty;
306
 
307
        MOD_INC_USE_COUNT;
308
 
309
        lock_kernel();
310
 
311
        if (acm->used++) {
312
                unlock_kernel();
313
                return 0;
314
        }
315
 
316
        unlock_kernel();
317
 
318
        acm->ctrlurb.dev = acm->dev;
319
        if (usb_submit_urb(&acm->ctrlurb))
320
                dbg("usb_submit_urb(ctrl irq) failed");
321
 
322
        acm->readurb.dev = acm->dev;
323
        if (usb_submit_urb(&acm->readurb))
324
                dbg("usb_submit_urb(read bulk) failed");
325
 
326
        acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS);
327
 
328
        /* force low_latency on so that our tty_push actually forces the data through,
329
           otherwise it is scheduled, and with high data rates data can get lost. */
330
        tty->low_latency = 1;
331
 
332
        return 0;
333
}
334
 
335
static void acm_tty_close(struct tty_struct *tty, struct file *filp)
336
{
337
        struct acm *acm = tty->driver_data;
338
 
339
        if (!acm || !acm->used) return;
340
 
341
        if (!--acm->used) {
342
                if (acm->dev) {
343
                        acm_set_control(acm, acm->ctrlout = 0);
344
                        usb_unlink_urb(&acm->ctrlurb);
345
                        usb_unlink_urb(&acm->writeurb);
346
                        usb_unlink_urb(&acm->readurb);
347
                } else {
348
                        tty_unregister_devfs(&acm_tty_driver, acm->minor);
349
                        acm_table[acm->minor] = NULL;
350
                        kfree(acm);
351
                }
352
        }
353
        MOD_DEC_USE_COUNT;
354
}
355
 
356
static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
357
{
358
        struct acm *acm = tty->driver_data;
359
 
360
        if (!ACM_READY(acm)) return -EINVAL;
361
        if (acm->writeurb.status == -EINPROGRESS) return 0;
362
        if (!count) return 0;
363
 
364
        count = (count > acm->writesize) ? acm->writesize : count;
365
 
366
        if (from_user) {
367
                if (copy_from_user(acm->writeurb.transfer_buffer, buf, count))
368
                        return -EFAULT;
369
        } else
370
                memcpy(acm->writeurb.transfer_buffer, buf, count);
371
 
372
        acm->writeurb.transfer_buffer_length = count;
373
        acm->writeurb.dev = acm->dev;
374
 
375
        if (usb_submit_urb(&acm->writeurb))
376
                dbg("usb_submit_urb(write bulk) failed");
377
 
378
        return count;
379
}
380
 
381
static int acm_tty_write_room(struct tty_struct *tty)
382
{
383
        struct acm *acm = tty->driver_data;
384
        if (!ACM_READY(acm)) return -EINVAL;
385
        return acm->writeurb.status == -EINPROGRESS ? 0 : acm->writesize;
386
}
387
 
388
static int acm_tty_chars_in_buffer(struct tty_struct *tty)
389
{
390
        struct acm *acm = tty->driver_data;
391
        if (!ACM_READY(acm)) return -EINVAL;
392
        return acm->writeurb.status == -EINPROGRESS ? acm->writeurb.transfer_buffer_length : 0;
393
}
394
 
395
static void acm_tty_throttle(struct tty_struct *tty)
396
{
397
        struct acm *acm = tty->driver_data;
398
        if (!ACM_READY(acm)) return;
399
        acm->throttle = 1;
400
}
401
 
402
static void acm_tty_unthrottle(struct tty_struct *tty)
403
{
404
        struct acm *acm = tty->driver_data;
405
        if (!ACM_READY(acm)) return;
406
        acm->throttle = 0;
407
        if (acm->readurb.status != -EINPROGRESS)
408
                acm_read_bulk(&acm->readurb);
409
}
410
 
411
static void acm_tty_break_ctl(struct tty_struct *tty, int state)
412
{
413
        struct acm *acm = tty->driver_data;
414
        if (!ACM_READY(acm)) return;
415
        if (acm_send_break(acm, state ? 0xffff : 0))
416
                dbg("send break failed");
417
}
418
 
419
static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
420
{
421
        struct acm *acm = tty->driver_data;
422
        unsigned int mask, newctrl;
423
 
424
        if (!ACM_READY(acm)) return -EINVAL;
425
 
426
        switch (cmd) {
427
 
428
                case TIOCMGET:
429
 
430
                        return put_user((acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
431
                                (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
432
                                (acm->ctrlin  & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
433
                                (acm->ctrlin  & ACM_CTRL_RI  ? TIOCM_RI  : 0) |
434
                                (acm->ctrlin  & ACM_CTRL_DCD ? TIOCM_CD  : 0) |
435
                                 TIOCM_CTS, (unsigned long *) arg);
436
 
437
                case TIOCMSET:
438
                case TIOCMBIS:
439
                case TIOCMBIC:
440
 
441
                        if (get_user(mask, (unsigned long *) arg))
442
                                return -EFAULT;
443
 
444
                        newctrl = acm->ctrlout;
445
                        mask = (mask & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (mask & TIOCM_RTS ? ACM_CTRL_RTS : 0);
446
 
447
                        switch (cmd) {
448
                                case TIOCMSET: newctrl  =  mask; break;
449
                                case TIOCMBIS: newctrl |=  mask; break;
450
                                case TIOCMBIC: newctrl &= ~mask; break;
451
                        }
452
 
453
                        if (acm->ctrlout == newctrl) return 0;
454
                        return acm_set_control(acm, acm->ctrlout = newctrl);
455
        }
456
 
457
        return -ENOIOCTLCMD;
458
}
459
 
460
static __u32 acm_tty_speed[] = {
461
        0, 50, 75, 110, 134, 150, 200, 300, 600,
462
        1200, 1800, 2400, 4800, 9600, 19200, 38400,
463
        57600, 115200, 230400, 460800, 500000, 576000,
464
        921600, 1000000, 1152000, 1500000, 2000000,
465
        2500000, 3000000, 3500000, 4000000
466
};
467
 
468
static __u8 acm_tty_size[] = {
469
        5, 6, 7, 8
470
};
471
 
472
static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_old)
473
{
474
        struct acm *acm = tty->driver_data;
475
        struct termios *termios = tty->termios;
476
        struct acm_line newline;
477
        int newctrl = acm->ctrlout;
478
 
479
        if (!ACM_READY(acm)) return;
480
 
481
        newline.speed = cpu_to_le32p(acm_tty_speed +
482
                (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
483
        newline.stopbits = termios->c_cflag & CSTOPB ? 2 : 0;
484
        newline.parity = termios->c_cflag & PARENB ?
485
                (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
486
        newline.databits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
487
 
488
        acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
489
 
490
        if (!newline.speed) {
491
                newline.speed = acm->line.speed;
492
                newctrl &= ~ACM_CTRL_DTR;
493
        } else  newctrl |=  ACM_CTRL_DTR;
494
 
495
        if (newctrl != acm->ctrlout)
496
                acm_set_control(acm, acm->ctrlout = newctrl);
497
 
498
        if (memcmp(&acm->line, &newline, sizeof(struct acm_line))) {
499
                memcpy(&acm->line, &newline, sizeof(struct acm_line));
500
                dbg("set line: %d %d %d %d", newline.speed, newline.stopbits, newline.parity, newline.databits);
501
                acm_set_line(acm, &acm->line);
502
        }
503
}
504
 
505
/*
506
 * USB probe and disconnect routines.
507
 */
508
 
509
static void *acm_probe(struct usb_device *dev, unsigned int ifnum,
510
                       const struct usb_device_id *id)
511
{
512
        struct acm *acm;
513
        struct usb_config_descriptor *cfacm;
514
        struct usb_interface_descriptor *ifcom, *ifdata;
515
        struct usb_endpoint_descriptor *epctrl, *epread, *epwrite;
516
        int readsize, ctrlsize, minor, i, j;
517
        unsigned char *buf;
518
 
519
        for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
520
 
521
                cfacm = dev->config + i;
522
 
523
                dbg("probing config %d", cfacm->bConfigurationValue);
524
 
525
                for (j = 0; j < cfacm->bNumInterfaces - 1; j++) {
526
 
527
                        if (usb_interface_claimed(cfacm->interface + j) ||
528
                            usb_interface_claimed(cfacm->interface + j + 1))
529
                                continue;
530
 
531
                        ifcom = cfacm->interface[j].altsetting + 0;
532
                        ifdata = cfacm->interface[j + 1].altsetting + 0;
533
 
534
                        if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2) {
535
                                ifcom = cfacm->interface[j + 1].altsetting + 0;
536
                                ifdata = cfacm->interface[j].altsetting + 0;
537
                                if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2)
538
                                        continue;
539
                        }
540
 
541
                        if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
542
                            ifcom->bInterfaceProtocol < 1 || ifcom->bInterfaceProtocol > 6 ||
543
                            ifcom->bNumEndpoints < 1)
544
                                continue;
545
 
546
                        epctrl = ifcom->endpoint + 0;
547
                        epread = ifdata->endpoint + 0;
548
                        epwrite = ifdata->endpoint + 1;
549
 
550
                        if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 ||
551
                            (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
552
                            ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
553
                                continue;
554
 
555
                        dbg("using interface %d\n", j);
556
 
557
                        if ((epread->bEndpointAddress & 0x80) != 0x80) {
558
                                epread = ifdata->endpoint + 1;
559
                                epwrite = ifdata->endpoint + 0;
560
                        }
561
 
562
                        usb_set_configuration(dev, cfacm->bConfigurationValue);
563
 
564
                        for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
565
                        if (acm_table[minor]) {
566
                                err("no more free acm devices");
567
                                return NULL;
568
                        }
569
 
570
                        if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
571
                                err("out of memory");
572
                                return NULL;
573
                        }
574
                        memset(acm, 0, sizeof(struct acm));
575
 
576
                        ctrlsize = epctrl->wMaxPacketSize;
577
                        readsize = epread->wMaxPacketSize;
578
                        acm->writesize = epwrite->wMaxPacketSize;
579
                        acm->iface = cfacm->interface + j;
580
                        acm->minor = minor;
581
                        acm->dev = dev;
582
 
583
                        acm->tqueue.routine = acm_softint;
584
                        acm->tqueue.data = acm;
585
 
586
                        if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
587
                                err("out of memory");
588
                                kfree(acm);
589
                                return NULL;
590
                        }
591
 
592
                        FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
593
                                     buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
594
 
595
                        FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
596
                                      buf += ctrlsize, readsize, acm_read_bulk, acm);
597
                        acm->readurb.transfer_flags |= USB_NO_FSBR;
598
 
599
                        FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
600
                                      buf += readsize, acm->writesize, acm_write_bulk, acm);
601
                        acm->writeurb.transfer_flags |= USB_NO_FSBR;
602
 
603
                        printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
604
 
605
                        acm_set_control(acm, acm->ctrlout);
606
 
607
                        acm->line.speed = cpu_to_le32(9600);
608
                        acm->line.databits = 8;
609
                        acm_set_line(acm, &acm->line);
610
 
611
                        usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
612
                        usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
613
 
614
                        tty_register_devfs(&acm_tty_driver, 0, minor);
615
                        return acm_table[minor] = acm;
616
                }
617
        }
618
 
619
        return NULL;
620
}
621
 
622
static void acm_disconnect(struct usb_device *dev, void *ptr)
623
{
624
        struct acm *acm = ptr;
625
 
626
        if (!acm || !acm->dev) {
627
                dbg("disconnect on nonexisting interface");
628
                return;
629
        }
630
 
631
        acm->dev = NULL;
632
 
633
        usb_unlink_urb(&acm->ctrlurb);
634
        usb_unlink_urb(&acm->readurb);
635
        usb_unlink_urb(&acm->writeurb);
636
 
637
        kfree(acm->ctrlurb.transfer_buffer);
638
 
639
        usb_driver_release_interface(&acm_driver, acm->iface + 0);
640
        usb_driver_release_interface(&acm_driver, acm->iface + 1);
641
 
642
        if (!acm->used) {
643
                tty_unregister_devfs(&acm_tty_driver, acm->minor);
644
                acm_table[acm->minor] = NULL;
645
                kfree(acm);
646
                return;
647
        }
648
 
649
        if (acm->tty)
650
                tty_hangup(acm->tty);
651
}
652
 
653
/*
654
 * USB driver structure.
655
 */
656
 
657
static struct usb_device_id acm_ids[] = {
658
        { USB_DEVICE(0x22B8, 0x1005) },         /* Motorola TimePort 280 */
659
        { USB_DEVICE_INFO(USB_CLASS_COMM, 0, 0) },
660
        { USB_DEVICE_INFO(USB_CLASS_COMM, 2, 0) },
661
        { }
662
};
663
 
664
MODULE_DEVICE_TABLE (usb, acm_ids);
665
 
666
static struct usb_driver acm_driver = {
667
        name:           "acm",
668
        probe:          acm_probe,
669
        disconnect:     acm_disconnect,
670
        id_table:       acm_ids,
671
};
672
 
673
/*
674
 * TTY driver structures.
675
 */
676
 
677
static int acm_tty_refcount;
678
 
679
static struct tty_struct *acm_tty_table[ACM_TTY_MINORS];
680
static struct termios *acm_tty_termios[ACM_TTY_MINORS];
681
static struct termios *acm_tty_termios_locked[ACM_TTY_MINORS];
682
 
683
static struct tty_driver acm_tty_driver = {
684
        magic:                  TTY_DRIVER_MAGIC,
685
        driver_name:            "acm",
686
        name:                   "usb/acm/%d",
687
        major:                  ACM_TTY_MAJOR,
688
        minor_start:            0,
689
        num:                    ACM_TTY_MINORS,
690
        type:                   TTY_DRIVER_TYPE_SERIAL,
691
        subtype:                SERIAL_TYPE_NORMAL,
692
        flags:                  TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
693
 
694
        refcount:               &acm_tty_refcount,
695
 
696
        table:                  acm_tty_table,
697
        termios:                acm_tty_termios,
698
        termios_locked:         acm_tty_termios_locked,
699
 
700
        open:                   acm_tty_open,
701
        close:                  acm_tty_close,
702
        write:                  acm_tty_write,
703
        write_room:             acm_tty_write_room,
704
        ioctl:                  acm_tty_ioctl,
705
        throttle:               acm_tty_throttle,
706
        unthrottle:             acm_tty_unthrottle,
707
        chars_in_buffer:        acm_tty_chars_in_buffer,
708
        break_ctl:              acm_tty_break_ctl,
709
        set_termios:            acm_tty_set_termios
710
};
711
 
712
/*
713
 * Init / exit.
714
 */
715
 
716
static int __init acm_init(void)
717
{
718
        acm_tty_driver.init_termios =           tty_std_termios;
719
        acm_tty_driver.init_termios.c_cflag =   B9600 | CS8 | CREAD | HUPCL | CLOCAL;
720
 
721
        if (tty_register_driver(&acm_tty_driver))
722
                return -1;
723
 
724
        if (usb_register(&acm_driver) < 0) {
725
                tty_unregister_driver(&acm_tty_driver);
726
                return -1;
727
        }
728
 
729
        info(DRIVER_VERSION ":" DRIVER_DESC);
730
 
731
        return 0;
732
}
733
 
734
static void __exit acm_exit(void)
735
{
736
        usb_deregister(&acm_driver);
737
        tty_unregister_driver(&acm_tty_driver);
738
}
739
 
740
module_init(acm_init);
741
module_exit(acm_exit);
742
 
743
MODULE_AUTHOR( DRIVER_AUTHOR );
744
MODULE_DESCRIPTION( DRIVER_DESC );
745
MODULE_LICENSE("GPL");
746
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.