11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cdc-acm.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 1999 Armin Fuerst <fuerst@in.tum.de> 5a2531293dbb7608fa672ff28efe3ab4027917a2fPavel Machek * Copyright (c) 1999 Pavel Machek <pavel@ucw.cz> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 1999 Johannes Erdfelt <johannes@erdfelt.com> 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz> 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2004 Oliver Neukum <oliver@neukum.name> 961a87adf2e7b410da8e41799c61c21a7b8c8b001David Kubicek * Copyright (c) 2005 David Kubicek <dave@awk.cz> 10088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold * Copyright (c) 2011 Johan Hovold <jhovold@gmail.com> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * USB Abstract Control Model driver for USB modems and ISDN adapters 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Sponsored by SuSE 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef DEBUG 32e5fbab51b4219fbd1dab28666affe38a920b5f7eDavid Brownell#undef VERBOSE_DEBUG 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 397af25b4b34a2439020d78da765a3bed0ff73f25cOliver Neukum#include <linux/serial.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h> 4218c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum#include <linux/serial.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 444186ecf8ad16dd05759a09594de6a87e48759ba6Arjan van de Ven#include <linux/mutex.h> 4510077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox#include <linux/uaccess.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h> 47a8c28f2389942bab376e39351d27525499630248David Brownell#include <linux/usb/cdc.h> 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/unaligned.h> 5061a87adf2e7b410da8e41799c61c21a7b8c8b001David Kubicek#include <linux/list.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "cdc-acm.h" 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54e5fbab51b4219fbd1dab28666affe38a920b5f7eDavid Brownell 55088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek, Johan Hovold" 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters" 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver acm_driver; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct tty_driver *acm_tty_driver; 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct acm *acm_table[ACM_TTY_MINORS]; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 627fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoenstatic DEFINE_MUTEX(acm_table_lock); 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 647fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen/* 657fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen * acm_table accessors 667fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen */ 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 687fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen/* 697fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen * Look up an ACM structure by index. If found and not disconnected, increment 707fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen * its refcount and return it with its mutex held. 717fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen */ 727fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoenstatic struct acm *acm_get_by_index(unsigned index) 737fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen{ 747fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen struct acm *acm; 757fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 767fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen mutex_lock(&acm_table_lock); 777fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen acm = acm_table[index]; 787fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen if (acm) { 797fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen mutex_lock(&acm->mutex); 807fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen if (acm->disconnected) { 817fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen mutex_unlock(&acm->mutex); 827fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen acm = NULL; 837fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen } else { 847fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen tty_port_get(&acm->port); 857fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen mutex_unlock(&acm->mutex); 867fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen } 877fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen } 887fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen mutex_unlock(&acm_table_lock); 897fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen return acm; 907fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen} 917fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 927fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen/* 937fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen * Try to find an available minor number and if found, associate it with 'acm'. 947fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen */ 957fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoenstatic int acm_alloc_minor(struct acm *acm) 967fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen{ 977fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen int minor; 987fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 997fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen mutex_lock(&acm_table_lock); 1007fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen for (minor = 0; minor < ACM_TTY_MINORS; minor++) { 1017fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen if (!acm_table[minor]) { 1027fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen acm_table[minor] = acm; 1037fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen break; 1047fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen } 1057fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen } 1067fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen mutex_unlock(&acm_table_lock); 1077fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 1087fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen return minor; 1097fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen} 1107fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 1117fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen/* Release the minor number associated with 'acm'. */ 1127fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoenstatic void acm_release_minor(struct acm *acm) 1137fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen{ 1147fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen mutex_lock(&acm_table_lock); 1157fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen acm_table[acm->minor] = NULL; 1167fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen mutex_unlock(&acm_table_lock); 1177fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen} 118739e0285cbb162c8ddd0061fda581ee54a34c19aAlan Cox 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Functions for ACM control messages. 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1236e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Coxstatic int acm_ctrl_msg(struct acm *acm, int request, int value, 1246e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox void *buf, int len) 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request, USB_RT_ACM, value, 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm->control->altsetting[0].desc.bInterfaceNumber, 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf, len, 5000); 130a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold dev_dbg(&acm->control->dev, 131a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold "%s - rq 0x%02x, val %#x, len %#x, result %d\n", 132a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold __func__, request, value, len, retval); 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval < 0 ? retval : 0; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* devices aren't required to support these requests. 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the cdc acm descriptor tells whether they do... 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define acm_set_control(acm, control) \ 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm_ctrl_msg(acm, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0) 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define acm_set_line(acm, line) \ 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm_ctrl_msg(acm, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line)) 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define acm_send_break(acm, ms) \ 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0) 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 147884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum * Write buffer management. 148884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum * All of these assume proper locks taken by the caller. 149884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum */ 150884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum 151884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukumstatic int acm_wb_alloc(struct acm *acm) 152884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum{ 153884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum int i, wbn; 154884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum struct acm_wb *wb; 155884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum 156e4cf3aa8f9cd6ee4d583b5d445b5c152acefcde4David Engraf wbn = 0; 157884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum i = 0; 158884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum for (;;) { 159884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum wb = &acm->wb[wbn]; 160884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum if (!wb->use) { 161884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum wb->use = 1; 162884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum return wbn; 163884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum } 16486478944eba887f149e151bacc023ae4b2d23ea6Oliver Neukum wbn = (wbn + 1) % ACM_NW; 16586478944eba887f149e151bacc023ae4b2d23ea6Oliver Neukum if (++i >= ACM_NW) 166884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum return -1; 167884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum } 168884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum} 169884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum 170884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukumstatic int acm_wb_is_avail(struct acm *acm) 171884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum{ 172884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum int i, n; 173e5fbab51b4219fbd1dab28666affe38a920b5f7eDavid Brownell unsigned long flags; 174884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum 17586478944eba887f149e151bacc023ae4b2d23ea6Oliver Neukum n = ACM_NW; 176e5fbab51b4219fbd1dab28666affe38a920b5f7eDavid Brownell spin_lock_irqsave(&acm->write_lock, flags); 1776e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox for (i = 0; i < ACM_NW; i++) 17886478944eba887f149e151bacc023ae4b2d23ea6Oliver Neukum n -= acm->wb[i].use; 179e5fbab51b4219fbd1dab28666affe38a920b5f7eDavid Brownell spin_unlock_irqrestore(&acm->write_lock, flags); 180884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum return n; 181884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum} 182884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum 183884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum/* 184ad0b65efd12d020b046cde8d6f474e37bb98dd73Brandon Philips * Finish write. Caller must hold acm->write_lock 185884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum */ 186e4cf3aa8f9cd6ee4d583b5d445b5c152acefcde4David Engrafstatic void acm_write_done(struct acm *acm, struct acm_wb *wb) 187884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum{ 188e4cf3aa8f9cd6ee4d583b5d445b5c152acefcde4David Engraf wb->use = 0; 18911ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum acm->transmitting--; 19097d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum usb_autopm_put_interface_async(acm->control); 191884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum} 192884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum 193884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum/* 194884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum * Poke write. 19511ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum * 19611ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum * the caller is responsible for locking 197884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum */ 19811ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum 19911ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukumstatic int acm_start_wb(struct acm *acm, struct acm_wb *wb) 20011ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum{ 20111ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum int rc; 20211ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum 20311ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum acm->transmitting++; 20411ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum 20511ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum wb->urb->transfer_buffer = wb->buf; 20611ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum wb->urb->transfer_dma = wb->dmah; 20711ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum wb->urb->transfer_buffer_length = wb->len; 20811ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum wb->urb->dev = acm->dev; 20911ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum 2106e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox rc = usb_submit_urb(wb->urb, GFP_ATOMIC); 2116e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox if (rc < 0) { 212a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold dev_err(&acm->data->dev, 213a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold "%s - usb_submit_urb(write bulk) failed: %d\n", 214a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold __func__, rc); 21511ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum acm_write_done(acm, wb); 21611ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum } 21711ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum return rc; 21811ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum} 21911ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum 220e4cf3aa8f9cd6ee4d583b5d445b5c152acefcde4David Engrafstatic int acm_write_start(struct acm *acm, int wbn) 221884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum{ 222884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum unsigned long flags; 223934da4635c2d05cef474e5243ef05df95b2ad264David Brownell struct acm_wb *wb = &acm->wb[wbn]; 224884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum int rc; 225884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum 226884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum spin_lock_irqsave(&acm->write_lock, flags); 227884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum if (!acm->dev) { 228934da4635c2d05cef474e5243ef05df95b2ad264David Brownell wb->use = 0; 229884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum spin_unlock_irqrestore(&acm->write_lock, flags); 230884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum return -ENODEV; 231884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum } 232884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum 2335e9e75f8bd97864d552ec2b8d1a00e2b3012a6b3Johan Hovold dev_vdbg(&acm->data->dev, "%s - susp_count %d\n", __func__, 234a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold acm->susp_count); 23597d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum usb_autopm_get_interface_async(acm->control); 23611ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum if (acm->susp_count) { 23797d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum if (!acm->delayed_wb) 23897d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum acm->delayed_wb = wb; 23997d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum else 24097d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum usb_autopm_put_interface_async(acm->control); 24111ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum spin_unlock_irqrestore(&acm->write_lock, flags); 24211ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum return 0; /* A white lie */ 24311ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum } 24411ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum usb_mark_last_busy(acm->dev); 24511ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum 24611ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum rc = acm_start_wb(acm, wb); 247884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum spin_unlock_irqrestore(&acm->write_lock, flags); 248884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum 249884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum return rc; 25011ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum 251884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum} 252c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum/* 253c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum * attributes exported through sysfs 254c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum */ 255c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukumstatic ssize_t show_caps 256c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum(struct device *dev, struct device_attribute *attr, char *buf) 257c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum{ 258c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum struct usb_interface *intf = to_usb_interface(dev); 259c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum struct acm *acm = usb_get_intfdata(intf); 260c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum 261c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum return sprintf(buf, "%d", acm->ctrl_caps); 262c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum} 263c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukumstatic DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL); 264c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum 265c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukumstatic ssize_t show_country_codes 266c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum(struct device *dev, struct device_attribute *attr, char *buf) 267c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum{ 268c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum struct usb_interface *intf = to_usb_interface(dev); 269c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum struct acm *acm = usb_get_intfdata(intf); 270c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum 271c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum memcpy(buf, acm->country_codes, acm->country_code_size); 272c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum return acm->country_code_size; 273c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum} 274c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum 275c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukumstatic DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL); 276c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum 277c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukumstatic ssize_t show_country_rel_date 278c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum(struct device *dev, struct device_attribute *attr, char *buf) 279c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum{ 280c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum struct usb_interface *intf = to_usb_interface(dev); 281c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum struct acm *acm = usb_get_intfdata(intf); 282c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum 283c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum return sprintf(buf, "%d", acm->country_rel_date); 284c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum} 285884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum 286c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukumstatic DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL); 287884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum/* 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Interrupt handlers for various ACM device responses 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* control interface reports status changes with "interrupt" transfers */ 2927d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void acm_ctrl_irq(struct urb *urb) 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acm *acm = urb->context; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_cdc_notification *dr = urb->transfer_buffer; 29610077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox struct tty_struct *tty; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int newctrl; 299185d40587d22fe604962fb53c0c9a9f1670feb66Greg Kroah-Hartman int retval; 300185d40587d22fe604962fb53c0c9a9f1670feb66Greg Kroah-Hartman int status = urb->status; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 302185d40587d22fe604962fb53c0c9a9f1670feb66Greg Kroah-Hartman switch (status) { 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* success */ 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ECONNRESET: 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ENOENT: 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ESHUTDOWN: 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* this urb is terminated, clean up */ 310a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold dev_dbg(&acm->control->dev, 311a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold "%s - urb shutting down with status: %d\n", 312a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold __func__, status); 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 315a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold dev_dbg(&acm->control->dev, 316a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold "%s - nonzero urb status received: %d\n", 317a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold __func__, status); 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3217e7797e7f6f7bfab73fca02c65e40eaa5bb9000cJohan Hovold usb_mark_last_busy(acm->dev); 3227e7797e7f6f7bfab73fca02c65e40eaa5bb9000cJohan Hovold 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = (unsigned char *)(dr + 1); 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dr->bNotificationType) { 3256e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox case USB_CDC_NOTIFY_NETWORK_CONNECTION: 326a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold dev_dbg(&acm->control->dev, "%s - network connection: %d\n", 327a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold __func__, dr->wValue); 3286e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox break; 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3306e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox case USB_CDC_NOTIFY_SERIAL_STATE: 3316e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox tty = tty_port_tty_get(&acm->port); 3326e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox newctrl = get_unaligned_le16(data); 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3346e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox if (tty) { 3356e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox if (!acm->clocal && 3366e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { 337a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold dev_dbg(&acm->control->dev, 338a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold "%s - calling hangup\n", __func__); 3396e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox tty_hangup(tty); 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3416e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox tty_kref_put(tty); 3426e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox } 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3446e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox acm->ctrlin = newctrl; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 346a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold dev_dbg(&acm->control->dev, 347a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold "%s - input control lines: dcd%c dsr%c break%c " 348a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold "ring%c framing%c parity%c overrun%c\n", 349a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold __func__, 3506e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', 3516e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox acm->ctrlin & ACM_CTRL_DSR ? '+' : '-', 3526e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', 3536e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox acm->ctrlin & ACM_CTRL_RI ? '+' : '-', 3546e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', 3556e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-', 3566e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-'); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3596e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox default: 360a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold dev_dbg(&acm->control->dev, 361a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold "%s - unknown notification %d received: index %d " 362a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold "len %d data0 %d data1 %d\n", 363a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold __func__, 3646e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox dr->bNotificationType, dr->wIndex, 3656e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox dr->wLength, data[0], data[1]); 3666e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox break; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 3696e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox retval = usb_submit_urb(urb, GFP_ATOMIC); 370185d40587d22fe604962fb53c0c9a9f1670feb66Greg Kroah-Hartman if (retval) 3711d9846e505febb71255b098910ace741433312b7Johan Hovold dev_err(&acm->control->dev, "%s - usb_submit_urb failed: %d\n", 3721d9846e505febb71255b098910ace741433312b7Johan Hovold __func__, retval); 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 375088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovoldstatic int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags) 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 377088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold int res; 378185d40587d22fe604962fb53c0c9a9f1670feb66Greg Kroah-Hartman 379088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold if (!test_and_clear_bit(index, &acm->read_urbs_free)) 380088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold return 0; 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 382088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold dev_vdbg(&acm->data->dev, "%s - urb %d\n", __func__, index); 383088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold 384088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold res = usb_submit_urb(acm->read_urbs[index], mem_flags); 385088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold if (res) { 386088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold if (res != -EPERM) { 387088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold dev_err(&acm->data->dev, 388088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold "%s - usb_submit_urb failed: %d\n", 389088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold __func__, res); 390088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold } 391088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold set_bit(index, &acm->read_urbs_free); 392088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold return res; 39311ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum } 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 395088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold return 0; 396088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold} 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 398088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovoldstatic int acm_submit_read_urbs(struct acm *acm, gfp_t mem_flags) 399088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold{ 400088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold int res; 401088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold int i; 40261a87adf2e7b410da8e41799c61c21a7b8c8b001David Kubicek 403088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold for (i = 0; i < acm->rx_buflimit; ++i) { 404088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold res = acm_submit_read_urb(acm, i, mem_flags); 405088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold if (res) 406088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold return res; 40786478944eba887f149e151bacc023ae4b2d23ea6Oliver Neukum } 408088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold 409088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold return 0; 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 412088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovoldstatic void acm_process_read_urb(struct acm *acm, struct urb *urb) 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 41410077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox struct tty_struct *tty; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 416088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold if (!urb->actual_length) 417ca79b7b4158cbf32625793a1fc1d59ac46d44197Oliver Neukum return; 41861a87adf2e7b410da8e41799c61c21a7b8c8b001David Kubicek 41910077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox tty = tty_port_tty_get(&acm->port); 420088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold if (!tty) 421088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold return; 42210077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox 423088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold tty_insert_flip_string(tty, urb->transfer_buffer, urb->actual_length); 424088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold tty_flip_buffer_push(tty); 42561a87adf2e7b410da8e41799c61c21a7b8c8b001David Kubicek 42610077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox tty_kref_put(tty); 427088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold} 42810077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox 429088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovoldstatic void acm_read_bulk_callback(struct urb *urb) 430088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold{ 431088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold struct acm_rb *rb = urb->context; 432088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold struct acm *acm = rb->instance; 433088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold unsigned long flags; 43461a87adf2e7b410da8e41799c61c21a7b8c8b001David Kubicek 435088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold dev_vdbg(&acm->data->dev, "%s - urb %d, len %d\n", __func__, 436088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold rb->index, urb->actual_length); 437088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold set_bit(rb->index, &acm->read_urbs_free); 43861a87adf2e7b410da8e41799c61c21a7b8c8b001David Kubicek 439088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold if (!acm->dev) { 440088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__); 441088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold return; 442088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold } 443088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold usb_mark_last_busy(acm->dev); 44461a87adf2e7b410da8e41799c61c21a7b8c8b001David Kubicek 445088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold if (urb->status) { 446088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n", 447088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold __func__, urb->status); 448088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold return; 44961a87adf2e7b410da8e41799c61c21a7b8c8b001David Kubicek } 450088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold acm_process_read_urb(acm, urb); 451088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold 452088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold /* throttle device if requested by tty */ 45311ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum spin_lock_irqsave(&acm->read_lock, flags); 454088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold acm->throttled = acm->throttle_req; 455088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold if (!acm->throttled && !acm->susp_count) { 456088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold spin_unlock_irqrestore(&acm->read_lock, flags); 457088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold acm_submit_read_urb(acm, rb->index, GFP_ATOMIC); 458088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold } else { 459088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold spin_unlock_irqrestore(&acm->read_lock, flags); 460088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold } 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* data interface wrote those outgoing bytes */ 4647d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void acm_write_bulk(struct urb *urb) 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 466cdc97792289179974af6dda781c855696358d307Ming Lei struct acm_wb *wb = urb->context; 467e5fbab51b4219fbd1dab28666affe38a920b5f7eDavid Brownell struct acm *acm = wb->instance; 468ad0b65efd12d020b046cde8d6f474e37bb98dd73Brandon Philips unsigned long flags; 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4704fa4626cd43679dc62a73ee3e347665e761abc9cJohan Hovold if (urb->status || (urb->actual_length != urb->transfer_buffer_length)) 4714fa4626cd43679dc62a73ee3e347665e761abc9cJohan Hovold dev_vdbg(&acm->data->dev, "%s - len %d/%d, status %d\n", 4721d9846e505febb71255b098910ace741433312b7Johan Hovold __func__, 473e5fbab51b4219fbd1dab28666affe38a920b5f7eDavid Brownell urb->actual_length, 474e5fbab51b4219fbd1dab28666affe38a920b5f7eDavid Brownell urb->transfer_buffer_length, 475e5fbab51b4219fbd1dab28666affe38a920b5f7eDavid Brownell urb->status); 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 477ad0b65efd12d020b046cde8d6f474e37bb98dd73Brandon Philips spin_lock_irqsave(&acm->write_lock, flags); 478e4cf3aa8f9cd6ee4d583b5d445b5c152acefcde4David Engraf acm_write_done(acm, wb); 479ad0b65efd12d020b046cde8d6f474e37bb98dd73Brandon Philips spin_unlock_irqrestore(&acm->write_lock, flags); 48099823f457d5994b3bd3775515578c8bfacc64b04Havard Skinnemoen schedule_work(&acm->work); 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 483c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void acm_softint(struct work_struct *work) 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 485c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells struct acm *acm = container_of(work, struct acm, work); 48610077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox struct tty_struct *tty; 487e5fbab51b4219fbd1dab28666affe38a920b5f7eDavid Brownell 4881d9846e505febb71255b098910ace741433312b7Johan Hovold dev_vdbg(&acm->data->dev, "%s\n", __func__); 4891d9846e505febb71255b098910ace741433312b7Johan Hovold 49010077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox tty = tty_port_tty_get(&acm->port); 49115e5bee33ffc11d0e5c6f819a65e7881c5c407beJohan Hovold if (!tty) 49215e5bee33ffc11d0e5c6f819a65e7881c5c407beJohan Hovold return; 49310077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox tty_wakeup(tty); 49410077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox tty_kref_put(tty); 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * TTY handlers 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5017fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoenstatic int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty) 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acm *acm; 5047fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen int retval; 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5067fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen dev_dbg(tty->dev, "%s\n", __func__); 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5087fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen acm = acm_get_by_index(tty->index); 5097fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen if (!acm) 5107fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen return -ENODEV; 511a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold 512f8a8c10f4a662dcf3cb621d7a3eba564c5963284Jiri Slaby retval = tty_standard_install(driver, tty); 5137fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen if (retval) 5147fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen goto error_init_termios; 51510077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty->driver_data = acm; 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5187fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen return 0; 5197fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 5207fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoenerror_init_termios: 5217fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen tty_port_put(&acm->port); 5227fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen return retval; 5237fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen} 5247fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 5257fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoenstatic int acm_tty_open(struct tty_struct *tty, struct file *filp) 5267fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen{ 5277fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen struct acm *acm = tty->driver_data; 5287fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 5297fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen dev_dbg(tty->dev, "%s\n", __func__); 5307fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 5317fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen return tty_port_open(&acm->port, tty, filp); 5327fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen} 5337fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 5347fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoenstatic int acm_port_activate(struct tty_port *port, struct tty_struct *tty) 5357fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen{ 5367fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen struct acm *acm = container_of(port, struct acm, port); 5377fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen int retval = -ENODEV; 5387fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 5397fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen dev_dbg(&acm->control->dev, "%s\n", __func__); 5401365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum 5411365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum mutex_lock(&acm->mutex); 5427fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen if (acm->disconnected) 5437fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen goto disconnected; 5447fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 5457fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen retval = usb_autopm_get_interface(acm->control); 5467fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen if (retval) 5477fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen goto error_get_interface; 5487fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 5497fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen /* 5507fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen * FIXME: Why do we need this? Allocating 64K of physically contiguous 5517fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen * memory is really nasty... 5527fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen */ 5537fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); 5547fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen acm->control->needs_remote_wakeup = 1; 5551365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm->ctrlurb->dev = acm->dev; 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { 558a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold dev_err(&acm->control->dev, 559a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold "%s - usb_submit_urb(ctrl irq) failed\n", __func__); 5607fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen goto error_submit_urb; 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5637fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS; 5647fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen if (acm_set_control(acm, acm->ctrlout) < 0 && 565ca79b7b4158cbf32625793a1fc1d59ac46d44197Oliver Neukum (acm->ctrl_caps & USB_CDC_CAP_LINE)) 5667fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen goto error_set_control; 56710077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox 56811ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum usb_autopm_put_interface(acm->control); 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5709cc2d461d9ae92fdabd9097fb5ff2977fe59d995Otto Meta /* 5719cc2d461d9ae92fdabd9097fb5ff2977fe59d995Otto Meta * Unthrottle device in case the TTY was closed while throttled. 5729cc2d461d9ae92fdabd9097fb5ff2977fe59d995Otto Meta */ 5739cc2d461d9ae92fdabd9097fb5ff2977fe59d995Otto Meta spin_lock_irq(&acm->read_lock); 5749cc2d461d9ae92fdabd9097fb5ff2977fe59d995Otto Meta acm->throttled = 0; 5759cc2d461d9ae92fdabd9097fb5ff2977fe59d995Otto Meta acm->throttle_req = 0; 5769cc2d461d9ae92fdabd9097fb5ff2977fe59d995Otto Meta spin_unlock_irq(&acm->read_lock); 5779cc2d461d9ae92fdabd9097fb5ff2977fe59d995Otto Meta 578088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold if (acm_submit_read_urbs(acm, GFP_KERNEL)) 5797fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen goto error_submit_read_urbs; 5802b626dc134d38d0001b98acf8c7293b6bc5ee86dOliver Neukum 5811365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum mutex_unlock(&acm->mutex); 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5837fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen return 0; 5847fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 5857fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoenerror_submit_read_urbs: 5867fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen acm->ctrlout = 0; 5877fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen acm_set_control(acm, acm->ctrlout); 5887fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoenerror_set_control: 5897fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen usb_kill_urb(acm->ctrlurb); 5907fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoenerror_submit_urb: 5912b626dc134d38d0001b98acf8c7293b6bc5ee86dOliver Neukum usb_autopm_put_interface(acm->control); 5927fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoenerror_get_interface: 5937fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoendisconnected: 5947fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen mutex_unlock(&acm->mutex); 5957fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen return retval; 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5987fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoenstatic void acm_port_destruct(struct tty_port *port) 59983ef344a7539aa55a787790bc036f0bf3466e191brian@murphy.dk{ 6007fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen struct acm *acm = container_of(port, struct acm, port); 6017fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 6027fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen dev_dbg(&acm->control->dev, "%s\n", __func__); 60361a87adf2e7b410da8e41799c61c21a7b8c8b001David Kubicek 60483ef344a7539aa55a787790bc036f0bf3466e191brian@murphy.dk tty_unregister_device(acm_tty_driver, acm->minor); 6057fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen acm_release_minor(acm); 60683ef344a7539aa55a787790bc036f0bf3466e191brian@murphy.dk usb_put_intf(acm->control); 607c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum kfree(acm->country_codes); 60883ef344a7539aa55a787790bc036f0bf3466e191brian@murphy.dk kfree(acm); 60983ef344a7539aa55a787790bc036f0bf3466e191brian@murphy.dk} 61083ef344a7539aa55a787790bc036f0bf3466e191brian@murphy.dk 6117fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoenstatic void acm_port_shutdown(struct tty_port *port) 61210077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox{ 6137fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen struct acm *acm = container_of(port, struct acm, port); 614dab54c9f1e26f47a3313300bc1f4dc0eecb47375Johan Hovold int i; 615dab54c9f1e26f47a3313300bc1f4dc0eecb47375Johan Hovold 6167fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen dev_dbg(&acm->control->dev, "%s\n", __func__); 6177fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 6187fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen mutex_lock(&acm->mutex); 6197fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen if (!acm->disconnected) { 62010077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox usb_autopm_get_interface(acm->control); 62110077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox acm_set_control(acm, acm->ctrlout = 0); 62210077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox usb_kill_urb(acm->ctrlurb); 62310077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox for (i = 0; i < ACM_NW; i++) 62410077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox usb_kill_urb(acm->wb[i].urb); 625dab54c9f1e26f47a3313300bc1f4dc0eecb47375Johan Hovold for (i = 0; i < acm->rx_buflimit; i++) 626088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold usb_kill_urb(acm->read_urbs[i]); 62710077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox acm->control->needs_remote_wakeup = 0; 62810077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox usb_autopm_put_interface(acm->control); 62910077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox } 6307fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen mutex_unlock(&acm->mutex); 6317fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen} 6327fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 6337fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoenstatic void acm_tty_cleanup(struct tty_struct *tty) 6347fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen{ 6357fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen struct acm *acm = tty->driver_data; 6367fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen dev_dbg(&acm->control->dev, "%s\n", __func__); 6377fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen tty_port_put(&acm->port); 63810077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox} 63910077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox 64010077d4a6674f535abdbe25cdecb1202af7948f1Alan Coxstatic void acm_tty_hangup(struct tty_struct *tty) 64110077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox{ 64210077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox struct acm *acm = tty->driver_data; 6437fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen dev_dbg(&acm->control->dev, "%s\n", __func__); 64410077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox tty_port_hangup(&acm->port); 64510077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox} 64610077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void acm_tty_close(struct tty_struct *tty, struct file *filp) 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acm *acm = tty->driver_data; 6507fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen dev_dbg(&acm->control->dev, "%s\n", __func__); 6517fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen tty_port_close(&acm->port, tty, filp); 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6546e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Coxstatic int acm_tty_write(struct tty_struct *tty, 6556e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox const unsigned char *buf, int count) 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acm *acm = tty->driver_data; 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int stat; 659884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum unsigned long flags; 660884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum int wbn; 661884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum struct acm_wb *wb; 662884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!count) 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6665e9e75f8bd97864d552ec2b8d1a00e2b3012a6b3Johan Hovold dev_vdbg(&acm->data->dev, "%s - count %d\n", __func__, count); 667a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold 668884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum spin_lock_irqsave(&acm->write_lock, flags); 6696e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox wbn = acm_wb_alloc(acm); 6706e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox if (wbn < 0) { 671884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum spin_unlock_irqrestore(&acm->write_lock, flags); 672884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum return 0; 673884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum } 674884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum wb = &acm->wb[wbn]; 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 676884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum count = (count > acm->writesize) ? acm->writesize : count; 6775e9e75f8bd97864d552ec2b8d1a00e2b3012a6b3Johan Hovold dev_vdbg(&acm->data->dev, "%s - write %d\n", __func__, count); 678884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum memcpy(wb->buf, buf, count); 679884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum wb->len = count; 680884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum spin_unlock_irqrestore(&acm->write_lock, flags); 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6826e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox stat = acm_write_start(acm, wbn); 6836e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox if (stat < 0) 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return stat; 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acm_tty_write_room(struct tty_struct *tty) 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acm *acm = tty->driver_data; 691884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum /* 692884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum * Do not let the line discipline to know that we have a reserve, 693884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum * or it might get too enthusiastic. 694884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum */ 695934da4635c2d05cef474e5243ef05df95b2ad264David Brownell return acm_wb_is_avail(acm) ? acm->writesize : 0; 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int acm_tty_chars_in_buffer(struct tty_struct *tty) 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acm *acm = tty->driver_data; 7017fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen /* 7027fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen * if the device was unplugged then any remaining characters fell out 7037fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen * of the connector ;) 7047fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen */ 7057fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen if (acm->disconnected) 70623198fda7182969b619613a555f8645fdc3dc334Alan Cox return 0; 707884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum /* 708884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum * This is inaccurate (overcounts), but it works. 709884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum */ 71086478944eba887f149e151bacc023ae4b2d23ea6Oliver Neukum return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize; 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void acm_tty_throttle(struct tty_struct *tty) 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acm *acm = tty->driver_data; 716088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold 717088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold spin_lock_irq(&acm->read_lock); 718088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold acm->throttle_req = 1; 719088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold spin_unlock_irq(&acm->read_lock); 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void acm_tty_unthrottle(struct tty_struct *tty) 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acm *acm = tty->driver_data; 725088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold unsigned int was_throttled; 726088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold 727088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold spin_lock_irq(&acm->read_lock); 728088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold was_throttled = acm->throttled; 729088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold acm->throttled = 0; 730088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold acm->throttle_req = 0; 731088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold spin_unlock_irq(&acm->read_lock); 732088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold 733088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold if (was_throttled) 734088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold acm_submit_read_urbs(acm, GFP_KERNEL); 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7379e98966c7bb94355689478bc84cc3e0c190f977eAlan Coxstatic int acm_tty_break_ctl(struct tty_struct *tty, int state) 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acm *acm = tty->driver_data; 7409e98966c7bb94355689478bc84cc3e0c190f977eAlan Cox int retval; 7417fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 7429e98966c7bb94355689478bc84cc3e0c190f977eAlan Cox retval = acm_send_break(acm, state ? 0xffff : 0); 7439e98966c7bb94355689478bc84cc3e0c190f977eAlan Cox if (retval < 0) 744a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold dev_dbg(&acm->control->dev, "%s - send break failed\n", 745a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold __func__); 7469e98966c7bb94355689478bc84cc3e0c190f977eAlan Cox return retval; 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74960b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int acm_tty_tiocmget(struct tty_struct *tty) 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acm *acm = tty->driver_data; 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) | 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) | 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) | 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) | 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) | 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TIOCM_CTS; 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76120b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int acm_tty_tiocmset(struct tty_struct *tty, 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int set, unsigned int clear) 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acm *acm = tty->driver_data; 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int newctrl; 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newctrl = acm->ctrlout; 7686e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | 7696e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox (set & TIOCM_RTS ? ACM_CTRL_RTS : 0); 7706e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | 7716e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0); 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newctrl = (newctrl & ~clear) | set; 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acm->ctrlout == newctrl) 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return acm_set_control(acm, acm->ctrlout = newctrl); 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 78018c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukumstatic int get_serial_info(struct acm *acm, struct serial_struct __user *info) 78118c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum{ 78218c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum struct serial_struct tmp; 78318c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum 78418c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum if (!info) 78518c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum return -EINVAL; 78618c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum 78718c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum memset(&tmp, 0, sizeof(tmp)); 78818c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum tmp.flags = ASYNC_LOW_LATENCY; 78918c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum tmp.xmit_fifo_size = acm->writesize; 79018c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum tmp.baud_base = le32_to_cpu(acm->line.dwDTERate); 79118c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum 79218c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum if (copy_to_user(info, &tmp, sizeof(tmp))) 79318c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum return -EFAULT; 79418c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum else 79518c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum return 0; 79618c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum} 79718c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum 7986caa76b7786891b42b66a0e61e2c2fff2c884620Alan Coxstatic int acm_tty_ioctl(struct tty_struct *tty, 7996e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox unsigned int cmd, unsigned long arg) 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 80118c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum struct acm *acm = tty->driver_data; 80218c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum int rv = -ENOIOCTLCMD; 80318c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum 80418c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum switch (cmd) { 80518c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum case TIOCGSERIAL: /* gets serial port data */ 80618c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum rv = get_serial_info(acm, (struct serial_struct __user *) arg); 80718c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum break; 80818c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum } 80918c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum 81018c75720e667719c923e0547abb60dfcd9c4ee90Oliver Neukum return rv; 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8134c4c9432a6c916729c7296c47fe93b053a73e20cArjan van de Venstatic const __u32 acm_tty_speed[] = { 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, 50, 75, 110, 134, 150, 200, 300, 600, 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1200, 1800, 2400, 4800, 9600, 19200, 38400, 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57600, 115200, 230400, 460800, 500000, 576000, 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921600, 1000000, 1152000, 1500000, 2000000, 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2500000, 3000000, 3500000, 4000000 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8214c4c9432a6c916729c7296c47fe93b053a73e20cArjan van de Venstatic const __u8 acm_tty_size[] = { 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5, 6, 7, 8 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8256e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Coxstatic void acm_tty_set_termios(struct tty_struct *tty, 8266e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox struct ktermios *termios_old) 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acm *acm = tty->driver_data; 829606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox struct ktermios *termios = tty->termios; 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_cdc_line_coding newline; 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int newctrl = acm->ctrlout; 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8339b80fee149a875a6292b2556ab2c64dc7ab7d6f5Alan Cox newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty)); 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0; 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newline.bParityType = termios->c_cflag & PARENB ? 8366e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox (termios->c_cflag & PARODD ? 1 : 2) + 8376e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox (termios->c_cflag & CMSPAR ? 2 : 0) : 0; 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4]; 8396e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox /* FIXME: Needs to clear unsupported bits in the termios */ 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm->clocal = ((termios->c_cflag & CLOCAL) != 0); 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!newline.dwDTERate) { 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newline.dwDTERate = acm->line.dwDTERate; 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newctrl &= ~ACM_CTRL_DTR; 8456e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox } else 8466e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox newctrl |= ACM_CTRL_DTR; 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (newctrl != acm->ctrlout) 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm_set_control(acm, acm->ctrlout = newctrl); 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (memcmp(&acm->line, &newline, sizeof newline)) { 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(&acm->line, &newline, sizeof newline); 853a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold dev_dbg(&acm->control->dev, "%s - set line: %d %d %d %d\n", 854a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold __func__, 855a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold le32_to_cpu(newline.dwDTERate), 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newline.bCharFormat, newline.bParityType, 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newline.bDataBits); 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm_set_line(acm, &acm->line); 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8627fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoenstatic const struct tty_port_operations acm_port_ops = { 8637fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen .shutdown = acm_port_shutdown, 8647fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen .activate = acm_port_activate, 8657fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen .destruct = acm_port_destruct, 8667fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen}; 8677fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * USB probe and disconnect routines. 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 872830f4021a8d5ce97c6bed267132e5e90fb166192Oliver Neukum/* Little helpers: write/read buffers free */ 873884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukumstatic void acm_write_buffers_free(struct acm *acm) 874884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum{ 875884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum int i; 876884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum struct acm_wb *wb; 877a496c64f1363ec4d67ebdc1e1f619ad6372a574cOliver Neukum struct usb_device *usb_dev = interface_to_usbdev(acm->control); 878884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum 8796e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) 880997ea58eb92f9970b8af7aae48800d0ef43b9423Daniel Mack usb_free_coherent(usb_dev, acm->writesize, wb->buf, wb->dmah); 881884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum} 882884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum 883830f4021a8d5ce97c6bed267132e5e90fb166192Oliver Neukumstatic void acm_read_buffers_free(struct acm *acm) 884830f4021a8d5ce97c6bed267132e5e90fb166192Oliver Neukum{ 885830f4021a8d5ce97c6bed267132e5e90fb166192Oliver Neukum struct usb_device *usb_dev = interface_to_usbdev(acm->control); 886dab54c9f1e26f47a3313300bc1f4dc0eecb47375Johan Hovold int i; 887830f4021a8d5ce97c6bed267132e5e90fb166192Oliver Neukum 888dab54c9f1e26f47a3313300bc1f4dc0eecb47375Johan Hovold for (i = 0; i < acm->rx_buflimit; i++) 889997ea58eb92f9970b8af7aae48800d0ef43b9423Daniel Mack usb_free_coherent(usb_dev, acm->readsize, 890088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold acm->read_buffers[i].base, acm->read_buffers[i].dma); 891830f4021a8d5ce97c6bed267132e5e90fb166192Oliver Neukum} 892830f4021a8d5ce97c6bed267132e5e90fb166192Oliver Neukum 893884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum/* Little helper: write buffers allocate */ 894884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukumstatic int acm_write_buffers_alloc(struct acm *acm) 895884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum{ 896884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum int i; 897884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum struct acm_wb *wb; 898884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum 89986478944eba887f149e151bacc023ae4b2d23ea6Oliver Neukum for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) { 900997ea58eb92f9970b8af7aae48800d0ef43b9423Daniel Mack wb->buf = usb_alloc_coherent(acm->dev, acm->writesize, GFP_KERNEL, 901884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum &wb->dmah); 902884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum if (!wb->buf) { 903884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum while (i != 0) { 904884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum --i; 905884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum --wb; 906997ea58eb92f9970b8af7aae48800d0ef43b9423Daniel Mack usb_free_coherent(acm->dev, acm->writesize, 907884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum wb->buf, wb->dmah); 908884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum } 909884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum return -ENOMEM; 910884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum } 911884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum } 912884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum return 0; 913884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum} 914884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum 91510077d4a6674f535abdbe25cdecb1202af7948f1Alan Coxstatic int acm_probe(struct usb_interface *intf, 91610077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox const struct usb_device_id *id) 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_cdc_union_desc *union_header = NULL; 919c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum struct usb_cdc_country_functional_desc *cfd = NULL; 920c6dbf554bc8a79c9caab3dbf891a33c19068f646David Brownell unsigned char *buffer = intf->altsetting->extra; 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int buflen = intf->altsetting->extralen; 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_interface *control_interface; 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_interface *data_interface; 924a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum struct usb_endpoint_descriptor *epctrl = NULL; 925a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum struct usb_endpoint_descriptor *epread = NULL; 926a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum struct usb_endpoint_descriptor *epwrite = NULL; 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_device *usb_dev = interface_to_usbdev(intf); 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acm *acm; 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int minor; 9306e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox int ctrlsize, readsize; 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *buf; 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 ac_management_function = 0; 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 call_management_function = 0; 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int call_interface_num = -1; 935fd5054c169d29747a44b4e1419ff47f57ae82dbcErik Slagter int data_interface_num = -1; 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long quirks; 93786478944eba887f149e151bacc023ae4b2d23ea6Oliver Neukum int num_rx_buf; 93861a87adf2e7b410da8e41799c61c21a7b8c8b001David Kubicek int i; 939a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum int combined_interfaces = 0; 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 94186478944eba887f149e151bacc023ae4b2d23ea6Oliver Neukum /* normal quirks */ 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds quirks = (unsigned long)id->driver_info; 94386478944eba887f149e151bacc023ae4b2d23ea6Oliver Neukum num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR; 94486478944eba887f149e151bacc023ae4b2d23ea6Oliver Neukum 94586478944eba887f149e151bacc023ae4b2d23ea6Oliver Neukum /* handle quirks deadly to normal probing*/ 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (quirks == NO_UNION_NORMAL) { 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_interface = usb_ifnum_to_if(usb_dev, 1); 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control_interface = usb_ifnum_to_if(usb_dev, 0); 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto skip_normal_probe; 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9516e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* normal probing*/ 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!buffer) { 9549908a32e94de2141463e104c9924279ed3509447Greg Kroah-Hartman dev_err(&intf->dev, "Weird descriptor references\n"); 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!buflen) { 959577045c0a76e34294f902a7d5d60e90b04d094d0Toby Gray if (intf->cur_altsetting->endpoint && 960577045c0a76e34294f902a7d5d60e90b04d094d0Toby Gray intf->cur_altsetting->endpoint->extralen && 9616e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox intf->cur_altsetting->endpoint->extra) { 9626e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox dev_dbg(&intf->dev, 9636e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox "Seeking extra descriptors on endpoint\n"); 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buflen = intf->cur_altsetting->endpoint->extralen; 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer = intf->cur_altsetting->endpoint->extra; 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 9679908a32e94de2141463e104c9924279ed3509447Greg Kroah-Hartman dev_err(&intf->dev, 9689908a32e94de2141463e104c9924279ed3509447Greg Kroah-Hartman "Zero length descriptor references\n"); 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (buflen > 0) { 9746e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox if (buffer[1] != USB_DT_CS_INTERFACE) { 9759908a32e94de2141463e104c9924279ed3509447Greg Kroah-Hartman dev_err(&intf->dev, "skipping garbage\n"); 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto next_desc; 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9796e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox switch (buffer[2]) { 9806e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox case USB_CDC_UNION_TYPE: /* we've found it */ 9816e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox if (union_header) { 9826e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox dev_err(&intf->dev, "More than one " 9836e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox "union descriptor, skipping ...\n"); 9846e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox goto next_desc; 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9866e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox union_header = (struct usb_cdc_union_desc *)buffer; 9876e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox break; 9886e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ 9896e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox cfd = (struct usb_cdc_country_functional_desc *)buffer; 9906e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox break; 9916e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox case USB_CDC_HEADER_TYPE: /* maybe check version */ 9926e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox break; /* for now we ignore it */ 9936e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox case USB_CDC_ACM_TYPE: 9946e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox ac_management_function = buffer[3]; 9956e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox break; 9966e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox case USB_CDC_CALL_MANAGEMENT_TYPE: 9976e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox call_management_function = buffer[3]; 9986e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox call_interface_num = buffer[4]; 999ce126644aa10bf1d8f1c1929b65adab026095761Julian Calaby if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3) 10006e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n"); 10016e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox break; 10026e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox default: 10036e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox /* there are LOTS more CDC descriptors that 10046e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox * could legitimately be found here. 10056e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox */ 10066e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox dev_dbg(&intf->dev, "Ignoring descriptor: " 10076e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox "type %02x, length %d\n", 10086e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox buffer[2], buffer[0]); 10096e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox break; 10106e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox } 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnext_desc: 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buflen -= buffer[0]; 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer += buffer[0]; 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!union_header) { 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (call_interface_num > 0) { 10186e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n"); 1019fd5054c169d29747a44b4e1419ff47f57ae82dbcErik Slagter /* quirks for Droids MuIn LCD */ 1020fd5054c169d29747a44b4e1419ff47f57ae82dbcErik Slagter if (quirks & NO_DATA_INTERFACE) 1021fd5054c169d29747a44b4e1419ff47f57ae82dbcErik Slagter data_interface = usb_ifnum_to_if(usb_dev, 0); 1022fd5054c169d29747a44b4e1419ff47f57ae82dbcErik Slagter else 1023fd5054c169d29747a44b4e1419ff47f57ae82dbcErik Slagter data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control_interface = intf; 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1026a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum if (intf->cur_altsetting->desc.bNumEndpoints != 3) { 1027a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum dev_dbg(&intf->dev,"No union descriptor, giving up\n"); 1028a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum return -ENODEV; 1029a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum } else { 1030a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum dev_warn(&intf->dev,"No union descriptor, testing for castrated device\n"); 1031a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum combined_interfaces = 1; 1032a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum control_interface = data_interface = intf; 1033a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum goto look_for_collapsed_interface; 1034a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum } 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!control_interface || !data_interface) { 10406e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox dev_dbg(&intf->dev, "no interfaces\n"); 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10446e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data_interface_num != call_interface_num) 10466e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n"); 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1048a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum if (control_interface == data_interface) { 1049a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum /* some broken devices designed for windows work this way */ 1050a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum dev_warn(&intf->dev,"Control and data interfaces are not separated!\n"); 1051a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum combined_interfaces = 1; 1052a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum /* a popular other OS doesn't use it */ 1053a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum quirks |= NO_CAP_LINE; 1054a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum if (data_interface->cur_altsetting->desc.bNumEndpoints != 3) { 1055a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum dev_err(&intf->dev, "This needs exactly 3 endpoints\n"); 1056a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum return -EINVAL; 1057a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum } 1058a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukumlook_for_collapsed_interface: 1059a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum for (i = 0; i < 3; i++) { 1060a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum struct usb_endpoint_descriptor *ep; 1061a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum ep = &data_interface->cur_altsetting->endpoint[i].desc; 1062a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum 1063a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum if (usb_endpoint_is_int_in(ep)) 1064a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum epctrl = ep; 1065a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum else if (usb_endpoint_is_bulk_out(ep)) 1066a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum epwrite = ep; 1067a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum else if (usb_endpoint_is_bulk_in(ep)) 1068a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum epread = ep; 1069a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum else 1070a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum return -EINVAL; 1071a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum } 1072a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum if (!epctrl || !epread || !epwrite) 1073a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum return -ENODEV; 1074a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum else 1075a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum goto made_compressed_probe; 1076a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum } 1077a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsskip_normal_probe: 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*workaround for switched interfaces */ 10816e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox if (data_interface->cur_altsetting->desc.bInterfaceClass 10826e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox != CDC_DATA_INTERFACE_TYPE) { 10836e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox if (control_interface->cur_altsetting->desc.bInterfaceClass 10846e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox == CDC_DATA_INTERFACE_TYPE) { 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_interface *t; 10866e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox dev_dbg(&intf->dev, 10876e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox "Your device has switched interfaces.\n"); 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds t = control_interface; 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control_interface = data_interface; 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_interface = t; 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 109574da5d68a54d66667664fbe233ededab2376a070Alan Stern 109674da5d68a54d66667664fbe233ededab2376a070Alan Stern /* Accept probe requests only for the control interface */ 1097a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum if (!combined_interfaces && intf != control_interface) 109874da5d68a54d66667664fbe233ededab2376a070Alan Stern return -ENODEV; 10996e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox 1100a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum if (!combined_interfaces && usb_interface_claimed(data_interface)) { 1101a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum /* valid in this context */ 11026e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox dev_dbg(&intf->dev, "The data interface isn't available\n"); 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data_interface->cur_altsetting->desc.bNumEndpoints < 2) 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds epctrl = &control_interface->cur_altsetting->endpoint[0].desc; 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds epread = &data_interface->cur_altsetting->endpoint[0].desc; 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds epwrite = &data_interface->cur_altsetting->endpoint[1].desc; 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* workaround for switched endpoints */ 111645aea704d12d05f06b3f82974aa1438460f42398Luiz Fernando N. Capitulino if (!usb_endpoint_dir_in(epread)) { 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* descriptors are swapped */ 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_endpoint_descriptor *t; 11196e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox dev_dbg(&intf->dev, 11206e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox "The data interface has switched endpoints\n"); 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds t = epread; 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds epread = epwrite; 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds epwrite = t; 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1125a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukummade_compressed_probe: 1126a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold dev_dbg(&intf->dev, "interfaces are valid\n"); 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11286e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox acm = kzalloc(sizeof(struct acm), GFP_KERNEL); 11296e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox if (acm == NULL) { 1130255ab56c5ae30165d506b837f6576944a02ecdf0Johan Hovold dev_err(&intf->dev, "out of memory (acm kzalloc)\n"); 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto alloc_fail; 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11347fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen minor = acm_alloc_minor(acm); 11357fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen if (minor == ACM_TTY_MINORS) { 11367fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen dev_err(&intf->dev, "no more free acm devices\n"); 11377fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen kfree(acm); 11387fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen return -ENODEV; 11397fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen } 11407fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 114129cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto ctrlsize = usb_endpoint_maxp(epctrl); 114229cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto readsize = usb_endpoint_maxp(epread) * 11436e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox (quirks == SINGLE_RX_URB ? 1 : 2); 1144a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum acm->combined_interfaces = combined_interfaces; 114529cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto acm->writesize = usb_endpoint_maxp(epwrite) * 20; 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm->control = control_interface; 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm->data = data_interface; 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm->minor = minor; 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm->dev = usb_dev; 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm->ctrl_caps = ac_management_function; 1151a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum if (quirks & NO_CAP_LINE) 1152a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum acm->ctrl_caps &= ~USB_CDC_CAP_LINE; 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm->ctrlsize = ctrlsize; 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm->readsize = readsize; 115586478944eba887f149e151bacc023ae4b2d23ea6Oliver Neukum acm->rx_buflimit = num_rx_buf; 1156c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells INIT_WORK(&acm->work, acm_softint); 1157884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum spin_lock_init(&acm->write_lock); 115861a87adf2e7b410da8e41799c61c21a7b8c8b001David Kubicek spin_lock_init(&acm->read_lock); 11591365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum mutex_init(&acm->mutex); 116061a87adf2e7b410da8e41799c61c21a7b8c8b001David Kubicek acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); 1161cf7fdd57f978d40ceb9a0f58a25f5cf9c84d6f33Oliver Neukum acm->is_int_ep = usb_endpoint_xfer_int(epread); 1162cf7fdd57f978d40ceb9a0f58a25f5cf9c84d6f33Oliver Neukum if (acm->is_int_ep) 1163cf7fdd57f978d40ceb9a0f58a25f5cf9c84d6f33Oliver Neukum acm->bInterval = epread->bInterval; 1164739e0285cbb162c8ddd0061fda581ee54a34c19aAlan Cox tty_port_init(&acm->port); 1165739e0285cbb162c8ddd0061fda581ee54a34c19aAlan Cox acm->port.ops = &acm_port_ops; 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1167997ea58eb92f9970b8af7aae48800d0ef43b9423Daniel Mack buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!buf) { 1169255ab56c5ae30165d506b837f6576944a02ecdf0Johan Hovold dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n"); 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto alloc_fail2; 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm->ctrl_buffer = buf; 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1174884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum if (acm_write_buffers_alloc(acm) < 0) { 1175255ab56c5ae30165d506b837f6576944a02ecdf0Johan Hovold dev_err(&intf->dev, "out of memory (write buffer alloc)\n"); 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto alloc_fail4; 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!acm->ctrlurb) { 1181255ab56c5ae30165d506b837f6576944a02ecdf0Johan Hovold dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n"); 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto alloc_fail5; 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 118486478944eba887f149e151bacc023ae4b2d23ea6Oliver Neukum for (i = 0; i < num_rx_buf; i++) { 1185088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold struct acm_rb *rb = &(acm->read_buffers[i]); 1186088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold struct urb *urb; 118761a87adf2e7b410da8e41799c61c21a7b8c8b001David Kubicek 118874f5e1babde76149c2bb35ca5dbf4d0b9b38f161Johan Hovold rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL, 118974f5e1babde76149c2bb35ca5dbf4d0b9b38f161Johan Hovold &rb->dma); 119074f5e1babde76149c2bb35ca5dbf4d0b9b38f161Johan Hovold if (!rb->base) { 119174f5e1babde76149c2bb35ca5dbf4d0b9b38f161Johan Hovold dev_err(&intf->dev, "out of memory " 119274f5e1babde76149c2bb35ca5dbf4d0b9b38f161Johan Hovold "(read bufs usb_alloc_coherent)\n"); 119374f5e1babde76149c2bb35ca5dbf4d0b9b38f161Johan Hovold goto alloc_fail6; 119474f5e1babde76149c2bb35ca5dbf4d0b9b38f161Johan Hovold } 1195088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold rb->index = i; 1196088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold rb->instance = acm; 119774f5e1babde76149c2bb35ca5dbf4d0b9b38f161Johan Hovold 1198088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold urb = usb_alloc_urb(0, GFP_KERNEL); 1199088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold if (!urb) { 1200255ab56c5ae30165d506b837f6576944a02ecdf0Johan Hovold dev_err(&intf->dev, 12016e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox "out of memory (read urbs usb_alloc_urb)\n"); 1202c2572b78aa0447244a38e555ebb1b3b48a0088a5Axel Lin goto alloc_fail6; 120361a87adf2e7b410da8e41799c61c21a7b8c8b001David Kubicek } 1204088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 1205088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold urb->transfer_dma = rb->dma; 1206088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold if (acm->is_int_ep) { 1207088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold usb_fill_int_urb(urb, acm->dev, 1208088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold acm->rx_endpoint, 1209088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold rb->base, 1210088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold acm->readsize, 1211088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold acm_read_bulk_callback, rb, 1212088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold acm->bInterval); 1213088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold } else { 1214088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold usb_fill_bulk_urb(urb, acm->dev, 1215088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold acm->rx_endpoint, 1216088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold rb->base, 1217088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold acm->readsize, 1218088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold acm_read_bulk_callback, rb); 1219088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold } 122061a87adf2e7b410da8e41799c61c21a7b8c8b001David Kubicek 1221088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold acm->read_urbs[i] = urb; 1222088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold __set_bit(i, &acm->read_urbs_free); 122361a87adf2e7b410da8e41799c61c21a7b8c8b001David Kubicek } 12246e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox for (i = 0; i < ACM_NW; i++) { 1225e4cf3aa8f9cd6ee4d583b5d445b5c152acefcde4David Engraf struct acm_wb *snd = &(acm->wb[i]); 1226e4cf3aa8f9cd6ee4d583b5d445b5c152acefcde4David Engraf 12276e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox snd->urb = usb_alloc_urb(0, GFP_KERNEL); 12286e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox if (snd->urb == NULL) { 1229255ab56c5ae30165d506b837f6576944a02ecdf0Johan Hovold dev_err(&intf->dev, 123059d7fec7c6908604862658a3679ac44c2c3eea44Johan Hovold "out of memory (write urbs usb_alloc_urb)\n"); 123174f5e1babde76149c2bb35ca5dbf4d0b9b38f161Johan Hovold goto alloc_fail7; 1232e4cf3aa8f9cd6ee4d583b5d445b5c152acefcde4David Engraf } 1233e4cf3aa8f9cd6ee4d583b5d445b5c152acefcde4David Engraf 12345186ffee2320942c3dc9745f7930e0eb15329ca6Arseniy Lartsev if (usb_endpoint_xfer_int(epwrite)) 12355186ffee2320942c3dc9745f7930e0eb15329ca6Arseniy Lartsev usb_fill_int_urb(snd->urb, usb_dev, 12365186ffee2320942c3dc9745f7930e0eb15329ca6Arseniy Lartsev usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), 12375186ffee2320942c3dc9745f7930e0eb15329ca6Arseniy Lartsev NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval); 12385186ffee2320942c3dc9745f7930e0eb15329ca6Arseniy Lartsev else 12395186ffee2320942c3dc9745f7930e0eb15329ca6Arseniy Lartsev usb_fill_bulk_urb(snd->urb, usb_dev, 12405186ffee2320942c3dc9745f7930e0eb15329ca6Arseniy Lartsev usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), 12415186ffee2320942c3dc9745f7930e0eb15329ca6Arseniy Lartsev NULL, acm->writesize, acm_write_bulk, snd); 1242e4cf3aa8f9cd6ee4d583b5d445b5c152acefcde4David Engraf snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 1243e4cf3aa8f9cd6ee4d583b5d445b5c152acefcde4David Engraf snd->instance = acm; 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12466e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox usb_set_intfdata(intf, acm); 1247c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum 1248c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum i = device_create_file(&intf->dev, &dev_attr_bmCapabilities); 1249c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum if (i < 0) 125074f5e1babde76149c2bb35ca5dbf4d0b9b38f161Johan Hovold goto alloc_fail7; 1251c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum 1252c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum if (cfd) { /* export the country data */ 1253c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL); 1254c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum if (!acm->country_codes) 1255c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum goto skip_countries; 1256c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum acm->country_code_size = cfd->bLength - 4; 12576e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, 12586e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox cfd->bLength - 4); 1259c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum acm->country_rel_date = cfd->iCountryCodeRelDate; 1260c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum 1261c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); 1262c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum if (i < 0) { 1263c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum kfree(acm->country_codes); 1264e7c8e8605d0bafc705ff27f9da98a1668427cc0fJulia Lawall acm->country_codes = NULL; 1265e7c8e8605d0bafc705ff27f9da98a1668427cc0fJulia Lawall acm->country_code_size = 0; 1266c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum goto skip_countries; 1267c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum } 1268c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum 12696e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox i = device_create_file(&intf->dev, 12706e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox &dev_attr_iCountryCodeRelDate); 1271c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum if (i < 0) { 1272c2572b78aa0447244a38e555ebb1b3b48a0088a5Axel Lin device_remove_file(&intf->dev, &dev_attr_wCountryCodes); 1273c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum kfree(acm->country_codes); 1274e7c8e8605d0bafc705ff27f9da98a1668427cc0fJulia Lawall acm->country_codes = NULL; 1275e7c8e8605d0bafc705ff27f9da98a1668427cc0fJulia Lawall acm->country_code_size = 0; 1276c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum goto skip_countries; 1277c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum } 1278c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum } 1279c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum 1280c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukumskip_countries: 12816e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox usb_fill_int_urb(acm->ctrlurb, usb_dev, 1282a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), 1283a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, 1284a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum /* works around buggy devices */ 1285a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum epctrl->bInterval ? epctrl->bInterval : 0xff); 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm->ctrlurb->transfer_dma = acm->ctrl_dma; 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm_set_control(acm, acm->ctrlout); 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm->line.dwDTERate = cpu_to_le32(9600); 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm->line.bDataBits = 8; 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm_set_line(acm, &acm->line); 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_driver_claim_interface(&acm_driver, data_interface, acm); 1298672c4e1843c54227ff1bdf1fdd96f9c45c56aa85David Brownell usb_set_intfdata(data_interface, acm); 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 130083ef344a7539aa55a787790bc036f0bf3466e191brian@murphy.dk usb_get_intf(control_interface); 130183ef344a7539aa55a787790bc036f0bf3466e191brian@murphy.dk tty_register_device(acm_tty_driver, minor, &control_interface->dev); 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1303c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum return 0; 130474f5e1babde76149c2bb35ca5dbf4d0b9b38f161Johan Hovoldalloc_fail7: 1305e4cf3aa8f9cd6ee4d583b5d445b5c152acefcde4David Engraf for (i = 0; i < ACM_NW; i++) 1306e4cf3aa8f9cd6ee4d583b5d445b5c152acefcde4David Engraf usb_free_urb(acm->wb[i].urb); 1307c2572b78aa0447244a38e555ebb1b3b48a0088a5Axel Linalloc_fail6: 130886478944eba887f149e151bacc023ae4b2d23ea6Oliver Neukum for (i = 0; i < num_rx_buf; i++) 1309088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold usb_free_urb(acm->read_urbs[i]); 131074f5e1babde76149c2bb35ca5dbf4d0b9b38f161Johan Hovold acm_read_buffers_free(acm); 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_free_urb(acm->ctrlurb); 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsalloc_fail5: 1313884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum acm_write_buffers_free(acm); 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsalloc_fail4: 1315997ea58eb92f9970b8af7aae48800d0ef43b9423Daniel Mack usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsalloc_fail2: 13177fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen acm_release_minor(acm); 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(acm); 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsalloc_fail: 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13231365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukumstatic void stop_data_traffic(struct acm *acm) 13241365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum{ 13251365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum int i; 1326a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold 1327a5cc7ef92f69a88a1984cc3e09f6c19656efeb2eJohan Hovold dev_dbg(&acm->control->dev, "%s\n", __func__); 13281365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum 13291365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum usb_kill_urb(acm->ctrlurb); 13306e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox for (i = 0; i < ACM_NW; i++) 1331e4cf3aa8f9cd6ee4d583b5d445b5c152acefcde4David Engraf usb_kill_urb(acm->wb[i].urb); 13321365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum for (i = 0; i < acm->rx_buflimit; i++) 1333088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold usb_kill_urb(acm->read_urbs[i]); 13341365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum 13351365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum cancel_work_sync(&acm->work); 13361365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum} 13371365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void acm_disconnect(struct usb_interface *intf) 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1340c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum struct acm *acm = usb_get_intfdata(intf); 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_device *usb_dev = interface_to_usbdev(intf); 134210077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox struct tty_struct *tty; 13437fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen int i; 13447fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 13457fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen dev_dbg(&intf->dev, "%s\n", __func__); 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1347672c4e1843c54227ff1bdf1fdd96f9c45c56aa85David Brownell /* sibling interface is already cleaning up */ 1348672c4e1843c54227ff1bdf1fdd96f9c45c56aa85David Brownell if (!acm) 134986067eead5a6c6fa413ef5cb59f7129f5ed80292Oliver Neukum return; 1350672c4e1843c54227ff1bdf1fdd96f9c45c56aa85David Brownell 13517fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen mutex_lock(&acm->mutex); 13527fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen acm->disconnected = true; 13536e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox if (acm->country_codes) { 135474da5d68a54d66667664fbe233ededab2376a070Alan Stern device_remove_file(&acm->control->dev, 135574da5d68a54d66667664fbe233ededab2376a070Alan Stern &dev_attr_wCountryCodes); 135674da5d68a54d66667664fbe233ededab2376a070Alan Stern device_remove_file(&acm->control->dev, 135774da5d68a54d66667664fbe233ededab2376a070Alan Stern &dev_attr_iCountryCodeRelDate); 1358c4cabd28c73116716dcfd0d5f91414b48c0cf5ceOliver Neukum } 135974da5d68a54d66667664fbe233ededab2376a070Alan Stern device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities); 136086067eead5a6c6fa413ef5cb59f7129f5ed80292Oliver Neukum usb_set_intfdata(acm->control, NULL); 136186067eead5a6c6fa413ef5cb59f7129f5ed80292Oliver Neukum usb_set_intfdata(acm->data, NULL); 13627fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen mutex_unlock(&acm->mutex); 13637fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 13647fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen tty = tty_port_tty_get(&acm->port); 13657fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen if (tty) { 13667fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen tty_vhangup(tty); 13677fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen tty_kref_put(tty); 13687fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen } 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13701365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum stop_data_traffic(acm); 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13727fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen usb_free_urb(acm->ctrlurb); 13737fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen for (i = 0; i < ACM_NW; i++) 13747fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen usb_free_urb(acm->wb[i].urb); 13757fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen for (i = 0; i < acm->rx_buflimit; i++) 13767fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen usb_free_urb(acm->read_urbs[i]); 1377884b600f63dc7c646f415a5d8f356df1f66ff6f2Oliver Neukum acm_write_buffers_free(acm); 13787fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); 1379830f4021a8d5ce97c6bed267132e5e90fb166192Oliver Neukum acm_read_buffers_free(acm); 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum if (!acm->combined_interfaces) 1382a2bfb4a346d2c2e25f84b35c6044ff53296be1eeOliver Neukum usb_driver_release_interface(&acm_driver, intf == acm->control ? 1383830f4021a8d5ce97c6bed267132e5e90fb166192Oliver Neukum acm->data : acm->control); 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13857fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen tty_port_put(&acm->port); 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1388357585892e56f7c7bec4a9c8dfaf90257c8756c6Oliver Neukum#ifdef CONFIG_PM 13891365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukumstatic int acm_suspend(struct usb_interface *intf, pm_message_t message) 13901365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum{ 13911365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum struct acm *acm = usb_get_intfdata(intf); 139211ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum int cnt; 139311ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum 13945b1b0b812a7b1a5b968c5d06d90d1cb88621b941Alan Stern if (PMSG_IS_AUTO(message)) { 139511ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum int b; 139611ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum 1397088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold spin_lock_irq(&acm->write_lock); 1398088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold b = acm->transmitting; 1399088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold spin_unlock_irq(&acm->write_lock); 140011ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum if (b) 140111ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum return -EBUSY; 140211ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum } 140311ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum 140411ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum spin_lock_irq(&acm->read_lock); 140511ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum spin_lock(&acm->write_lock); 140611ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum cnt = acm->susp_count++; 140711ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum spin_unlock(&acm->write_lock); 140811ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum spin_unlock_irq(&acm->read_lock); 14091365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum 141011ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum if (cnt) 14111365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum return 0; 14121365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum 14137fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) 14141365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum stop_data_traffic(acm); 14151365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum 14161365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum return 0; 14171365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum} 14181365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum 14191365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukumstatic int acm_resume(struct usb_interface *intf) 14201365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum{ 14211365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum struct acm *acm = usb_get_intfdata(intf); 142297d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum struct acm_wb *wb; 14231365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum int rv = 0; 142411ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum int cnt; 14251365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum 142611ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum spin_lock_irq(&acm->read_lock); 142711ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum acm->susp_count -= 1; 142811ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum cnt = acm->susp_count; 142911ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum spin_unlock_irq(&acm->read_lock); 143011ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum 143111ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum if (cnt) 14321365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum return 0; 14331365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum 14347fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { 14351365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); 143697d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum 143797d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum spin_lock_irq(&acm->write_lock); 143897d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum if (acm->delayed_wb) { 143997d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum wb = acm->delayed_wb; 144097d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum acm->delayed_wb = NULL; 144197d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum spin_unlock_irq(&acm->write_lock); 1442f0730924e9e32bb8935c60040a26d94179355088Oliver Neukum acm_start_wb(acm, wb); 144397d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum } else { 144497d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum spin_unlock_irq(&acm->write_lock); 144597d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum } 144697d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum 144797d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum /* 144897d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum * delayed error checking because we must 144997d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum * do the write path at all cost 145097d35f95552c9a0ee4777a7f04431a9fd1260478Oliver Neukum */ 14511365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum if (rv < 0) 145211ea859d64b69a747d6b060b9ed1520eab1161feOliver Neukum goto err_out; 14531365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum 1454088c64f812847b3623b03d167ed329f90f3e38a4Johan Hovold rv = acm_submit_read_urbs(acm, GFP_NOIO); 14551365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum } 14561365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum 14571365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukumerr_out: 14581365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum return rv; 14591365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum} 1460357585892e56f7c7bec4a9c8dfaf90257c8756c6Oliver Neukum 1461a91b0c502285fd0c569fae1222fdd945ef739233Francesco Lavrastatic int acm_reset_resume(struct usb_interface *intf) 1462a91b0c502285fd0c569fae1222fdd945ef739233Francesco Lavra{ 1463a91b0c502285fd0c569fae1222fdd945ef739233Francesco Lavra struct acm *acm = usb_get_intfdata(intf); 1464a91b0c502285fd0c569fae1222fdd945ef739233Francesco Lavra struct tty_struct *tty; 1465a91b0c502285fd0c569fae1222fdd945ef739233Francesco Lavra 14667fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { 1467a91b0c502285fd0c569fae1222fdd945ef739233Francesco Lavra tty = tty_port_tty_get(&acm->port); 1468a91b0c502285fd0c569fae1222fdd945ef739233Francesco Lavra if (tty) { 1469a91b0c502285fd0c569fae1222fdd945ef739233Francesco Lavra tty_hangup(tty); 1470a91b0c502285fd0c569fae1222fdd945ef739233Francesco Lavra tty_kref_put(tty); 1471a91b0c502285fd0c569fae1222fdd945ef739233Francesco Lavra } 1472a91b0c502285fd0c569fae1222fdd945ef739233Francesco Lavra } 14737fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen 1474a91b0c502285fd0c569fae1222fdd945ef739233Francesco Lavra return acm_resume(intf); 1475a91b0c502285fd0c569fae1222fdd945ef739233Francesco Lavra} 1476a91b0c502285fd0c569fae1222fdd945ef739233Francesco Lavra 1477357585892e56f7c7bec4a9c8dfaf90257c8756c6Oliver Neukum#endif /* CONFIG_PM */ 1478c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor 1479c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor#define NOKIA_PCSUITE_ACM_INFO(x) \ 1480c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor USB_DEVICE_AND_INTERFACE_INFO(0x0421, x, \ 1481c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \ 1482c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor USB_CDC_ACM_PROTO_VENDOR) 1483c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor 14844035e45632c2a8bb4edae83c20447051bd9a9604Toby Gray#define SAMSUNG_PCSUITE_ACM_INFO(x) \ 14854035e45632c2a8bb4edae83c20447051bd9a9604Toby Gray USB_DEVICE_AND_INTERFACE_INFO(0x04e7, x, \ 14864035e45632c2a8bb4edae83c20447051bd9a9604Toby Gray USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \ 14874035e45632c2a8bb4edae83c20447051bd9a9604Toby Gray USB_CDC_ACM_PROTO_VENDOR) 14884035e45632c2a8bb4edae83c20447051bd9a9604Toby Gray 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * USB driver structure. 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14936ef4852b1326301f6e9657e99b2c3221be1a3a44Németh Mártonstatic const struct usb_device_id acm_ids[] = { 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* quirky and broken devices */ 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */ 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ 14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 1498b0e2a705bffbfb70d9bed8b5f9094901f28d9563Andrey Arapov { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */ 1499b0e2a705bffbfb70d9bed8b5f9094901f28d9563Andrey Arapov .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ 1500b0e2a705bffbfb70d9bed8b5f9094901f28d9563Andrey Arapov }, 15010f9c7b4a1cc24d6f05a848f0acf72dbff7c5d42dAndrew Lunn { USB_DEVICE(0x0e8d, 0x3329), /* MediaTek Inc GPS */ 15020f9c7b4a1cc24d6f05a848f0acf72dbff7c5d42dAndrew Lunn .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ 15030f9c7b4a1cc24d6f05a848f0acf72dbff7c5d42dAndrew Lunn }, 15048753e65e34a7b02f8473e7c6ce1cf7e08db4c6e3Masahito Omote { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */ 15058753e65e34a7b02f8473e7c6ce1cf7e08db4c6e3Masahito Omote .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ 15068753e65e34a7b02f8473e7c6ce1cf7e08db4c6e3Masahito Omote }, 150791a9c9214e34c364bf15406aadb922787ae7129bChris Malley { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */ 150891a9c9214e34c364bf15406aadb922787ae7129bChris Malley .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ 150991a9c9214e34c364bf15406aadb922787ae7129bChris Malley }, 15107abcf20b8f32dd679b162b33c07e427c67d4a1fbAlan Cox { USB_DEVICE(0x0ace, 0x1602), /* ZyDAS 56K USB MODEM */ 15117abcf20b8f32dd679b162b33c07e427c67d4a1fbAlan Cox .driver_info = SINGLE_RX_URB, 15127abcf20b8f32dd679b162b33c07e427c67d4a1fbAlan Cox }, 151386478944eba887f149e151bacc023ae4b2d23ea6Oliver Neukum { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */ 151486478944eba887f149e151bacc023ae4b2d23ea6Oliver Neukum .driver_info = SINGLE_RX_URB, /* firmware bug */ 151586478944eba887f149e151bacc023ae4b2d23ea6Oliver Neukum }, 15163dd2ae81f70f191f5b6751d18fdfe61dbafda7e8Oliver Neukum { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */ 15173dd2ae81f70f191f5b6751d18fdfe61dbafda7e8Oliver Neukum .driver_info = SINGLE_RX_URB, /* firmware bug */ 15183dd2ae81f70f191f5b6751d18fdfe61dbafda7e8Oliver Neukum }, 15199be8456c00c5bd603b933e6e9d82041e8b32c401Oliver Neukum { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */ 15209be8456c00c5bd603b933e6e9d82041e8b32c401Oliver Neukum .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ 15219be8456c00c5bd603b933e6e9d82041e8b32c401Oliver Neukum }, 15226149ed5e3a6207595bd7362af7724d64f44af216Iain McFarlane { USB_DEVICE(0x0803, 0x3095), /* Zoom Telephonics Model 3095F USB MODEM */ 15236149ed5e3a6207595bd7362af7724d64f44af216Iain McFarlane .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ 15246149ed5e3a6207595bd7362af7724d64f44af216Iain McFarlane }, 1525c8fd2c37b99c55c8d24888e0ed9d5f4f73458c9cEric Sandeen { USB_DEVICE(0x0572, 0x1321), /* Conexant USB MODEM CX93010 */ 1526c8fd2c37b99c55c8d24888e0ed9d5f4f73458c9cEric Sandeen .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ 1527c8fd2c37b99c55c8d24888e0ed9d5f4f73458c9cEric Sandeen }, 1528c89c60e9d6b306fb6963030abb3bd07cc3de66b2Alan Cox { USB_DEVICE(0x0572, 0x1324), /* Conexant USB MODEM RD02-D400 */ 1529c89c60e9d6b306fb6963030abb3bd07cc3de66b2Alan Cox .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ 1530c89c60e9d6b306fb6963030abb3bd07cc3de66b2Alan Cox }, 1531cab98a0a349829b145d924c0649a2d30cd6a9e3dXiao Kaijian { USB_DEVICE(0x0572, 0x1328), /* Shiro / Aztech USB MODEM UM-3100 */ 1532cab98a0a349829b145d924c0649a2d30cd6a9e3dXiao Kaijian .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ 1533cab98a0a349829b145d924c0649a2d30cd6a9e3dXiao Kaijian }, 1534155df65ae11dfc322214c6f887185929c809df1bDmitriy Taychenachev { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */ 1535155df65ae11dfc322214c6f887185929c809df1bDmitriy Taychenachev }, 15366abff5dc4d5a2c90e597137ce8987e7fd439259bKrzysztof Hałasa /* Motorola H24 HSPA module: */ 15376abff5dc4d5a2c90e597137ce8987e7fd439259bKrzysztof Hałasa { USB_DEVICE(0x22b8, 0x2d91) }, /* modem */ 15386abff5dc4d5a2c90e597137ce8987e7fd439259bKrzysztof Hałasa { USB_DEVICE(0x22b8, 0x2d92) }, /* modem + diagnostics */ 15396abff5dc4d5a2c90e597137ce8987e7fd439259bKrzysztof Hałasa { USB_DEVICE(0x22b8, 0x2d93) }, /* modem + AT port */ 15406abff5dc4d5a2c90e597137ce8987e7fd439259bKrzysztof Hałasa { USB_DEVICE(0x22b8, 0x2d95) }, /* modem + AT port + diagnostics */ 15416abff5dc4d5a2c90e597137ce8987e7fd439259bKrzysztof Hałasa { USB_DEVICE(0x22b8, 0x2d96) }, /* modem + NMEA */ 15426abff5dc4d5a2c90e597137ce8987e7fd439259bKrzysztof Hałasa { USB_DEVICE(0x22b8, 0x2d97) }, /* modem + diagnostics + NMEA */ 15436abff5dc4d5a2c90e597137ce8987e7fd439259bKrzysztof Hałasa { USB_DEVICE(0x22b8, 0x2d99) }, /* modem + AT port + NMEA */ 15446abff5dc4d5a2c90e597137ce8987e7fd439259bKrzysztof Hałasa { USB_DEVICE(0x22b8, 0x2d9a) }, /* modem + AT port + diagnostics + NMEA */ 15456abff5dc4d5a2c90e597137ce8987e7fd439259bKrzysztof Hałasa 1546c332b4e1bfd56fe9028d8ef9708cb06179dd1a23Adam Richter { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */ 1547c332b4e1bfd56fe9028d8ef9708cb06179dd1a23Adam Richter .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on 1548c332b4e1bfd56fe9028d8ef9708cb06179dd1a23Adam Richter data interface instead of 1549c332b4e1bfd56fe9028d8ef9708cb06179dd1a23Adam Richter communications interface. 1550c332b4e1bfd56fe9028d8ef9708cb06179dd1a23Adam Richter Maybe we should define a new 1551c332b4e1bfd56fe9028d8ef9708cb06179dd1a23Adam Richter quirk for this. */ 1552c332b4e1bfd56fe9028d8ef9708cb06179dd1a23Adam Richter }, 15531f17c5026ce27d0449903d34f9fca461a45fe1cbKir Kolyshkin { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */ 15541f17c5026ce27d0449903d34f9fca461a45fe1cbKir Kolyshkin .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ 15551f17c5026ce27d0449903d34f9fca461a45fe1cbKir Kolyshkin }, 1556c3baa19b0a9b711b02cec81d9fea33b7b9628957Russ Nelson { USB_DEVICE(0x1576, 0x03b1), /* Maretron USB100 */ 1557c3baa19b0a9b711b02cec81d9fea33b7b9628957Russ Nelson .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ 1558c3baa19b0a9b711b02cec81d9fea33b7b9628957Russ Nelson }, 15599be8456c00c5bd603b933e6e9d82041e8b32c401Oliver Neukum 1560c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor /* Nokia S60 phones expose two ACM channels. The first is 1561c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor * a modem and is picked up by the standard AT-command 1562c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor * information below. The second is 'vendor-specific' but 1563c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor * is treated as a serial device at the S60 end, so we want 1564c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor * to expose it on Linux too. */ 1565c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x042D), }, /* Nokia 3250 */ 1566c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x04D8), }, /* Nokia 5500 Sport */ 1567c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x04C9), }, /* Nokia E50 */ 1568c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0419), }, /* Nokia E60 */ 1569c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x044D), }, /* Nokia E61 */ 1570c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0001), }, /* Nokia E61i */ 1571c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0475), }, /* Nokia E62 */ 1572c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0508), }, /* Nokia E65 */ 1573c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0418), }, /* Nokia E70 */ 1574c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0425), }, /* Nokia N71 */ 1575c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0486), }, /* Nokia N73 */ 1576c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x04DF), }, /* Nokia N75 */ 1577c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x000e), }, /* Nokia N77 */ 1578c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0445), }, /* Nokia N80 */ 1579c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x042F), }, /* Nokia N91 & N91 8GB */ 1580c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x048E), }, /* Nokia N92 */ 1581c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0420), }, /* Nokia N93 */ 1582c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x04E6), }, /* Nokia N93i */ 1583c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x04B2), }, /* Nokia 5700 XpressMusic */ 1584c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0134), }, /* Nokia 6110 Navigator (China) */ 1585c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x046E), }, /* Nokia 6110 Navigator */ 1586c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x002f), }, /* Nokia 6120 classic & */ 1587c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0088), }, /* Nokia 6121 classic */ 1588c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x00fc), }, /* Nokia 6124 classic */ 1589c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0042), }, /* Nokia E51 */ 1590c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x00b0), }, /* Nokia E66 */ 1591c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x00ab), }, /* Nokia E71 */ 1592c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0481), }, /* Nokia N76 */ 1593c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0007), }, /* Nokia N81 & N81 8GB */ 1594c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0071), }, /* Nokia N82 */ 1595c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x04F0), }, /* Nokia N95 & N95-3 NAM */ 1596c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0070), }, /* Nokia N95 8GB */ 1597c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */ 1598c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0099), }, /* Nokia 6210 Navigator, RM-367 */ 1599c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0128), }, /* Nokia 6210 Navigator, RM-419 */ 1600c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x008f), }, /* Nokia 6220 Classic */ 1601c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x00a0), }, /* Nokia 6650 */ 1602c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x007b), }, /* Nokia N78 */ 1603c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0094), }, /* Nokia N85 */ 1604c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x003a), }, /* Nokia N96 & N96-3 */ 1605c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */ 1606c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x0108), }, /* Nokia 5320 XpressMusic 2G */ 1607c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor { NOKIA_PCSUITE_ACM_INFO(0x01f5), }, /* Nokia N97, RM-505 */ 160883a4eae9aeed4a69e89e323a105e653ae06e7c1fPrzemo Firszt { NOKIA_PCSUITE_ACM_INFO(0x02e3), }, /* Nokia 5230, RM-588 */ 16094035e45632c2a8bb4edae83c20447051bd9a9604Toby Gray { NOKIA_PCSUITE_ACM_INFO(0x0178), }, /* Nokia E63 */ 16104035e45632c2a8bb4edae83c20447051bd9a9604Toby Gray { NOKIA_PCSUITE_ACM_INFO(0x010e), }, /* Nokia E75 */ 16114035e45632c2a8bb4edae83c20447051bd9a9604Toby Gray { NOKIA_PCSUITE_ACM_INFO(0x02d9), }, /* Nokia 6760 Slide */ 16124035e45632c2a8bb4edae83c20447051bd9a9604Toby Gray { NOKIA_PCSUITE_ACM_INFO(0x01d0), }, /* Nokia E52 */ 16134035e45632c2a8bb4edae83c20447051bd9a9604Toby Gray { NOKIA_PCSUITE_ACM_INFO(0x0223), }, /* Nokia E72 */ 16144035e45632c2a8bb4edae83c20447051bd9a9604Toby Gray { NOKIA_PCSUITE_ACM_INFO(0x0275), }, /* Nokia X6 */ 16154035e45632c2a8bb4edae83c20447051bd9a9604Toby Gray { NOKIA_PCSUITE_ACM_INFO(0x026c), }, /* Nokia N97 Mini */ 16164035e45632c2a8bb4edae83c20447051bd9a9604Toby Gray { NOKIA_PCSUITE_ACM_INFO(0x0154), }, /* Nokia 5800 XpressMusic */ 16174035e45632c2a8bb4edae83c20447051bd9a9604Toby Gray { NOKIA_PCSUITE_ACM_INFO(0x04ce), }, /* Nokia E90 */ 16184035e45632c2a8bb4edae83c20447051bd9a9604Toby Gray { NOKIA_PCSUITE_ACM_INFO(0x01d4), }, /* Nokia E55 */ 1619721d92fc6373dee15846216f9d178ec240ec0fd7Arvid Ephraim Picciani { NOKIA_PCSUITE_ACM_INFO(0x0302), }, /* Nokia N8 */ 16204061fde2fa80f40cb27114f60500d38d0afcf350Toby Gray { NOKIA_PCSUITE_ACM_INFO(0x0335), }, /* Nokia E7 */ 16214061fde2fa80f40cb27114f60500d38d0afcf350Toby Gray { NOKIA_PCSUITE_ACM_INFO(0x03cd), }, /* Nokia C7 */ 16224035e45632c2a8bb4edae83c20447051bd9a9604Toby Gray { SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */ 1623c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor 162465e52f41fa944cef2e6d4222b8c54f46cc575214Denis Pershin /* Support for Owen devices */ 162565e52f41fa944cef2e6d4222b8c54f46cc575214Denis Pershin { USB_DEVICE(0x03eb, 0x0030), }, /* Owen SI30 */ 162665e52f41fa944cef2e6d4222b8c54f46cc575214Denis Pershin 1627c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */ 1628c1479a92cf0a7792298d364e44a781550621cb58Adrian Taylor 16297c5d8c394a077a686cfa646cd85dc159a2a940ccJulian Calaby /* Support Lego NXT using pbLua firmware */ 1630ce126644aa10bf1d8f1c1929b65adab026095761Julian Calaby { USB_DEVICE(0x0694, 0xff00), 1631ce126644aa10bf1d8f1c1929b65adab026095761Julian Calaby .driver_info = NOT_A_MODEM, 16327893afc035590383a14b176c1497cba984276ef4Otavio Salvador }, 16337c5d8c394a077a686cfa646cd85dc159a2a940ccJulian Calaby 1634fd5054c169d29747a44b4e1419ff47f57ae82dbcErik Slagter /* Support for Droids MuIn LCD */ 1635fd5054c169d29747a44b4e1419ff47f57ae82dbcErik Slagter { USB_DEVICE(0x04d8, 0x000b), 1636fd5054c169d29747a44b4e1419ff47f57ae82dbcErik Slagter .driver_info = NO_DATA_INTERFACE, 1637fd5054c169d29747a44b4e1419ff47f57ae82dbcErik Slagter }, 1638fd5054c169d29747a44b4e1419ff47f57ae82dbcErik Slagter 16395b239f0aebd4dd6f85b13decf5e18e86e35d57f0Philippe Corbes /* control interfaces without any protocol set */ 16405b239f0aebd4dd6f85b13decf5e18e86e35d57f0Philippe Corbes { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, 16415b239f0aebd4dd6f85b13decf5e18e86e35d57f0Philippe Corbes USB_CDC_PROTO_NONE) }, 16425b239f0aebd4dd6f85b13decf5e18e86e35d57f0Philippe Corbes 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* control interfaces with various AT-command sets */ 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_CDC_ACM_PROTO_AT_V25TER) }, 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_CDC_ACM_PROTO_AT_PCCA101) }, 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, 16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) }, 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_CDC_ACM_PROTO_AT_GSM) }, 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, 16536e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox USB_CDC_ACM_PROTO_AT_3G) }, 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_CDC_ACM_PROTO_AT_CDMA) }, 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16606e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan CoxMODULE_DEVICE_TABLE(usb, acm_ids); 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver acm_driver = { 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "cdc_acm", 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = acm_probe, 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = acm_disconnect, 1666357585892e56f7c7bec4a9c8dfaf90257c8756c6Oliver Neukum#ifdef CONFIG_PM 16671365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum .suspend = acm_suspend, 16681365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum .resume = acm_resume, 1669a91b0c502285fd0c569fae1222fdd945ef739233Francesco Lavra .reset_resume = acm_reset_resume, 1670357585892e56f7c7bec4a9c8dfaf90257c8756c6Oliver Neukum#endif 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = acm_ids, 1672357585892e56f7c7bec4a9c8dfaf90257c8756c6Oliver Neukum#ifdef CONFIG_PM 16731365baf7249bb2d05e774e7681237b8e86f5007aOliver Neukum .supports_autosuspend = 1, 1674357585892e56f7c7bec4a9c8dfaf90257c8756c6Oliver Neukum#endif 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * TTY driver structures. 16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1681b68e31d0ebbcc909d1941f9f230c9d062a3a13d3Jeff Dikestatic const struct tty_operations acm_ops = { 16827fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen .install = acm_tty_install, 16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = acm_tty_open, 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = acm_tty_close, 16857fb57a019f94ea0c1290c39b8da753be155af41cHavard Skinnemoen .cleanup = acm_tty_cleanup, 168610077d4a6674f535abdbe25cdecb1202af7948f1Alan Cox .hangup = acm_tty_hangup, 16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = acm_tty_write, 16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_room = acm_tty_write_room, 16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = acm_tty_ioctl, 16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .throttle = acm_tty_throttle, 16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .unthrottle = acm_tty_unthrottle, 16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .chars_in_buffer = acm_tty_chars_in_buffer, 16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .break_ctl = acm_tty_break_ctl, 16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_termios = acm_tty_set_termios, 16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .tiocmget = acm_tty_tiocmget, 16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .tiocmset = acm_tty_tiocmset, 16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Init / exit. 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acm_init(void) 17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS); 17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!acm_tty_driver) 17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm_tty_driver->driver_name = "acm", 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm_tty_driver->name = "ttyACM", 17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm_tty_driver->major = ACM_TTY_MAJOR, 17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm_tty_driver->minor_start = 0, 17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL, 17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm_tty_driver->subtype = SERIAL_TYPE_NORMAL, 1715331b831983f9d706f4a40d08a996d5c2c7a6ea7bGreg Kroah-Hartman acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acm_tty_driver->init_termios = tty_std_termios; 17176e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | 17186e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan Cox HUPCL | CLOCAL; 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_set_operations(acm_tty_driver, &acm_ops); 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = tty_register_driver(acm_tty_driver); 17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) { 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_tty_driver(acm_tty_driver); 17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_register(&acm_driver); 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) { 17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_unregister_driver(acm_tty_driver); 17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_tty_driver(acm_tty_driver); 17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1734a2c7b9353e8f782590852052fe2948692020147eJohan Hovold printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); 17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit acm_exit(void) 17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_deregister(&acm_driver); 17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_unregister_driver(acm_tty_driver); 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_tty_driver(acm_tty_driver); 17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(acm_init); 17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(acm_exit); 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17496e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan CoxMODULE_AUTHOR(DRIVER_AUTHOR); 17506e47e069eb4dffa88ad91ddfc3fd85f32c35654bAlan CoxMODULE_DESCRIPTION(DRIVER_DESC); 17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 1752e766aeb882b41355d8732cf49aa9412baef852c5Scott James RemnantMODULE_ALIAS_CHARDEV_MAJOR(ACM_TTY_MAJOR); 1753