rawbulk.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. /*
  2. * Rawbulk Gadget Function Driver from VIA Telecom
  3. *
  4. * Copyright (C) 2011 VIA Telecom, Inc.
  5. * Author: Karfield Chen (kfchen@via-telecom.com)
  6. * Copyright (C) 2012 VIA Telecom, Inc.
  7. * Author: Juelun Guo (jlguo@via-telecom.com)
  8. * Changes:
  9. *
  10. * Sep 2012: Juelun Guo <jlguo@via-telecom.com>
  11. * Version 1.0.2
  12. * changed to support for sdio bypass.
  13. * This software is licensed under the terms of the GNU General Public
  14. * License version 2, as published by the Free Software Foundation, and
  15. * may be copied, distributed, and modified under those terms.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU General Public License for more details.
  21. *
  22. */
  23. /* #define DEBUG */
  24. /* #define VERBOSE_DEBUG */
  25. #define DRIVER_AUTHOR "Juelun Guo <jlguo@via-telecom.com>"
  26. #define DRIVER_DESC "Rawbulk Gadget - transport data from CP to Gadget"
  27. #define DRIVER_VERSION "1.0.2"
  28. #define DRIVER_NAME "usb_rawbulk"
  29. #include <linux/kernel.h>
  30. #include <linux/init.h>
  31. #include <linux/module.h>
  32. #include <linux/moduleparam.h>
  33. #include <linux/err.h>
  34. #include <linux/wakelock.h>
  35. #include <linux/interrupt.h>
  36. #include <linux/delay.h>
  37. #include <linux/wait.h>
  38. #include <linux/types.h>
  39. #include <linux/device.h>
  40. #include <linux/version.h>
  41. #include <linux/usb/composite.h>
  42. #include "viatel_rawbulk.h"
  43. #define C2K_TTY_USB_SKIP
  44. #ifdef C2K_USB_UT
  45. #include <linux/random.h>
  46. #define UT_CMD 3
  47. #define UT_CLR_ERR 4
  48. #define SZ 4096
  49. int ut_err = 0;
  50. int modem_dtr_set(int on, int low_latency)
  51. {
  52. return 0;
  53. }
  54. int modem_dcd_state(void)
  55. {
  56. return 0;
  57. }
  58. int modem_buffer_push(int port_num, void *buf, int count)
  59. {
  60. return 0;
  61. }
  62. int sdio_rawbulk_intercept(int port_num, unsigned int inception)
  63. {
  64. return 0;
  65. }
  66. #endif
  67. /* sysfs attr idx assignment */
  68. enum _attr_idx {
  69. ATTR_ENABLE = 0, /** enable switch for Rawbulk */
  70. #ifdef SUPPORT_LEGACY_CONTROL
  71. ATTR_ENABLE_C, /** enable switch too, but for legacy */
  72. #endif
  73. ATTR_AUTORECONN, /** enable to rebind cp when it reconnect */
  74. ATTR_STATISTICS, /** Rawbulk summary/statistics for one pipe */
  75. ATTR_NUPS, /** upstream transfers count */
  76. ATTR_NDOWNS, /** downstram transfers count */
  77. ATTR_UPSIZE, /** upstream buffer for each transaction */
  78. ATTR_DOWNSIZE, /** downstram buffer for each transaction */
  79. ATTR_DTR, /** DTR control, only for Data-Call port */
  80. };
  81. struct rawbulk_function *prealloced_functions[_MAX_TID] = { NULL };
  82. struct rawbulk_function *rawbulk_lookup_function(int transfer_id)
  83. {
  84. C2K_NOTE("%s\n", __func__);
  85. if (transfer_id >= 0 && transfer_id < _MAX_TID)
  86. return prealloced_functions[transfer_id];
  87. return NULL;
  88. }
  89. EXPORT_SYMBOL_GPL(rawbulk_lookup_function);
  90. static inline int check_enable_state(struct rawbulk_function *fn)
  91. {
  92. int enab;
  93. unsigned long flags;
  94. C2K_NOTE("%s\n", __func__);
  95. spin_lock_irqsave(&fn->lock, flags);
  96. enab = fn->enable ? 1 : 0;
  97. C2K_NOTE("enab(%d)\n", enab);
  98. spin_unlock_irqrestore(&fn->lock, flags);
  99. return enab;
  100. }
  101. int rawbulk_check_enable(struct rawbulk_function *fn)
  102. {
  103. C2K_NOTE("%s\n", __func__);
  104. return check_enable_state(fn);
  105. }
  106. EXPORT_SYMBOL_GPL(rawbulk_check_enable);
  107. static inline void set_enable_state(struct rawbulk_function *fn, int enab)
  108. {
  109. unsigned long flags;
  110. spin_lock_irqsave(&fn->lock, flags);
  111. fn->enable = !!enab;
  112. spin_unlock_irqrestore(&fn->lock, flags);
  113. }
  114. void rawbulk_disable_function(struct rawbulk_function *fn)
  115. {
  116. C2K_NOTE("enable to 0\n");
  117. set_enable_state(fn, 0);
  118. }
  119. EXPORT_SYMBOL_GPL(rawbulk_disable_function);
  120. #define port_to_rawbulk(p) container_of(p, struct rawbulk_function, port)
  121. #define function_to_rawbulk(f) container_of(f, struct rawbulk_function, function)
  122. static void init_endpoint_desc(struct usb_endpoint_descriptor *epdesc, int in, int maxpacksize)
  123. {
  124. struct usb_endpoint_descriptor template = {
  125. .bLength = USB_DT_ENDPOINT_SIZE,
  126. .bDescriptorType = USB_DT_ENDPOINT,
  127. .bmAttributes = USB_ENDPOINT_XFER_BULK,
  128. };
  129. *epdesc = template;
  130. if (in)
  131. epdesc->bEndpointAddress = USB_DIR_IN;
  132. else
  133. epdesc->bEndpointAddress = USB_DIR_OUT;
  134. epdesc->wMaxPacketSize = cpu_to_le16(maxpacksize);
  135. }
  136. static void init_interface_desc(struct usb_interface_descriptor *ifdesc)
  137. {
  138. struct usb_interface_descriptor template = {
  139. .bLength = USB_DT_INTERFACE_SIZE,
  140. .bDescriptorType = USB_DT_INTERFACE,
  141. .bInterfaceNumber = 0,
  142. .bAlternateSetting = 0,
  143. .bNumEndpoints = 2,
  144. .bInterfaceClass = 0xff, /* USB_CLASS_VENDOR_SPEC, */
  145. .bInterfaceSubClass = 0xff,
  146. .bInterfaceProtocol = 0xff,
  147. .iInterface = 0,
  148. };
  149. *ifdesc = template;
  150. }
  151. static ssize_t rawbulk_attr_show(struct device *dev, struct device_attribute
  152. *attr, char *buf);
  153. static ssize_t rawbulk_attr_store(struct device *dev, struct device_attribute
  154. *attr, const char *buf, size_t count);
  155. static inline void add_device_attr(struct rawbulk_function *fn, int n, const char
  156. *name, int mode)
  157. {
  158. if (n < MAX_ATTRIBUTES) {
  159. fn->attr[n].attr.name = name;
  160. fn->attr[n].attr.mode = mode;
  161. fn->attr[n].show = rawbulk_attr_show;
  162. fn->attr[n].store = rawbulk_attr_store;
  163. }
  164. }
  165. static int which_attr(struct rawbulk_function *fn, struct device_attribute
  166. *attr)
  167. {
  168. int n;
  169. for (n = 0; n < fn->max_attrs; n++) {
  170. if (attr == &fn->attr[n])
  171. return n;
  172. }
  173. return -1;
  174. }
  175. static ssize_t rawbulk_attr_show(struct device *dev, struct device_attribute *attr, char *buf)
  176. {
  177. int n;
  178. int idx;
  179. int enab;
  180. struct rawbulk_function *fn;
  181. ssize_t count = 0;
  182. for (n = 0; n < _MAX_TID; n++) {
  183. fn = rawbulk_lookup_function(n);
  184. if (fn->dev == dev) {
  185. idx = which_attr(fn, attr);
  186. break;
  187. }
  188. #ifdef SUPPORT_LEGACY_CONTROL
  189. if (!strcmp(attr->attr.name, fn->shortname)) {
  190. idx = ATTR_ENABLE_C;
  191. break;
  192. }
  193. #endif
  194. }
  195. if (n == _MAX_TID)
  196. return 0;
  197. enab = check_enable_state(fn);
  198. switch (idx) {
  199. case ATTR_ENABLE:
  200. count = sprintf(buf, "%d", enab);
  201. break;
  202. #ifdef SUPPORT_LEGACY_CONTROL
  203. case ATTR_ENABLE_C:
  204. count = sprintf(buf, "%s", enab ? "gadget" : "tty");
  205. break;
  206. #endif
  207. case ATTR_AUTORECONN:
  208. count = sprintf(buf, "%d", fn->autoreconn);
  209. break;
  210. case ATTR_STATISTICS:
  211. count = rawbulk_transfer_statistics(fn->transfer_id, buf);
  212. break;
  213. case ATTR_NUPS:
  214. count = sprintf(buf,
  215. "nups<%d>,udata<%d>,ucnt<%d>,drop<%d>,alloc_fail<%d>,tran<%d>\n",
  216. enab ? fn->nups : -1, upstream_data[fn->transfer_id],
  217. upstream_cnt[fn->transfer_id], total_drop[fn->transfer_id],
  218. alloc_fail[fn->transfer_id], total_tran[fn->transfer_id]);
  219. break;
  220. case ATTR_NDOWNS:
  221. count = sprintf(buf, "%d", enab ? fn->ndowns : -1);
  222. break;
  223. case ATTR_UPSIZE:
  224. count = sprintf(buf, "%d", enab ? fn->upsz : -1);
  225. break;
  226. case ATTR_DOWNSIZE:
  227. count = sprintf(buf, "%d", enab ? fn->downsz : -1);
  228. break;
  229. default:
  230. break;
  231. }
  232. return count;
  233. }
  234. #ifdef C2K_USB_UT
  235. int total_cnt;
  236. void do_push_upstream(int transfer_id, char *buf, int len)
  237. {
  238. int ret;
  239. while (1) {
  240. ret = rawbulk_push_upstream_buffer(transfer_id, buf, len);
  241. if (ret == len || ret == 0) {
  242. C2K_DBG("push ret(%d)\n", ret);
  243. #ifdef C2K_USB_PERF
  244. total_cnt += 1;
  245. if (total_cnt == 1024) {
  246. C2K_NOTE("4MB got\n");
  247. total_cnt = 0;
  248. }
  249. #endif
  250. break;
  251. }
  252. C2K_DBG("push ret(%d)\n", ret);
  253. #ifndef C2K_USB_PERF
  254. udelay(1000);
  255. #endif
  256. }
  257. }
  258. #endif
  259. static ssize_t rawbulk_attr_store(struct device *dev, struct device_attribute *attr,
  260. const char *buf, size_t count)
  261. {
  262. int n;
  263. int rc = 0;
  264. int idx = -1;
  265. int nups;
  266. int ndowns;
  267. int upsz;
  268. int downsz;
  269. struct rawbulk_function *fn;
  270. for (n = 0; n < _MAX_TID; n++) {
  271. fn = rawbulk_lookup_function(n);
  272. if (fn->dev == dev) {
  273. idx = which_attr(fn, attr);
  274. break;
  275. }
  276. #ifdef SUPPORT_LEGACY_CONTROL
  277. if (!strcmp(attr->attr.name, fn->shortname)) {
  278. idx = ATTR_ENABLE_C;
  279. break;
  280. }
  281. #endif
  282. }
  283. if (idx < 0) {
  284. C2K_ERR("sorry, I cannot find rawbulk fn '%s'\n", attr->attr.name);
  285. goto exit;
  286. }
  287. nups = fn->nups;
  288. ndowns = fn->ndowns;
  289. upsz = fn->upsz;
  290. downsz = fn->downsz;
  291. /* find out which attr(file) we write */
  292. #ifdef SUPPORT_LEGACY_CONTROL
  293. if (idx <= ATTR_ENABLE_C) {
  294. #else
  295. if (idx == ATTR_ENABLE) {
  296. #endif
  297. int enable;
  298. if (idx == ATTR_ENABLE) {
  299. int ret;
  300. ret = kstrtol(buf, 0, (long *)&enable);
  301. C2K_NOTE("enable:%d\n", enable);
  302. #ifdef C2K_USB_UT
  303. if (enable == UT_CMD) {
  304. int i;
  305. unsigned int len;
  306. int transfer_id = n;
  307. static char last_end = 0x0;
  308. char *buf = kmalloc(SZ, GFP_KERNEL);
  309. C2K_NOTE("buf(%p)\n", buf);
  310. /* #define C2K_USB_PERF */
  311. #ifdef C2K_USB_PERF
  312. total_cnt = 0;
  313. memset(buf, 0x41, SZ);
  314. #endif
  315. while (!signal_pending(current)) {
  316. #ifdef C2K_USB_PERF
  317. len = SZ;
  318. #else
  319. if (ut_err) {
  320. C2K_NOTE("errrrrrrrrrrrrrrrrrrrrrrrr\n");
  321. break;
  322. }
  323. get_random_bytes(&len, sizeof(len));
  324. C2K_NOTE("len before(%d)\n", len);
  325. len %= SZ;
  326. len += 1;
  327. C2K_NOTE("len after(%d)\n", len);
  328. buf[0] = last_end + 1;
  329. for (i = 1; i < len; i++)
  330. buf[i] = buf[i - 1] + 1;
  331. last_end = buf[i - 1];
  332. #endif
  333. do_push_upstream(transfer_id, buf, len);
  334. #ifdef C2K_USB_PERF
  335. /* simulate 4MB per sec */
  336. udelay(delay_set);
  337. #endif
  338. }
  339. if (buf) {
  340. C2K_NOTE("free buf\n");
  341. kfree(buf);
  342. }
  343. ut_err = 0;
  344. C2K_NOTE("exit UT\n");
  345. goto exit;
  346. } else if (enable == UT_CLR_ERR) {
  347. ut_err = 0;
  348. goto exit;
  349. }
  350. #endif
  351. #ifdef SUPPORT_LEGACY_CONTROL
  352. } else if (idx == ATTR_ENABLE_C) {
  353. if (!strncmp(buf, "tty", 3))
  354. enable = 0;
  355. else if (!strncmp(buf, "gadget", 6))
  356. enable = 1;
  357. else {
  358. C2K_ERR("invalid option(%s) for bypass, try again...\n", buf);
  359. goto exit;
  360. }
  361. #endif /* SUPPORT_LEGACY_CONTROL */
  362. } else
  363. goto exit;
  364. if ((check_enable_state(fn) != (!!enable))) {
  365. C2K_NOTE("enable:%d\n", enable);
  366. set_enable_state(fn, enable);
  367. if (!!enable && fn->activated) {
  368. C2K_NOTE("enable rawbulk %s channel, been activated? %s\n",
  369. fn->shortname, fn->activated ? "yes" : "no");
  370. if (fn->transfer_id == RAWBULK_TID_MODEM) {
  371. /* clear DTR to endup last session between AP and CP */
  372. modem_dtr_set(1, 1);
  373. modem_dtr_set(0, 1);
  374. modem_dtr_set(1, 1);
  375. modem_dcd_state();
  376. }
  377. /* Start rawbulk transfer */
  378. wake_lock(&fn->keep_awake);
  379. rc = rawbulk_start_transactions(fn->transfer_id, nups,
  380. ndowns, upsz, downsz);
  381. if (rc < 0)
  382. C2K_ERR("%s rc = %d bypass failed\n", __func__, rc);
  383. } else {
  384. /* Stop rawbulk transfer */
  385. C2K_NOTE("disable rawbulk %s channel, been activated? %s\n",
  386. fn->shortname, fn->activated ? "yes" : "no");
  387. rawbulk_stop_transactions(fn->transfer_id);
  388. if (fn->transfer_id == RAWBULK_TID_MODEM) {
  389. /* clear DTR automatically when disable modem rawbulk */
  390. modem_dtr_set(1, 1);
  391. modem_dtr_set(0, 1);
  392. modem_dtr_set(1, 1);
  393. modem_dcd_state();
  394. }
  395. wake_unlock(&fn->keep_awake);
  396. }
  397. }
  398. } else if (idx == ATTR_DTR) {
  399. if (fn->transfer_id == RAWBULK_TID_MODEM) {
  400. if (check_enable_state(fn)) {
  401. int val, ret;
  402. ret = kstrtol(buf, 0, (long *)&val);
  403. modem_dtr_set(val, 1);
  404. }
  405. }
  406. } else if (idx == ATTR_AUTORECONN) {
  407. int val, ret;
  408. ret = kstrtol(buf, 0, (long *)&val);
  409. fn->autoreconn = !!val;
  410. } else {
  411. int val, ret;
  412. ret = kstrtol(buf, 0, (long *)&val);
  413. switch (idx) {
  414. case ATTR_NUPS:
  415. nups = val;
  416. break;
  417. case ATTR_NDOWNS:
  418. ndowns = val;
  419. break;
  420. case ATTR_UPSIZE:
  421. upsz = val;
  422. break;
  423. case ATTR_DOWNSIZE:
  424. downsz = val;
  425. break;
  426. default:
  427. goto exit;
  428. }
  429. if (!check_enable_state(fn))
  430. goto exit;
  431. if (!fn->activated)
  432. goto exit;
  433. rawbulk_stop_transactions(fn->transfer_id);
  434. rc = rawbulk_start_transactions(fn->transfer_id, nups, ndowns, upsz, downsz);
  435. if (rc >= 0) {
  436. fn->nups = nups;
  437. fn->ndowns = ndowns;
  438. fn->upsz = upsz;
  439. fn->downsz = downsz;
  440. } else {
  441. rawbulk_stop_transactions(fn->transfer_id);
  442. wake_unlock(&fn->keep_awake);
  443. C2K_NOTE("enable to 0\n");
  444. set_enable_state(fn, 0);
  445. }
  446. }
  447. exit:
  448. return count;
  449. }
  450. static int rawbulk_create_files(struct rawbulk_function *fn)
  451. {
  452. int n, rc;
  453. for (n = 0; n < fn->max_attrs; n++) {
  454. #ifdef SUPPORT_LEGACY_CONTROL
  455. if (n == ATTR_ENABLE_C)
  456. continue;
  457. #endif
  458. rc = device_create_file(fn->dev, &fn->attr[n]);
  459. if (rc < 0) {
  460. while (--n >= 0) {
  461. #ifdef SUPPORT_LEGACY_CONTROL
  462. if (n == ATTR_ENABLE_C)
  463. continue;
  464. #endif
  465. device_remove_file(fn->dev, &fn->attr[n]);
  466. }
  467. return rc;
  468. }
  469. }
  470. return 0;
  471. }
  472. static void rawbulk_remove_files(struct rawbulk_function *fn)
  473. {
  474. int n = fn->max_attrs;
  475. while (--n >= 0) {
  476. #ifdef SUPPORT_LEGACY_CONTROL
  477. if (n == ATTR_ENABLE_C)
  478. continue;
  479. #endif
  480. device_remove_file(fn->dev, &fn->attr[n]);
  481. }
  482. }
  483. /******************************************************************************/
  484. static struct class *rawbulk_class;
  485. static struct _function_init_stuff {
  486. const char *longname;
  487. const char *shortname;
  488. const char *iString;
  489. unsigned int nups;
  490. unsigned int ndowns;
  491. unsigned int upsz;
  492. unsigned int downsz;
  493. bool autoreconn;
  494. bool pushable;
  495. } _init_params[] = {
  496. #ifdef CONFIG_EVDO_DT_VIA_SUPPORT
  497. {
  498. "rawbulk-modem", "data", "Modem Port", 32, 32, 4096, 4096, true, false}, {
  499. "rawbulk-ets", "ets", "ETS Port", 32, 32, 4096, 4096, true, false}, {
  500. "rawbulk-at", "atc", "AT Channel", 3, 3, 4096, 4096, true, false}, {
  501. "rawbulk-pcv", "pcv", "PCM Voice", 1, 1, 4096, 4096, true, false}, {
  502. "rawbulk-gps", "gps", "LBS GPS Port", 1, 1, 4096, 4096, true, false}, {
  503. }, /* End of configurations */
  504. #else
  505. {
  506. "rawbulk-pcv", "pcv", "PCM Voice", 1, 1, 4096, 4096, true, false}, {
  507. "rawbulk-modem", "data", "Modem Port", 32, 32, 4096, 4096, true, false}, {
  508. "rawbulk-ets", "ets", "ETS Port", 32, 32, 4096, 4096, true, false}, {
  509. "rawbulk-at", "atc", "AT Channel", 3, 3, 4096, 4096, true, false}, {
  510. "rawbulk-gps", "gps", "LBS GPS Port", 1, 1, 4096, 4096, true, false}, {
  511. }, /* End of configurations */
  512. #endif
  513. };
  514. static __init struct rawbulk_function *rawbulk_alloc_function(int transfer_id)
  515. {
  516. int rc;
  517. struct rawbulk_function *fn;
  518. C2K_NOTE("%s\n", __func__);
  519. if (transfer_id == _MAX_TID)
  520. return NULL;
  521. fn = kzalloc(sizeof(*fn), GFP_KERNEL);
  522. if (IS_ERR(fn))
  523. return NULL;
  524. /* init default features of rawbulk functions */
  525. fn->longname = _init_params[transfer_id].longname;
  526. fn->shortname = _init_params[transfer_id].shortname;
  527. fn->string_defs[0].s = _init_params[transfer_id].iString;
  528. fn->nups = _init_params[transfer_id].nups;
  529. fn->ndowns = _init_params[transfer_id].ndowns;
  530. fn->upsz = _init_params[transfer_id].upsz;
  531. fn->downsz = _init_params[transfer_id].downsz;
  532. fn->autoreconn = _init_params[transfer_id].autoreconn;
  533. fn->tty_minor = -1;
  534. /* init descriptors */
  535. init_interface_desc(&fn->interface);
  536. init_endpoint_desc(&fn->fs_bulkin_endpoint, 1, 512);
  537. init_endpoint_desc(&fn->hs_bulkin_endpoint, 1, 512);
  538. init_endpoint_desc(&fn->fs_bulkout_endpoint, 0, 512);
  539. init_endpoint_desc(&fn->hs_bulkout_endpoint, 0, 512);
  540. fn->fs_descs[INTF_DESC] = (struct usb_descriptor_header *)&fn->interface;
  541. fn->fs_descs[BULKIN_DESC] = (struct usb_descriptor_header *)&fn->fs_bulkin_endpoint;
  542. fn->fs_descs[BULKOUT_DESC] = (struct usb_descriptor_header *)&fn->fs_bulkout_endpoint;
  543. fn->hs_descs[INTF_DESC] = (struct usb_descriptor_header *)&fn->interface;
  544. fn->hs_descs[BULKIN_DESC] = (struct usb_descriptor_header *)&fn->hs_bulkin_endpoint;
  545. fn->hs_descs[BULKOUT_DESC] = (struct usb_descriptor_header *)&fn->hs_bulkout_endpoint;
  546. fn->string_table.language = 0x0409;
  547. fn->string_table.strings = fn->string_defs;
  548. fn->strings[0] = &fn->string_table;
  549. fn->strings[1] = NULL;
  550. fn->transfer_id = transfer_id;
  551. fn->tty_throttled = 0;
  552. /* init function callbacks */
  553. fn->function.strings = fn->strings;
  554. fn->function.fs_descriptors = fn->fs_descs;
  555. fn->function.hs_descriptors = fn->hs_descs;
  556. /* init device attributes */
  557. add_device_attr(fn, ATTR_ENABLE, "enable", 0660);
  558. #ifdef SUPPORT_LEGACY_CONTROL
  559. add_device_attr(fn, ATTR_ENABLE_C, fn->shortname, 0660);
  560. #endif
  561. add_device_attr(fn, ATTR_AUTORECONN, "autoreconn", 0660);
  562. add_device_attr(fn, ATTR_STATISTICS, "statistics", 0660);
  563. add_device_attr(fn, ATTR_NUPS, "nups", 0660);
  564. add_device_attr(fn, ATTR_NDOWNS, "ndowns", 0660);
  565. add_device_attr(fn, ATTR_UPSIZE, "ups_size", 0660);
  566. add_device_attr(fn, ATTR_DOWNSIZE, "downs_size", 0660);
  567. fn->max_attrs = ATTR_DOWNSIZE + 1;
  568. if (transfer_id == RAWBULK_TID_MODEM) {
  569. add_device_attr(fn, ATTR_DTR, "dtr", 0220);
  570. fn->max_attrs++;
  571. }
  572. fn->dev = device_create(rawbulk_class, NULL, MKDEV(0,
  573. fn->transfer_id), NULL, fn->shortname);
  574. if (IS_ERR(fn->dev)) {
  575. kfree(fn);
  576. return NULL;
  577. }
  578. rc = rawbulk_create_files(fn);
  579. if (rc < 0) {
  580. device_destroy(rawbulk_class, fn->dev->devt);
  581. kfree(fn);
  582. return NULL;
  583. }
  584. spin_lock_init(&fn->lock);
  585. wake_lock_init(&fn->keep_awake, WAKE_LOCK_SUSPEND, fn->longname);
  586. return fn;
  587. }
  588. static void rawbulk_destroy_function(struct rawbulk_function *fn)
  589. {
  590. C2K_NOTE("%s\n", __func__);
  591. if (!fn)
  592. return;
  593. wake_lock_destroy(&fn->keep_awake);
  594. rawbulk_remove_files(fn);
  595. device_destroy(rawbulk_class, fn->dev->devt);
  596. kfree(fn);
  597. }
  598. #ifdef SUPPORT_LEGACY_CONTROL
  599. static struct attribute *legacy_sysfs[_MAX_TID + 1] = { NULL };
  600. static struct attribute_group legacy_sysfs_group = {
  601. .attrs = legacy_sysfs,
  602. };
  603. struct kobject *legacy_sysfs_stuff;
  604. #endif /* SUPPORT_LEGACY_CONTROL */
  605. static int __init init(void)
  606. {
  607. int n;
  608. int rc = 0;
  609. C2K_NOTE("rawbulk functions init.\n");
  610. rawbulk_class = class_create(THIS_MODULE, "usb_rawbulk");
  611. if (IS_ERR(rawbulk_class))
  612. return PTR_ERR(rawbulk_class);
  613. for (n = 0; n < _MAX_TID; n++) {
  614. struct rawbulk_function *fn = rawbulk_alloc_function(n);
  615. if (IS_ERR(fn)) {
  616. while (n--)
  617. rawbulk_destroy_function(prealloced_functions[n]);
  618. rc = PTR_ERR(fn);
  619. break;
  620. }
  621. prealloced_functions[n] = fn;
  622. #ifdef SUPPORT_LEGACY_CONTROL
  623. legacy_sysfs[n] = &fn->attr[ATTR_ENABLE_C].attr;
  624. #endif
  625. }
  626. if (rc < 0) {
  627. class_destroy(rawbulk_class);
  628. return rc;
  629. }
  630. #ifdef SUPPORT_LEGACY_CONTROL
  631. /* make compatiable with old bypass sysfs access */
  632. legacy_sysfs_stuff = kobject_create_and_add("usb_bypass", NULL);
  633. if (legacy_sysfs_stuff) {
  634. rc = sysfs_create_group(legacy_sysfs_stuff, &legacy_sysfs_group);
  635. if (rc < 0)
  636. C2K_ERR("failed to create legacy bypass sys-stuff, but continue...\n");
  637. }
  638. #endif /* SUPPORT_LEGACY_CONTROL */
  639. return 0;
  640. }
  641. module_init(init);
  642. MODULE_AUTHOR(DRIVER_AUTHOR);
  643. MODULE_DESCRIPTION(DRIVER_DESC);
  644. MODULE_VERSION(DRIVER_VERSION);
  645. MODULE_LICENSE("GPL");