diff options
Diffstat (limited to 'drivers/usb/class')
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 291 |
1 files changed, 160 insertions, 131 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index b4e73aa759d6..ddeb69192537 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
@@ -16,7 +16,8 @@ | |||
16 | * v0.9 - thorough cleaning, URBification, almost a rewrite | 16 | * v0.9 - thorough cleaning, URBification, almost a rewrite |
17 | * v0.10 - some more cleanups | 17 | * v0.10 - some more cleanups |
18 | * v0.11 - fixed flow control, read error doesn't stop reads | 18 | * v0.11 - fixed flow control, read error doesn't stop reads |
19 | * v0.12 - added TIOCM ioctls, added break handling, made struct acm kmalloced | 19 | * v0.12 - added TIOCM ioctls, added break handling, made struct acm |
20 | * kmalloced | ||
20 | * v0.13 - added termios, added hangup | 21 | * v0.13 - added termios, added hangup |
21 | * v0.14 - sized down struct acm | 22 | * v0.14 - sized down struct acm |
22 | * v0.15 - fixed flow control again - characters could be lost | 23 | * v0.15 - fixed flow control again - characters could be lost |
@@ -102,13 +103,15 @@ static const struct tty_port_operations acm_port_ops = { | |||
102 | * Functions for ACM control messages. | 103 | * Functions for ACM control messages. |
103 | */ | 104 | */ |
104 | 105 | ||
105 | static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len) | 106 | static int acm_ctrl_msg(struct acm *acm, int request, int value, |
107 | void *buf, int len) | ||
106 | { | 108 | { |
107 | int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), | 109 | int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), |
108 | request, USB_RT_ACM, value, | 110 | request, USB_RT_ACM, value, |
109 | acm->control->altsetting[0].desc.bInterfaceNumber, | 111 | acm->control->altsetting[0].desc.bInterfaceNumber, |
110 | buf, len, 5000); | 112 | buf, len, 5000); |
111 | dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval); | 113 | dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", |
114 | request, value, len, retval); | ||
112 | return retval < 0 ? retval : 0; | 115 | return retval < 0 ? retval : 0; |
113 | } | 116 | } |
114 | 117 | ||
@@ -153,9 +156,8 @@ static int acm_wb_is_avail(struct acm *acm) | |||
153 | 156 | ||
154 | n = ACM_NW; | 157 | n = ACM_NW; |
155 | spin_lock_irqsave(&acm->write_lock, flags); | 158 | spin_lock_irqsave(&acm->write_lock, flags); |
156 | for (i = 0; i < ACM_NW; i++) { | 159 | for (i = 0; i < ACM_NW; i++) |
157 | n -= acm->wb[i].use; | 160 | n -= acm->wb[i].use; |
158 | } | ||
159 | spin_unlock_irqrestore(&acm->write_lock, flags); | 161 | spin_unlock_irqrestore(&acm->write_lock, flags); |
160 | return n; | 162 | return n; |
161 | } | 163 | } |
@@ -186,7 +188,8 @@ static int acm_start_wb(struct acm *acm, struct acm_wb *wb) | |||
186 | wb->urb->transfer_buffer_length = wb->len; | 188 | wb->urb->transfer_buffer_length = wb->len; |
187 | wb->urb->dev = acm->dev; | 189 | wb->urb->dev = acm->dev; |
188 | 190 | ||
189 | if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) { | 191 | rc = usb_submit_urb(wb->urb, GFP_ATOMIC); |
192 | if (rc < 0) { | ||
190 | dbg("usb_submit_urb(write bulk) failed: %d", rc); | 193 | dbg("usb_submit_urb(write bulk) failed: %d", rc); |
191 | acm_write_done(acm, wb); | 194 | acm_write_done(acm, wb); |
192 | } | 195 | } |
@@ -291,44 +294,45 @@ static void acm_ctrl_irq(struct urb *urb) | |||
291 | 294 | ||
292 | data = (unsigned char *)(dr + 1); | 295 | data = (unsigned char *)(dr + 1); |
293 | switch (dr->bNotificationType) { | 296 | switch (dr->bNotificationType) { |
297 | case USB_CDC_NOTIFY_NETWORK_CONNECTION: | ||
298 | dbg("%s network", dr->wValue ? | ||
299 | "connected to" : "disconnected from"); | ||
300 | break; | ||
294 | 301 | ||
295 | case USB_CDC_NOTIFY_NETWORK_CONNECTION: | 302 | case USB_CDC_NOTIFY_SERIAL_STATE: |
303 | tty = tty_port_tty_get(&acm->port); | ||
304 | newctrl = get_unaligned_le16(data); | ||
296 | 305 | ||
297 | dbg("%s network", dr->wValue ? "connected to" : "disconnected from"); | 306 | if (tty) { |
298 | break; | 307 | if (!acm->clocal && |
299 | 308 | (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { | |
300 | case USB_CDC_NOTIFY_SERIAL_STATE: | 309 | dbg("calling hangup"); |
301 | tty = tty_port_tty_get(&acm->port); | 310 | tty_hangup(tty); |
302 | newctrl = get_unaligned_le16(data); | ||
303 | |||
304 | if (tty) { | ||
305 | if (!acm->clocal && | ||
306 | (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { | ||
307 | dbg("calling hangup"); | ||
308 | tty_hangup(tty); | ||
309 | } | ||
310 | tty_kref_put(tty); | ||
311 | } | 311 | } |
312 | tty_kref_put(tty); | ||
313 | } | ||
312 | 314 | ||
313 | acm->ctrlin = newctrl; | 315 | acm->ctrlin = newctrl; |
314 | |||
315 | dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c", | ||
316 | acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', acm->ctrlin & ACM_CTRL_DSR ? '+' : '-', | ||
317 | acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', acm->ctrlin & ACM_CTRL_RI ? '+' : '-', | ||
318 | acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-', | ||
319 | acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-'); | ||
320 | 316 | ||
317 | dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c", | ||
318 | acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', | ||
319 | acm->ctrlin & ACM_CTRL_DSR ? '+' : '-', | ||
320 | acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', | ||
321 | acm->ctrlin & ACM_CTRL_RI ? '+' : '-', | ||
322 | acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', | ||
323 | acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-', | ||
324 | acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-'); | ||
321 | break; | 325 | break; |
322 | 326 | ||
323 | default: | 327 | default: |
324 | dbg("unknown notification %d received: index %d len %d data0 %d data1 %d", | 328 | dbg("unknown notification %d received: index %d len %d data0 %d data1 %d", |
325 | dr->bNotificationType, dr->wIndex, | 329 | dr->bNotificationType, dr->wIndex, |
326 | dr->wLength, data[0], data[1]); | 330 | dr->wLength, data[0], data[1]); |
327 | break; | 331 | break; |
328 | } | 332 | } |
329 | exit: | 333 | exit: |
330 | usb_mark_last_busy(acm->dev); | 334 | usb_mark_last_busy(acm->dev); |
331 | retval = usb_submit_urb (urb, GFP_ATOMIC); | 335 | retval = usb_submit_urb(urb, GFP_ATOMIC); |
332 | if (retval) | 336 | if (retval) |
333 | dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with " | 337 | dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with " |
334 | "result %d", __func__, retval); | 338 | "result %d", __func__, retval); |
@@ -466,10 +470,11 @@ urbs: | |||
466 | rcv->urb->transfer_dma = buf->dma; | 470 | rcv->urb->transfer_dma = buf->dma; |
467 | rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 471 | rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
468 | 472 | ||
469 | /* This shouldn't kill the driver as unsuccessful URBs are returned to the | 473 | /* This shouldn't kill the driver as unsuccessful URBs are |
470 | free-urbs-pool and resubmited ASAP */ | 474 | returned to the free-urbs-pool and resubmited ASAP */ |
471 | spin_lock_irqsave(&acm->read_lock, flags); | 475 | spin_lock_irqsave(&acm->read_lock, flags); |
472 | if (acm->susp_count || usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) { | 476 | if (acm->susp_count || |
477 | usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) { | ||
473 | list_add(&buf->list, &acm->spare_read_bufs); | 478 | list_add(&buf->list, &acm->spare_read_bufs); |
474 | list_add(&rcv->list, &acm->spare_read_urbs); | 479 | list_add(&rcv->list, &acm->spare_read_urbs); |
475 | acm->processing = 0; | 480 | acm->processing = 0; |
@@ -588,12 +593,11 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
588 | INIT_LIST_HEAD(&acm->spare_read_urbs); | 593 | INIT_LIST_HEAD(&acm->spare_read_urbs); |
589 | INIT_LIST_HEAD(&acm->spare_read_bufs); | 594 | INIT_LIST_HEAD(&acm->spare_read_bufs); |
590 | INIT_LIST_HEAD(&acm->filled_read_bufs); | 595 | INIT_LIST_HEAD(&acm->filled_read_bufs); |
591 | for (i = 0; i < acm->rx_buflimit; i++) { | 596 | |
597 | for (i = 0; i < acm->rx_buflimit; i++) | ||
592 | list_add(&(acm->ru[i].list), &acm->spare_read_urbs); | 598 | list_add(&(acm->ru[i].list), &acm->spare_read_urbs); |
593 | } | 599 | for (i = 0; i < acm->rx_buflimit; i++) |
594 | for (i = 0; i < acm->rx_buflimit; i++) { | ||
595 | list_add(&(acm->rb[i].list), &acm->spare_read_bufs); | 600 | list_add(&(acm->rb[i].list), &acm->spare_read_bufs); |
596 | } | ||
597 | 601 | ||
598 | acm->throttle = 0; | 602 | acm->throttle = 0; |
599 | 603 | ||
@@ -684,7 +688,8 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) | |||
684 | mutex_unlock(&open_mutex); | 688 | mutex_unlock(&open_mutex); |
685 | } | 689 | } |
686 | 690 | ||
687 | static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) | 691 | static int acm_tty_write(struct tty_struct *tty, |
692 | const unsigned char *buf, int count) | ||
688 | { | 693 | { |
689 | struct acm *acm = tty->driver_data; | 694 | struct acm *acm = tty->driver_data; |
690 | int stat; | 695 | int stat; |
@@ -700,7 +705,8 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c | |||
700 | return 0; | 705 | return 0; |
701 | 706 | ||
702 | spin_lock_irqsave(&acm->write_lock, flags); | 707 | spin_lock_irqsave(&acm->write_lock, flags); |
703 | if ((wbn = acm_wb_alloc(acm)) < 0) { | 708 | wbn = acm_wb_alloc(acm); |
709 | if (wbn < 0) { | ||
704 | spin_unlock_irqrestore(&acm->write_lock, flags); | 710 | spin_unlock_irqrestore(&acm->write_lock, flags); |
705 | return 0; | 711 | return 0; |
706 | } | 712 | } |
@@ -712,7 +718,8 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c | |||
712 | wb->len = count; | 718 | wb->len = count; |
713 | spin_unlock_irqrestore(&acm->write_lock, flags); | 719 | spin_unlock_irqrestore(&acm->write_lock, flags); |
714 | 720 | ||
715 | if ((stat = acm_write_start(acm, wbn)) < 0) | 721 | stat = acm_write_start(acm, wbn); |
722 | if (stat < 0) | ||
716 | return stat; | 723 | return stat; |
717 | return count; | 724 | return count; |
718 | } | 725 | } |
@@ -798,8 +805,10 @@ static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file, | |||
798 | return -EINVAL; | 805 | return -EINVAL; |
799 | 806 | ||
800 | newctrl = acm->ctrlout; | 807 | newctrl = acm->ctrlout; |
801 | set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0); | 808 | set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | |
802 | clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0); | 809 | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0); |
810 | clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | | ||
811 | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0); | ||
803 | 812 | ||
804 | newctrl = (newctrl & ~clear) | set; | 813 | newctrl = (newctrl & ~clear) | set; |
805 | 814 | ||
@@ -808,7 +817,8 @@ static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file, | |||
808 | return acm_set_control(acm, acm->ctrlout = newctrl); | 817 | return acm_set_control(acm, acm->ctrlout = newctrl); |
809 | } | 818 | } |
810 | 819 | ||
811 | static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) | 820 | static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, |
821 | unsigned int cmd, unsigned long arg) | ||
812 | { | 822 | { |
813 | struct acm *acm = tty->driver_data; | 823 | struct acm *acm = tty->driver_data; |
814 | 824 | ||
@@ -830,7 +840,8 @@ static const __u8 acm_tty_size[] = { | |||
830 | 5, 6, 7, 8 | 840 | 5, 6, 7, 8 |
831 | }; | 841 | }; |
832 | 842 | ||
833 | static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old) | 843 | static void acm_tty_set_termios(struct tty_struct *tty, |
844 | struct ktermios *termios_old) | ||
834 | { | 845 | { |
835 | struct acm *acm = tty->driver_data; | 846 | struct acm *acm = tty->driver_data; |
836 | struct ktermios *termios = tty->termios; | 847 | struct ktermios *termios = tty->termios; |
@@ -840,19 +851,23 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios | |||
840 | if (!ACM_READY(acm)) | 851 | if (!ACM_READY(acm)) |
841 | return; | 852 | return; |
842 | 853 | ||
854 | /* FIXME: Needs to support the tty_baud interface */ | ||
855 | /* FIXME: Broken on sparc */ | ||
843 | newline.dwDTERate = cpu_to_le32p(acm_tty_speed + | 856 | newline.dwDTERate = cpu_to_le32p(acm_tty_speed + |
844 | (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0)); | 857 | (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0)); |
845 | newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0; | 858 | newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0; |
846 | newline.bParityType = termios->c_cflag & PARENB ? | 859 | newline.bParityType = termios->c_cflag & PARENB ? |
847 | (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0; | 860 | (termios->c_cflag & PARODD ? 1 : 2) + |
861 | (termios->c_cflag & CMSPAR ? 2 : 0) : 0; | ||
848 | newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4]; | 862 | newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4]; |
849 | 863 | /* FIXME: Needs to clear unsupported bits in the termios */ | |
850 | acm->clocal = ((termios->c_cflag & CLOCAL) != 0); | 864 | acm->clocal = ((termios->c_cflag & CLOCAL) != 0); |
851 | 865 | ||
852 | if (!newline.dwDTERate) { | 866 | if (!newline.dwDTERate) { |
853 | newline.dwDTERate = acm->line.dwDTERate; | 867 | newline.dwDTERate = acm->line.dwDTERate; |
854 | newctrl &= ~ACM_CTRL_DTR; | 868 | newctrl &= ~ACM_CTRL_DTR; |
855 | } else newctrl |= ACM_CTRL_DTR; | 869 | } else |
870 | newctrl |= ACM_CTRL_DTR; | ||
856 | 871 | ||
857 | if (newctrl != acm->ctrlout) | 872 | if (newctrl != acm->ctrlout) |
858 | acm_set_control(acm, acm->ctrlout = newctrl); | 873 | acm_set_control(acm, acm->ctrlout = newctrl); |
@@ -877,9 +892,8 @@ static void acm_write_buffers_free(struct acm *acm) | |||
877 | struct acm_wb *wb; | 892 | struct acm_wb *wb; |
878 | struct usb_device *usb_dev = interface_to_usbdev(acm->control); | 893 | struct usb_device *usb_dev = interface_to_usbdev(acm->control); |
879 | 894 | ||
880 | for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) { | 895 | for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) |
881 | usb_buffer_free(usb_dev, acm->writesize, wb->buf, wb->dmah); | 896 | usb_buffer_free(usb_dev, acm->writesize, wb->buf, wb->dmah); |
882 | } | ||
883 | } | 897 | } |
884 | 898 | ||
885 | static void acm_read_buffers_free(struct acm *acm) | 899 | static void acm_read_buffers_free(struct acm *acm) |
@@ -888,7 +902,8 @@ static void acm_read_buffers_free(struct acm *acm) | |||
888 | int i, n = acm->rx_buflimit; | 902 | int i, n = acm->rx_buflimit; |
889 | 903 | ||
890 | for (i = 0; i < n; i++) | 904 | for (i = 0; i < n; i++) |
891 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); | 905 | usb_buffer_free(usb_dev, acm->readsize, |
906 | acm->rb[i].base, acm->rb[i].dma); | ||
892 | } | 907 | } |
893 | 908 | ||
894 | /* Little helper: write buffers allocate */ | 909 | /* Little helper: write buffers allocate */ |
@@ -928,7 +943,7 @@ static int acm_probe(struct usb_interface *intf, | |||
928 | struct usb_device *usb_dev = interface_to_usbdev(intf); | 943 | struct usb_device *usb_dev = interface_to_usbdev(intf); |
929 | struct acm *acm; | 944 | struct acm *acm; |
930 | int minor; | 945 | int minor; |
931 | int ctrlsize,readsize; | 946 | int ctrlsize, readsize; |
932 | u8 *buf; | 947 | u8 *buf; |
933 | u8 ac_management_function = 0; | 948 | u8 ac_management_function = 0; |
934 | u8 call_management_function = 0; | 949 | u8 call_management_function = 0; |
@@ -948,7 +963,7 @@ static int acm_probe(struct usb_interface *intf, | |||
948 | control_interface = usb_ifnum_to_if(usb_dev, 0); | 963 | control_interface = usb_ifnum_to_if(usb_dev, 0); |
949 | goto skip_normal_probe; | 964 | goto skip_normal_probe; |
950 | } | 965 | } |
951 | 966 | ||
952 | /* normal probing*/ | 967 | /* normal probing*/ |
953 | if (!buffer) { | 968 | if (!buffer) { |
954 | dev_err(&intf->dev, "Weird descriptor references\n"); | 969 | dev_err(&intf->dev, "Weird descriptor references\n"); |
@@ -956,8 +971,10 @@ static int acm_probe(struct usb_interface *intf, | |||
956 | } | 971 | } |
957 | 972 | ||
958 | if (!buflen) { | 973 | if (!buflen) { |
959 | if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) { | 974 | if (intf->cur_altsetting->endpoint->extralen && |
960 | dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint\n"); | 975 | intf->cur_altsetting->endpoint->extra) { |
976 | dev_dbg(&intf->dev, | ||
977 | "Seeking extra descriptors on endpoint\n"); | ||
961 | buflen = intf->cur_altsetting->endpoint->extralen; | 978 | buflen = intf->cur_altsetting->endpoint->extralen; |
962 | buffer = intf->cur_altsetting->endpoint->extra; | 979 | buffer = intf->cur_altsetting->endpoint->extra; |
963 | } else { | 980 | } else { |
@@ -968,47 +985,43 @@ static int acm_probe(struct usb_interface *intf, | |||
968 | } | 985 | } |
969 | 986 | ||
970 | while (buflen > 0) { | 987 | while (buflen > 0) { |
971 | if (buffer [1] != USB_DT_CS_INTERFACE) { | 988 | if (buffer[1] != USB_DT_CS_INTERFACE) { |
972 | dev_err(&intf->dev, "skipping garbage\n"); | 989 | dev_err(&intf->dev, "skipping garbage\n"); |
973 | goto next_desc; | 990 | goto next_desc; |
974 | } | 991 | } |
975 | 992 | ||
976 | switch (buffer [2]) { | 993 | switch (buffer[2]) { |
977 | case USB_CDC_UNION_TYPE: /* we've found it */ | 994 | case USB_CDC_UNION_TYPE: /* we've found it */ |
978 | if (union_header) { | 995 | if (union_header) { |
979 | dev_err(&intf->dev, "More than one " | 996 | dev_err(&intf->dev, "More than one " |
980 | "union descriptor, " | 997 | "union descriptor, skipping ...\n"); |
981 | "skipping ...\n"); | 998 | goto next_desc; |
982 | goto next_desc; | ||
983 | } | ||
984 | union_header = (struct usb_cdc_union_desc *) | ||
985 | buffer; | ||
986 | break; | ||
987 | case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ | ||
988 | cfd = (struct usb_cdc_country_functional_desc *)buffer; | ||
989 | break; | ||
990 | case USB_CDC_HEADER_TYPE: /* maybe check version */ | ||
991 | break; /* for now we ignore it */ | ||
992 | case USB_CDC_ACM_TYPE: | ||
993 | ac_management_function = buffer[3]; | ||
994 | break; | ||
995 | case USB_CDC_CALL_MANAGEMENT_TYPE: | ||
996 | call_management_function = buffer[3]; | ||
997 | call_interface_num = buffer[4]; | ||
998 | if ((call_management_function & 3) != 3) | ||
999 | dev_err(&intf->dev, "This device " | ||
1000 | "cannot do calls on its own. " | ||
1001 | "It is no modem.\n"); | ||
1002 | break; | ||
1003 | default: | ||
1004 | /* there are LOTS more CDC descriptors that | ||
1005 | * could legitimately be found here. | ||
1006 | */ | ||
1007 | dev_dbg(&intf->dev, "Ignoring descriptor: " | ||
1008 | "type %02x, length %d\n", | ||
1009 | buffer[2], buffer[0]); | ||
1010 | break; | ||
1011 | } | 999 | } |
1000 | union_header = (struct usb_cdc_union_desc *)buffer; | ||
1001 | break; | ||
1002 | case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ | ||
1003 | cfd = (struct usb_cdc_country_functional_desc *)buffer; | ||
1004 | break; | ||
1005 | case USB_CDC_HEADER_TYPE: /* maybe check version */ | ||
1006 | break; /* for now we ignore it */ | ||
1007 | case USB_CDC_ACM_TYPE: | ||
1008 | ac_management_function = buffer[3]; | ||
1009 | break; | ||
1010 | case USB_CDC_CALL_MANAGEMENT_TYPE: | ||
1011 | call_management_function = buffer[3]; | ||
1012 | call_interface_num = buffer[4]; | ||
1013 | if ((call_management_function & 3) != 3) | ||
1014 | dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n"); | ||
1015 | break; | ||
1016 | default: | ||
1017 | /* there are LOTS more CDC descriptors that | ||
1018 | * could legitimately be found here. | ||
1019 | */ | ||
1020 | dev_dbg(&intf->dev, "Ignoring descriptor: " | ||
1021 | "type %02x, length %d\n", | ||
1022 | buffer[2], buffer[0]); | ||
1023 | break; | ||
1024 | } | ||
1012 | next_desc: | 1025 | next_desc: |
1013 | buflen -= buffer[0]; | 1026 | buflen -= buffer[0]; |
1014 | buffer += buffer[0]; | 1027 | buffer += buffer[0]; |
@@ -1016,33 +1029,36 @@ next_desc: | |||
1016 | 1029 | ||
1017 | if (!union_header) { | 1030 | if (!union_header) { |
1018 | if (call_interface_num > 0) { | 1031 | if (call_interface_num > 0) { |
1019 | dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n"); | 1032 | dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n"); |
1020 | data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); | 1033 | data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); |
1021 | control_interface = intf; | 1034 | control_interface = intf; |
1022 | } else { | 1035 | } else { |
1023 | dev_dbg(&intf->dev,"No union descriptor, giving up\n"); | 1036 | dev_dbg(&intf->dev, |
1037 | "No union descriptor, giving up\n"); | ||
1024 | return -ENODEV; | 1038 | return -ENODEV; |
1025 | } | 1039 | } |
1026 | } else { | 1040 | } else { |
1027 | control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); | 1041 | control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); |
1028 | data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); | 1042 | data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); |
1029 | if (!control_interface || !data_interface) { | 1043 | if (!control_interface || !data_interface) { |
1030 | dev_dbg(&intf->dev,"no interfaces\n"); | 1044 | dev_dbg(&intf->dev, "no interfaces\n"); |
1031 | return -ENODEV; | 1045 | return -ENODEV; |
1032 | } | 1046 | } |
1033 | } | 1047 | } |
1034 | 1048 | ||
1035 | if (data_interface_num != call_interface_num) | 1049 | if (data_interface_num != call_interface_num) |
1036 | dev_dbg(&intf->dev,"Separate call control interface. That is not fully supported.\n"); | 1050 | dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n"); |
1037 | 1051 | ||
1038 | skip_normal_probe: | 1052 | skip_normal_probe: |
1039 | 1053 | ||
1040 | /*workaround for switched interfaces */ | 1054 | /*workaround for switched interfaces */ |
1041 | if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) { | 1055 | if (data_interface->cur_altsetting->desc.bInterfaceClass |
1042 | if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) { | 1056 | != CDC_DATA_INTERFACE_TYPE) { |
1057 | if (control_interface->cur_altsetting->desc.bInterfaceClass | ||
1058 | == CDC_DATA_INTERFACE_TYPE) { | ||
1043 | struct usb_interface *t; | 1059 | struct usb_interface *t; |
1044 | dev_dbg(&intf->dev,"Your device has switched interfaces.\n"); | 1060 | dev_dbg(&intf->dev, |
1045 | 1061 | "Your device has switched interfaces.\n"); | |
1046 | t = control_interface; | 1062 | t = control_interface; |
1047 | control_interface = data_interface; | 1063 | control_interface = data_interface; |
1048 | data_interface = t; | 1064 | data_interface = t; |
@@ -1054,9 +1070,9 @@ skip_normal_probe: | |||
1054 | /* Accept probe requests only for the control interface */ | 1070 | /* Accept probe requests only for the control interface */ |
1055 | if (intf != control_interface) | 1071 | if (intf != control_interface) |
1056 | return -ENODEV; | 1072 | return -ENODEV; |
1057 | 1073 | ||
1058 | if (usb_interface_claimed(data_interface)) { /* valid in this context */ | 1074 | if (usb_interface_claimed(data_interface)) { /* valid in this context */ |
1059 | dev_dbg(&intf->dev,"The data interface isn't available\n"); | 1075 | dev_dbg(&intf->dev, "The data interface isn't available\n"); |
1060 | return -EBUSY; | 1076 | return -EBUSY; |
1061 | } | 1077 | } |
1062 | 1078 | ||
@@ -1073,8 +1089,8 @@ skip_normal_probe: | |||
1073 | if (!usb_endpoint_dir_in(epread)) { | 1089 | if (!usb_endpoint_dir_in(epread)) { |
1074 | /* descriptors are swapped */ | 1090 | /* descriptors are swapped */ |
1075 | struct usb_endpoint_descriptor *t; | 1091 | struct usb_endpoint_descriptor *t; |
1076 | dev_dbg(&intf->dev,"The data interface has switched endpoints\n"); | 1092 | dev_dbg(&intf->dev, |
1077 | 1093 | "The data interface has switched endpoints\n"); | |
1078 | t = epread; | 1094 | t = epread; |
1079 | epread = epwrite; | 1095 | epread = epwrite; |
1080 | epwrite = t; | 1096 | epwrite = t; |
@@ -1087,13 +1103,15 @@ skip_normal_probe: | |||
1087 | return -ENODEV; | 1103 | return -ENODEV; |
1088 | } | 1104 | } |
1089 | 1105 | ||
1090 | if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) { | 1106 | acm = kzalloc(sizeof(struct acm), GFP_KERNEL); |
1107 | if (acm == NULL) { | ||
1091 | dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n"); | 1108 | dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n"); |
1092 | goto alloc_fail; | 1109 | goto alloc_fail; |
1093 | } | 1110 | } |
1094 | 1111 | ||
1095 | ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); | 1112 | ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); |
1096 | readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2); | 1113 | readsize = le16_to_cpu(epread->wMaxPacketSize) * |
1114 | (quirks == SINGLE_RX_URB ? 1 : 2); | ||
1097 | acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20; | 1115 | acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20; |
1098 | acm->control = control_interface; | 1116 | acm->control = control_interface; |
1099 | acm->data = data_interface; | 1117 | acm->data = data_interface; |
@@ -1136,8 +1154,10 @@ skip_normal_probe: | |||
1136 | for (i = 0; i < num_rx_buf; i++) { | 1154 | for (i = 0; i < num_rx_buf; i++) { |
1137 | struct acm_ru *rcv = &(acm->ru[i]); | 1155 | struct acm_ru *rcv = &(acm->ru[i]); |
1138 | 1156 | ||
1139 | if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) { | 1157 | rcv->urb = usb_alloc_urb(0, GFP_KERNEL); |
1140 | dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n"); | 1158 | if (rcv->urb == NULL) { |
1159 | dev_dbg(&intf->dev, | ||
1160 | "out of memory (read urbs usb_alloc_urb)\n"); | ||
1141 | goto alloc_fail7; | 1161 | goto alloc_fail7; |
1142 | } | 1162 | } |
1143 | 1163 | ||
@@ -1150,26 +1170,29 @@ skip_normal_probe: | |||
1150 | rb->base = usb_buffer_alloc(acm->dev, readsize, | 1170 | rb->base = usb_buffer_alloc(acm->dev, readsize, |
1151 | GFP_KERNEL, &rb->dma); | 1171 | GFP_KERNEL, &rb->dma); |
1152 | if (!rb->base) { | 1172 | if (!rb->base) { |
1153 | dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n"); | 1173 | dev_dbg(&intf->dev, |
1174 | "out of memory (read bufs usb_buffer_alloc)\n"); | ||
1154 | goto alloc_fail7; | 1175 | goto alloc_fail7; |
1155 | } | 1176 | } |
1156 | } | 1177 | } |
1157 | for(i = 0; i < ACM_NW; i++) | 1178 | for (i = 0; i < ACM_NW; i++) { |
1158 | { | ||
1159 | struct acm_wb *snd = &(acm->wb[i]); | 1179 | struct acm_wb *snd = &(acm->wb[i]); |
1160 | 1180 | ||
1161 | if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) { | 1181 | snd->urb = usb_alloc_urb(0, GFP_KERNEL); |
1162 | dev_dbg(&intf->dev, "out of memory (write urbs usb_alloc_urb)"); | 1182 | if (snd->urb == NULL) { |
1183 | dev_dbg(&intf->dev, | ||
1184 | "out of memory (write urbs usb_alloc_urb)"); | ||
1163 | goto alloc_fail7; | 1185 | goto alloc_fail7; |
1164 | } | 1186 | } |
1165 | 1187 | ||
1166 | usb_fill_bulk_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), | 1188 | usb_fill_bulk_urb(snd->urb, usb_dev, |
1167 | NULL, acm->writesize, acm_write_bulk, snd); | 1189 | usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), |
1190 | NULL, acm->writesize, acm_write_bulk, snd); | ||
1168 | snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 1191 | snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
1169 | snd->instance = acm; | 1192 | snd->instance = acm; |
1170 | } | 1193 | } |
1171 | 1194 | ||
1172 | usb_set_intfdata (intf, acm); | 1195 | usb_set_intfdata(intf, acm); |
1173 | 1196 | ||
1174 | i = device_create_file(&intf->dev, &dev_attr_bmCapabilities); | 1197 | i = device_create_file(&intf->dev, &dev_attr_bmCapabilities); |
1175 | if (i < 0) | 1198 | if (i < 0) |
@@ -1180,7 +1203,8 @@ skip_normal_probe: | |||
1180 | if (!acm->country_codes) | 1203 | if (!acm->country_codes) |
1181 | goto skip_countries; | 1204 | goto skip_countries; |
1182 | acm->country_code_size = cfd->bLength - 4; | 1205 | acm->country_code_size = cfd->bLength - 4; |
1183 | memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4); | 1206 | memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, |
1207 | cfd->bLength - 4); | ||
1184 | acm->country_rel_date = cfd->iCountryCodeRelDate; | 1208 | acm->country_rel_date = cfd->iCountryCodeRelDate; |
1185 | 1209 | ||
1186 | i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); | 1210 | i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); |
@@ -1189,7 +1213,8 @@ skip_normal_probe: | |||
1189 | goto skip_countries; | 1213 | goto skip_countries; |
1190 | } | 1214 | } |
1191 | 1215 | ||
1192 | i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate); | 1216 | i = device_create_file(&intf->dev, |
1217 | &dev_attr_iCountryCodeRelDate); | ||
1193 | if (i < 0) { | 1218 | if (i < 0) { |
1194 | kfree(acm->country_codes); | 1219 | kfree(acm->country_codes); |
1195 | goto skip_countries; | 1220 | goto skip_countries; |
@@ -1197,8 +1222,10 @@ skip_normal_probe: | |||
1197 | } | 1222 | } |
1198 | 1223 | ||
1199 | skip_countries: | 1224 | skip_countries: |
1200 | usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), | 1225 | usb_fill_int_urb(acm->ctrlurb, usb_dev, |
1201 | acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); | 1226 | usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), |
1227 | acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, | ||
1228 | epctrl->bInterval); | ||
1202 | acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 1229 | acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
1203 | acm->ctrlurb->transfer_dma = acm->ctrl_dma; | 1230 | acm->ctrlurb->transfer_dma = acm->ctrl_dma; |
1204 | 1231 | ||
@@ -1245,7 +1272,7 @@ static void stop_data_traffic(struct acm *acm) | |||
1245 | tasklet_disable(&acm->urb_task); | 1272 | tasklet_disable(&acm->urb_task); |
1246 | 1273 | ||
1247 | usb_kill_urb(acm->ctrlurb); | 1274 | usb_kill_urb(acm->ctrlurb); |
1248 | for(i = 0; i < ACM_NW; i++) | 1275 | for (i = 0; i < ACM_NW; i++) |
1249 | usb_kill_urb(acm->wb[i].urb); | 1276 | usb_kill_urb(acm->wb[i].urb); |
1250 | for (i = 0; i < acm->rx_buflimit; i++) | 1277 | for (i = 0; i < acm->rx_buflimit; i++) |
1251 | usb_kill_urb(acm->ru[i].urb); | 1278 | usb_kill_urb(acm->ru[i].urb); |
@@ -1267,7 +1294,7 @@ static void acm_disconnect(struct usb_interface *intf) | |||
1267 | return; | 1294 | return; |
1268 | 1295 | ||
1269 | mutex_lock(&open_mutex); | 1296 | mutex_lock(&open_mutex); |
1270 | if (acm->country_codes){ | 1297 | if (acm->country_codes) { |
1271 | device_remove_file(&acm->control->dev, | 1298 | device_remove_file(&acm->control->dev, |
1272 | &dev_attr_wCountryCodes); | 1299 | &dev_attr_wCountryCodes); |
1273 | device_remove_file(&acm->control->dev, | 1300 | device_remove_file(&acm->control->dev, |
@@ -1281,7 +1308,8 @@ static void acm_disconnect(struct usb_interface *intf) | |||
1281 | stop_data_traffic(acm); | 1308 | stop_data_traffic(acm); |
1282 | 1309 | ||
1283 | acm_write_buffers_free(acm); | 1310 | acm_write_buffers_free(acm); |
1284 | usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); | 1311 | usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, |
1312 | acm->ctrl_dma); | ||
1285 | acm_read_buffers_free(acm); | 1313 | acm_read_buffers_free(acm); |
1286 | 1314 | ||
1287 | usb_driver_release_interface(&acm_driver, intf == acm->control ? | 1315 | usb_driver_release_interface(&acm_driver, intf == acm->control ? |
@@ -1434,7 +1462,7 @@ static struct usb_device_id acm_ids[] = { | |||
1434 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, | 1462 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, |
1435 | USB_CDC_ACM_PROTO_AT_GSM) }, | 1463 | USB_CDC_ACM_PROTO_AT_GSM) }, |
1436 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, | 1464 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, |
1437 | USB_CDC_ACM_PROTO_AT_3G ) }, | 1465 | USB_CDC_ACM_PROTO_AT_3G) }, |
1438 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, | 1466 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, |
1439 | USB_CDC_ACM_PROTO_AT_CDMA) }, | 1467 | USB_CDC_ACM_PROTO_AT_CDMA) }, |
1440 | 1468 | ||
@@ -1442,7 +1470,7 @@ static struct usb_device_id acm_ids[] = { | |||
1442 | { } | 1470 | { } |
1443 | }; | 1471 | }; |
1444 | 1472 | ||
1445 | MODULE_DEVICE_TABLE (usb, acm_ids); | 1473 | MODULE_DEVICE_TABLE(usb, acm_ids); |
1446 | 1474 | ||
1447 | static struct usb_driver acm_driver = { | 1475 | static struct usb_driver acm_driver = { |
1448 | .name = "cdc_acm", | 1476 | .name = "cdc_acm", |
@@ -1497,7 +1525,8 @@ static int __init acm_init(void) | |||
1497 | acm_tty_driver->subtype = SERIAL_TYPE_NORMAL, | 1525 | acm_tty_driver->subtype = SERIAL_TYPE_NORMAL, |
1498 | acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; | 1526 | acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; |
1499 | acm_tty_driver->init_termios = tty_std_termios; | 1527 | acm_tty_driver->init_termios = tty_std_termios; |
1500 | acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; | 1528 | acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | |
1529 | HUPCL | CLOCAL; | ||
1501 | tty_set_operations(acm_tty_driver, &acm_ops); | 1530 | tty_set_operations(acm_tty_driver, &acm_ops); |
1502 | 1531 | ||
1503 | retval = tty_register_driver(acm_tty_driver); | 1532 | retval = tty_register_driver(acm_tty_driver); |
@@ -1529,7 +1558,7 @@ static void __exit acm_exit(void) | |||
1529 | module_init(acm_init); | 1558 | module_init(acm_init); |
1530 | module_exit(acm_exit); | 1559 | module_exit(acm_exit); |
1531 | 1560 | ||
1532 | MODULE_AUTHOR( DRIVER_AUTHOR ); | 1561 | MODULE_AUTHOR(DRIVER_AUTHOR); |
1533 | MODULE_DESCRIPTION( DRIVER_DESC ); | 1562 | MODULE_DESCRIPTION(DRIVER_DESC); |
1534 | MODULE_LICENSE("GPL"); | 1563 | MODULE_LICENSE("GPL"); |
1535 | MODULE_ALIAS_CHARDEV_MAJOR(ACM_TTY_MAJOR); | 1564 | MODULE_ALIAS_CHARDEV_MAJOR(ACM_TTY_MAJOR); |