mdm6600: Add mdm6600 usb-serial driver.
authorNick Pelly <npelly@google.com>
Thu, 29 Jul 2010 19:05:22 +0000 (12:05 -0700)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:33:35 +0000 (16:33 -0700)
This is a re-write of the Motorola mdm6600_modem driver.

The usb_serial_generic_* handlers actually cover the USB bulk to serial data
path. So that code disappears.

The USB interrupt data to TIOCMGET ioctl path does not appear to be used by
pppd in userspace, using a temporary BUG_ON() to confirm.

So we end up with very little but a hook to register generic usb-serial
handlers for the MDM6600 vendor id.

I have not spent time testing behavior in low-power-modes, it is likely I will
need to over-ride some of the generic handlers at that point.

Change-Id: I65fdd06c2764416f365995761aa653878c0e393b
Signed-off-by: Nick Pelly <npelly@google.com>
drivers/usb/serial/Kconfig
drivers/usb/serial/Makefile
drivers/usb/serial/mdm6600.c [new file with mode: 0644]

index 22e2552a9b601890b183459b8a20ee157b768102..724e46fd0264858cd1ed143a4a6e4113c15b91fb 100644 (file)
@@ -467,6 +467,11 @@ config USB_MDM6600_CDMA_MODEM
           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
+         Say Y here if you want to use a Qualcomm MDM6600 modem over USB.
+
 config USB_SERIAL_MOTO_FLASH_MODEM
        tristate "USB Motorola modem flash driver"
        ---help---
index fb818a50c189fa0d019d458915a05f6f7eea96a2..eb910e28c6d976529eb1519aab05f423e606ba69 100644 (file)
@@ -40,6 +40,7 @@ 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
 obj-$(CONFIG_USB_SERIAL_OMNINET)               += omninet.o
diff --git a/drivers/usb/serial/mdm6600.c b/drivers/usb/serial/mdm6600.c
new file mode 100644 (file)
index 0000000..c20a413
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2010 Google, Inc.
+ * Re-write of Motorola's mdm6600_modem driver
+ *
+ * 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
+ */
+
+/*
+ * TODO check suspend/resume/LP0/LP1
+ * TODO remove dummy tiocmget handler
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+#define MODEM_INTERFACE_NUM 4
+
+static const struct usb_device_id mdm6600_id_table[] = {
+       { USB_DEVICE(0x22b8, 0x2a70) },
+       { },
+};
+MODULE_DEVICE_TABLE(usb, mdm6600_id_table);
+
+static int mdm6600_dtr_control(struct usb_serial_port *port, int ctrl)
+{
+       struct usb_device *dev = port->serial->dev;
+       struct usb_interface *iface = port->serial->interface;
+       u8 request = 0x22;
+       u8 request_type = USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT;
+       int timeout = HZ * 5;
+       int rc;
+
+       rc = usb_autopm_get_interface(iface);
+       if (rc < 0) {
+               dev_err(&dev->dev, "%s %s autopm failed %d",
+                       dev_driver_string(&iface->dev), dev_name(&iface->dev),
+                       rc);
+               return rc;
+       }
+
+       rc = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
+               request_type, ctrl, port->number, NULL, 0, timeout);
+       usb_autopm_put_interface(iface);
+
+       return rc;
+}
+
+static int mdm6600_tiocmget(struct tty_struct *tty, struct file *file)
+{
+       /* testing if this ever really gets called */
+       BUG_ON(1);
+}
+
+static int mdm6600_tiocmset(struct tty_struct *tty, struct file *file,
+                                       unsigned int set, unsigned int clear)
+{
+       struct usb_serial_port *port = tty->driver_data;
+
+       if (port->number != MODEM_INTERFACE_NUM)
+               return 0;
+       if (clear & TIOCM_DTR)
+               return mdm6600_dtr_control(port, 0);
+       if (set & TIOCM_DTR)
+               return mdm6600_dtr_control(port, 1);
+       return 0;
+}
+
+static struct usb_driver mdm6600_usb_driver = {
+       .name =         "mdm6600",
+       .probe =        usb_serial_probe,
+       .disconnect =   usb_serial_disconnect,
+       .id_table =     mdm6600_id_table,
+       .no_dynamic_id =        1,
+};
+
+static struct usb_serial_driver mdm6600_usb_serial_driver = {
+       .driver = {
+               .owner =        THIS_MODULE,
+               .name =         "mdm6600",
+       },
+       .description =          "MDM 6600 modem usb-serial driver",
+       .id_table =             mdm6600_id_table,
+       .num_ports =            1,  /* TODO: confirm this number is useless */
+       .usb_driver =           &mdm6600_usb_driver,
+       .tiocmset =             mdm6600_tiocmset,
+       .tiocmget =             mdm6600_tiocmget,
+};
+
+static int __init mdm6600_init(void)
+{
+       int retval;
+
+       retval = usb_serial_register(&mdm6600_usb_serial_driver);
+       if (retval)
+               return retval;
+       retval = usb_register(&mdm6600_usb_driver);
+       if (retval)
+               usb_serial_deregister(&mdm6600_usb_serial_driver);
+       return retval;
+}
+
+static void __exit mdm6600_exit(void)
+{
+       usb_deregister(&mdm6600_usb_driver);
+       usb_serial_deregister(&mdm6600_usb_serial_driver);
+}
+
+module_init(mdm6600_init);
+module_exit(mdm6600_exit);
+MODULE_LICENSE("GPL");