f_rawbulk.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. /*
  2. * Rawbulk Gadget Function Driver from VIA Telecom
  3. *
  4. * Copyright (C) 2011 VIA Telecom, Inc.
  5. * Author: Juelun Guo (jlguo@via-telecom.com)
  6. *
  7. * This software is licensed under the terms of the GNU General Public
  8. * License version 2, as published by the Free Software Foundation, and
  9. * may be copied, distributed, and modified under those terms.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. */
  17. #define DRIVER_AUTHOR "jlguo <jlguo@via-telecom.com>"
  18. #define DRIVER_DESC "Rawbulk Gadget - transport data from CP to Gadget"
  19. #define DRIVER_VERSION "1.0.1"
  20. #include <linux/err.h>
  21. #include <linux/wakelock.h>
  22. #include <linux/interrupt.h>
  23. #include <linux/delay.h>
  24. #include <linux/wait.h>
  25. #include <linux/version.h>
  26. #include <linux/types.h>
  27. #include <linux/device.h>
  28. #include <linux/usb/composite.h>
  29. #include "viatel_rawbulk.h"
  30. /* int setdtr, data_connect; */
  31. /* struct work_struct flow_control; */
  32. /* struct work_struct dtr_status; */
  33. #define function_to_rbf(f) container_of(f, struct rawbulk_function, function)
  34. static int usb_state;
  35. void simple_setup_complete(struct usb_ep *ep, struct usb_request *req)
  36. {
  37. ; /* DO NOTHING */
  38. }
  39. #define FINISH_DISABLE 0
  40. #define START_DISABLE 1
  41. int rawbulk_function_setup(struct usb_function *f, const struct
  42. usb_ctrlrequest * ctrl)
  43. {
  44. struct rawbulk_function *fn = function_to_rbf(f);
  45. unsigned int setdtr = 0;
  46. unsigned int data_connect = 0;
  47. struct usb_composite_dev *cdev = f->config->cdev;
  48. struct usb_request *req = cdev->req;
  49. int value = -EOPNOTSUPP;
  50. u16 w_index = le16_to_cpu(ctrl->wIndex);
  51. u16 w_value = le16_to_cpu(ctrl->wValue);
  52. u16 w_length = le16_to_cpu(ctrl->wLength);
  53. C2K_NOTE("%s\n", __func__);
  54. if (ctrl->bRequest) {
  55. C2K_NOTE("ctrl->bRequestType = %0x ctrl->bRequest = %0x\n", ctrl->bRequestType,
  56. ctrl->bRequest);
  57. }
  58. switch (ctrl->bRequest) {
  59. case 0x01:
  60. if (ctrl->bRequestType == (USB_DIR_OUT | USB_TYPE_VENDOR)) { /* 0x40 */
  61. /* set/clear DTR */
  62. C2K_NOTE("setdtr = %d, w_value =%d\n", setdtr, w_value);
  63. if (fn->activated) {
  64. setdtr = w_value & 0x01;
  65. /* schedule_work(&flow_control); */
  66. modem_dtr_set(setdtr, 0);
  67. modem_dcd_state();
  68. }
  69. value = 0;
  70. }
  71. break;
  72. case 0x02:
  73. if (ctrl->bRequestType == (USB_DIR_IN | USB_TYPE_VENDOR)) { /* 0xC0 */
  74. /* DSR | CD109 */
  75. /* schedule_work(&dtr_status); */
  76. data_connect = modem_dcd_state();
  77. /* modem_dtr_query(&data_connect, 0); */
  78. if (fn->activated) {
  79. if (data_connect && fn->enable) {
  80. *((unsigned char *)req->buf) = 0x3;
  81. C2K_NOTE("connect %d\n", data_connect);
  82. } else {
  83. *((unsigned char *)req->buf) = 0x2;
  84. C2K_NOTE("disconnect=%d, setdtr=%d\n", data_connect,
  85. setdtr);
  86. }
  87. } else /* set CD CSR state to 0 if modem bypass not inactive */
  88. *((unsigned char *)req->buf) = 0x0;
  89. value = 1;
  90. }
  91. break;
  92. case 0x03:
  93. if (ctrl->bRequestType == (USB_DIR_OUT | USB_TYPE_VENDOR)) { /* 0x40 */
  94. /* xcvr */
  95. C2K_NOTE("CTRL SET XCVR 0x%02x\n", w_value);
  96. value = 0;
  97. }
  98. break;
  99. case 0x04:
  100. if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR) {
  101. if (ctrl->bRequestType & USB_DIR_IN) { /* 0xC0 */
  102. /* return ID */
  103. sprintf(req->buf, "CBP_8.2");
  104. value = 1;
  105. } else { /* 0x40 */
  106. value = 0;
  107. }
  108. }
  109. break;
  110. case 0x05:
  111. if (ctrl->bRequestType == (USB_DIR_IN | USB_TYPE_VENDOR)) { /* 0xC0 */
  112. /* connect status */
  113. C2K_NOTE("CTRL CONNECT STATUS\n");
  114. *((unsigned char *)req->buf) = 0x0;
  115. value = 1;
  116. }
  117. break;
  118. default:
  119. C2K_NOTE("invalid control req%02x.%02x v%04x i%04x l%d\n",
  120. ctrl->bRequestType, ctrl->bRequest, w_value, w_index, w_length);
  121. }
  122. /* respond with data transfer or status phase? */
  123. if (value >= 0) {
  124. req->zero = 0;
  125. req->length = value;
  126. req->complete = simple_setup_complete;
  127. value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
  128. if (value < 0)
  129. C2K_ERR("response err %d\n", value);
  130. }
  131. /* device either stalls (value < 0) or reports success */
  132. return value;
  133. }
  134. static void rawbulk_auto_reconnect(int transfer_id)
  135. {
  136. int rc;
  137. struct rawbulk_function *fn = rawbulk_lookup_function(transfer_id);
  138. C2K_NOTE("%s\n", __func__);
  139. if (!fn || fn->autoreconn == 0)
  140. return;
  141. if (rawbulk_check_enable(fn) && fn->activated) {
  142. C2K_ERR("start %s again automatically.\n", fn->longname);
  143. rc = rawbulk_start_transactions(transfer_id, fn->nups,
  144. fn->ndowns, fn->upsz, fn->downsz);
  145. if (rc < 0) {
  146. rawbulk_disable_function(fn);
  147. }
  148. }
  149. }
  150. int rawbulk_function_bind(struct usb_configuration *c, struct
  151. usb_function * f)
  152. {
  153. int rc, ifnum;
  154. struct rawbulk_function *fn = function_to_rbf(f);
  155. struct usb_gadget *gadget = c->cdev->gadget;
  156. struct usb_ep *ep_out, *ep_in;
  157. C2K_ERR("%s\n", __func__);
  158. rc = usb_interface_id(c, f);
  159. if (rc < 0)
  160. return rc;
  161. ifnum = rc;
  162. fn->interface.bInterfaceNumber = cpu_to_le16(ifnum);
  163. ep_out = usb_ep_autoconfig(gadget, (struct usb_endpoint_descriptor *)
  164. fn->fs_descs[BULKOUT_DESC]);
  165. if (!ep_out) {
  166. C2K_ERR("%s %d config ep_out error\n", __func__, __LINE__);
  167. return -ENOMEM;
  168. }
  169. ep_in = usb_ep_autoconfig(gadget, (struct usb_endpoint_descriptor *)
  170. fn->fs_descs[BULKIN_DESC]);
  171. if (!ep_in) {
  172. usb_ep_disable(ep_out);
  173. C2K_ERR("%s %d config ep_in error\n", __func__, __LINE__);
  174. return -ENOMEM;
  175. }
  176. ep_out->driver_data = fn;
  177. ep_in->driver_data = fn;
  178. fn->bulk_out = ep_out;
  179. fn->bulk_in = ep_in;
  180. f->fs_descriptors = usb_copy_descriptors(fn->fs_descs);
  181. if (unlikely(!f->fs_descriptors))
  182. return -ENOMEM;
  183. if (gadget_is_dualspeed(gadget)) {
  184. fn->hs_bulkin_endpoint.bEndpointAddress = fn->fs_bulkin_endpoint.bEndpointAddress;
  185. fn->hs_bulkout_endpoint.bEndpointAddress = fn->fs_bulkout_endpoint.bEndpointAddress;
  186. }
  187. fn->cdev = c->cdev;
  188. fn->activated = 0;
  189. return rawbulk_bind_function(fn->transfer_id, f, ep_out, ep_in, rawbulk_auto_reconnect);
  190. }
  191. void rawbulk_function_unbind(struct usb_configuration *c, struct
  192. usb_function * f)
  193. {
  194. struct rawbulk_function *fn = function_to_rbf(f);
  195. C2K_NOTE("%s\n", __func__);
  196. /* cancel_work_sync(&fn->activator); */
  197. /* cancel_work_sync(&flow_control); */
  198. /* cancel_work_sync(&dtr_status); */
  199. rawbulk_unbind_function(fn->transfer_id);
  200. }
  201. /*void modem_flow_control(struct work_struct *work) {
  202. modem_dtr_set(!!setdtr);
  203. modem_dtr_query(&data_connect, 1);
  204. }
  205. void dtr_status_query(struct work_struct *work) {
  206. modem_dtr_query(&data_connect, 1);
  207. }
  208. */
  209. static void do_activate(struct work_struct *data)
  210. {
  211. struct rawbulk_function *fn = container_of(data, struct rawbulk_function,
  212. activator);
  213. int rc;
  214. struct usb_function *functionp = &(fn->function);
  215. C2K_ERR("%s usb state %s, <%d>\n", __func__, (fn->activated ? "connect" : "disconnect"),
  216. fn->transfer_id);
  217. if (fn->activated) { /* enumerated */
  218. /* enabled endpoints */
  219. rc = config_ep_by_speed(fn->cdev->gadget, functionp, fn->bulk_out);
  220. if (rc < 0) {
  221. C2K_ERR("failed to config speed rawbulk %s %d\n",
  222. fn->bulk_out->name, rc);
  223. return;
  224. }
  225. rc = usb_ep_enable(fn->bulk_out);
  226. if (rc < 0) {
  227. C2K_ERR("failed to enable rawbulk %s %d\n", fn->bulk_out->name, rc);
  228. return;
  229. }
  230. rc = config_ep_by_speed(fn->cdev->gadget, functionp, fn->bulk_in);
  231. if (rc < 0) {
  232. C2K_ERR("failed to config speed rawbulk %s %d\n",
  233. fn->bulk_in->name, rc);
  234. return;
  235. }
  236. rc = usb_ep_enable(fn->bulk_in);
  237. if (rc < 0) {
  238. C2K_ERR("failed to enable rawbulk %s %d\n", fn->bulk_in->name, rc);
  239. usb_ep_disable(fn->bulk_out);
  240. return;
  241. }
  242. /* start rawbulk if enabled */
  243. if (rawbulk_check_enable(fn)) {
  244. wake_lock(&fn->keep_awake);
  245. rc = rawbulk_start_transactions(fn->transfer_id, fn->nups,
  246. fn->ndowns, fn->upsz, fn->downsz);
  247. if (rc < 0)
  248. /* rawbulk_disable_function(fn); */
  249. C2K_ERR("%s: failed to bypass, channel id = %d\n",
  250. __func__, fn->transfer_id);
  251. }
  252. } else { /* disconnect */
  253. if (rawbulk_check_enable(fn)) {
  254. if (fn->transfer_id == RAWBULK_TID_MODEM) {
  255. /* this in interrupt, but DTR need be set firstly then clear it
  256. * */
  257. modem_dtr_set(1, 1);
  258. modem_dtr_set(0, 1);
  259. modem_dtr_set(1, 1);
  260. modem_dcd_state();
  261. }
  262. rawbulk_stop_transactions(fn->transfer_id);
  263. /* keep the enable state, so we can enable again in next time */
  264. /* set_enable_state(fn, 0); */
  265. wake_unlock(&fn->keep_awake);
  266. }
  267. usb_ep_disable(fn->bulk_out);
  268. usb_ep_disable(fn->bulk_in);
  269. fn->bulk_out->driver_data = NULL;
  270. fn->bulk_in->driver_data = NULL;
  271. }
  272. }
  273. static void rawbulk_usb_state_set(int state)
  274. {
  275. usb_state = state ? 1 : 0;
  276. C2K_ERR("%s usb_state = %d\n", __func__, usb_state);
  277. }
  278. int rawbulk_usb_state_check(void)
  279. {
  280. return usb_state ? 1 : 0;
  281. }
  282. EXPORT_SYMBOL_GPL(rawbulk_usb_state_check);
  283. static int rawbulk_function_setalt(struct usb_function *f, unsigned intf, unsigned alt)
  284. {
  285. struct rawbulk_function *fn = function_to_rbf(f);
  286. C2K_NOTE("%s\n", __func__);
  287. fn->activated = 1;
  288. rawbulk_usb_state_set(fn->activated);
  289. schedule_work(&fn->activator);
  290. return 0;
  291. }
  292. static void rawbulk_function_disable(struct usb_function *f)
  293. {
  294. struct rawbulk_function *fn = function_to_rbf(f);
  295. C2K_NOTE("%s, %s\n", __func__, f->name);
  296. fn->activated = 0;
  297. rawbulk_usb_state_set(fn->activated);
  298. schedule_work(&fn->activator);
  299. }
  300. int rawbulk_bind_config(struct usb_configuration *c, int transfer_id)
  301. {
  302. int rc;
  303. struct rawbulk_function *fn = rawbulk_lookup_function(transfer_id);
  304. if (!fn)
  305. return -ENOMEM;
  306. C2K_ERR("add %s to config.\n", fn->longname);
  307. if (fn->string_defs[0].id == 0) {
  308. rc = usb_string_id(c->cdev);
  309. if (rc < 0)
  310. return rc;
  311. fn->string_defs[0].id = rc;
  312. fn->interface.iInterface = rc;
  313. }
  314. if (!fn->initialized) {
  315. fn->function.name = fn->longname;
  316. fn->function.setup = rawbulk_function_setup;
  317. fn->function.bind = rawbulk_function_bind;
  318. fn->function.unbind = rawbulk_function_unbind;
  319. fn->function.set_alt = rawbulk_function_setalt;
  320. fn->function.disable = rawbulk_function_disable;
  321. INIT_WORK(&fn->activator, do_activate);
  322. /*if(fn->transfer_id == RAWBULK_TID_MODEM) {
  323. INIT_WORK(&flow_control, modem_flow_control);
  324. INIT_WORK(&dtr_status, dtr_status_query);
  325. } */
  326. fn->initialized = 1;
  327. }
  328. rc = usb_add_function(c, &fn->function);
  329. if (rc < 0)
  330. C2K_ERR("%s - failed to config %d.\n", __func__, rc);
  331. return rc;
  332. }