usbpipe.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
  4. * All rights reserved.
  5. *
  6. * File: usbpipe.c
  7. *
  8. * Purpose: Handle USB control endpoint
  9. *
  10. * Author: Warren Hsu
  11. *
  12. * Date: Mar. 29, 2005
  13. *
  14. * Functions:
  15. * vnt_control_out - Write variable length bytes to MEM/BB/MAC/EEPROM
  16. * vnt_control_in - Read variable length bytes from MEM/BB/MAC/EEPROM
  17. * vnt_control_out_u8 - Write one byte to MEM/BB/MAC/EEPROM
  18. * vnt_control_in_u8 - Read one byte from MEM/BB/MAC/EEPROM
  19. *
  20. * Revision History:
  21. * 04-05-2004 Jerry Chen: Initial release
  22. * 11-24-2004 Warren Hsu: Add ControlvWriteByte,ControlvReadByte,
  23. * ControlvMaskByte
  24. *
  25. */
  26. #include "int.h"
  27. #include "rxtx.h"
  28. #include "dpc.h"
  29. #include "desc.h"
  30. #include "device.h"
  31. #include "usbpipe.h"
  32. #define USB_CTL_WAIT 500 /* ms */
  33. int vnt_control_out(struct vnt_private *priv, u8 request, u16 value,
  34. u16 index, u16 length, u8 *buffer)
  35. {
  36. int status = 0;
  37. u8 *usb_buffer;
  38. if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags))
  39. return STATUS_FAILURE;
  40. mutex_lock(&priv->usb_lock);
  41. usb_buffer = kmemdup(buffer, length, GFP_KERNEL);
  42. if (!usb_buffer) {
  43. mutex_unlock(&priv->usb_lock);
  44. return -ENOMEM;
  45. }
  46. status = usb_control_msg(priv->usb,
  47. usb_sndctrlpipe(priv->usb, 0),
  48. request, 0x40, value,
  49. index, usb_buffer, length, USB_CTL_WAIT);
  50. kfree(usb_buffer);
  51. mutex_unlock(&priv->usb_lock);
  52. if (status < (int)length)
  53. return STATUS_FAILURE;
  54. return STATUS_SUCCESS;
  55. }
  56. void vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 data)
  57. {
  58. vnt_control_out(priv, MESSAGE_TYPE_WRITE,
  59. reg_off, reg, sizeof(u8), &data);
  60. }
  61. int vnt_control_in(struct vnt_private *priv, u8 request, u16 value,
  62. u16 index, u16 length, u8 *buffer)
  63. {
  64. int status;
  65. u8 *usb_buffer;
  66. if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags))
  67. return STATUS_FAILURE;
  68. mutex_lock(&priv->usb_lock);
  69. usb_buffer = kmalloc(length, GFP_KERNEL);
  70. if (!usb_buffer) {
  71. mutex_unlock(&priv->usb_lock);
  72. return -ENOMEM;
  73. }
  74. status = usb_control_msg(priv->usb,
  75. usb_rcvctrlpipe(priv->usb, 0),
  76. request, 0xc0, value,
  77. index, usb_buffer, length, USB_CTL_WAIT);
  78. if (status == length)
  79. memcpy(buffer, usb_buffer, length);
  80. kfree(usb_buffer);
  81. mutex_unlock(&priv->usb_lock);
  82. if (status < (int)length)
  83. return STATUS_FAILURE;
  84. return STATUS_SUCCESS;
  85. }
  86. void vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data)
  87. {
  88. vnt_control_in(priv, MESSAGE_TYPE_READ,
  89. reg_off, reg, sizeof(u8), data);
  90. }
  91. static void vnt_start_interrupt_urb_complete(struct urb *urb)
  92. {
  93. struct vnt_private *priv = urb->context;
  94. int status = urb->status;
  95. switch (status) {
  96. case 0:
  97. case -ETIMEDOUT:
  98. break;
  99. case -ECONNRESET:
  100. case -ENOENT:
  101. case -ESHUTDOWN:
  102. priv->int_buf.in_use = false;
  103. return;
  104. default:
  105. break;
  106. }
  107. if (status) {
  108. priv->int_buf.in_use = false;
  109. dev_dbg(&priv->usb->dev, "%s status = %d\n", __func__, status);
  110. } else {
  111. vnt_int_process_data(priv);
  112. }
  113. status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
  114. if (status)
  115. dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status);
  116. else
  117. priv->int_buf.in_use = true;
  118. }
  119. int vnt_start_interrupt_urb(struct vnt_private *priv)
  120. {
  121. int status = STATUS_FAILURE;
  122. if (priv->int_buf.in_use)
  123. return STATUS_FAILURE;
  124. priv->int_buf.in_use = true;
  125. usb_fill_int_urb(priv->interrupt_urb,
  126. priv->usb,
  127. usb_rcvintpipe(priv->usb, 1),
  128. priv->int_buf.data_buf,
  129. MAX_INTERRUPT_SIZE,
  130. vnt_start_interrupt_urb_complete,
  131. priv,
  132. priv->int_interval);
  133. status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
  134. if (status) {
  135. dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status);
  136. priv->int_buf.in_use = false;
  137. }
  138. return status;
  139. }
  140. static void vnt_submit_rx_urb_complete(struct urb *urb)
  141. {
  142. struct vnt_rcb *rcb = urb->context;
  143. struct vnt_private *priv = rcb->priv;
  144. switch (urb->status) {
  145. case 0:
  146. break;
  147. case -ECONNRESET:
  148. case -ENOENT:
  149. case -ESHUTDOWN:
  150. return;
  151. case -ETIMEDOUT:
  152. default:
  153. dev_dbg(&priv->usb->dev, "BULK In failed %d\n", urb->status);
  154. break;
  155. }
  156. if (urb->actual_length) {
  157. if (vnt_rx_data(priv, rcb, urb->actual_length)) {
  158. rcb->skb = dev_alloc_skb(priv->rx_buf_sz);
  159. if (!rcb->skb) {
  160. rcb->in_use = false;
  161. return;
  162. }
  163. } else {
  164. skb_push(rcb->skb, skb_headroom(rcb->skb));
  165. skb_trim(rcb->skb, 0);
  166. }
  167. urb->transfer_buffer = skb_put(rcb->skb,
  168. skb_tailroom(rcb->skb));
  169. }
  170. if (usb_submit_urb(urb, GFP_ATOMIC)) {
  171. dev_dbg(&priv->usb->dev, "Failed to re submit rx skb\n");
  172. rcb->in_use = false;
  173. }
  174. }
  175. int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb)
  176. {
  177. int status = 0;
  178. struct urb *urb = rcb->urb;
  179. if (!rcb->skb) {
  180. dev_dbg(&priv->usb->dev, "rcb->skb is null\n");
  181. return status;
  182. }
  183. usb_fill_bulk_urb(urb,
  184. priv->usb,
  185. usb_rcvbulkpipe(priv->usb, 2),
  186. skb_put(rcb->skb, skb_tailroom(rcb->skb)),
  187. MAX_TOTAL_SIZE_WITH_ALL_HEADERS,
  188. vnt_submit_rx_urb_complete,
  189. rcb);
  190. status = usb_submit_urb(urb, GFP_ATOMIC);
  191. if (status) {
  192. dev_dbg(&priv->usb->dev, "Submit Rx URB failed %d\n", status);
  193. return STATUS_FAILURE;
  194. }
  195. rcb->in_use = true;
  196. return status;
  197. }
  198. static void vnt_tx_context_complete(struct urb *urb)
  199. {
  200. struct vnt_usb_send_context *context = urb->context;
  201. struct vnt_private *priv = context->priv;
  202. switch (urb->status) {
  203. case 0:
  204. dev_dbg(&priv->usb->dev, "Write %d bytes\n", context->buf_len);
  205. break;
  206. case -ECONNRESET:
  207. case -ENOENT:
  208. case -ESHUTDOWN:
  209. context->in_use = false;
  210. return;
  211. case -ETIMEDOUT:
  212. default:
  213. dev_dbg(&priv->usb->dev, "BULK Out failed %d\n", urb->status);
  214. break;
  215. }
  216. if (context->type == CONTEXT_DATA_PACKET)
  217. ieee80211_wake_queues(priv->hw);
  218. if (urb->status || context->type == CONTEXT_BEACON_PACKET) {
  219. if (context->skb)
  220. ieee80211_free_txskb(priv->hw, context->skb);
  221. context->in_use = false;
  222. }
  223. }
  224. int vnt_tx_context(struct vnt_private *priv,
  225. struct vnt_usb_send_context *context)
  226. {
  227. int status;
  228. struct urb *urb = context->urb;
  229. if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) {
  230. context->in_use = false;
  231. return STATUS_RESOURCES;
  232. }
  233. usb_fill_bulk_urb(urb,
  234. priv->usb,
  235. usb_sndbulkpipe(priv->usb, 3),
  236. context->data,
  237. context->buf_len,
  238. vnt_tx_context_complete,
  239. context);
  240. status = usb_submit_urb(urb, GFP_ATOMIC);
  241. if (status) {
  242. dev_dbg(&priv->usb->dev, "Submit Tx URB failed %d\n", status);
  243. context->in_use = false;
  244. return STATUS_FAILURE;
  245. }
  246. return STATUS_PENDING;
  247. }