blob: e3791b91999627bdad4ed2703ba6a572e9024d1c [file] [log] [blame]
Felipe Balbif358f5b2010-01-05 16:10:13 +02001/*
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>
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +020019#include <linux/module.h>
Felipe Balbif358f5b2010-01-05 16:10:13 +020020#include <linux/device.h>
21
22#include "u_serial.h"
23#include "u_ether.h"
24#include "u_phonet.h"
Andrzej Pietrasiewiczb904d082013-05-23 10:51:14 +020025#include "u_ecm.h"
Felipe Balbif358f5b2010-01-05 16:10:13 +020026#include "gadget_chips.h"
Pali Rohár5ea75092015-06-08 08:20:05 +020027#include "f_mass_storage.h"
Felipe Balbif358f5b2010-01-05 16:10:13 +020028
29/* Defines */
30
31#define NOKIA_VERSION_NUM 0x0211
32#define NOKIA_LONG_NAME "N900 (PC-Suite Mode)"
33
Sebastian Andrzej Siewior7d16e8d2012-09-10 15:01:53 +020034USB_GADGET_COMPOSITE_OPTIONS();
Felipe Balbif358f5b2010-01-05 16:10:13 +020035
Andrzej Pietrasiewiczf1a18232013-05-23 09:22:03 +020036USB_ETHERNET_MODULE_PARAMETERS();
37
Pali Rohár5ea75092015-06-08 08:20:05 +020038static struct fsg_module_parameters fsg_mod_data = {
39 .stall = 0,
40 .luns = 2,
41 .removable_count = 2,
42 .removable = { 1, 1, },
43};
44
45#ifdef CONFIG_USB_GADGET_DEBUG_FILES
46
47static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
48
49#else
50
51/*
52 * Number of buffers we will use.
53 * 2 is usually enough for good buffering pipeline
54 */
55#define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
56
57#endif /* CONFIG_USB_DEBUG */
58
59FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
60
Felipe Balbif358f5b2010-01-05 16:10:13 +020061#define NOKIA_VENDOR_ID 0x0421 /* Nokia */
62#define NOKIA_PRODUCT_ID 0x01c8 /* Nokia Gadget */
63
64/* string IDs are assigned dynamically */
65
Sebastian Andrzej Siewior276e2e42012-09-06 20:11:21 +020066#define STRING_DESCRIPTION_IDX USB_GADGET_FIRST_AVAIL_IDX
Felipe Balbif358f5b2010-01-05 16:10:13 +020067
68static char manufacturer_nokia[] = "Nokia";
69static const char product_nokia[] = NOKIA_LONG_NAME;
70static const char description_nokia[] = "PC-Suite Configuration";
71
72static struct usb_string strings_dev[] = {
Sebastian Andrzej Siewior276e2e42012-09-06 20:11:21 +020073 [USB_GADGET_MANUFACTURER_IDX].s = manufacturer_nokia,
74 [USB_GADGET_PRODUCT_IDX].s = NOKIA_LONG_NAME,
75 [USB_GADGET_SERIAL_IDX].s = "",
Felipe Balbif358f5b2010-01-05 16:10:13 +020076 [STRING_DESCRIPTION_IDX].s = description_nokia,
77 { } /* end of list */
78};
79
80static struct usb_gadget_strings stringtab_dev = {
81 .language = 0x0409, /* en-us */
82 .strings = strings_dev,
83};
84
85static struct usb_gadget_strings *dev_strings[] = {
86 &stringtab_dev,
87 NULL,
88};
89
90static struct usb_device_descriptor device_desc = {
91 .bLength = USB_DT_DEVICE_SIZE,
92 .bDescriptorType = USB_DT_DEVICE,
93 .bcdUSB = __constant_cpu_to_le16(0x0200),
94 .bDeviceClass = USB_CLASS_COMM,
95 .idVendor = __constant_cpu_to_le16(NOKIA_VENDOR_ID),
96 .idProduct = __constant_cpu_to_le16(NOKIA_PRODUCT_ID),
Sebastian Andrzej Siewiored9cbda2012-09-10 09:16:07 +020097 .bcdDevice = cpu_to_le16(NOKIA_VERSION_NUM),
Felipe Balbif358f5b2010-01-05 16:10:13 +020098 /* .iManufacturer = DYNAMIC */
99 /* .iProduct = DYNAMIC */
100 .bNumConfigurations = 1,
101};
102
103/*-------------------------------------------------------------------------*/
104
105/* Module */
106MODULE_DESCRIPTION("Nokia composite gadget driver for N900");
107MODULE_AUTHOR("Felipe Balbi");
108MODULE_LICENSE("GPL");
109
110/*-------------------------------------------------------------------------*/
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100111static struct usb_function *f_acm_cfg1;
112static struct usb_function *f_acm_cfg2;
Andrzej Pietrasiewiczb904d082013-05-23 10:51:14 +0200113static struct usb_function *f_ecm_cfg1;
114static struct usb_function *f_ecm_cfg2;
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200115static struct usb_function *f_obex1_cfg1;
116static struct usb_function *f_obex2_cfg1;
117static struct usb_function *f_obex1_cfg2;
118static struct usb_function *f_obex2_cfg2;
Andrzej Pietrasiewicz83167f12013-05-23 10:51:12 +0200119static struct usb_function *f_phonet_cfg1;
120static struct usb_function *f_phonet_cfg2;
Pali Rohár5ea75092015-06-08 08:20:05 +0200121static struct usb_function *f_msg_cfg1;
122static struct usb_function *f_msg_cfg2;
Andrzej Pietrasiewicz0189e632013-05-23 10:51:10 +0200123
Felipe Balbif358f5b2010-01-05 16:10:13 +0200124
Felipe Balbif358f5b2010-01-05 16:10:13 +0200125static struct usb_configuration nokia_config_500ma_driver = {
126 .label = "Bus Powered",
Felipe Balbif358f5b2010-01-05 16:10:13 +0200127 .bConfigurationValue = 1,
128 /* .iConfiguration = DYNAMIC */
129 .bmAttributes = USB_CONFIG_ATT_ONE,
Sebastian Andrzej Siewior8f900a92012-12-03 20:07:05 +0100130 .MaxPower = 500,
Felipe Balbif358f5b2010-01-05 16:10:13 +0200131};
132
133static struct usb_configuration nokia_config_100ma_driver = {
134 .label = "Self Powered",
Felipe Balbif358f5b2010-01-05 16:10:13 +0200135 .bConfigurationValue = 2,
136 /* .iConfiguration = DYNAMIC */
137 .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
Sebastian Andrzej Siewior8f900a92012-12-03 20:07:05 +0100138 .MaxPower = 100,
Felipe Balbif358f5b2010-01-05 16:10:13 +0200139};
140
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100141static struct usb_function_instance *fi_acm;
Andrzej Pietrasiewiczb904d082013-05-23 10:51:14 +0200142static struct usb_function_instance *fi_ecm;
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200143static struct usb_function_instance *fi_obex1;
144static struct usb_function_instance *fi_obex2;
Andrzej Pietrasiewicz83167f12013-05-23 10:51:12 +0200145static struct usb_function_instance *fi_phonet;
Pali Rohár5ea75092015-06-08 08:20:05 +0200146static struct usb_function_instance *fi_msg;
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100147
Arnd Bergmannc94e289f2015-04-11 00:14:21 +0200148static int nokia_bind_config(struct usb_configuration *c)
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100149{
150 struct usb_function *f_acm;
Andrzej Pietrasiewicz83167f12013-05-23 10:51:12 +0200151 struct usb_function *f_phonet = NULL;
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200152 struct usb_function *f_obex1 = NULL;
Andrzej Pietrasiewiczb904d082013-05-23 10:51:14 +0200153 struct usb_function *f_ecm;
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200154 struct usb_function *f_obex2 = NULL;
Pali Rohár5ea75092015-06-08 08:20:05 +0200155 struct usb_function *f_msg;
156 struct fsg_opts *fsg_opts;
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100157 int status = 0;
Andrzej Pietrasiewicz45ab4602013-12-13 14:46:40 +0100158 int obex1_stat = -1;
159 int obex2_stat = -1;
160 int phonet_stat = -1;
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100161
Andrzej Pietrasiewicz83167f12013-05-23 10:51:12 +0200162 if (!IS_ERR(fi_phonet)) {
163 f_phonet = usb_get_function(fi_phonet);
164 if (IS_ERR(f_phonet))
165 pr_debug("could not get phonet function\n");
166 }
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100167
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200168 if (!IS_ERR(fi_obex1)) {
169 f_obex1 = usb_get_function(fi_obex1);
170 if (IS_ERR(f_obex1))
171 pr_debug("could not get obex function 0\n");
172 }
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100173
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200174 if (!IS_ERR(fi_obex2)) {
175 f_obex2 = usb_get_function(fi_obex2);
176 if (IS_ERR(f_obex2))
177 pr_debug("could not get obex function 1\n");
178 }
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100179
180 f_acm = usb_get_function(fi_acm);
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200181 if (IS_ERR(f_acm)) {
182 status = PTR_ERR(f_acm);
183 goto err_get_acm;
184 }
185
Andrzej Pietrasiewiczb904d082013-05-23 10:51:14 +0200186 f_ecm = usb_get_function(fi_ecm);
187 if (IS_ERR(f_ecm)) {
188 status = PTR_ERR(f_ecm);
189 goto err_get_ecm;
190 }
191
Pali Rohár5ea75092015-06-08 08:20:05 +0200192 f_msg = usb_get_function(fi_msg);
193 if (IS_ERR(f_msg)) {
194 status = PTR_ERR(f_msg);
195 goto err_get_msg;
196 }
197
Andrzej Pietrasiewicz83167f12013-05-23 10:51:12 +0200198 if (!IS_ERR_OR_NULL(f_phonet)) {
199 phonet_stat = usb_add_function(c, f_phonet);
200 if (phonet_stat)
201 pr_debug("could not add phonet function\n");
202 }
203
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200204 if (!IS_ERR_OR_NULL(f_obex1)) {
205 obex1_stat = usb_add_function(c, f_obex1);
206 if (obex1_stat)
207 pr_debug("could not add obex function 0\n");
208 }
209
210 if (!IS_ERR_OR_NULL(f_obex2)) {
211 obex2_stat = usb_add_function(c, f_obex2);
212 if (obex2_stat)
213 pr_debug("could not add obex function 1\n");
214 }
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100215
216 status = usb_add_function(c, f_acm);
217 if (status)
218 goto err_conf;
219
Andrzej Pietrasiewiczb904d082013-05-23 10:51:14 +0200220 status = usb_add_function(c, f_ecm);
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100221 if (status) {
222 pr_debug("could not bind ecm config %d\n", status);
223 goto err_ecm;
224 }
Pali Rohár5ea75092015-06-08 08:20:05 +0200225
226 fsg_opts = fsg_opts_from_func_inst(fi_msg);
227
228 status = fsg_common_run_thread(fsg_opts->common);
229 if (status)
230 goto err_msg;
231
232 status = usb_add_function(c, f_msg);
233 if (status)
234 goto err_msg;
235
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200236 if (c == &nokia_config_500ma_driver) {
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100237 f_acm_cfg1 = f_acm;
Andrzej Pietrasiewiczb904d082013-05-23 10:51:14 +0200238 f_ecm_cfg1 = f_ecm;
Andrzej Pietrasiewicz83167f12013-05-23 10:51:12 +0200239 f_phonet_cfg1 = f_phonet;
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200240 f_obex1_cfg1 = f_obex1;
241 f_obex2_cfg1 = f_obex2;
Pali Rohár5ea75092015-06-08 08:20:05 +0200242 f_msg_cfg1 = f_msg;
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200243 } else {
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100244 f_acm_cfg2 = f_acm;
Andrzej Pietrasiewiczb904d082013-05-23 10:51:14 +0200245 f_ecm_cfg2 = f_ecm;
Andrzej Pietrasiewicz83167f12013-05-23 10:51:12 +0200246 f_phonet_cfg2 = f_phonet;
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200247 f_obex1_cfg2 = f_obex1;
248 f_obex2_cfg2 = f_obex2;
Pali Rohár5ea75092015-06-08 08:20:05 +0200249 f_msg_cfg2 = f_msg;
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200250 }
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100251
252 return status;
Pali Rohár5ea75092015-06-08 08:20:05 +0200253err_msg:
254 usb_remove_function(c, f_ecm);
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100255err_ecm:
256 usb_remove_function(c, f_acm);
257err_conf:
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200258 if (!obex2_stat)
259 usb_remove_function(c, f_obex2);
260 if (!obex1_stat)
261 usb_remove_function(c, f_obex1);
Andrzej Pietrasiewicz83167f12013-05-23 10:51:12 +0200262 if (!phonet_stat)
263 usb_remove_function(c, f_phonet);
Pali Rohár5ea75092015-06-08 08:20:05 +0200264 usb_put_function(f_msg);
265err_get_msg:
Andrzej Pietrasiewiczb904d082013-05-23 10:51:14 +0200266 usb_put_function(f_ecm);
267err_get_ecm:
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100268 usb_put_function(f_acm);
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200269err_get_acm:
270 if (!IS_ERR_OR_NULL(f_obex2))
271 usb_put_function(f_obex2);
272 if (!IS_ERR_OR_NULL(f_obex1))
273 usb_put_function(f_obex1);
Andrzej Pietrasiewicz83167f12013-05-23 10:51:12 +0200274 if (!IS_ERR_OR_NULL(f_phonet))
275 usb_put_function(f_phonet);
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100276 return status;
277}
278
Arnd Bergmannc94e289f2015-04-11 00:14:21 +0200279static int nokia_bind(struct usb_composite_dev *cdev)
Felipe Balbif358f5b2010-01-05 16:10:13 +0200280{
Felipe Balbif358f5b2010-01-05 16:10:13 +0200281 struct usb_gadget *gadget = cdev->gadget;
Pali Rohár5ea75092015-06-08 08:20:05 +0200282 struct fsg_opts *fsg_opts;
283 struct fsg_config fsg_config;
Felipe Balbif358f5b2010-01-05 16:10:13 +0200284 int status;
285
Sebastian Andrzej Siewiore1f15cc2012-09-06 20:11:16 +0200286 status = usb_string_ids_tab(cdev, strings_dev);
Felipe Balbif358f5b2010-01-05 16:10:13 +0200287 if (status < 0)
288 goto err_usb;
Sebastian Andrzej Siewior276e2e42012-09-06 20:11:21 +0200289 device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
290 device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
Sebastian Andrzej Siewiore1f15cc2012-09-06 20:11:16 +0200291 status = strings_dev[STRING_DESCRIPTION_IDX].id;
Felipe Balbif358f5b2010-01-05 16:10:13 +0200292 nokia_config_500ma_driver.iConfiguration = status;
293 nokia_config_100ma_driver.iConfiguration = status;
294
Andrzej Pietrasiewiczb904d082013-05-23 10:51:14 +0200295 if (!gadget_supports_altsettings(gadget)) {
296 status = -ENODEV;
Felipe Balbif358f5b2010-01-05 16:10:13 +0200297 goto err_usb;
Andrzej Pietrasiewiczb904d082013-05-23 10:51:14 +0200298 }
Felipe Balbif358f5b2010-01-05 16:10:13 +0200299
Andrzej Pietrasiewicz83167f12013-05-23 10:51:12 +0200300 fi_phonet = usb_get_function_instance("phonet");
301 if (IS_ERR(fi_phonet))
302 pr_debug("could not find phonet function\n");
303
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200304 fi_obex1 = usb_get_function_instance("obex");
305 if (IS_ERR(fi_obex1))
306 pr_debug("could not find obex function 1\n");
307
308 fi_obex2 = usb_get_function_instance("obex");
309 if (IS_ERR(fi_obex2))
310 pr_debug("could not find obex function 2\n");
311
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100312 fi_acm = usb_get_function_instance("acm");
Andrzej Pietrasiewiczb904d082013-05-23 10:51:14 +0200313 if (IS_ERR(fi_acm)) {
314 status = PTR_ERR(fi_acm);
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200315 goto err_obex2_inst;
Andrzej Pietrasiewiczb904d082013-05-23 10:51:14 +0200316 }
317
318 fi_ecm = usb_get_function_instance("ecm");
319 if (IS_ERR(fi_ecm)) {
320 status = PTR_ERR(fi_ecm);
321 goto err_acm_inst;
322 }
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100323
Pali Rohár5ea75092015-06-08 08:20:05 +0200324 fi_msg = usb_get_function_instance("mass_storage");
325 if (IS_ERR(fi_msg)) {
326 status = PTR_ERR(fi_msg);
327 goto err_ecm_inst;
328 }
329
330 /* set up mass storage function */
331 fsg_config_from_params(&fsg_config, &fsg_mod_data, fsg_num_buffers);
332 fsg_config.vendor_name = "Nokia";
333 fsg_config.product_name = "N900";
334
335 fsg_opts = fsg_opts_from_func_inst(fi_msg);
336 fsg_opts->no_configfs = true;
337
338 status = fsg_common_set_num_buffers(fsg_opts->common, fsg_num_buffers);
339 if (status)
340 goto err_msg_inst;
341
342 status = fsg_common_set_nluns(fsg_opts->common, fsg_config.nluns);
343 if (status)
344 goto err_msg_buf;
345
346 status = fsg_common_set_cdev(fsg_opts->common, cdev, fsg_config.can_stall);
347 if (status)
348 goto err_msg_set_nluns;
349
350 fsg_common_set_sysfs(fsg_opts->common, true);
351
352 status = fsg_common_create_luns(fsg_opts->common, &fsg_config);
353 if (status)
354 goto err_msg_set_nluns;
355
356 fsg_common_set_inquiry_string(fsg_opts->common, fsg_config.vendor_name,
357 fsg_config.product_name);
358
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300359 /* finally register the configuration */
Uwe Kleine-Königc9bfff92010-08-12 17:43:55 +0200360 status = usb_add_config(cdev, &nokia_config_500ma_driver,
361 nokia_bind_config);
Felipe Balbif358f5b2010-01-05 16:10:13 +0200362 if (status < 0)
Pali Rohár5ea75092015-06-08 08:20:05 +0200363 goto err_msg_set_cdev;
Felipe Balbif358f5b2010-01-05 16:10:13 +0200364
Uwe Kleine-Königc9bfff92010-08-12 17:43:55 +0200365 status = usb_add_config(cdev, &nokia_config_100ma_driver,
366 nokia_bind_config);
Felipe Balbif358f5b2010-01-05 16:10:13 +0200367 if (status < 0)
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100368 goto err_put_cfg1;
Felipe Balbif358f5b2010-01-05 16:10:13 +0200369
Sebastian Andrzej Siewior7d16e8d2012-09-10 15:01:53 +0200370 usb_composite_overwrite_options(cdev, &coverwrite);
Felipe Balbif358f5b2010-01-05 16:10:13 +0200371 dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME);
372
373 return 0;
374
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100375err_put_cfg1:
376 usb_put_function(f_acm_cfg1);
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200377 if (!IS_ERR_OR_NULL(f_obex1_cfg1))
378 usb_put_function(f_obex1_cfg1);
379 if (!IS_ERR_OR_NULL(f_obex2_cfg1))
380 usb_put_function(f_obex2_cfg1);
Andrzej Pietrasiewicz83167f12013-05-23 10:51:12 +0200381 if (!IS_ERR_OR_NULL(f_phonet_cfg1))
382 usb_put_function(f_phonet_cfg1);
Andrzej Pietrasiewiczb904d082013-05-23 10:51:14 +0200383 usb_put_function(f_ecm_cfg1);
Pali Rohár5ea75092015-06-08 08:20:05 +0200384err_msg_set_cdev:
385 fsg_common_remove_luns(fsg_opts->common);
386err_msg_set_nluns:
387 fsg_common_free_luns(fsg_opts->common);
388err_msg_buf:
389 fsg_common_free_buffers(fsg_opts->common);
390err_msg_inst:
391 usb_put_function_instance(fi_msg);
Andrzej Pietrasiewiczb904d082013-05-23 10:51:14 +0200392err_ecm_inst:
393 usb_put_function_instance(fi_ecm);
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100394err_acm_inst:
395 usb_put_function_instance(fi_acm);
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200396err_obex2_inst:
397 if (!IS_ERR(fi_obex2))
398 usb_put_function_instance(fi_obex2);
399 if (!IS_ERR(fi_obex1))
400 usb_put_function_instance(fi_obex1);
Andrzej Pietrasiewicz83167f12013-05-23 10:51:12 +0200401 if (!IS_ERR(fi_phonet))
402 usb_put_function_instance(fi_phonet);
Felipe Balbif358f5b2010-01-05 16:10:13 +0200403err_usb:
Felipe Balbif358f5b2010-01-05 16:10:13 +0200404 return status;
405}
406
Arnd Bergmannc94e289f2015-04-11 00:14:21 +0200407static int nokia_unbind(struct usb_composite_dev *cdev)
Felipe Balbif358f5b2010-01-05 16:10:13 +0200408{
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200409 if (!IS_ERR_OR_NULL(f_obex1_cfg2))
410 usb_put_function(f_obex1_cfg2);
411 if (!IS_ERR_OR_NULL(f_obex2_cfg2))
412 usb_put_function(f_obex2_cfg2);
413 if (!IS_ERR_OR_NULL(f_obex1_cfg1))
414 usb_put_function(f_obex1_cfg1);
415 if (!IS_ERR_OR_NULL(f_obex2_cfg1))
416 usb_put_function(f_obex2_cfg1);
Andrzej Pietrasiewicz83167f12013-05-23 10:51:12 +0200417 if (!IS_ERR_OR_NULL(f_phonet_cfg1))
418 usb_put_function(f_phonet_cfg1);
419 if (!IS_ERR_OR_NULL(f_phonet_cfg2))
420 usb_put_function(f_phonet_cfg2);
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100421 usb_put_function(f_acm_cfg1);
422 usb_put_function(f_acm_cfg2);
Andrzej Pietrasiewiczb904d082013-05-23 10:51:14 +0200423 usb_put_function(f_ecm_cfg1);
424 usb_put_function(f_ecm_cfg2);
Pali Rohár5ea75092015-06-08 08:20:05 +0200425 usb_put_function(f_msg_cfg1);
426 usb_put_function(f_msg_cfg2);
Andrzej Pietrasiewicz83167f12013-05-23 10:51:12 +0200427
Pali Rohár5ea75092015-06-08 08:20:05 +0200428 usb_put_function_instance(fi_msg);
Andrzej Pietrasiewiczb904d082013-05-23 10:51:14 +0200429 usb_put_function_instance(fi_ecm);
Andrzej Pietrasiewicz3a343442013-05-23 10:51:08 +0200430 if (!IS_ERR(fi_obex2))
431 usb_put_function_instance(fi_obex2);
Andrzej Pietrasiewicz83167f12013-05-23 10:51:12 +0200432 if (!IS_ERR(fi_obex1))
433 usb_put_function_instance(fi_obex1);
434 if (!IS_ERR(fi_phonet))
435 usb_put_function_instance(fi_phonet);
Sebastian Andrzej Siewior15761822013-01-25 14:09:17 +0100436 usb_put_function_instance(fi_acm);
Sebastian Andrzej Siewior19b10a82012-12-23 21:10:06 +0100437
Felipe Balbif358f5b2010-01-05 16:10:13 +0200438 return 0;
439}
440
Arnd Bergmannc94e289f2015-04-11 00:14:21 +0200441static struct usb_composite_driver nokia_driver = {
Felipe Balbif358f5b2010-01-05 16:10:13 +0200442 .name = "g_nokia",
443 .dev = &device_desc,
444 .strings = dev_strings,
Tatyana Brokhman35a0e0b2011-06-29 16:41:49 +0300445 .max_speed = USB_SPEED_HIGH,
Sebastian Andrzej Siewior03e42bd2012-09-06 20:11:04 +0200446 .bind = nokia_bind,
Arnd Bergmannc94e289f2015-04-11 00:14:21 +0200447 .unbind = nokia_unbind,
Felipe Balbif358f5b2010-01-05 16:10:13 +0200448};
449
Tobias Klauser909346a2014-07-09 18:09:56 +0200450module_usb_composite_driver(nokia_driver);