From 39be60cbd61c3857544d3a343a43c9964c7461b5 Mon Sep 17 00:00:00 2001 From: Benoit Goby Date: Fri, 12 Nov 2010 16:11:02 -0800 Subject: [PATCH] usb: serial: Remove mdm6600_modem driver Replaced by mdm6600 driver Change-Id: I04fed22901055da6fb3e296d62a9452aa93225f2 Signed-off-by: Benoit Goby --- drivers/usb/serial/Kconfig | 9 - drivers/usb/serial/Makefile | 1 - drivers/usb/serial/mdm6600_modem.c | 1380 ---------------------------- 3 files changed, 1390 deletions(-) delete mode 100644 drivers/usb/serial/mdm6600_modem.c diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 724e46fd0264..1bdab84a7ea1 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -458,15 +458,6 @@ config USB_SERIAL_MOTOROLA To compile this driver as a module, choose M here: the module will be called moto_modem. If unsure, choose N. -config USB_MDM6600_CDMA_MODEM - tristate "USB Motorola Phone modem driver" - ---help--- - Say Y here if you want to use a Motorola phone with a USB - connector as a modem link. - - To compile this driver as a module, choose M here: the - module will be called mdm6600_modem. If unsure, choose N. - config USB_SERIAL_MDM6600 tristate "USB MDM6600 modem" help diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index eb910e28c6d9..3da56db47c76 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -39,7 +39,6 @@ obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o obj-$(CONFIG_USB_SERIAL_MOS7720) += mos7720.o obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o obj-$(CONFIG_USB_SERIAL_MOTOROLA) += moto_modem.o -obj-$(CONFIG_USB_MDM6600_CDMA_MODEM) += mdm6600_modem.o obj-$(CONFIG_USB_SERIAL_MDM6600) += mdm6600.o obj-$(CONFIG_USB_SERIAL_MOTO_FLASH_MODEM) += moto_flashmdm.o obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o diff --git a/drivers/usb/serial/mdm6600_modem.c b/drivers/usb/serial/mdm6600_modem.c deleted file mode 100644 index 2221ade318fc..000000000000 --- a/drivers/usb/serial/mdm6600_modem.c +++ /dev/null @@ -1,1380 +0,0 @@ -/* - * Copyright (C) 2010 Motorola, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307, USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define WDR_TIMEOUT (HZ * 5) -#define MODEM_NO_TRAFFIC_TIME (HZ/4) -#define MODEM_WAKELOCK_TIME (HZ/2) - -#define BP_MODEM_STATUS 0x20a1 -#define BP_RSP_AVAIL 0x01a1 -#define BP_SPEED_CHANGE 0x2aa1 - -#define BP_CAR 0x01 -#define BP_DSR 0x02 -#define BP_BREAK 0x04 -#define BP_RNG 0x08 - -#define BULKOUT_SIZE 1280 -#define MODEM_INTERFACE_NUM 4 - -#define AP_NW 16 -#define AP_NR 16 - -struct ap_wb { - unsigned char *buf; - dma_addr_t dmah; - int len; - int use; - struct urb *urb; - struct modem_port *instance; -}; - -struct ap_rb { - struct list_head list; - int size; - unsigned char *base; - dma_addr_t dma; -}; - -struct ap_ru { - struct list_head list; - struct ap_rb *buffer; - struct urb *urb; - struct modem_port *instance; -}; - -struct modem_port { - __u16 modem_status; /* only used for data modem port */ - __u8 wakeup_gpio; - struct ap_ru ru[AP_NR]; - struct ap_rb rb[AP_NR]; - struct ap_wb wb[AP_NW]; - struct ap_wb *delayed_wb; - int rx_buflimit; - int rx_endpoint; - unsigned int susp_count; - unsigned int resuming; - struct tasklet_struct urb_task; - struct usb_serial_port *port; - spinlock_t read_lock; - spinlock_t write_lock; - atomic_t wakeup_flag; - spinlock_t last_traffic_lock; - unsigned long last_traffic; - unsigned int readsize; - unsigned int writesize; - struct list_head spare_read_urbs; - struct list_head spare_read_bufs; - struct list_head filled_read_bufs; - int processing; - int sending; - int opened; - struct work_struct wake_and_write; - struct work_struct usb_wkup_work; -}; - -static struct usb_device_id id_table[] = { - {USB_DEVICE(0x22b8, 0x2a70)}, /* Olympus MDM6600 BP modem */ - {}, -}; - -MODULE_DEVICE_TABLE(usb, id_table); - -static uint32_t cdma_modem_debug = 0; -module_param_named(cdma_mdm_debug, cdma_modem_debug, uint, 0664); - -static struct wake_lock modem_wakelock; - -static int modem_wb_alloc(struct modem_port *modem_ptr) -{ - int i; - struct ap_wb *wb; - - for (i = 0; i < AP_NW; i++) { - wb = &modem_ptr->wb[i]; - if (!wb->use) { - wb->use = 1; - return i; - } - } - return -1; -} - -static void modem_write_buffers_free( - struct modem_port *modem_ptr, - struct usb_serial *serial) -{ - int i; - struct ap_wb *wb; - struct usb_device *usb_dev = serial->dev; - - for (wb = &modem_ptr->wb[0], i = 0; i < AP_NW; i++, wb++) - usb_free_coherent(usb_dev, modem_ptr->writesize, - wb->buf, wb->dmah); -} - -static int modem_write_buffers_alloc( - struct modem_port *modem_ptr, - struct usb_serial *serial) -{ - int i; - struct ap_wb *wb; - - for (wb = &modem_ptr->wb[0], i = 0; i < AP_NW; i++, wb++) { - wb->buf = usb_alloc_coherent(serial->dev, modem_ptr->writesize, - GFP_KERNEL, &wb->dmah); - if (!wb->buf) { - while (i != 0) { - --i; - --wb; - usb_free_coherent(serial->dev, - modem_ptr->writesize, - wb->buf, wb->dmah); - } - return -ENOMEM; - } - } - return 0; -} - -static void mark_latest_traffic_time(struct modem_port *modem_port_ptr) -{ - unsigned long flags; - spin_lock_irqsave(&modem_port_ptr->last_traffic_lock, flags); - modem_port_ptr->last_traffic = jiffies; - spin_unlock_irqrestore(&modem_port_ptr->last_traffic_lock, flags); -} - -static void stop_data_traffic(struct modem_port *modem_port_ptr) -{ - int i; - struct usb_serial_port *port = modem_port_ptr->port; - - if (port == NULL) - return; - if (cdma_modem_debug) - dev_info(&port->dev, "%s() port %d\n", - __func__, port->number); - - tasklet_disable(&modem_port_ptr->urb_task); - - for (i = 0; i < AP_NW; i++) - usb_kill_urb(modem_port_ptr->wb[i].urb); - for (i = 0; i < modem_port_ptr->rx_buflimit; i++) - usb_kill_urb(modem_port_ptr->ru[i].urb); - - usb_kill_urb(modem_port_ptr->port->interrupt_in_urb); - - tasklet_enable(&modem_port_ptr->urb_task); - - cancel_work_sync(&port->work); - cancel_work_sync(&modem_port_ptr->usb_wkup_work); -} - -static void modem_read_buffers_free( - struct modem_port *modem_ptr, - struct usb_serial *serial) -{ - struct usb_device *usb_dev = serial->dev; - int i; - int n = modem_ptr->rx_buflimit; - - for (i = 0; i < n; i++) - usb_free_coherent(usb_dev, modem_ptr->readsize, - modem_ptr->rb[i].base, - modem_ptr->rb[i].dma); -} - -static int modem_dtr_control(struct usb_serial *serial, int ctrl) -{ - struct modem_port *modem_port_ptr = - usb_get_serial_data(serial); - uint8_t bRequesttype = - (USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT); - uint16_t wLength = 0; - uint8_t bRequest = 0x22; - uint16_t wValue = ctrl; - uint16_t wIndex = MODEM_INTERFACE_NUM; - unsigned int pipe; - int status; - - status = usb_autopm_get_interface(serial->interface); - if (status < 0) { - dev_err(&serial->dev->dev, "%s %s autopm failed %d", - dev_driver_string - (&serial->interface->dev), - dev_name(&serial->interface->dev), status); - return status; - } - - pipe = usb_sndctrlpipe(serial->dev, 0); - status = usb_control_msg(serial->dev, pipe, - bRequest, bRequesttype, - wValue, wIndex, NULL, wLength, - WDR_TIMEOUT); - usb_autopm_put_interface(serial->interface); - if (modem_port_ptr) - mark_latest_traffic_time(modem_port_ptr); - - return status; -} - -static int modem_tiocmget(struct tty_struct *tty, struct file *file) -{ - struct usb_serial_port *port = tty->driver_data; - struct modem_port *modem_port_ptr = usb_get_serial_data(port->serial); - - if (modem_port_ptr == NULL) - return 0; - - return (int)modem_port_ptr->modem_status; -} - -static int modem_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - int status = 0; - - if (cdma_modem_debug) - dev_info(&port->dev, "%s: Enter. clear is %d, set is %d\n", - __func__, clear, set); - - if (port->number == MODEM_INTERFACE_NUM) { - - if (clear & TIOCM_DTR) - status = modem_dtr_control(port->serial, 0); - - if (set & TIOCM_DTR) - status = modem_dtr_control(port->serial, 1); - } - - if (cdma_modem_debug) - dev_info(&port->dev, "%s: Exit. Status %d\n", - __func__, status); - - return status; -} - -static void modem_read_bulk_callback(struct urb *urb) -{ - struct ap_rb *buf; - struct ap_ru *rcv = urb->context; - struct modem_port *modem_port_ptr; - int status = urb->status; - - modem_port_ptr = rcv->instance; - if (modem_port_ptr == NULL) - return; - - if (modem_port_ptr->port == NULL) - return; - - mark_latest_traffic_time(modem_port_ptr); - buf = rcv->buffer; - buf->size = urb->actual_length; - - spin_lock(&modem_port_ptr->read_lock); - list_add_tail(&rcv->list, &modem_port_ptr->spare_read_urbs); - - if (likely(status == 0)) { - modem_port_ptr->processing++; - list_add_tail(&buf->list, &modem_port_ptr->filled_read_bufs); - } else { - if (cdma_modem_debug) - dev_info(&modem_port_ptr->port->dev, - "%s: bulk rx err %d\n", __func__, status); - /* we drop the buffer due to an error */ - list_add(&buf->list, &modem_port_ptr->spare_read_bufs); - /* nevertheless the tasklet must be kicked unconditionally - so the queue cannot dry up */ - } - - if (modem_port_ptr->opened != 1) { - spin_unlock(&modem_port_ptr->read_lock); - return; - } - - if (likely(modem_port_ptr->susp_count == 0)) - tasklet_schedule(&modem_port_ptr->urb_task); - spin_unlock(&modem_port_ptr->read_lock); - -} - -static void modem_update_modem_status(struct usb_serial_port *port, - __u8 modem_status) -{ - struct modem_port *modem_port_ptr; - - if (port->number == MODEM_INTERFACE_NUM) { - modem_port_ptr = usb_get_serial_data(port->serial); - if (modem_port_ptr == NULL) { - dev_err(&port->dev, - "%s: null modem port pointer.\n", - __func__); - return; - } - - if (modem_status & BP_CAR) - modem_port_ptr->modem_status |= TIOCM_CAR; - else - modem_port_ptr->modem_status &= ~TIOCM_CAR; - - if (modem_status & BP_DSR) - modem_port_ptr->modem_status |= TIOCM_DSR; - else - modem_port_ptr->modem_status &= ~TIOCM_DSR; - - if (modem_status & BP_RNG) - modem_port_ptr->modem_status |= TIOCM_RNG; - else - modem_port_ptr->modem_status &= ~TIOCM_RNG; - - if (cdma_modem_debug) - dev_info(&port->dev, "%s: modem status is now %d\n", - __func__, - modem_port_ptr->modem_status); - } -} - -static void modem_interrupt_callback(struct urb *urb) -{ - int status = urb->status; - uint16_t request_and_type; - uint8_t modem_status; - uint8_t *data; - int length; - int retval; - unsigned long flags; - - struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - struct modem_port *modem_port_ptr = - usb_get_serial_data(port->serial); - - if (modem_port_ptr->port == NULL) - return; - - if (port->number != MODEM_INTERFACE_NUM) { - if (cdma_modem_debug) - dev_info(&port->dev, - "%s: Not Modem port.\n", __func__); - goto exit; - } - - switch (status) { - case 0: - if (cdma_modem_debug) - dev_info(&port->dev, "%s: usb -inter_cbk\n", __func__); - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - if (cdma_modem_debug) - dev_info(&port->dev, "%s: urb shutting down\n", - __func__); - return; - default: - dev_err(&port->dev, "%s: nonzero urb status, %d.\n", - __func__, status); - goto exit; - } - - spin_lock_irqsave(&modem_port_ptr->read_lock, flags); - modem_port_ptr->processing++; - spin_unlock_irqrestore(&modem_port_ptr->read_lock, flags); - - length = urb->actual_length; - data = (__u8 *) urb->transfer_buffer; - - request_and_type = *((__u16 *) data); - - if (cdma_modem_debug) - dev_info(&port->dev, "%s: request and type is %d\n", - __func__, request_and_type); - - switch (request_and_type) { - case BP_MODEM_STATUS: - modem_status = data[8]; - if (cdma_modem_debug) - dev_info(&port->dev, "%s: MODEM status %d\n", - __func__, modem_status); - modem_update_modem_status(port, modem_status); - break; - - case BP_RSP_AVAIL: - if (cdma_modem_debug) - dev_info(&port->dev, "%s: BP_RSP_AVAIL\n", - __func__); - break; - - case BP_SPEED_CHANGE: - if (cdma_modem_debug) - dev_info(&port->dev, "%s: BP_SPEED_CHANGE\n", - __func__); - break; - - default: - if (cdma_modem_debug) - dev_info(&port->dev, - "%s: undefined BP request type %d\n", - __func__, request_and_type); - break; - } - -exit: - spin_lock_irqsave(&modem_port_ptr->read_lock, flags); - if (modem_port_ptr->susp_count == 0) { - retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval) { - dev_err(&port->dev, - "%s: submit int usb failed. ret = %d\n", - __func__, retval); - } - } - modem_port_ptr->processing--; - spin_unlock_irqrestore(&modem_port_ptr->read_lock, flags); - mark_latest_traffic_time(modem_port_ptr); - return; -} - -static int modem_open(struct tty_struct *tty, - struct usb_serial_port *port) -{ - struct modem_port *modem_port_ptr = - usb_get_serial_data(port->serial); - int retval = 0; - int i; - unsigned long flags; - - if (cdma_modem_debug) - dev_info(&port->dev, "%s: Enter. Open Port %d\n", - __func__, port->number); - - /* clear the throttle flags */ - port->throttled = 0; - port->throttle_req = 0; - - if (modem_port_ptr == NULL) { - dev_err(&port->dev, - "%s: null modem port pointer.\n", - __func__); - return -ENODEV; - } - - port->serial->interface->needs_remote_wakeup = 1; - - modem_port_ptr->port = port; - - INIT_LIST_HEAD(&modem_port_ptr->spare_read_urbs); - INIT_LIST_HEAD(&modem_port_ptr->spare_read_bufs); - INIT_LIST_HEAD(&modem_port_ptr->filled_read_bufs); - - for (i = 0; i < modem_port_ptr->rx_buflimit; i++) { - list_add(&(modem_port_ptr->ru[i].list), - &modem_port_ptr->spare_read_urbs); - } - - for (i = 0; i < modem_port_ptr->rx_buflimit; i++) { - list_add(&(modem_port_ptr->rb[i].list), - &modem_port_ptr->spare_read_bufs); - } - - spin_lock_irqsave(&modem_port_ptr->read_lock, flags); - if (modem_port_ptr->susp_count == 0) - tasklet_schedule(&modem_port_ptr->urb_task); - spin_unlock_irqrestore(&modem_port_ptr->read_lock, flags); - - if (port->number == MODEM_INTERFACE_NUM) { - spin_lock_irqsave(&modem_port_ptr->read_lock, flags); - if (modem_port_ptr->susp_count == 0) { - if (port->interrupt_in_urb) { - /* start to read INT EP data */ - port->interrupt_in_urb->dev = port->serial->dev; - retval = - usb_submit_urb(port->interrupt_in_urb, - GFP_KERNEL); - if (retval) { - usb_kill_urb(port->interrupt_in_urb); - dev_err(&port->dev, - "%s: retval is %d\n", - __func__, retval); - } - } else { - dev_err(&port->dev, - "%s: no interrupt endpoint\n", - __func__); - } - - } - spin_unlock_irqrestore(&modem_port_ptr->read_lock, - flags); - - /* clean up the modem status data */ - modem_port_ptr->modem_status = 0; - - wake_lock_init(&modem_wakelock, WAKE_LOCK_SUSPEND, - "omap_usb_modem"); - } - - /* pm interface is taken at - * serial_open() at usb-serial.c. - * For data modem port: the pm count needs to be put back here - * to support the auto-suspend/auto-resume. - * For other test command port: the pm count will be put back at - * the time when port is closed. - */ - if (port->number == MODEM_INTERFACE_NUM) - usb_autopm_put_interface(port->serial->interface); - - if (cdma_modem_debug) - dev_info(&port->dev, "%s: Exit. retval = %d\n", - __func__, retval); - - modem_port_ptr->opened = 1; - - return retval; -} - -static void modem_rx_tasklet(unsigned long _modem_port) -{ - struct modem_port *modem_port_ptr = (void *)_modem_port; - struct ap_rb *buf; - struct tty_struct *tty; - struct usb_serial_port *port; - struct ap_ru *rcv; - unsigned long flags; - unsigned char throttled; - - if (!modem_port_ptr) - return; - - port = modem_port_ptr->port; - if (!port) - return; - - tty = port->port.tty; - if (!tty) - return; - - spin_lock_irqsave(&modem_port_ptr->port->lock, flags); - throttled = modem_port_ptr->port->throttle_req; - spin_unlock_irqrestore(&modem_port_ptr->port->lock, flags); - if (throttled) { - dev_err(&port->dev, "%s: throttled.\n", __func__); - return; - } - -next_buffer: - spin_lock_irqsave(&modem_port_ptr->read_lock, flags); - if (list_empty(&modem_port_ptr->filled_read_bufs)) { - spin_unlock_irqrestore(&modem_port_ptr->read_lock, flags); - goto urbs; - } - buf = list_entry(modem_port_ptr->filled_read_bufs.next, - struct ap_rb, list); - list_del(&buf->list); - spin_unlock_irqrestore(&modem_port_ptr->read_lock, flags); - - tty_buffer_request_room(tty, buf->size); - spin_lock_irqsave(&modem_port_ptr->port->lock, flags); - throttled = modem_port_ptr->port->throttle_req; - spin_unlock_irqrestore(&modem_port_ptr->port->lock, flags); - if (!throttled) - tty_insert_flip_string(tty, buf->base, buf->size); - tty_flip_buffer_push(tty); - - if (throttled) { - dev_err(&port->dev, "%s: Throttling noticed.\n", __func__); - spin_lock_irqsave(&modem_port_ptr->read_lock, flags); - list_add(&buf->list, &modem_port_ptr->filled_read_bufs); - spin_unlock_irqrestore(&modem_port_ptr->read_lock, flags); - return; - } - - spin_lock_irqsave(&modem_port_ptr->read_lock, flags); - list_add(&buf->list, &modem_port_ptr->spare_read_bufs); - spin_unlock_irqrestore(&modem_port_ptr->read_lock, flags); - goto next_buffer; - -urbs: - while (!list_empty(&modem_port_ptr->spare_read_bufs)) { - spin_lock_irqsave(&modem_port_ptr->read_lock, flags); - if (list_empty(&modem_port_ptr->spare_read_urbs)) { - modem_port_ptr->processing = 0; - spin_unlock_irqrestore(&modem_port_ptr->read_lock, - flags); - if (cdma_modem_debug) - dev_info(&port->dev, - "%s: no urb to create.\n", __func__); - return; - } - rcv = list_entry(modem_port_ptr->spare_read_urbs.next, - struct ap_ru, list); - list_del(&rcv->list); - - buf = list_entry(modem_port_ptr->spare_read_bufs.next, - struct ap_rb, list); - list_del(&buf->list); - - spin_unlock_irqrestore(&modem_port_ptr->read_lock, flags); - - rcv->buffer = buf; - - usb_fill_bulk_urb(rcv->urb, modem_port_ptr->port->serial->dev, - modem_port_ptr->rx_endpoint, - buf->base, - modem_port_ptr->readsize, - modem_read_bulk_callback, rcv); - rcv->urb->transfer_dma = buf->dma; - rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - spin_lock_irqsave(&modem_port_ptr->read_lock, flags); - if ((modem_port_ptr->susp_count > 0) || - usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) { - list_add(&buf->list, &modem_port_ptr->spare_read_bufs); - list_add(&rcv->list, &modem_port_ptr->spare_read_urbs); - modem_port_ptr->processing = 0; - dev_err(&port->dev, "%s: submit bulk in urb failed.\n", - __func__); - spin_unlock_irqrestore(&modem_port_ptr->read_lock, - flags); - return; - } else { - spin_unlock_irqrestore(&modem_port_ptr->read_lock, - flags); - } - } - spin_lock_irqsave(&modem_port_ptr->read_lock, flags); - modem_port_ptr->processing = 0; - spin_unlock_irqrestore(&modem_port_ptr->read_lock, flags); - -} - -static void modem_close(struct usb_serial_port *port) -{ - struct modem_port *modem_port_ptr; - - if (cdma_modem_debug) - dev_info(&port->dev, "%s: Enter. Close Port %d\n", - __func__, port->number); - - modem_port_ptr = usb_get_serial_data(port->serial); - if (!modem_port_ptr) { - dev_err(&port->dev, - "%s: null modem port pointer.\n", - __func__); - return; - } - - modem_port_ptr->opened = 0; - /* For the data modem port, the pm interface needs to be get here - * and will be put back at serial_close() of usb-serial.c - */ - - if (port->number == MODEM_INTERFACE_NUM) { - usb_autopm_get_interface(port->serial->interface); - } - - stop_data_traffic(modem_port_ptr); - cancel_work_sync(&modem_port_ptr->wake_and_write); - modem_port_ptr->port = 0; - modem_port_ptr->modem_status = 0; - if (modem_port_ptr->delayed_wb) - modem_port_ptr->delayed_wb->use = 0; - - if (port->number == MODEM_INTERFACE_NUM) - wake_lock_destroy(&modem_wakelock); - - if (cdma_modem_debug) - dev_info(&port->dev, "%s: Exit.\n", __func__); -} - -/* caller hold modem_port_ptr->write_lock */ -static void modem_write_done(struct modem_port *modem_port_ptr, - struct ap_wb *wb) -{ - wb->use = 0; - modem_port_ptr->sending--; -} - -static int modem_start_wb(struct modem_port *modem_port_ptr, - struct ap_wb *wb) -{ - int result = 0; - struct usb_serial_port *port = modem_port_ptr->port; - unsigned long flags; - - if (port == NULL) - return -ENODEV; - - spin_lock_irqsave(&modem_port_ptr->write_lock, flags); - modem_port_ptr->sending++; - - wb->urb->transfer_buffer = wb->buf; - wb->urb->transfer_dma = wb->dmah; - wb->urb->transfer_buffer_length = wb->len; - wb->urb->dev = modem_port_ptr->port->serial->dev; - - result = usb_submit_urb(wb->urb, GFP_ATOMIC); - if (result < 0) { - dev_err(&port->dev, - "%s: Submit bulk out URB failed. ret = %d\n", - __func__, result); - modem_write_done(modem_port_ptr, wb); - } - - spin_unlock_irqrestore(&modem_port_ptr->write_lock, flags); - mark_latest_traffic_time(modem_port_ptr); - - return result; -} - -static void modem_wake_and_write(struct work_struct *work) -{ - struct modem_port *modem_port_ptr = - container_of(work, struct modem_port, wake_and_write); - struct usb_serial *serial; - struct usb_serial_port *port = modem_port_ptr->port; - int result; - - if (modem_port_ptr->port == NULL) - return; - - serial = modem_port_ptr->port->serial; - - result = usb_autopm_get_interface(serial->interface); - if (result < 0) { - dev_err(&port->dev, "%s: autopm failed. result = %d \n", - __func__, result); - return; - } - if (modem_port_ptr->delayed_wb) { - modem_start_wb(modem_port_ptr, modem_port_ptr->delayed_wb); - modem_port_ptr->delayed_wb = NULL; - } - - usb_autopm_put_interface(serial->interface); -} - -static void modem_write_bulk_callback(struct urb *urb) -{ - struct ap_wb *wb = urb->context; - int status = urb->status; - struct modem_port *modem_port_ptr = wb->instance; - struct usb_serial_port *port = modem_port_ptr->port; - unsigned long flags; - - if (port == NULL) - return; - - spin_lock_irqsave(&modem_port_ptr->write_lock, flags); - modem_write_done(modem_port_ptr, wb); - spin_unlock_irqrestore(&modem_port_ptr->write_lock, flags); - if (status) { - dev_err(&port->dev, "%s: status non-zero. status = %d\n", - __func__, status); - return; - } - usb_serial_port_softint(port); -} - -static int modem_write(struct tty_struct *tty, - struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - struct usb_serial *serial = port->serial; - int result, wbn; - struct ap_wb *wb; - struct modem_port *modem_port_ptr = - usb_get_serial_data(port->serial); - - - if (count == 0) { - if (cdma_modem_debug) - dev_info(&port->dev, "%s: Exit1: %s count = 0\n", - __func__, dev_name(&port->dev)); - return 0; - } - - if (serial->num_bulk_out) { - unsigned long flags; - spin_lock_irqsave(&modem_port_ptr->write_lock, flags); - - if ((modem_port_ptr->susp_count > 0) && - (modem_port_ptr->resuming != 0)) { - spin_unlock_irqrestore(&modem_port_ptr->write_lock, - flags); - return 0; - } - - wbn = modem_wb_alloc(modem_port_ptr); - if (wbn < 0) { - spin_unlock_irqrestore(&modem_port_ptr->write_lock, - flags); - if (cdma_modem_debug) - dev_info(&port->dev, - "%s: all buffers busy!\n", __func__); - return 0; - } - wb = &modem_port_ptr->wb[wbn]; - - count = min((int)(modem_port_ptr->writesize), count); - - if (cdma_modem_debug) - dev_info(&port->dev, "%s: Get %d bytes.\n", - __func__, count); - memcpy(wb->buf, buf, count); - wb->len = count; - - /* start sending */ - if (modem_port_ptr->susp_count > 0) { - modem_port_ptr->resuming = 1; - modem_port_ptr->delayed_wb = wb; - spin_unlock_irqrestore(&modem_port_ptr->write_lock, - flags); - - /* for the data modem, add wakelock to bypass the issue - * caused by skip_sys_resume for FS USB - */ - if (modem_port_ptr->port->number - == MODEM_INTERFACE_NUM) { - wake_lock_timeout(&modem_wakelock, - MODEM_WAKELOCK_TIME); - if (cdma_modem_debug) - dev_info(&modem_port_ptr->port->dev, - "%s: add wakelock\n", __func__); - } - schedule_work(&modem_port_ptr->wake_and_write); - return count; - } - spin_unlock_irqrestore(&modem_port_ptr->write_lock, flags); - result = modem_start_wb(modem_port_ptr, wb); - if (result >= 0) - result = count; - return result; - } - - /* no bulk out, so return 0 bytes written */ - return 0; -} - -//#ifdef CONFIG_PM -static void modem_usb_wkup_work(struct work_struct *work) -{ - struct modem_port *modem_port_ptr = - container_of(work, struct modem_port, usb_wkup_work); - struct usb_serial *serial; - int result; - - if (modem_port_ptr->port == 0) - return; - - if (cdma_modem_debug) - printk("%s +++ \n", __func__); - - serial = modem_port_ptr->port->serial; - if ((modem_port_ptr->port != 0) && - !(atomic_cmpxchg(&modem_port_ptr->wakeup_flag, 0, 1))) { - /* for the data modem, add wakelock to bypass the issue - * caused by skip_sys_resume for FS USB - */ - if (modem_port_ptr->port->number == MODEM_INTERFACE_NUM) { - if (cdma_modem_debug) - dev_info(&modem_port_ptr->port->dev, - "%s: add wakelock\n", __func__); - wake_lock_timeout(&modem_wakelock, MODEM_WAKELOCK_TIME); - } - result = usb_autopm_get_interface(serial->interface); - if (result < 0) { - atomic_set(&modem_port_ptr->wakeup_flag, 0); - dev_err(&modem_port_ptr->port->dev, - "%s: autopm failed. result = %d \n", - __func__, result); - return; - } - - if (cdma_modem_debug) - dev_info(&modem_port_ptr->port->dev, - "%s: woke up interface\n", __func__); - usb_autopm_put_interface(serial->interface); - } -} - -static int modem_usb_enable_wakeup_irq(struct usb_interface *intf) -{ - struct usb_serial *serial = usb_get_intfdata(intf); - struct modem_port *modem_port_ptr = - usb_get_serial_data(serial); - int ret = 0; - - if (modem_port_ptr == NULL) - return -ENODEV; - - return ret; -} - -static int modem_suspend(struct usb_interface *intf, - pm_message_t message) -{ - struct usb_serial *serial = usb_get_intfdata(intf); - struct modem_port *modem_port_ptr = - usb_get_serial_data(serial); - struct usb_serial_port *port; - unsigned long flags; - unsigned long threshold_time; - int tmp; - - if (modem_port_ptr == NULL) { - dev_err(&intf->dev, " NULL modem_port ptr \n"); - return 0; - } - - if (cdma_modem_debug) - dev_info(&intf->dev, "%s +++ \n", __func__); - - port = modem_port_ptr->port; - - if (port == NULL) { - if (cdma_modem_debug) - dev_info(&intf->dev, - "%s: port not open yet \n", - __func__); - modem_port_ptr->susp_count++; - return 0; - } - - if (cdma_modem_debug) - dev_info(&intf->dev, "%s: Suspend Port num %d.\n", - __func__, port->number); - - spin_lock_irqsave(&modem_port_ptr->read_lock, flags); - spin_lock(&modem_port_ptr->write_lock); - tmp = modem_port_ptr->processing + modem_port_ptr->sending; - spin_unlock(&modem_port_ptr->write_lock); - spin_unlock_irqrestore(&modem_port_ptr->read_lock, flags); - - if (tmp) { - if (cdma_modem_debug) - dev_info(&intf->dev, - "%s: sending = %d, receiving = %d.\n", - __func__, modem_port_ptr->sending, - modem_port_ptr->processing); - return -EBUSY; - } - - threshold_time = modem_port_ptr->last_traffic + MODEM_NO_TRAFFIC_TIME; - - if (time_before(jiffies, threshold_time)) { - if (cdma_modem_debug) - dev_info(&intf->dev, - "%s: busy. suspend failed.\n", __func__); - return -EBUSY; - } - - spin_lock_irqsave(&modem_port_ptr->read_lock, flags); - spin_lock(&modem_port_ptr->write_lock); - modem_port_ptr->susp_count++; - spin_unlock(&modem_port_ptr->write_lock); - spin_unlock_irqrestore(&modem_port_ptr->read_lock, flags); - - stop_data_traffic(modem_port_ptr); - - if (port->number == MODEM_INTERFACE_NUM) { - //modem_usb_enable_wakeup_irq(intf); - atomic_set(&modem_port_ptr->wakeup_flag, 0); - } - - if (cdma_modem_debug) - dev_info(&intf->dev, "%s: Port num %d.suspended\n", - __func__, port->number); - - return 0; -} - -static int modem_resume(struct usb_interface *intf) -{ - struct usb_serial *serial = usb_get_intfdata(intf); - struct modem_port *modem_port_ptr = - usb_get_serial_data(serial); - struct usb_serial_port *port; - unsigned long flags; - int retval; - - if (modem_port_ptr == NULL) { - dev_err(&intf->dev, "%s: null modem port pointer. \n", - __func__); - return 0; - } - if (cdma_modem_debug) - dev_info(&intf->dev, "%s +++ \n", __func__); - - port = modem_port_ptr->port; - - if (port == NULL) { - if (cdma_modem_debug) - dev_info(&intf->dev, - "%s: port not open yet \n", - __func__); - modem_port_ptr->susp_count--; - return 0; - - } - - spin_lock_irqsave(&modem_port_ptr->read_lock, flags); - spin_lock(&modem_port_ptr->write_lock); - if (modem_port_ptr->susp_count > 0) { - modem_port_ptr->susp_count--; - spin_unlock(&modem_port_ptr->write_lock); - spin_unlock_irqrestore(&modem_port_ptr->read_lock, flags); - - modem_port_ptr->resuming = 0; - - if (cdma_modem_debug) - dev_info(&intf->dev, "%s: port %d is resumed here \n", - __func__, port->number); - - if (port->number == MODEM_INTERFACE_NUM) { - spin_lock_irqsave(&modem_port_ptr->read_lock, flags); - if (port->interrupt_in_urb) { - port->interrupt_in_urb->dev = port->serial->dev; - retval = - usb_submit_urb(port->interrupt_in_urb, - GFP_KERNEL); - if (retval) { - usb_kill_urb(port->interrupt_in_urb); - dev_err(&port->dev, - "%s: retval is %d \n", - __func__, retval); - } - } else { - dev_err(&port->dev, - "%s: no interrupt endpoint \n", - __func__); - } - spin_unlock_irqrestore(&modem_port_ptr->read_lock, - flags); - - //modem_usb_disable_wakeup_irq(intf); - - } - - tasklet_schedule(&modem_port_ptr->urb_task); - } else { - spin_unlock(&modem_port_ptr->write_lock); - spin_unlock_irqrestore(&modem_port_ptr->read_lock, flags); - } - - if (cdma_modem_debug) - dev_info(&intf->dev, "%s: Port num %d.resumed\n", - __func__, port->number); - - return 0; -} - -static int modem_reset_resume(struct usb_interface *intf) -{ - int ret = 0; - - if (cdma_modem_debug) - dev_info(&intf->dev, - "%s: Enter \n", __func__); - - ret = modem_resume(intf); - - if (cdma_modem_debug) - dev_info(&intf->dev, - "%s: Exit ret is %d \n", __func__, ret); - - return ret; -} - -static int modem_pre_reset(struct usb_interface *intf) -{ - return 0; -} - -static int modem_post_reset(struct usb_interface *intf) -{ - return 0; -} - -//#endif /* CONFIG_PM */ - -static int modem_startup(struct usb_serial *serial) -{ - struct usb_serial_port *port = serial->port[0]; - struct modem_port *modem_port_ptr = NULL; - struct usb_interface *interface; - struct usb_endpoint_descriptor *endpoint; - struct usb_endpoint_descriptor *epread = NULL; - struct usb_endpoint_descriptor *epwrite = NULL; - struct usb_host_interface *iface_desc; - int readsize; - int num_rx_buf; - int i; - - interface = serial->interface; - iface_desc = interface->cur_altsetting; - - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - if (usb_endpoint_is_bulk_in(endpoint)) - epread = endpoint; - if (usb_endpoint_is_bulk_out(endpoint)) - epwrite = endpoint; - } - - if (epread == NULL) { - dev_err(&serial->dev->dev, - "%s: No Bulk In Endpoint for this Interface\n", - __func__); - return -EPERM; - } - if (epwrite == NULL) { - dev_err(&serial->dev->dev, - "%s: No Bulk Out Endpoint for this Interface\n", - __func__); - return -EPERM; - } - - num_rx_buf = AP_NR; - readsize = le16_to_cpu(epread->wMaxPacketSize) * 2; - - /* setup a buffer to store interface data */ - modem_port_ptr = - kzalloc(sizeof(struct modem_port), GFP_KERNEL); - if (modem_port_ptr == NULL) { - dev_err(&serial->dev->dev, - "%s: error -- no memory on start up.\n", - __func__); - return -ENOMEM; - } - - /* init tasklet for rx processing */ - tasklet_init(&modem_port_ptr->urb_task, modem_rx_tasklet, - (unsigned long)modem_port_ptr); - modem_port_ptr->rx_buflimit = num_rx_buf; - modem_port_ptr->rx_endpoint = - usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress); - spin_lock_init(&modem_port_ptr->read_lock); - spin_lock_init(&modem_port_ptr->write_lock); - spin_lock_init(&modem_port_ptr->last_traffic_lock); - - atomic_set(&modem_port_ptr->wakeup_flag, 0); - modem_port_ptr->susp_count = 0; - modem_port_ptr->resuming = 0; - modem_port_ptr->port = 0; - modem_port_ptr->last_traffic = 0; - modem_port_ptr->readsize = readsize; - modem_port_ptr->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20; - - INIT_WORK(&modem_port_ptr->wake_and_write, modem_wake_and_write); - INIT_WORK(&modem_port_ptr->usb_wkup_work, modem_usb_wkup_work); - - if (modem_write_buffers_alloc(modem_port_ptr, serial) < 0) { - dev_err(&serial->dev->dev, - "%s: out of memory\n", __func__); - goto alloc_write_buf_fail; - } - - /* allocate multiple receive urb pool */ - for (i = 0; i < num_rx_buf; i++) { - struct ap_ru *rcv = &(modem_port_ptr->ru[i]); - - rcv->urb = usb_alloc_urb(0, GFP_KERNEL); - if (rcv->urb == NULL) { - dev_err(&serial->dev->dev, - "%s: out of memory\n", __func__); - goto alloc_rb_urb_fail; - } - - rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - rcv->instance = modem_port_ptr; - } - - /* allocate multiple receive buffer */ - for (i = 0; i < num_rx_buf; i++) { - struct ap_rb *rb = &(modem_port_ptr->rb[i]); - - rb->base = usb_alloc_coherent(serial->dev, readsize, - GFP_KERNEL, &rb->dma); - if (!rb->base) { - dev_err(&serial->dev->dev, - "%s : out of memory\n", - __func__); - goto alloc_rb_buffer_fail; - } - } - for (i = 0; i < AP_NW; i++) { - struct ap_wb *snd = &(modem_port_ptr->wb[i]); - - snd->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!snd->urb) { - dev_err(&serial->dev->dev, "%s : out of memory " - "(write urbs usb_alloc_urb)\n", __func__); - goto alloc_wb_urb_fail; - } - usb_fill_bulk_urb(snd->urb, serial->dev, - usb_sndbulkpipe(serial->dev, - epwrite->bEndpointAddress), - NULL, modem_port_ptr->writesize, - modem_write_bulk_callback, snd); - snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - snd->instance = modem_port_ptr; - } - - modem_port_ptr->modem_status = 0; - - /* install serial private data */ - usb_set_serial_data(serial, modem_port_ptr); - - return 0; - -alloc_wb_urb_fail: - for (i = 0; i < AP_NW; i++) - usb_free_urb(modem_port_ptr->wb[i].urb); -alloc_rb_buffer_fail: - modem_read_buffers_free(modem_port_ptr, serial); -alloc_rb_urb_fail: - for (i = 0; i < num_rx_buf; i++) - usb_free_urb(modem_port_ptr->ru[i].urb); -alloc_write_buf_fail: - modem_write_buffers_free(modem_port_ptr, serial); - if (modem_port_ptr != NULL) { - kfree(modem_port_ptr); - usb_set_serial_data(serial, NULL); - } - return -ENOMEM; -} - -static void modem_disconnect(struct usb_serial *serial) -{ - struct modem_port *modem_port_ptr = - usb_get_serial_data(serial); - - uint8_t interface_num = - serial->interface->cur_altsetting->desc.bInterfaceNumber; - - if (cdma_modem_debug) - dev_info(&serial->dev->dev, - "%s: Shutdown Interface %d\n", __func__, - interface_num); - - stop_data_traffic(modem_port_ptr); - cancel_work_sync(&modem_port_ptr->wake_and_write); -} - -static void modem_release(struct usb_serial *serial) -{ - struct modem_port *modem_port_ptr = - usb_get_serial_data(serial); - int i; - - modem_write_buffers_free(modem_port_ptr, serial); - modem_read_buffers_free(modem_port_ptr, serial); - - for (i = 0; i < AP_NW; i++) - usb_free_urb(modem_port_ptr->wb[i].urb); - - for (i = 0; i < modem_port_ptr->rx_buflimit; i++) - usb_free_urb(modem_port_ptr->ru[i].urb); - - if (modem_port_ptr) { - /* free private structure allocated for serial device */ - kfree(modem_port_ptr); - usb_set_serial_data(serial, NULL); - } -} - - -static struct usb_driver modem_driver = { - .name = "cdma-modem", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .no_dynamic_id = 1, -#ifdef CONFIG_PM - .supports_autosuspend = 1, - .suspend = modem_suspend, - .resume = modem_resume, - .reset_resume = modem_reset_resume, - .pre_reset = modem_pre_reset, - .post_reset = modem_post_reset, -#endif -}; - -static struct usb_serial_driver modem_device = { - .driver = { - .owner = THIS_MODULE, - .name = "mdm6600-modem", - }, - .description = "MDM 6600 Modem Driver", - .usb_driver = &modem_driver, - .id_table = id_table, - .num_ports = 1, - .write = modem_write, - .write_bulk_callback = modem_write_bulk_callback, - .read_int_callback = modem_interrupt_callback, - .tiocmset = modem_tiocmset, - .tiocmget = modem_tiocmget, - .open = modem_open, - .close = modem_close, - .attach = modem_startup, - .disconnect = modem_disconnect, - .release = modem_release, -}; - -static void __exit modem_exit(void) -{ - usb_deregister(&modem_driver); - usb_serial_deregister(&modem_device); -} - -static int __init modem_init(void) -{ - int retval; - - retval = usb_serial_register(&modem_device); - if (retval) - return retval; - retval = usb_register(&modem_driver); - if (retval) - usb_serial_deregister(&modem_device); - return retval; -} - -module_init(modem_init); -module_exit(modem_exit); - -MODULE_DESCRIPTION("USB IPC Driver for MDM 6600"); -MODULE_AUTHOR("Motorola"); -MODULE_LICENSE("GPL"); -- 2.34.1