321 lines
8.5 KiB
Diff
321 lines
8.5 KiB
Diff
From d96b241bd2ad42b6c49d5f6435c69b23818f001e Mon Sep 17 00:00:00 2001
|
|
From: Felipe Balbi <felipe.balbi@nokia.com>
|
|
Date: Tue, 5 Jan 2010 16:10:13 +0200
|
|
Subject: [PATCH 9/10] USB: gadget: introduce g_nokia gadget driver
|
|
|
|
Patch-mainline: 2.6.34
|
|
Git-commit: f358f5b40af67caf28b627889d007294614170b2
|
|
|
|
g_nokia is the gadget driver implementing
|
|
WMCDC Wireless Handset Control Model for the N900
|
|
device.
|
|
|
|
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
|
|
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
|
---
|
|
drivers/usb/gadget/Kconfig | 10 +
|
|
drivers/usb/gadget/Makefile | 2
|
|
drivers/usb/gadget/nokia.c | 259 ++++++++++++++++++++++++++++++++++++++++++++
|
|
3 files changed, 271 insertions(+)
|
|
create mode 100644 drivers/usb/gadget/nokia.c
|
|
|
|
--- a/drivers/usb/gadget/Kconfig
|
|
+++ b/drivers/usb/gadget/Kconfig
|
|
@@ -828,6 +828,16 @@
|
|
Say "y" to link the driver statically, or "m" to build a
|
|
dynamically linked module.
|
|
|
|
+config USB_G_NOKIA
|
|
+ tristate "Nokia composite gadget"
|
|
+ depends on PHONET
|
|
+ help
|
|
+ The Nokia composite gadget provides support for acm, obex
|
|
+ and phonet in only one composite gadget driver.
|
|
+
|
|
+ It's only really useful for N900 hardware. If you're building
|
|
+ a kernel for N900, say Y or M here. If unsure, say N.
|
|
+
|
|
config USB_G_MULTI
|
|
tristate "Multifunction Composite Gadget (EXPERIMENTAL)"
|
|
depends on BLOCK && NET
|
|
--- a/drivers/usb/gadget/Makefile
|
|
+++ b/drivers/usb/gadget/Makefile
|
|
@@ -44,6 +44,7 @@
|
|
g_cdc-objs := cdc2.o
|
|
g_multi-objs := multi.o
|
|
g_still_image-objs := still_image.o
|
|
+g_nokia-objs := nokia.o
|
|
|
|
obj-$(CONFIG_USB_ZERO) += g_zero.o
|
|
obj-$(CONFIG_USB_AUDIO) += g_audio.o
|
|
@@ -57,6 +58,7 @@
|
|
obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
|
|
obj-$(CONFIG_USB_G_MULTI) += g_multi.o
|
|
obj-$(CONFIG_USB_STILL_IMAGE) += g_still_image.o
|
|
+obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o
|
|
|
|
ifeq ($(CONFIG_USB_GADGET_DEBUG),y)
|
|
EXTRA_CFLAGS += -DDMA_PPB_MODE
|
|
--- /dev/null
|
|
+++ b/drivers/usb/gadget/nokia.c
|
|
@@ -0,0 +1,259 @@
|
|
+/*
|
|
+ * nokia.c -- Nokia Composite Gadget Driver
|
|
+ *
|
|
+ * Copyright (C) 2008-2010 Nokia Corporation
|
|
+ * Contact: Felipe Balbi <felipe.balbi@nokia.com>
|
|
+ *
|
|
+ * This gadget driver borrows from serial.c which is:
|
|
+ *
|
|
+ * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
|
|
+ * Copyright (C) 2008 by David Brownell
|
|
+ * Copyright (C) 2008 by Nokia Corporation
|
|
+ *
|
|
+ * This software is distributed under the terms of the GNU General
|
|
+ * Public License ("GPL") as published by the Free Software Foundation,
|
|
+ * version 2 of that License.
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/utsname.h>
|
|
+#include <linux/device.h>
|
|
+
|
|
+#include "u_serial.h"
|
|
+#include "u_ether.h"
|
|
+#include "u_phonet.h"
|
|
+#include "gadget_chips.h"
|
|
+
|
|
+/* Defines */
|
|
+
|
|
+#define NOKIA_VERSION_NUM 0x0211
|
|
+#define NOKIA_LONG_NAME "N900 (PC-Suite Mode)"
|
|
+
|
|
+/*-------------------------------------------------------------------------*/
|
|
+
|
|
+/*
|
|
+ * Kbuild is not very cooperative with respect to linking separately
|
|
+ * compiled library objects into one module. So for now we won't use
|
|
+ * separate compilation ... ensuring init/exit sections work to shrink
|
|
+ * the runtime footprint, and giving us at least some parts of what
|
|
+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
|
|
+ */
|
|
+#include "composite.c"
|
|
+#include "usbstring.c"
|
|
+#include "config.c"
|
|
+#include "epautoconf.c"
|
|
+
|
|
+#include "u_serial.c"
|
|
+#include "f_acm.c"
|
|
+#include "f_ecm.c"
|
|
+#include "f_obex.c"
|
|
+#include "f_serial.c"
|
|
+#include "f_phonet.c"
|
|
+#include "u_ether.c"
|
|
+
|
|
+/*-------------------------------------------------------------------------*/
|
|
+
|
|
+#define NOKIA_VENDOR_ID 0x0421 /* Nokia */
|
|
+#define NOKIA_PRODUCT_ID 0x01c8 /* Nokia Gadget */
|
|
+
|
|
+/* string IDs are assigned dynamically */
|
|
+
|
|
+#define STRING_MANUFACTURER_IDX 0
|
|
+#define STRING_PRODUCT_IDX 1
|
|
+#define STRING_DESCRIPTION_IDX 2
|
|
+
|
|
+static char manufacturer_nokia[] = "Nokia";
|
|
+static const char product_nokia[] = NOKIA_LONG_NAME;
|
|
+static const char description_nokia[] = "PC-Suite Configuration";
|
|
+
|
|
+static struct usb_string strings_dev[] = {
|
|
+ [STRING_MANUFACTURER_IDX].s = manufacturer_nokia,
|
|
+ [STRING_PRODUCT_IDX].s = NOKIA_LONG_NAME,
|
|
+ [STRING_DESCRIPTION_IDX].s = description_nokia,
|
|
+ { } /* end of list */
|
|
+};
|
|
+
|
|
+static struct usb_gadget_strings stringtab_dev = {
|
|
+ .language = 0x0409, /* en-us */
|
|
+ .strings = strings_dev,
|
|
+};
|
|
+
|
|
+static struct usb_gadget_strings *dev_strings[] = {
|
|
+ &stringtab_dev,
|
|
+ NULL,
|
|
+};
|
|
+
|
|
+static struct usb_device_descriptor device_desc = {
|
|
+ .bLength = USB_DT_DEVICE_SIZE,
|
|
+ .bDescriptorType = USB_DT_DEVICE,
|
|
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
|
|
+ .bDeviceClass = USB_CLASS_COMM,
|
|
+ .idVendor = __constant_cpu_to_le16(NOKIA_VENDOR_ID),
|
|
+ .idProduct = __constant_cpu_to_le16(NOKIA_PRODUCT_ID),
|
|
+ /* .iManufacturer = DYNAMIC */
|
|
+ /* .iProduct = DYNAMIC */
|
|
+ .bNumConfigurations = 1,
|
|
+};
|
|
+
|
|
+/*-------------------------------------------------------------------------*/
|
|
+
|
|
+/* Module */
|
|
+MODULE_DESCRIPTION("Nokia composite gadget driver for N900");
|
|
+MODULE_AUTHOR("Felipe Balbi");
|
|
+MODULE_LICENSE("GPL");
|
|
+
|
|
+/*-------------------------------------------------------------------------*/
|
|
+
|
|
+static u8 hostaddr[ETH_ALEN];
|
|
+
|
|
+static int __init nokia_bind_config(struct usb_configuration *c)
|
|
+{
|
|
+ int status = 0;
|
|
+
|
|
+ status = phonet_bind_config(c);
|
|
+ if (status)
|
|
+ printk(KERN_DEBUG "could not bind phonet config\n");
|
|
+
|
|
+ status = obex_bind_config(c, 0);
|
|
+ if (status)
|
|
+ printk(KERN_DEBUG "could not bind obex config %d\n", 0);
|
|
+
|
|
+ status = obex_bind_config(c, 1);
|
|
+ if (status)
|
|
+ printk(KERN_DEBUG "could not bind obex config %d\n", 0);
|
|
+
|
|
+ status = acm_bind_config(c, 2);
|
|
+ if (status)
|
|
+ printk(KERN_DEBUG "could not bind acm config\n");
|
|
+
|
|
+ status = ecm_bind_config(c, hostaddr);
|
|
+ if (status)
|
|
+ printk(KERN_DEBUG "could not bind ecm config\n");
|
|
+
|
|
+ return status;
|
|
+}
|
|
+
|
|
+static struct usb_configuration nokia_config_500ma_driver = {
|
|
+ .label = "Bus Powered",
|
|
+ .bind = nokia_bind_config,
|
|
+ .bConfigurationValue = 1,
|
|
+ /* .iConfiguration = DYNAMIC */
|
|
+ .bmAttributes = USB_CONFIG_ATT_ONE,
|
|
+ .bMaxPower = 250, /* 500mA */
|
|
+};
|
|
+
|
|
+static struct usb_configuration nokia_config_100ma_driver = {
|
|
+ .label = "Self Powered",
|
|
+ .bind = nokia_bind_config,
|
|
+ .bConfigurationValue = 2,
|
|
+ /* .iConfiguration = DYNAMIC */
|
|
+ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
|
|
+ .bMaxPower = 50, /* 100 mA */
|
|
+};
|
|
+
|
|
+static int __init nokia_bind(struct usb_composite_dev *cdev)
|
|
+{
|
|
+ int gcnum;
|
|
+ struct usb_gadget *gadget = cdev->gadget;
|
|
+ int status;
|
|
+
|
|
+ status = gphonet_setup(cdev->gadget);
|
|
+ if (status < 0)
|
|
+ goto err_phonet;
|
|
+
|
|
+ status = gserial_setup(cdev->gadget, 3);
|
|
+ if (status < 0)
|
|
+ goto err_serial;
|
|
+
|
|
+ status = gether_setup(cdev->gadget, hostaddr);
|
|
+ if (status < 0)
|
|
+ goto err_ether;
|
|
+
|
|
+ status = usb_string_id(cdev);
|
|
+ if (status < 0)
|
|
+ goto err_usb;
|
|
+ strings_dev[STRING_MANUFACTURER_IDX].id = status;
|
|
+
|
|
+ device_desc.iManufacturer = status;
|
|
+
|
|
+ status = usb_string_id(cdev);
|
|
+ if (status < 0)
|
|
+ goto err_usb;
|
|
+ strings_dev[STRING_PRODUCT_IDX].id = status;
|
|
+
|
|
+ device_desc.iProduct = status;
|
|
+
|
|
+ /* config description */
|
|
+ status = usb_string_id(cdev);
|
|
+ if (status < 0)
|
|
+ goto err_usb;
|
|
+ strings_dev[STRING_DESCRIPTION_IDX].id = status;
|
|
+
|
|
+ nokia_config_500ma_driver.iConfiguration = status;
|
|
+ nokia_config_100ma_driver.iConfiguration = status;
|
|
+
|
|
+ /* set up other descriptors */
|
|
+ gcnum = usb_gadget_controller_number(gadget);
|
|
+ if (gcnum >= 0)
|
|
+ device_desc.bcdDevice = cpu_to_le16(NOKIA_VERSION_NUM);
|
|
+ else {
|
|
+ /* this should only work with hw that supports altsettings
|
|
+ * and several endpoints, anything else, panic.
|
|
+ */
|
|
+ pr_err("nokia_bind: controller '%s' not recognized\n",
|
|
+ gadget->name);
|
|
+ goto err_usb;
|
|
+ }
|
|
+
|
|
+ /* finaly register the configuration */
|
|
+ status = usb_add_config(cdev, &nokia_config_500ma_driver);
|
|
+ if (status < 0)
|
|
+ goto err_usb;
|
|
+
|
|
+ status = usb_add_config(cdev, &nokia_config_100ma_driver);
|
|
+ if (status < 0)
|
|
+ goto err_usb;
|
|
+
|
|
+ dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err_usb:
|
|
+ gether_cleanup();
|
|
+err_ether:
|
|
+ gserial_cleanup();
|
|
+err_serial:
|
|
+ gphonet_cleanup();
|
|
+err_phonet:
|
|
+ return status;
|
|
+}
|
|
+
|
|
+static int __exit nokia_unbind(struct usb_composite_dev *cdev)
|
|
+{
|
|
+ gphonet_cleanup();
|
|
+ gserial_cleanup();
|
|
+ gether_cleanup();
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct usb_composite_driver nokia_driver = {
|
|
+ .name = "g_nokia",
|
|
+ .dev = &device_desc,
|
|
+ .strings = dev_strings,
|
|
+ .bind = nokia_bind,
|
|
+ .unbind = __exit_p(nokia_unbind),
|
|
+};
|
|
+
|
|
+static int __init nokia_init(void)
|
|
+{
|
|
+ return usb_composite_register(&nokia_driver);
|
|
+}
|
|
+module_init(nokia_init);
|
|
+
|
|
+static void __exit nokia_cleanup(void)
|
|
+{
|
|
+ usb_composite_unregister(&nokia_driver);
|
|
+}
|
|
+module_exit(nokia_cleanup);
|
|
+
|