diff options
author | Felipe Balbi <felipe.balbi@nokia.com> | 2010-01-05 09:10:13 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-03-02 17:54:02 -0500 |
commit | f358f5b40af67caf28b627889d007294614170b2 (patch) | |
tree | c28a199d25fb40e3407d879f4a82d9053d94452b /drivers/usb/gadget/nokia.c | |
parent | 9c9a7dbf9a73191a24a13b9a0412355254a122c7 (diff) |
USB: gadget: introduce g_nokia gadget driver
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>
Diffstat (limited to 'drivers/usb/gadget/nokia.c')
-rw-r--r-- | drivers/usb/gadget/nokia.c | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c new file mode 100644 index 000000000000..7d6b66a85724 --- /dev/null +++ b/drivers/usb/gadget/nokia.c | |||
@@ -0,0 +1,259 @@ | |||
1 | /* | ||
2 | * nokia.c -- Nokia Composite Gadget Driver | ||
3 | * | ||
4 | * Copyright (C) 2008-2010 Nokia Corporation | ||
5 | * Contact: Felipe Balbi <felipe.balbi@nokia.com> | ||
6 | * | ||
7 | * This gadget driver borrows from serial.c which is: | ||
8 | * | ||
9 | * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) | ||
10 | * Copyright (C) 2008 by David Brownell | ||
11 | * Copyright (C) 2008 by Nokia Corporation | ||
12 | * | ||
13 | * This software is distributed under the terms of the GNU General | ||
14 | * Public License ("GPL") as published by the Free Software Foundation, | ||
15 | * version 2 of that License. | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/utsname.h> | ||
20 | #include <linux/device.h> | ||
21 | |||
22 | #include "u_serial.h" | ||
23 | #include "u_ether.h" | ||
24 | #include "u_phonet.h" | ||
25 | #include "gadget_chips.h" | ||
26 | |||
27 | /* Defines */ | ||
28 | |||
29 | #define NOKIA_VERSION_NUM 0x0211 | ||
30 | #define NOKIA_LONG_NAME "N900 (PC-Suite Mode)" | ||
31 | |||
32 | /*-------------------------------------------------------------------------*/ | ||
33 | |||
34 | /* | ||
35 | * Kbuild is not very cooperative with respect to linking separately | ||
36 | * compiled library objects into one module. So for now we won't use | ||
37 | * separate compilation ... ensuring init/exit sections work to shrink | ||
38 | * the runtime footprint, and giving us at least some parts of what | ||
39 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. | ||
40 | */ | ||
41 | #include "composite.c" | ||
42 | #include "usbstring.c" | ||
43 | #include "config.c" | ||
44 | #include "epautoconf.c" | ||
45 | |||
46 | #include "u_serial.c" | ||
47 | #include "f_acm.c" | ||
48 | #include "f_ecm.c" | ||
49 | #include "f_obex.c" | ||
50 | #include "f_serial.c" | ||
51 | #include "f_phonet.c" | ||
52 | #include "u_ether.c" | ||
53 | |||
54 | /*-------------------------------------------------------------------------*/ | ||
55 | |||
56 | #define NOKIA_VENDOR_ID 0x0421 /* Nokia */ | ||
57 | #define NOKIA_PRODUCT_ID 0x01c8 /* Nokia Gadget */ | ||
58 | |||
59 | /* string IDs are assigned dynamically */ | ||
60 | |||
61 | #define STRING_MANUFACTURER_IDX 0 | ||
62 | #define STRING_PRODUCT_IDX 1 | ||
63 | #define STRING_DESCRIPTION_IDX 2 | ||
64 | |||
65 | static char manufacturer_nokia[] = "Nokia"; | ||
66 | static const char product_nokia[] = NOKIA_LONG_NAME; | ||
67 | static const char description_nokia[] = "PC-Suite Configuration"; | ||
68 | |||
69 | static struct usb_string strings_dev[] = { | ||
70 | [STRING_MANUFACTURER_IDX].s = manufacturer_nokia, | ||
71 | [STRING_PRODUCT_IDX].s = NOKIA_LONG_NAME, | ||
72 | [STRING_DESCRIPTION_IDX].s = description_nokia, | ||
73 | { } /* end of list */ | ||
74 | }; | ||
75 | |||
76 | static struct usb_gadget_strings stringtab_dev = { | ||
77 | .language = 0x0409, /* en-us */ | ||
78 | .strings = strings_dev, | ||
79 | }; | ||
80 | |||
81 | static struct usb_gadget_strings *dev_strings[] = { | ||
82 | &stringtab_dev, | ||
83 | NULL, | ||
84 | }; | ||
85 | |||
86 | static struct usb_device_descriptor device_desc = { | ||
87 | .bLength = USB_DT_DEVICE_SIZE, | ||
88 | .bDescriptorType = USB_DT_DEVICE, | ||
89 | .bcdUSB = __constant_cpu_to_le16(0x0200), | ||
90 | .bDeviceClass = USB_CLASS_COMM, | ||
91 | .idVendor = __constant_cpu_to_le16(NOKIA_VENDOR_ID), | ||
92 | .idProduct = __constant_cpu_to_le16(NOKIA_PRODUCT_ID), | ||
93 | /* .iManufacturer = DYNAMIC */ | ||
94 | /* .iProduct = DYNAMIC */ | ||
95 | .bNumConfigurations = 1, | ||
96 | }; | ||
97 | |||
98 | /*-------------------------------------------------------------------------*/ | ||
99 | |||
100 | /* Module */ | ||
101 | MODULE_DESCRIPTION("Nokia composite gadget driver for N900"); | ||
102 | MODULE_AUTHOR("Felipe Balbi"); | ||
103 | MODULE_LICENSE("GPL"); | ||
104 | |||
105 | /*-------------------------------------------------------------------------*/ | ||
106 | |||
107 | static u8 hostaddr[ETH_ALEN]; | ||
108 | |||
109 | static int __init nokia_bind_config(struct usb_configuration *c) | ||
110 | { | ||
111 | int status = 0; | ||
112 | |||
113 | status = phonet_bind_config(c); | ||
114 | if (status) | ||
115 | printk(KERN_DEBUG "could not bind phonet config\n"); | ||
116 | |||
117 | status = obex_bind_config(c, 0); | ||
118 | if (status) | ||
119 | printk(KERN_DEBUG "could not bind obex config %d\n", 0); | ||
120 | |||
121 | status = obex_bind_config(c, 1); | ||
122 | if (status) | ||
123 | printk(KERN_DEBUG "could not bind obex config %d\n", 0); | ||
124 | |||
125 | status = acm_bind_config(c, 2); | ||
126 | if (status) | ||
127 | printk(KERN_DEBUG "could not bind acm config\n"); | ||
128 | |||
129 | status = ecm_bind_config(c, hostaddr); | ||
130 | if (status) | ||
131 | printk(KERN_DEBUG "could not bind ecm config\n"); | ||
132 | |||
133 | return status; | ||
134 | } | ||
135 | |||
136 | static struct usb_configuration nokia_config_500ma_driver = { | ||
137 | .label = "Bus Powered", | ||
138 | .bind = nokia_bind_config, | ||
139 | .bConfigurationValue = 1, | ||
140 | /* .iConfiguration = DYNAMIC */ | ||
141 | .bmAttributes = USB_CONFIG_ATT_ONE, | ||
142 | .bMaxPower = 250, /* 500mA */ | ||
143 | }; | ||
144 | |||
145 | static struct usb_configuration nokia_config_100ma_driver = { | ||
146 | .label = "Self Powered", | ||
147 | .bind = nokia_bind_config, | ||
148 | .bConfigurationValue = 2, | ||
149 | /* .iConfiguration = DYNAMIC */ | ||
150 | .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, | ||
151 | .bMaxPower = 50, /* 100 mA */ | ||
152 | }; | ||
153 | |||
154 | static int __init nokia_bind(struct usb_composite_dev *cdev) | ||
155 | { | ||
156 | int gcnum; | ||
157 | struct usb_gadget *gadget = cdev->gadget; | ||
158 | int status; | ||
159 | |||
160 | status = gphonet_setup(cdev->gadget); | ||
161 | if (status < 0) | ||
162 | goto err_phonet; | ||
163 | |||
164 | status = gserial_setup(cdev->gadget, 3); | ||
165 | if (status < 0) | ||
166 | goto err_serial; | ||
167 | |||
168 | status = gether_setup(cdev->gadget, hostaddr); | ||
169 | if (status < 0) | ||
170 | goto err_ether; | ||
171 | |||
172 | status = usb_string_id(cdev); | ||
173 | if (status < 0) | ||
174 | goto err_usb; | ||
175 | strings_dev[STRING_MANUFACTURER_IDX].id = status; | ||
176 | |||
177 | device_desc.iManufacturer = status; | ||
178 | |||
179 | status = usb_string_id(cdev); | ||
180 | if (status < 0) | ||
181 | goto err_usb; | ||
182 | strings_dev[STRING_PRODUCT_IDX].id = status; | ||
183 | |||
184 | device_desc.iProduct = status; | ||
185 | |||
186 | /* config description */ | ||
187 | status = usb_string_id(cdev); | ||
188 | if (status < 0) | ||
189 | goto err_usb; | ||
190 | strings_dev[STRING_DESCRIPTION_IDX].id = status; | ||
191 | |||
192 | nokia_config_500ma_driver.iConfiguration = status; | ||
193 | nokia_config_100ma_driver.iConfiguration = status; | ||
194 | |||
195 | /* set up other descriptors */ | ||
196 | gcnum = usb_gadget_controller_number(gadget); | ||
197 | if (gcnum >= 0) | ||
198 | device_desc.bcdDevice = cpu_to_le16(NOKIA_VERSION_NUM); | ||
199 | else { | ||
200 | /* this should only work with hw that supports altsettings | ||
201 | * and several endpoints, anything else, panic. | ||
202 | */ | ||
203 | pr_err("nokia_bind: controller '%s' not recognized\n", | ||
204 | gadget->name); | ||
205 | goto err_usb; | ||
206 | } | ||
207 | |||
208 | /* finaly register the configuration */ | ||
209 | status = usb_add_config(cdev, &nokia_config_500ma_driver); | ||
210 | if (status < 0) | ||
211 | goto err_usb; | ||
212 | |||
213 | status = usb_add_config(cdev, &nokia_config_100ma_driver); | ||
214 | if (status < 0) | ||
215 | goto err_usb; | ||
216 | |||
217 | dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME); | ||
218 | |||
219 | return 0; | ||
220 | |||
221 | err_usb: | ||
222 | gether_cleanup(); | ||
223 | err_ether: | ||
224 | gserial_cleanup(); | ||
225 | err_serial: | ||
226 | gphonet_cleanup(); | ||
227 | err_phonet: | ||
228 | return status; | ||
229 | } | ||
230 | |||
231 | static int __exit nokia_unbind(struct usb_composite_dev *cdev) | ||
232 | { | ||
233 | gphonet_cleanup(); | ||
234 | gserial_cleanup(); | ||
235 | gether_cleanup(); | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static struct usb_composite_driver nokia_driver = { | ||
241 | .name = "g_nokia", | ||
242 | .dev = &device_desc, | ||
243 | .strings = dev_strings, | ||
244 | .bind = nokia_bind, | ||
245 | .unbind = __exit_p(nokia_unbind), | ||
246 | }; | ||
247 | |||
248 | static int __init nokia_init(void) | ||
249 | { | ||
250 | return usb_composite_register(&nokia_driver); | ||
251 | } | ||
252 | module_init(nokia_init); | ||
253 | |||
254 | static void __exit nokia_cleanup(void) | ||
255 | { | ||
256 | usb_composite_unregister(&nokia_driver); | ||
257 | } | ||
258 | module_exit(nokia_cleanup); | ||
259 | |||