ozusbsvc1.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. /* -----------------------------------------------------------------------------
  2. * Copyright (c) 2011 Ozmo Inc
  3. * Released under the GNU General Public License Version 2 (GPLv2).
  4. *
  5. * This file implements the protocol specific parts of the USB service for a PD.
  6. * -----------------------------------------------------------------------------
  7. */
  8. #include <linux/module.h>
  9. #include <linux/timer.h>
  10. #include <linux/sched.h>
  11. #include <linux/netdevice.h>
  12. #include <linux/errno.h>
  13. #include <linux/input.h>
  14. #include <asm/unaligned.h>
  15. #include "ozdbg.h"
  16. #include "ozprotocol.h"
  17. #include "ozeltbuf.h"
  18. #include "ozpd.h"
  19. #include "ozproto.h"
  20. #include "ozusbif.h"
  21. #include "ozhcd.h"
  22. #include "ozusbsvc.h"
  23. #define MAX_ISOC_FIXED_DATA (253-sizeof(struct oz_isoc_fixed))
  24. /*
  25. * Context: softirq
  26. */
  27. static int oz_usb_submit_elt(struct oz_elt_buf *eb, struct oz_elt_info *ei,
  28. struct oz_usb_ctx *usb_ctx, u8 strid, u8 isoc)
  29. {
  30. int ret;
  31. struct oz_elt *elt = (struct oz_elt *)ei->data;
  32. struct oz_app_hdr *app_hdr = (struct oz_app_hdr *)(elt+1);
  33. elt->type = OZ_ELT_APP_DATA;
  34. ei->app_id = OZ_APPID_USB;
  35. ei->length = elt->length + sizeof(struct oz_elt);
  36. app_hdr->app_id = OZ_APPID_USB;
  37. spin_lock_bh(&eb->lock);
  38. if (isoc == 0) {
  39. app_hdr->elt_seq_num = usb_ctx->tx_seq_num++;
  40. if (usb_ctx->tx_seq_num == 0)
  41. usb_ctx->tx_seq_num = 1;
  42. }
  43. ret = oz_queue_elt_info(eb, isoc, strid, ei);
  44. if (ret)
  45. oz_elt_info_free(eb, ei);
  46. spin_unlock_bh(&eb->lock);
  47. return ret;
  48. }
  49. /*
  50. * Context: softirq
  51. */
  52. int oz_usb_get_desc_req(void *hpd, u8 req_id, u8 req_type, u8 desc_type,
  53. u8 index, __le16 windex, int offset, int len)
  54. {
  55. struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
  56. struct oz_pd *pd = usb_ctx->pd;
  57. struct oz_elt *elt;
  58. struct oz_get_desc_req *body;
  59. struct oz_elt_buf *eb = &pd->elt_buff;
  60. struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff);
  61. oz_dbg(ON, " req_type = 0x%x\n", req_type);
  62. oz_dbg(ON, " desc_type = 0x%x\n", desc_type);
  63. oz_dbg(ON, " index = 0x%x\n", index);
  64. oz_dbg(ON, " windex = 0x%x\n", windex);
  65. oz_dbg(ON, " offset = 0x%x\n", offset);
  66. oz_dbg(ON, " len = 0x%x\n", len);
  67. if (len > 200)
  68. len = 200;
  69. if (ei == NULL)
  70. return -1;
  71. elt = (struct oz_elt *)ei->data;
  72. elt->length = sizeof(struct oz_get_desc_req);
  73. body = (struct oz_get_desc_req *)(elt+1);
  74. body->type = OZ_GET_DESC_REQ;
  75. body->req_id = req_id;
  76. put_unaligned(cpu_to_le16(offset), &body->offset);
  77. put_unaligned(cpu_to_le16(len), &body->size);
  78. body->req_type = req_type;
  79. body->desc_type = desc_type;
  80. body->w_index = windex;
  81. body->index = index;
  82. return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0);
  83. }
  84. /*
  85. * Context: tasklet
  86. */
  87. static int oz_usb_set_config_req(void *hpd, u8 req_id, u8 index)
  88. {
  89. struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
  90. struct oz_pd *pd = usb_ctx->pd;
  91. struct oz_elt *elt;
  92. struct oz_elt_buf *eb = &pd->elt_buff;
  93. struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff);
  94. struct oz_set_config_req *body;
  95. if (ei == NULL)
  96. return -1;
  97. elt = (struct oz_elt *)ei->data;
  98. elt->length = sizeof(struct oz_set_config_req);
  99. body = (struct oz_set_config_req *)(elt+1);
  100. body->type = OZ_SET_CONFIG_REQ;
  101. body->req_id = req_id;
  102. body->index = index;
  103. return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0);
  104. }
  105. /*
  106. * Context: tasklet
  107. */
  108. static int oz_usb_set_interface_req(void *hpd, u8 req_id, u8 index, u8 alt)
  109. {
  110. struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
  111. struct oz_pd *pd = usb_ctx->pd;
  112. struct oz_elt *elt;
  113. struct oz_elt_buf *eb = &pd->elt_buff;
  114. struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff);
  115. struct oz_set_interface_req *body;
  116. if (ei == NULL)
  117. return -1;
  118. elt = (struct oz_elt *)ei->data;
  119. elt->length = sizeof(struct oz_set_interface_req);
  120. body = (struct oz_set_interface_req *)(elt+1);
  121. body->type = OZ_SET_INTERFACE_REQ;
  122. body->req_id = req_id;
  123. body->index = index;
  124. body->alternative = alt;
  125. return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0);
  126. }
  127. /*
  128. * Context: tasklet
  129. */
  130. static int oz_usb_set_clear_feature_req(void *hpd, u8 req_id, u8 type,
  131. u8 recipient, u8 index, __le16 feature)
  132. {
  133. struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
  134. struct oz_pd *pd = usb_ctx->pd;
  135. struct oz_elt *elt;
  136. struct oz_elt_buf *eb = &pd->elt_buff;
  137. struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff);
  138. struct oz_feature_req *body;
  139. if (ei == NULL)
  140. return -1;
  141. elt = (struct oz_elt *)ei->data;
  142. elt->length = sizeof(struct oz_feature_req);
  143. body = (struct oz_feature_req *)(elt+1);
  144. body->type = type;
  145. body->req_id = req_id;
  146. body->recipient = recipient;
  147. body->index = index;
  148. put_unaligned(feature, &body->feature);
  149. return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0);
  150. }
  151. /*
  152. * Context: tasklet
  153. */
  154. static int oz_usb_vendor_class_req(void *hpd, u8 req_id, u8 req_type,
  155. u8 request, __le16 value, __le16 index, const u8 *data, int data_len)
  156. {
  157. struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
  158. struct oz_pd *pd = usb_ctx->pd;
  159. struct oz_elt *elt;
  160. struct oz_elt_buf *eb = &pd->elt_buff;
  161. struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff);
  162. struct oz_vendor_class_req *body;
  163. if (ei == NULL)
  164. return -1;
  165. elt = (struct oz_elt *)ei->data;
  166. elt->length = sizeof(struct oz_vendor_class_req) - 1 + data_len;
  167. body = (struct oz_vendor_class_req *)(elt+1);
  168. body->type = OZ_VENDOR_CLASS_REQ;
  169. body->req_id = req_id;
  170. body->req_type = req_type;
  171. body->request = request;
  172. put_unaligned(value, &body->value);
  173. put_unaligned(index, &body->index);
  174. if (data_len)
  175. memcpy(body->data, data, data_len);
  176. return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0);
  177. }
  178. /*
  179. * Context: tasklet
  180. */
  181. int oz_usb_control_req(void *hpd, u8 req_id, struct usb_ctrlrequest *setup,
  182. const u8 *data, int data_len)
  183. {
  184. unsigned wvalue = le16_to_cpu(setup->wValue);
  185. unsigned windex = le16_to_cpu(setup->wIndex);
  186. unsigned wlength = le16_to_cpu(setup->wLength);
  187. int rc = 0;
  188. if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
  189. switch (setup->bRequest) {
  190. case USB_REQ_GET_DESCRIPTOR:
  191. rc = oz_usb_get_desc_req(hpd, req_id,
  192. setup->bRequestType, (u8)(wvalue>>8),
  193. (u8)wvalue, setup->wIndex, 0, wlength);
  194. break;
  195. case USB_REQ_SET_CONFIGURATION:
  196. rc = oz_usb_set_config_req(hpd, req_id, (u8)wvalue);
  197. break;
  198. case USB_REQ_SET_INTERFACE: {
  199. u8 if_num = (u8)windex;
  200. u8 alt = (u8)wvalue;
  201. rc = oz_usb_set_interface_req(hpd, req_id,
  202. if_num, alt);
  203. }
  204. break;
  205. case USB_REQ_SET_FEATURE:
  206. rc = oz_usb_set_clear_feature_req(hpd, req_id,
  207. OZ_SET_FEATURE_REQ,
  208. setup->bRequestType & 0xf, (u8)windex,
  209. setup->wValue);
  210. break;
  211. case USB_REQ_CLEAR_FEATURE:
  212. rc = oz_usb_set_clear_feature_req(hpd, req_id,
  213. OZ_CLEAR_FEATURE_REQ,
  214. setup->bRequestType & 0xf,
  215. (u8)windex, setup->wValue);
  216. break;
  217. }
  218. } else {
  219. rc = oz_usb_vendor_class_req(hpd, req_id, setup->bRequestType,
  220. setup->bRequest, setup->wValue, setup->wIndex,
  221. data, data_len);
  222. }
  223. return rc;
  224. }
  225. /*
  226. * Context: softirq
  227. */
  228. int oz_usb_send_isoc(void *hpd, u8 ep_num, struct urb *urb)
  229. {
  230. struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
  231. struct oz_pd *pd = usb_ctx->pd;
  232. struct oz_elt_buf *eb;
  233. int i;
  234. int hdr_size;
  235. u8 *data;
  236. struct usb_iso_packet_descriptor *desc;
  237. if (pd->mode & OZ_F_ISOC_NO_ELTS) {
  238. for (i = 0; i < urb->number_of_packets; i++) {
  239. u8 *data;
  240. desc = &urb->iso_frame_desc[i];
  241. data = ((u8 *)urb->transfer_buffer)+desc->offset;
  242. oz_send_isoc_unit(pd, ep_num, data, desc->length);
  243. }
  244. return 0;
  245. }
  246. hdr_size = sizeof(struct oz_isoc_fixed) - 1;
  247. eb = &pd->elt_buff;
  248. i = 0;
  249. while (i < urb->number_of_packets) {
  250. struct oz_elt_info *ei = oz_elt_info_alloc(eb);
  251. struct oz_elt *elt;
  252. struct oz_isoc_fixed *body;
  253. int unit_count;
  254. int unit_size;
  255. int rem;
  256. if (ei == NULL)
  257. return -1;
  258. rem = MAX_ISOC_FIXED_DATA;
  259. elt = (struct oz_elt *)ei->data;
  260. body = (struct oz_isoc_fixed *)(elt + 1);
  261. body->type = OZ_USB_ENDPOINT_DATA;
  262. body->endpoint = ep_num;
  263. body->format = OZ_DATA_F_ISOC_FIXED;
  264. unit_size = urb->iso_frame_desc[i].length;
  265. body->unit_size = (u8)unit_size;
  266. data = ((u8 *)(elt+1)) + hdr_size;
  267. unit_count = 0;
  268. while (i < urb->number_of_packets) {
  269. desc = &urb->iso_frame_desc[i];
  270. if ((unit_size == desc->length) &&
  271. (desc->length <= rem)) {
  272. memcpy(data, ((u8 *)urb->transfer_buffer) +
  273. desc->offset, unit_size);
  274. data += unit_size;
  275. rem -= unit_size;
  276. unit_count++;
  277. desc->status = 0;
  278. desc->actual_length = desc->length;
  279. i++;
  280. } else {
  281. break;
  282. }
  283. }
  284. elt->length = hdr_size + MAX_ISOC_FIXED_DATA - rem;
  285. /* Store the number of units in body->frame_number for the
  286. * moment. This field will be correctly determined before
  287. * the element is sent. */
  288. body->frame_number = (u8)unit_count;
  289. oz_usb_submit_elt(eb, ei, usb_ctx, ep_num,
  290. pd->mode & OZ_F_ISOC_ANYTIME);
  291. }
  292. return 0;
  293. }
  294. /*
  295. * Context: softirq-serialized
  296. */
  297. static void oz_usb_handle_ep_data(struct oz_usb_ctx *usb_ctx,
  298. struct oz_usb_hdr *usb_hdr, int len)
  299. {
  300. struct oz_data *data_hdr = (struct oz_data *)usb_hdr;
  301. switch (data_hdr->format) {
  302. case OZ_DATA_F_MULTIPLE_FIXED: {
  303. struct oz_multiple_fixed *body =
  304. (struct oz_multiple_fixed *)data_hdr;
  305. u8 *data = body->data;
  306. unsigned int n;
  307. if (!body->unit_size ||
  308. len < sizeof(struct oz_multiple_fixed) - 1)
  309. break;
  310. n = (len - (sizeof(struct oz_multiple_fixed) - 1))
  311. / body->unit_size;
  312. while (n--) {
  313. oz_hcd_data_ind(usb_ctx->hport, body->endpoint,
  314. data, body->unit_size);
  315. data += body->unit_size;
  316. }
  317. }
  318. break;
  319. case OZ_DATA_F_ISOC_FIXED: {
  320. struct oz_isoc_fixed *body =
  321. (struct oz_isoc_fixed *)data_hdr;
  322. int data_len = len-sizeof(struct oz_isoc_fixed)+1;
  323. int unit_size = body->unit_size;
  324. u8 *data = body->data;
  325. int count;
  326. int i;
  327. if (!unit_size)
  328. break;
  329. count = data_len/unit_size;
  330. for (i = 0; i < count; i++) {
  331. oz_hcd_data_ind(usb_ctx->hport,
  332. body->endpoint, data, unit_size);
  333. data += unit_size;
  334. }
  335. }
  336. break;
  337. }
  338. }
  339. /*
  340. * This is called when the PD has received a USB element. The type of element
  341. * is determined and is then passed to an appropriate handler function.
  342. * Context: softirq-serialized
  343. */
  344. void oz_usb_rx(struct oz_pd *pd, struct oz_elt *elt)
  345. {
  346. struct oz_usb_hdr *usb_hdr = (struct oz_usb_hdr *)(elt + 1);
  347. struct oz_usb_ctx *usb_ctx;
  348. spin_lock_bh(&pd->app_lock[OZ_APPID_USB]);
  349. usb_ctx = (struct oz_usb_ctx *)pd->app_ctx[OZ_APPID_USB];
  350. if (usb_ctx)
  351. oz_usb_get(usb_ctx);
  352. spin_unlock_bh(&pd->app_lock[OZ_APPID_USB]);
  353. if (usb_ctx == NULL)
  354. return; /* Context has gone so nothing to do. */
  355. if (usb_ctx->stopped)
  356. goto done;
  357. /* If sequence number is non-zero then check it is not a duplicate.
  358. * Zero sequence numbers are always accepted.
  359. */
  360. if (usb_hdr->elt_seq_num != 0) {
  361. if (((usb_ctx->rx_seq_num - usb_hdr->elt_seq_num) & 0x80) == 0)
  362. /* Reject duplicate element. */
  363. goto done;
  364. }
  365. usb_ctx->rx_seq_num = usb_hdr->elt_seq_num;
  366. switch (usb_hdr->type) {
  367. case OZ_GET_DESC_RSP: {
  368. struct oz_get_desc_rsp *body =
  369. (struct oz_get_desc_rsp *)usb_hdr;
  370. u16 offs, total_size;
  371. u8 data_len;
  372. if (elt->length < sizeof(struct oz_get_desc_rsp) - 1)
  373. break;
  374. data_len = elt->length -
  375. (sizeof(struct oz_get_desc_rsp) - 1);
  376. offs = le16_to_cpu(get_unaligned(&body->offset));
  377. total_size =
  378. le16_to_cpu(get_unaligned(&body->total_size));
  379. oz_dbg(ON, "USB_REQ_GET_DESCRIPTOR - cnf\n");
  380. oz_hcd_get_desc_cnf(usb_ctx->hport, body->req_id,
  381. body->rcode, body->data,
  382. data_len, offs, total_size);
  383. }
  384. break;
  385. case OZ_SET_CONFIG_RSP: {
  386. struct oz_set_config_rsp *body =
  387. (struct oz_set_config_rsp *)usb_hdr;
  388. oz_hcd_control_cnf(usb_ctx->hport, body->req_id,
  389. body->rcode, NULL, 0);
  390. }
  391. break;
  392. case OZ_SET_INTERFACE_RSP: {
  393. struct oz_set_interface_rsp *body =
  394. (struct oz_set_interface_rsp *)usb_hdr;
  395. oz_hcd_control_cnf(usb_ctx->hport,
  396. body->req_id, body->rcode, NULL, 0);
  397. }
  398. break;
  399. case OZ_VENDOR_CLASS_RSP: {
  400. struct oz_vendor_class_rsp *body =
  401. (struct oz_vendor_class_rsp *)usb_hdr;
  402. oz_hcd_control_cnf(usb_ctx->hport, body->req_id,
  403. body->rcode, body->data, elt->length-
  404. sizeof(struct oz_vendor_class_rsp)+1);
  405. }
  406. break;
  407. case OZ_USB_ENDPOINT_DATA:
  408. oz_usb_handle_ep_data(usb_ctx, usb_hdr, elt->length);
  409. break;
  410. }
  411. done:
  412. oz_usb_put(usb_ctx);
  413. }
  414. /*
  415. * Context: softirq, process
  416. */
  417. void oz_usb_farewell(struct oz_pd *pd, u8 ep_num, u8 *data, u8 len)
  418. {
  419. struct oz_usb_ctx *usb_ctx;
  420. spin_lock_bh(&pd->app_lock[OZ_APPID_USB]);
  421. usb_ctx = (struct oz_usb_ctx *)pd->app_ctx[OZ_APPID_USB];
  422. if (usb_ctx)
  423. oz_usb_get(usb_ctx);
  424. spin_unlock_bh(&pd->app_lock[OZ_APPID_USB]);
  425. if (usb_ctx == NULL)
  426. return; /* Context has gone so nothing to do. */
  427. if (!usb_ctx->stopped) {
  428. oz_dbg(ON, "Farewell indicated ep = 0x%x\n", ep_num);
  429. oz_hcd_data_ind(usb_ctx->hport, ep_num, data, len);
  430. }
  431. oz_usb_put(usb_ctx);
  432. }