Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ath6kl: add full USB support

Now, with HTC pipe, it's possible to fully support USB version of AR6004.

Based on code by Kevin Fang.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>

+782 -4
+1
drivers/net/wireless/ath/ath6kl/debug.h
··· 43 43 ATH6KL_DBG_WMI_DUMP = BIT(19), 44 44 ATH6KL_DBG_SUSPEND = BIT(20), 45 45 ATH6KL_DBG_USB = BIT(21), 46 + ATH6KL_DBG_USB_BULK = BIT(22), 46 47 ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ 47 48 }; 48 49
+781 -4
drivers/net/wireless/ath/ath6kl/usb.c
··· 21 21 #include "debug.h" 22 22 #include "core.h" 23 23 24 + /* constants */ 25 + #define TX_URB_COUNT 32 26 + #define RX_URB_COUNT 32 27 + #define ATH6KL_USB_RX_BUFFER_SIZE 1700 28 + 29 + /* tx/rx pipes for usb */ 30 + enum ATH6KL_USB_PIPE_ID { 31 + ATH6KL_USB_PIPE_TX_CTRL = 0, 32 + ATH6KL_USB_PIPE_TX_DATA_LP, 33 + ATH6KL_USB_PIPE_TX_DATA_MP, 34 + ATH6KL_USB_PIPE_TX_DATA_HP, 35 + ATH6KL_USB_PIPE_RX_CTRL, 36 + ATH6KL_USB_PIPE_RX_DATA, 37 + ATH6KL_USB_PIPE_RX_DATA2, 38 + ATH6KL_USB_PIPE_RX_INT, 39 + ATH6KL_USB_PIPE_MAX 40 + }; 41 + 42 + #define ATH6KL_USB_PIPE_INVALID ATH6KL_USB_PIPE_MAX 43 + 44 + struct ath6kl_usb_pipe { 45 + struct list_head urb_list_head; 46 + struct usb_anchor urb_submitted; 47 + u32 urb_alloc; 48 + u32 urb_cnt; 49 + u32 urb_cnt_thresh; 50 + unsigned int usb_pipe_handle; 51 + u32 flags; 52 + u8 ep_address; 53 + u8 logical_pipe_num; 54 + struct ath6kl_usb *ar_usb; 55 + u16 max_packet_size; 56 + struct work_struct io_complete_work; 57 + struct sk_buff_head io_comp_queue; 58 + struct usb_endpoint_descriptor *ep_desc; 59 + }; 60 + 61 + #define ATH6KL_USB_PIPE_FLAG_TX (1 << 0) 62 + 24 63 /* usb device object */ 25 64 struct ath6kl_usb { 65 + /* protects pipe->urb_list_head and pipe->urb_cnt */ 66 + spinlock_t cs_lock; 67 + 26 68 struct usb_device *udev; 27 69 struct usb_interface *interface; 70 + struct ath6kl_usb_pipe pipes[ATH6KL_USB_PIPE_MAX]; 28 71 u8 *diag_cmd_buffer; 29 72 u8 *diag_resp_buffer; 30 73 struct ath6kl *ar; 31 74 }; 75 + 76 + /* usb urb object */ 77 + struct ath6kl_urb_context { 78 + struct list_head link; 79 + struct ath6kl_usb_pipe *pipe; 80 + struct sk_buff *skb; 81 + struct ath6kl *ar; 82 + }; 83 + 84 + /* USB endpoint definitions */ 85 + #define ATH6KL_USB_EP_ADDR_APP_CTRL_IN 0x81 86 + #define ATH6KL_USB_EP_ADDR_APP_DATA_IN 0x82 87 + #define ATH6KL_USB_EP_ADDR_APP_DATA2_IN 0x83 88 + #define ATH6KL_USB_EP_ADDR_APP_INT_IN 0x84 89 + 90 + #define ATH6KL_USB_EP_ADDR_APP_CTRL_OUT 0x01 91 + #define ATH6KL_USB_EP_ADDR_APP_DATA_LP_OUT 0x02 92 + #define ATH6KL_USB_EP_ADDR_APP_DATA_MP_OUT 0x03 93 + #define ATH6KL_USB_EP_ADDR_APP_DATA_HP_OUT 0x04 32 94 33 95 /* diagnostic command defnitions */ 34 96 #define ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD 1 ··· 117 55 __le32 value; 118 56 } __packed; 119 57 58 + /* function declarations */ 59 + static void ath6kl_usb_recv_complete(struct urb *urb); 60 + 61 + #define ATH6KL_USB_IS_BULK_EP(attr) (((attr) & 3) == 0x02) 62 + #define ATH6KL_USB_IS_INT_EP(attr) (((attr) & 3) == 0x03) 63 + #define ATH6KL_USB_IS_ISOC_EP(attr) (((attr) & 3) == 0x01) 64 + #define ATH6KL_USB_IS_DIR_IN(addr) ((addr) & 0x80) 65 + 66 + /* pipe/urb operations */ 67 + static struct ath6kl_urb_context * 68 + ath6kl_usb_alloc_urb_from_pipe(struct ath6kl_usb_pipe *pipe) 69 + { 70 + struct ath6kl_urb_context *urb_context = NULL; 71 + unsigned long flags; 72 + 73 + spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags); 74 + if (!list_empty(&pipe->urb_list_head)) { 75 + urb_context = 76 + list_first_entry(&pipe->urb_list_head, 77 + struct ath6kl_urb_context, link); 78 + list_del(&urb_context->link); 79 + pipe->urb_cnt--; 80 + } 81 + spin_unlock_irqrestore(&pipe->ar_usb->cs_lock, flags); 82 + 83 + return urb_context; 84 + } 85 + 86 + static void ath6kl_usb_free_urb_to_pipe(struct ath6kl_usb_pipe *pipe, 87 + struct ath6kl_urb_context *urb_context) 88 + { 89 + unsigned long flags; 90 + 91 + spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags); 92 + pipe->urb_cnt++; 93 + 94 + list_add(&urb_context->link, &pipe->urb_list_head); 95 + spin_unlock_irqrestore(&pipe->ar_usb->cs_lock, flags); 96 + } 97 + 98 + static void ath6kl_usb_cleanup_recv_urb(struct ath6kl_urb_context *urb_context) 99 + { 100 + if (urb_context->skb != NULL) { 101 + dev_kfree_skb(urb_context->skb); 102 + urb_context->skb = NULL; 103 + } 104 + 105 + ath6kl_usb_free_urb_to_pipe(urb_context->pipe, urb_context); 106 + } 107 + 108 + static inline struct ath6kl_usb *ath6kl_usb_priv(struct ath6kl *ar) 109 + { 110 + return ar->hif_priv; 111 + } 112 + 113 + /* pipe resource allocation/cleanup */ 114 + static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe, 115 + int urb_cnt) 116 + { 117 + struct ath6kl_urb_context *urb_context; 118 + int status = 0, i; 119 + 120 + INIT_LIST_HEAD(&pipe->urb_list_head); 121 + init_usb_anchor(&pipe->urb_submitted); 122 + 123 + for (i = 0; i < urb_cnt; i++) { 124 + urb_context = kzalloc(sizeof(struct ath6kl_urb_context), 125 + GFP_KERNEL); 126 + if (urb_context == NULL) 127 + /* FIXME: set status to -ENOMEM */ 128 + break; 129 + 130 + urb_context->pipe = pipe; 131 + 132 + /* 133 + * we are only allocate the urb contexts here, the actual URB 134 + * is allocated from the kernel as needed to do a transaction 135 + */ 136 + pipe->urb_alloc++; 137 + ath6kl_usb_free_urb_to_pipe(pipe, urb_context); 138 + } 139 + 140 + ath6kl_dbg(ATH6KL_DBG_USB, 141 + "ath6kl usb: alloc resources lpipe:%d hpipe:0x%X urbs:%d\n", 142 + pipe->logical_pipe_num, pipe->usb_pipe_handle, 143 + pipe->urb_alloc); 144 + 145 + return status; 146 + } 147 + 148 + static void ath6kl_usb_free_pipe_resources(struct ath6kl_usb_pipe *pipe) 149 + { 150 + struct ath6kl_urb_context *urb_context; 151 + 152 + if (pipe->ar_usb == NULL) { 153 + /* nothing allocated for this pipe */ 154 + return; 155 + } 156 + 157 + ath6kl_dbg(ATH6KL_DBG_USB, 158 + "ath6kl usb: free resources lpipe:%d" 159 + "hpipe:0x%X urbs:%d avail:%d\n", 160 + pipe->logical_pipe_num, pipe->usb_pipe_handle, 161 + pipe->urb_alloc, pipe->urb_cnt); 162 + 163 + if (pipe->urb_alloc != pipe->urb_cnt) { 164 + ath6kl_dbg(ATH6KL_DBG_USB, 165 + "ath6kl usb: urb leak! lpipe:%d" 166 + "hpipe:0x%X urbs:%d avail:%d\n", 167 + pipe->logical_pipe_num, pipe->usb_pipe_handle, 168 + pipe->urb_alloc, pipe->urb_cnt); 169 + } 170 + 171 + while (true) { 172 + urb_context = ath6kl_usb_alloc_urb_from_pipe(pipe); 173 + if (urb_context == NULL) 174 + break; 175 + kfree(urb_context); 176 + } 177 + 178 + } 179 + 180 + static void ath6kl_usb_cleanup_pipe_resources(struct ath6kl_usb *ar_usb) 181 + { 182 + int i; 183 + 184 + for (i = 0; i < ATH6KL_USB_PIPE_MAX; i++) 185 + ath6kl_usb_free_pipe_resources(&ar_usb->pipes[i]); 186 + 187 + } 188 + 189 + static u8 ath6kl_usb_get_logical_pipe_num(struct ath6kl_usb *ar_usb, 190 + u8 ep_address, int *urb_count) 191 + { 192 + u8 pipe_num = ATH6KL_USB_PIPE_INVALID; 193 + 194 + switch (ep_address) { 195 + case ATH6KL_USB_EP_ADDR_APP_CTRL_IN: 196 + pipe_num = ATH6KL_USB_PIPE_RX_CTRL; 197 + *urb_count = RX_URB_COUNT; 198 + break; 199 + case ATH6KL_USB_EP_ADDR_APP_DATA_IN: 200 + pipe_num = ATH6KL_USB_PIPE_RX_DATA; 201 + *urb_count = RX_URB_COUNT; 202 + break; 203 + case ATH6KL_USB_EP_ADDR_APP_INT_IN: 204 + pipe_num = ATH6KL_USB_PIPE_RX_INT; 205 + *urb_count = RX_URB_COUNT; 206 + break; 207 + case ATH6KL_USB_EP_ADDR_APP_DATA2_IN: 208 + pipe_num = ATH6KL_USB_PIPE_RX_DATA2; 209 + *urb_count = RX_URB_COUNT; 210 + break; 211 + case ATH6KL_USB_EP_ADDR_APP_CTRL_OUT: 212 + pipe_num = ATH6KL_USB_PIPE_TX_CTRL; 213 + *urb_count = TX_URB_COUNT; 214 + break; 215 + case ATH6KL_USB_EP_ADDR_APP_DATA_LP_OUT: 216 + pipe_num = ATH6KL_USB_PIPE_TX_DATA_LP; 217 + *urb_count = TX_URB_COUNT; 218 + break; 219 + case ATH6KL_USB_EP_ADDR_APP_DATA_MP_OUT: 220 + pipe_num = ATH6KL_USB_PIPE_TX_DATA_MP; 221 + *urb_count = TX_URB_COUNT; 222 + break; 223 + case ATH6KL_USB_EP_ADDR_APP_DATA_HP_OUT: 224 + pipe_num = ATH6KL_USB_PIPE_TX_DATA_HP; 225 + *urb_count = TX_URB_COUNT; 226 + break; 227 + default: 228 + /* note: there may be endpoints not currently used */ 229 + break; 230 + } 231 + 232 + return pipe_num; 233 + } 234 + 235 + static int ath6kl_usb_setup_pipe_resources(struct ath6kl_usb *ar_usb) 236 + { 237 + struct usb_interface *interface = ar_usb->interface; 238 + struct usb_host_interface *iface_desc = interface->cur_altsetting; 239 + struct usb_endpoint_descriptor *endpoint; 240 + struct ath6kl_usb_pipe *pipe; 241 + int i, urbcount, status = 0; 242 + u8 pipe_num; 243 + 244 + ath6kl_dbg(ATH6KL_DBG_USB, "setting up USB Pipes using interface\n"); 245 + 246 + /* walk decriptors and setup pipes */ 247 + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 248 + endpoint = &iface_desc->endpoint[i].desc; 249 + 250 + if (ATH6KL_USB_IS_BULK_EP(endpoint->bmAttributes)) { 251 + ath6kl_dbg(ATH6KL_DBG_USB, 252 + "%s Bulk Ep:0x%2.2X maxpktsz:%d\n", 253 + ATH6KL_USB_IS_DIR_IN 254 + (endpoint->bEndpointAddress) ? 255 + "RX" : "TX", endpoint->bEndpointAddress, 256 + le16_to_cpu(endpoint->wMaxPacketSize)); 257 + } else if (ATH6KL_USB_IS_INT_EP(endpoint->bmAttributes)) { 258 + ath6kl_dbg(ATH6KL_DBG_USB, 259 + "%s Int Ep:0x%2.2X maxpktsz:%d interval:%d\n", 260 + ATH6KL_USB_IS_DIR_IN 261 + (endpoint->bEndpointAddress) ? 262 + "RX" : "TX", endpoint->bEndpointAddress, 263 + le16_to_cpu(endpoint->wMaxPacketSize), 264 + endpoint->bInterval); 265 + } else if (ATH6KL_USB_IS_ISOC_EP(endpoint->bmAttributes)) { 266 + /* TODO for ISO */ 267 + ath6kl_dbg(ATH6KL_DBG_USB, 268 + "%s ISOC Ep:0x%2.2X maxpktsz:%d interval:%d\n", 269 + ATH6KL_USB_IS_DIR_IN 270 + (endpoint->bEndpointAddress) ? 271 + "RX" : "TX", endpoint->bEndpointAddress, 272 + le16_to_cpu(endpoint->wMaxPacketSize), 273 + endpoint->bInterval); 274 + } 275 + urbcount = 0; 276 + 277 + pipe_num = 278 + ath6kl_usb_get_logical_pipe_num(ar_usb, 279 + endpoint->bEndpointAddress, 280 + &urbcount); 281 + if (pipe_num == ATH6KL_USB_PIPE_INVALID) 282 + continue; 283 + 284 + pipe = &ar_usb->pipes[pipe_num]; 285 + if (pipe->ar_usb != NULL) { 286 + /* hmmm..pipe was already setup */ 287 + continue; 288 + } 289 + 290 + pipe->ar_usb = ar_usb; 291 + pipe->logical_pipe_num = pipe_num; 292 + pipe->ep_address = endpoint->bEndpointAddress; 293 + pipe->max_packet_size = le16_to_cpu(endpoint->wMaxPacketSize); 294 + 295 + if (ATH6KL_USB_IS_BULK_EP(endpoint->bmAttributes)) { 296 + if (ATH6KL_USB_IS_DIR_IN(pipe->ep_address)) { 297 + pipe->usb_pipe_handle = 298 + usb_rcvbulkpipe(ar_usb->udev, 299 + pipe->ep_address); 300 + } else { 301 + pipe->usb_pipe_handle = 302 + usb_sndbulkpipe(ar_usb->udev, 303 + pipe->ep_address); 304 + } 305 + } else if (ATH6KL_USB_IS_INT_EP(endpoint->bmAttributes)) { 306 + if (ATH6KL_USB_IS_DIR_IN(pipe->ep_address)) { 307 + pipe->usb_pipe_handle = 308 + usb_rcvintpipe(ar_usb->udev, 309 + pipe->ep_address); 310 + } else { 311 + pipe->usb_pipe_handle = 312 + usb_sndintpipe(ar_usb->udev, 313 + pipe->ep_address); 314 + } 315 + } else if (ATH6KL_USB_IS_ISOC_EP(endpoint->bmAttributes)) { 316 + /* TODO for ISO */ 317 + if (ATH6KL_USB_IS_DIR_IN(pipe->ep_address)) { 318 + pipe->usb_pipe_handle = 319 + usb_rcvisocpipe(ar_usb->udev, 320 + pipe->ep_address); 321 + } else { 322 + pipe->usb_pipe_handle = 323 + usb_sndisocpipe(ar_usb->udev, 324 + pipe->ep_address); 325 + } 326 + } 327 + 328 + pipe->ep_desc = endpoint; 329 + 330 + if (!ATH6KL_USB_IS_DIR_IN(pipe->ep_address)) 331 + pipe->flags |= ATH6KL_USB_PIPE_FLAG_TX; 332 + 333 + status = ath6kl_usb_alloc_pipe_resources(pipe, urbcount); 334 + if (status != 0) 335 + break; 336 + } 337 + 338 + return status; 339 + } 340 + 341 + /* pipe operations */ 342 + static void ath6kl_usb_post_recv_transfers(struct ath6kl_usb_pipe *recv_pipe, 343 + int buffer_length) 344 + { 345 + struct ath6kl_urb_context *urb_context; 346 + struct urb *urb; 347 + int usb_status; 348 + 349 + while (true) { 350 + urb_context = ath6kl_usb_alloc_urb_from_pipe(recv_pipe); 351 + if (urb_context == NULL) 352 + break; 353 + 354 + urb_context->skb = dev_alloc_skb(buffer_length); 355 + if (urb_context->skb == NULL) 356 + goto err_cleanup_urb; 357 + 358 + urb = usb_alloc_urb(0, GFP_ATOMIC); 359 + if (urb == NULL) 360 + goto err_cleanup_urb; 361 + 362 + usb_fill_bulk_urb(urb, 363 + recv_pipe->ar_usb->udev, 364 + recv_pipe->usb_pipe_handle, 365 + urb_context->skb->data, 366 + buffer_length, 367 + ath6kl_usb_recv_complete, urb_context); 368 + 369 + ath6kl_dbg(ATH6KL_DBG_USB_BULK, 370 + "ath6kl usb: bulk recv submit:%d, 0x%X (ep:0x%2.2X), %d bytes buf:0x%p\n", 371 + recv_pipe->logical_pipe_num, 372 + recv_pipe->usb_pipe_handle, recv_pipe->ep_address, 373 + buffer_length, urb_context->skb); 374 + 375 + usb_anchor_urb(urb, &recv_pipe->urb_submitted); 376 + usb_status = usb_submit_urb(urb, GFP_ATOMIC); 377 + 378 + if (usb_status) { 379 + ath6kl_dbg(ATH6KL_DBG_USB_BULK, 380 + "ath6kl usb : usb bulk recv failed %d\n", 381 + usb_status); 382 + usb_unanchor_urb(urb); 383 + usb_free_urb(urb); 384 + goto err_cleanup_urb; 385 + } 386 + usb_free_urb(urb); 387 + } 388 + return; 389 + 390 + err_cleanup_urb: 391 + ath6kl_usb_cleanup_recv_urb(urb_context); 392 + return; 393 + } 394 + 395 + static void ath6kl_usb_flush_all(struct ath6kl_usb *ar_usb) 396 + { 397 + int i; 398 + 399 + for (i = 0; i < ATH6KL_USB_PIPE_MAX; i++) { 400 + if (ar_usb->pipes[i].ar_usb != NULL) 401 + usb_kill_anchored_urbs(&ar_usb->pipes[i].urb_submitted); 402 + } 403 + 404 + /* 405 + * Flushing any pending I/O may schedule work this call will block 406 + * until all scheduled work runs to completion. 407 + */ 408 + flush_scheduled_work(); 409 + } 410 + 411 + static void ath6kl_usb_start_recv_pipes(struct ath6kl_usb *ar_usb) 412 + { 413 + /* 414 + * note: control pipe is no longer used 415 + * ar_usb->pipes[ATH6KL_USB_PIPE_RX_CTRL].urb_cnt_thresh = 416 + * ar_usb->pipes[ATH6KL_USB_PIPE_RX_CTRL].urb_alloc/2; 417 + * ath6kl_usb_post_recv_transfers(&ar_usb-> 418 + * pipes[ATH6KL_USB_PIPE_RX_CTRL], 419 + * ATH6KL_USB_RX_BUFFER_SIZE); 420 + */ 421 + 422 + ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh = 423 + ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_alloc / 2; 424 + ath6kl_usb_post_recv_transfers(&ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA], 425 + ATH6KL_USB_RX_BUFFER_SIZE); 426 + } 427 + 428 + /* hif usb rx/tx completion functions */ 429 + static void ath6kl_usb_recv_complete(struct urb *urb) 430 + { 431 + struct ath6kl_urb_context *urb_context = urb->context; 432 + struct ath6kl_usb_pipe *pipe = urb_context->pipe; 433 + struct sk_buff *skb = NULL; 434 + int status = 0; 435 + 436 + ath6kl_dbg(ATH6KL_DBG_USB_BULK, 437 + "%s: recv pipe: %d, stat:%d, len:%d urb:0x%p\n", __func__, 438 + pipe->logical_pipe_num, urb->status, urb->actual_length, 439 + urb); 440 + 441 + if (urb->status != 0) { 442 + status = -EIO; 443 + switch (urb->status) { 444 + case -ECONNRESET: 445 + case -ENOENT: 446 + case -ESHUTDOWN: 447 + /* 448 + * no need to spew these errors when device 449 + * removed or urb killed due to driver shutdown 450 + */ 451 + status = -ECANCELED; 452 + break; 453 + default: 454 + ath6kl_dbg(ATH6KL_DBG_USB_BULK, 455 + "%s recv pipe: %d (ep:0x%2.2X), failed:%d\n", 456 + __func__, pipe->logical_pipe_num, 457 + pipe->ep_address, urb->status); 458 + break; 459 + } 460 + goto cleanup_recv_urb; 461 + } 462 + 463 + if (urb->actual_length == 0) 464 + goto cleanup_recv_urb; 465 + 466 + skb = urb_context->skb; 467 + 468 + /* we are going to pass it up */ 469 + urb_context->skb = NULL; 470 + skb_put(skb, urb->actual_length); 471 + 472 + /* note: queue implements a lock */ 473 + skb_queue_tail(&pipe->io_comp_queue, skb); 474 + schedule_work(&pipe->io_complete_work); 475 + 476 + cleanup_recv_urb: 477 + ath6kl_usb_cleanup_recv_urb(urb_context); 478 + 479 + if (status == 0 && 480 + pipe->urb_cnt >= pipe->urb_cnt_thresh) { 481 + /* our free urbs are piling up, post more transfers */ 482 + ath6kl_usb_post_recv_transfers(pipe, ATH6KL_USB_RX_BUFFER_SIZE); 483 + } 484 + } 485 + 486 + static void ath6kl_usb_usb_transmit_complete(struct urb *urb) 487 + { 488 + struct ath6kl_urb_context *urb_context = urb->context; 489 + struct ath6kl_usb_pipe *pipe = urb_context->pipe; 490 + struct sk_buff *skb; 491 + 492 + ath6kl_dbg(ATH6KL_DBG_USB_BULK, 493 + "%s: pipe: %d, stat:%d, len:%d\n", 494 + __func__, pipe->logical_pipe_num, urb->status, 495 + urb->actual_length); 496 + 497 + if (urb->status != 0) { 498 + ath6kl_dbg(ATH6KL_DBG_USB_BULK, 499 + "%s: pipe: %d, failed:%d\n", 500 + __func__, pipe->logical_pipe_num, urb->status); 501 + } 502 + 503 + skb = urb_context->skb; 504 + urb_context->skb = NULL; 505 + ath6kl_usb_free_urb_to_pipe(urb_context->pipe, urb_context); 506 + 507 + /* note: queue implements a lock */ 508 + skb_queue_tail(&pipe->io_comp_queue, skb); 509 + schedule_work(&pipe->io_complete_work); 510 + } 511 + 512 + static void ath6kl_usb_io_comp_work(struct work_struct *work) 513 + { 514 + struct ath6kl_usb_pipe *pipe = container_of(work, 515 + struct ath6kl_usb_pipe, 516 + io_complete_work); 517 + struct ath6kl_usb *ar_usb; 518 + struct sk_buff *skb; 519 + 520 + ar_usb = pipe->ar_usb; 521 + 522 + while ((skb = skb_dequeue(&pipe->io_comp_queue))) { 523 + if (pipe->flags & ATH6KL_USB_PIPE_FLAG_TX) { 524 + ath6kl_dbg(ATH6KL_DBG_USB_BULK, 525 + "ath6kl usb xmit callback buf:0x%p\n", skb); 526 + ath6kl_core_tx_complete(ar_usb->ar, skb); 527 + } else { 528 + ath6kl_dbg(ATH6KL_DBG_USB_BULK, 529 + "ath6kl usb recv callback buf:0x%p\n", skb); 530 + ath6kl_core_rx_complete(ar_usb->ar, skb, 531 + pipe->logical_pipe_num); 532 + } 533 + } 534 + } 535 + 120 536 #define ATH6KL_USB_MAX_DIAG_CMD (sizeof(struct ath6kl_usb_ctrl_diag_cmd_write)) 121 537 #define ATH6KL_USB_MAX_DIAG_RESP (sizeof(struct ath6kl_usb_ctrl_diag_resp_read)) 122 538 123 539 static void ath6kl_usb_destroy(struct ath6kl_usb *ar_usb) 124 540 { 541 + ath6kl_usb_flush_all(ar_usb); 542 + 543 + ath6kl_usb_cleanup_pipe_resources(ar_usb); 544 + 125 545 usb_set_intfdata(ar_usb->interface, NULL); 126 546 127 547 kfree(ar_usb->diag_cmd_buffer); ··· 614 70 615 71 static struct ath6kl_usb *ath6kl_usb_create(struct usb_interface *interface) 616 72 { 617 - struct ath6kl_usb *ar_usb = NULL; 618 73 struct usb_device *dev = interface_to_usbdev(interface); 74 + struct ath6kl_usb *ar_usb; 75 + struct ath6kl_usb_pipe *pipe; 619 76 int status = 0; 77 + int i; 620 78 621 79 ar_usb = kzalloc(sizeof(struct ath6kl_usb), GFP_KERNEL); 622 80 if (ar_usb == NULL) 623 81 goto fail_ath6kl_usb_create; 624 82 625 - memset(ar_usb, 0, sizeof(struct ath6kl_usb)); 626 83 usb_set_intfdata(interface, ar_usb); 84 + spin_lock_init(&(ar_usb->cs_lock)); 627 85 ar_usb->udev = dev; 628 86 ar_usb->interface = interface; 87 + 88 + for (i = 0; i < ATH6KL_USB_PIPE_MAX; i++) { 89 + pipe = &ar_usb->pipes[i]; 90 + INIT_WORK(&pipe->io_complete_work, 91 + ath6kl_usb_io_comp_work); 92 + skb_queue_head_init(&pipe->io_comp_queue); 93 + } 629 94 630 95 ar_usb->diag_cmd_buffer = kzalloc(ATH6KL_USB_MAX_DIAG_CMD, GFP_KERNEL); 631 96 if (ar_usb->diag_cmd_buffer == NULL) { ··· 648 95 status = -ENOMEM; 649 96 goto fail_ath6kl_usb_create; 650 97 } 98 + 99 + status = ath6kl_usb_setup_pipe_resources(ar_usb); 651 100 652 101 fail_ath6kl_usb_create: 653 102 if (status != 0) { ··· 669 114 670 115 ath6kl_stop_txrx(ar_usb->ar); 671 116 117 + /* Delay to wait for the target to reboot */ 118 + mdelay(20); 672 119 ath6kl_core_cleanup(ar_usb->ar); 673 - 674 120 ath6kl_usb_destroy(ar_usb); 121 + } 122 + 123 + /* exported hif usb APIs for htc pipe */ 124 + static void hif_start(struct ath6kl *ar) 125 + { 126 + struct ath6kl_usb *device = ath6kl_usb_priv(ar); 127 + int i; 128 + 129 + ath6kl_usb_start_recv_pipes(device); 130 + 131 + /* set the TX resource avail threshold for each TX pipe */ 132 + for (i = ATH6KL_USB_PIPE_TX_CTRL; 133 + i <= ATH6KL_USB_PIPE_TX_DATA_HP; i++) { 134 + device->pipes[i].urb_cnt_thresh = 135 + device->pipes[i].urb_alloc / 2; 136 + } 137 + } 138 + 139 + static int ath6kl_usb_send(struct ath6kl *ar, u8 PipeID, 140 + struct sk_buff *hdr_skb, struct sk_buff *skb) 141 + { 142 + struct ath6kl_usb *device = ath6kl_usb_priv(ar); 143 + struct ath6kl_usb_pipe *pipe = &device->pipes[PipeID]; 144 + struct ath6kl_urb_context *urb_context; 145 + int usb_status, status = 0; 146 + struct urb *urb; 147 + u8 *data; 148 + u32 len; 149 + 150 + ath6kl_dbg(ATH6KL_DBG_USB_BULK, "+%s pipe : %d, buf:0x%p\n", 151 + __func__, PipeID, skb); 152 + 153 + urb_context = ath6kl_usb_alloc_urb_from_pipe(pipe); 154 + 155 + if (urb_context == NULL) { 156 + /* 157 + * TODO: it is possible to run out of urbs if 158 + * 2 endpoints map to the same pipe ID 159 + */ 160 + ath6kl_dbg(ATH6KL_DBG_USB_BULK, 161 + "%s pipe:%d no urbs left. URB Cnt : %d\n", 162 + __func__, PipeID, pipe->urb_cnt); 163 + status = -ENOMEM; 164 + goto fail_hif_send; 165 + } 166 + 167 + urb_context->skb = skb; 168 + 169 + data = skb->data; 170 + len = skb->len; 171 + 172 + urb = usb_alloc_urb(0, GFP_ATOMIC); 173 + if (urb == NULL) { 174 + status = -ENOMEM; 175 + ath6kl_usb_free_urb_to_pipe(urb_context->pipe, 176 + urb_context); 177 + goto fail_hif_send; 178 + } 179 + 180 + usb_fill_bulk_urb(urb, 181 + device->udev, 182 + pipe->usb_pipe_handle, 183 + data, 184 + len, 185 + ath6kl_usb_usb_transmit_complete, urb_context); 186 + 187 + if ((len % pipe->max_packet_size) == 0) { 188 + /* hit a max packet boundary on this pipe */ 189 + urb->transfer_flags |= URB_ZERO_PACKET; 190 + } 191 + 192 + ath6kl_dbg(ATH6KL_DBG_USB_BULK, 193 + "athusb bulk send submit:%d, 0x%X (ep:0x%2.2X), %d bytes\n", 194 + pipe->logical_pipe_num, pipe->usb_pipe_handle, 195 + pipe->ep_address, len); 196 + 197 + usb_anchor_urb(urb, &pipe->urb_submitted); 198 + usb_status = usb_submit_urb(urb, GFP_ATOMIC); 199 + 200 + if (usb_status) { 201 + ath6kl_dbg(ATH6KL_DBG_USB_BULK, 202 + "ath6kl usb : usb bulk transmit failed %d\n", 203 + usb_status); 204 + usb_unanchor_urb(urb); 205 + ath6kl_usb_free_urb_to_pipe(urb_context->pipe, 206 + urb_context); 207 + status = -EINVAL; 208 + } 209 + usb_free_urb(urb); 210 + 211 + fail_hif_send: 212 + return status; 213 + } 214 + 215 + static void hif_stop(struct ath6kl *ar) 216 + { 217 + struct ath6kl_usb *device = ath6kl_usb_priv(ar); 218 + 219 + ath6kl_usb_flush_all(device); 220 + } 221 + 222 + static void ath6kl_usb_get_default_pipe(struct ath6kl *ar, 223 + u8 *ul_pipe, u8 *dl_pipe) 224 + { 225 + *ul_pipe = ATH6KL_USB_PIPE_TX_CTRL; 226 + *dl_pipe = ATH6KL_USB_PIPE_RX_CTRL; 227 + } 228 + 229 + static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id, 230 + u8 *ul_pipe, u8 *dl_pipe) 231 + { 232 + int status = 0; 233 + 234 + switch (svc_id) { 235 + case HTC_CTRL_RSVD_SVC: 236 + case WMI_CONTROL_SVC: 237 + *ul_pipe = ATH6KL_USB_PIPE_TX_CTRL; 238 + /* due to large control packets, shift to data pipe */ 239 + *dl_pipe = ATH6KL_USB_PIPE_RX_DATA; 240 + break; 241 + case WMI_DATA_BE_SVC: 242 + case WMI_DATA_BK_SVC: 243 + *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP; 244 + /* 245 + * Disable rxdata2 directly, it will be enabled 246 + * if FW enable rxdata2 247 + */ 248 + *dl_pipe = ATH6KL_USB_PIPE_RX_DATA; 249 + break; 250 + case WMI_DATA_VI_SVC: 251 + *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP; 252 + /* 253 + * Disable rxdata2 directly, it will be enabled 254 + * if FW enable rxdata2 255 + */ 256 + *dl_pipe = ATH6KL_USB_PIPE_RX_DATA; 257 + break; 258 + case WMI_DATA_VO_SVC: 259 + *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_HP; 260 + /* 261 + * Disable rxdata2 directly, it will be enabled 262 + * if FW enable rxdata2 263 + */ 264 + *dl_pipe = ATH6KL_USB_PIPE_RX_DATA; 265 + break; 266 + default: 267 + status = -EPERM; 268 + break; 269 + } 270 + 271 + return status; 272 + } 273 + 274 + static u16 ath6kl_usb_get_free_queue_number(struct ath6kl *ar, u8 pipe_id) 275 + { 276 + struct ath6kl_usb *device = ath6kl_usb_priv(ar); 277 + 278 + return device->pipes[pipe_id].urb_cnt; 279 + } 280 + 281 + static void hif_detach_htc(struct ath6kl *ar) 282 + { 283 + struct ath6kl_usb *device = ath6kl_usb_priv(ar); 284 + 285 + ath6kl_usb_flush_all(device); 675 286 } 676 287 677 288 static int ath6kl_usb_submit_ctrl_out(struct ath6kl_usb *ar_usb, ··· 1022 301 1023 302 static int ath6kl_usb_power_on(struct ath6kl *ar) 1024 303 { 304 + hif_start(ar); 1025 305 return 0; 1026 306 } 1027 307 1028 308 static int ath6kl_usb_power_off(struct ath6kl *ar) 1029 309 { 310 + hif_detach_htc(ar); 1030 311 return 0; 312 + } 313 + 314 + static void ath6kl_usb_stop(struct ath6kl *ar) 315 + { 316 + hif_stop(ar); 1031 317 } 1032 318 1033 319 static const struct ath6kl_hif_ops ath6kl_usb_ops = { ··· 1044 316 .bmi_write = ath6kl_usb_bmi_write, 1045 317 .power_on = ath6kl_usb_power_on, 1046 318 .power_off = ath6kl_usb_power_off, 319 + .stop = ath6kl_usb_stop, 320 + .pipe_send = ath6kl_usb_send, 321 + .pipe_get_default = ath6kl_usb_get_default_pipe, 322 + .pipe_map_service = ath6kl_usb_map_service_pipe, 323 + .pipe_get_free_queue_number = ath6kl_usb_get_free_queue_number, 1047 324 }; 1048 325 1049 326 /* ath6kl usb driver registered functions */ ··· 1101 368 1102 369 ar_usb->ar = ar; 1103 370 1104 - ret = ath6kl_core_init(ar, ATH6KL_HTC_TYPE_MBOX); 371 + ret = ath6kl_core_init(ar, ATH6KL_HTC_TYPE_PIPE); 1105 372 if (ret) { 1106 373 ath6kl_err("Failed to init ath6kl core: %d\n", ret); 1107 374 goto err_core_free; ··· 1125 392 ath6kl_usb_device_detached(interface); 1126 393 } 1127 394 395 + #ifdef CONFIG_PM 396 + 397 + static int ath6kl_usb_suspend(struct usb_interface *interface, 398 + pm_message_t message) 399 + { 400 + struct ath6kl_usb *device; 401 + device = usb_get_intfdata(interface); 402 + 403 + ath6kl_usb_flush_all(device); 404 + return 0; 405 + } 406 + 407 + static int ath6kl_usb_resume(struct usb_interface *interface) 408 + { 409 + struct ath6kl_usb *device; 410 + device = usb_get_intfdata(interface); 411 + 412 + ath6kl_usb_post_recv_transfers(&device->pipes[ATH6KL_USB_PIPE_RX_DATA], 413 + ATH6KL_USB_RX_BUFFER_SIZE); 414 + ath6kl_usb_post_recv_transfers(&device->pipes[ATH6KL_USB_PIPE_RX_DATA2], 415 + ATH6KL_USB_RX_BUFFER_SIZE); 416 + 417 + return 0; 418 + } 419 + 420 + static int ath6kl_usb_reset_resume(struct usb_interface *intf) 421 + { 422 + if (usb_get_intfdata(intf)) 423 + ath6kl_usb_remove(intf); 424 + return 0; 425 + } 426 + 427 + #else 428 + 429 + #define ath6kl_usb_suspend NULL 430 + #define ath6kl_usb_resume NULL 431 + #define ath6kl_usb_reset_resume NULL 432 + 433 + #endif 434 + 1128 435 /* table of devices that work with this driver */ 1129 436 static struct usb_device_id ath6kl_usb_ids[] = { 1130 437 {USB_DEVICE(0x0cf3, 0x9374)}, ··· 1176 403 static struct usb_driver ath6kl_usb_driver = { 1177 404 .name = "ath6kl_usb", 1178 405 .probe = ath6kl_usb_probe, 406 + .suspend = ath6kl_usb_suspend, 407 + .resume = ath6kl_usb_resume, 408 + .reset_resume = ath6kl_usb_reset_resume, 1179 409 .disconnect = ath6kl_usb_remove, 1180 410 .id_table = ath6kl_usb_ids, 411 + .supports_autosuspend = true, 1181 412 }; 1182 413 1183 414 static int ath6kl_usb_init(void)