1/****************************************************************************** 2 * usb_ops_linux.c 3 * 4 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. 5 * Linux device driver for RTL8192SU 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of version 2 of the GNU General Public License as 9 * published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 * more details. 15 * 16 * You should have received a copy of the GNU General Public License along with 17 * this program; if not, write to the Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 19 * 20 * Modifications for inclusion into the Linux staging tree are 21 * Copyright(c) 2010 Larry Finger. All rights reserved. 22 * 23 * Contact information: 24 * WLAN FAE <wlanfae@realtek.com> 25 * Larry Finger <Larry.Finger@lwfinger.net> 26 * 27 ******************************************************************************/ 28 29#define _HCI_OPS_OS_C_ 30 31#include <linux/usb.h> 32 33#include "osdep_service.h" 34#include "drv_types.h" 35#include "osdep_intf.h" 36#include "usb_ops.h" 37 38#define RTL871X_VENQT_READ 0xc0 39#define RTL871X_VENQT_WRITE 0x40 40 41struct zero_bulkout_context { 42 void *pbuf; 43 void *purb; 44 void *pirp; 45 void *padapter; 46}; 47 48uint r8712_usb_init_intf_priv(struct intf_priv *pintfpriv) 49{ 50 pintfpriv->piorw_urb = usb_alloc_urb(0, GFP_ATOMIC); 51 if (!pintfpriv->piorw_urb) 52 return _FAIL; 53 sema_init(&(pintfpriv->io_retevt), 0); 54 return _SUCCESS; 55} 56 57void r8712_usb_unload_intf_priv(struct intf_priv *pintfpriv) 58{ 59 if (pintfpriv->piorw_urb) { 60 usb_kill_urb(pintfpriv->piorw_urb); 61 usb_free_urb(pintfpriv->piorw_urb); 62 } 63} 64 65static unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr) 66{ 67 unsigned int pipe = 0; 68 struct usb_device *pusbd = pdvobj->pusbdev; 69 70 if (pdvobj->nr_endpoint == 11) { 71 switch (addr) { 72 case RTL8712_DMA_BKQ: 73 pipe = usb_sndbulkpipe(pusbd, 0x07); 74 break; 75 case RTL8712_DMA_BEQ: 76 pipe = usb_sndbulkpipe(pusbd, 0x06); 77 break; 78 case RTL8712_DMA_VIQ: 79 pipe = usb_sndbulkpipe(pusbd, 0x05); 80 break; 81 case RTL8712_DMA_VOQ: 82 pipe = usb_sndbulkpipe(pusbd, 0x04); 83 break; 84 case RTL8712_DMA_BCNQ: 85 pipe = usb_sndbulkpipe(pusbd, 0x0a); 86 break; 87 case RTL8712_DMA_BMCQ: /* HI Queue */ 88 pipe = usb_sndbulkpipe(pusbd, 0x0b); 89 break; 90 case RTL8712_DMA_MGTQ: 91 pipe = usb_sndbulkpipe(pusbd, 0x0c); 92 break; 93 case RTL8712_DMA_RX0FF: 94 pipe = usb_rcvbulkpipe(pusbd, 0x03); /* in */ 95 break; 96 case RTL8712_DMA_C2HCMD: 97 pipe = usb_rcvbulkpipe(pusbd, 0x09); /* in */ 98 break; 99 case RTL8712_DMA_H2CCMD: 100 pipe = usb_sndbulkpipe(pusbd, 0x0d); 101 break; 102 } 103 } else if (pdvobj->nr_endpoint == 6) { 104 switch (addr) { 105 case RTL8712_DMA_BKQ: 106 pipe = usb_sndbulkpipe(pusbd, 0x07); 107 break; 108 case RTL8712_DMA_BEQ: 109 pipe = usb_sndbulkpipe(pusbd, 0x06); 110 break; 111 case RTL8712_DMA_VIQ: 112 pipe = usb_sndbulkpipe(pusbd, 0x05); 113 break; 114 case RTL8712_DMA_VOQ: 115 pipe = usb_sndbulkpipe(pusbd, 0x04); 116 break; 117 case RTL8712_DMA_RX0FF: 118 case RTL8712_DMA_C2HCMD: 119 pipe = usb_rcvbulkpipe(pusbd, 0x03); /* in */ 120 break; 121 case RTL8712_DMA_H2CCMD: 122 case RTL8712_DMA_BCNQ: 123 case RTL8712_DMA_BMCQ: 124 case RTL8712_DMA_MGTQ: 125 pipe = usb_sndbulkpipe(pusbd, 0x0d); 126 break; 127 } 128 } else if (pdvobj->nr_endpoint == 4) { 129 switch (addr) { 130 case RTL8712_DMA_BEQ: 131 pipe = usb_sndbulkpipe(pusbd, 0x06); 132 break; 133 case RTL8712_DMA_VOQ: 134 pipe = usb_sndbulkpipe(pusbd, 0x04); 135 break; 136 case RTL8712_DMA_RX0FF: 137 case RTL8712_DMA_C2HCMD: 138 pipe = usb_rcvbulkpipe(pusbd, 0x03); /* in */ 139 break; 140 case RTL8712_DMA_H2CCMD: 141 case RTL8712_DMA_BCNQ: 142 case RTL8712_DMA_BMCQ: 143 case RTL8712_DMA_MGTQ: 144 pipe = usb_sndbulkpipe(pusbd, 0x0d); 145 break; 146 } 147 } else 148 pipe = 0; 149 return pipe; 150} 151 152static void usb_write_mem_complete(struct urb *purb) 153{ 154 struct io_queue *pio_q = (struct io_queue *)purb->context; 155 struct intf_hdl *pintf = &(pio_q->intf); 156 struct intf_priv *pintfpriv = pintf->pintfpriv; 157 struct _adapter *padapter = (struct _adapter *)pintf->adapter; 158 159 if (purb->status != 0) { 160 if (purb->status == (-ESHUTDOWN)) 161 padapter->bDriverStopped = true; 162 else 163 padapter->bSurpriseRemoved = true; 164 } 165 up(&pintfpriv->io_retevt); 166} 167 168void r8712_usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) 169{ 170 unsigned int pipe; 171 int status; 172 struct _adapter *padapter = (struct _adapter *)pintfhdl->adapter; 173 struct intf_priv *pintfpriv = pintfhdl->pintfpriv; 174 struct io_queue *pio_queue = (struct io_queue *)padapter->pio_queue; 175 struct dvobj_priv *pdvobj = (struct dvobj_priv *)pintfpriv->intf_dev; 176 struct usb_device *pusbd = pdvobj->pusbdev; 177 struct urb *piorw_urb = pintfpriv->piorw_urb; 178 179 if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) || 180 (padapter->pwrctrlpriv.pnp_bstop_trx)) 181 return; 182 /* translate DMA FIFO addr to pipehandle */ 183 pipe = ffaddr2pipehdl(pdvobj, addr); 184 if (pipe == 0) 185 return; 186 usb_fill_bulk_urb(piorw_urb, pusbd, pipe, 187 wmem, cnt, usb_write_mem_complete, 188 pio_queue); 189 status = usb_submit_urb(piorw_urb, GFP_ATOMIC); 190 _down_sema(&pintfpriv->io_retevt); 191} 192 193static void r8712_usb_read_port_complete(struct urb *purb) 194{ 195 uint isevt, *pbuf; 196 struct recv_buf *precvbuf = (struct recv_buf *)purb->context; 197 struct _adapter *padapter = (struct _adapter *)precvbuf->adapter; 198 struct recv_priv *precvpriv = &padapter->recvpriv; 199 200 if (padapter->bSurpriseRemoved || padapter->bDriverStopped) 201 return; 202 if (purb->status == 0) { /* SUCCESS */ 203 if ((purb->actual_length > (MAX_RECVBUF_SZ)) || 204 (purb->actual_length < RXDESC_SIZE)) { 205 precvbuf->reuse = true; 206 r8712_read_port(padapter, precvpriv->ff_hwaddr, 0, 207 (unsigned char *)precvbuf); 208 } else { 209 precvbuf->transfer_len = purb->actual_length; 210 pbuf = (uint *)precvbuf->pbuf; 211 isevt = le32_to_cpu(*(pbuf + 1)) & 0x1ff; 212 if ((isevt & 0x1ff) == 0x1ff) { 213 r8712_rxcmd_event_hdl(padapter, pbuf); 214 precvbuf->reuse = true; 215 r8712_read_port(padapter, precvpriv->ff_hwaddr, 216 0, (unsigned char *)precvbuf); 217 } else { 218 _pkt *pskb = precvbuf->pskb; 219 220 skb_put(pskb, purb->actual_length); 221 skb_queue_tail(&precvpriv->rx_skb_queue, pskb); 222 tasklet_hi_schedule(&precvpriv->recv_tasklet); 223 precvbuf->pskb = NULL; 224 precvbuf->reuse = false; 225 r8712_read_port(padapter, precvpriv->ff_hwaddr, 226 0, (unsigned char *)precvbuf); 227 } 228 } 229 } else { 230 switch (purb->status) { 231 case -EINVAL: 232 case -EPIPE: 233 case -ENODEV: 234 case -ESHUTDOWN: 235 case -ENOENT: 236 padapter->bDriverStopped = true; 237 break; 238 case -EPROTO: 239 precvbuf->reuse = true; 240 r8712_read_port(padapter, precvpriv->ff_hwaddr, 0, 241 (unsigned char *)precvbuf); 242 break; 243 case -EINPROGRESS: 244 netdev_err(padapter->pnetdev, "ERROR: URB IS IN PROGRESS!\n"); 245 break; 246 default: 247 break; 248 } 249 } 250} 251 252u32 r8712_usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem) 253{ 254 unsigned int pipe; 255 int err; 256 u32 tmpaddr = 0; 257 int alignment = 0; 258 u32 ret = _SUCCESS; 259 struct urb *purb = NULL; 260 struct recv_buf *precvbuf = (struct recv_buf *)rmem; 261 struct intf_priv *pintfpriv = pintfhdl->pintfpriv; 262 struct dvobj_priv *pdvobj = (struct dvobj_priv *)pintfpriv->intf_dev; 263 struct _adapter *adapter = (struct _adapter *)pdvobj->padapter; 264 struct recv_priv *precvpriv = &adapter->recvpriv; 265 struct usb_device *pusbd = pdvobj->pusbdev; 266 267 if (adapter->bDriverStopped || adapter->bSurpriseRemoved || 268 adapter->pwrctrlpriv.pnp_bstop_trx) 269 return _FAIL; 270 if ((precvbuf->reuse == false) || (precvbuf->pskb == NULL)) { 271 precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue); 272 if (NULL != precvbuf->pskb) 273 precvbuf->reuse = true; 274 } 275 if (precvbuf != NULL) { 276 r8712_init_recvbuf(adapter, precvbuf); 277 /* re-assign for linux based on skb */ 278 if ((precvbuf->reuse == false) || (precvbuf->pskb == NULL)) { 279 precvbuf->pskb = netdev_alloc_skb(adapter->pnetdev, 280 MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); 281 if (precvbuf->pskb == NULL) 282 return _FAIL; 283 tmpaddr = (addr_t)precvbuf->pskb->data; 284 alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); 285 skb_reserve(precvbuf->pskb, 286 (RECVBUFF_ALIGN_SZ - alignment)); 287 precvbuf->phead = precvbuf->pskb->head; 288 precvbuf->pdata = precvbuf->pskb->data; 289 precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); 290 precvbuf->pend = skb_end_pointer(precvbuf->pskb); 291 precvbuf->pbuf = precvbuf->pskb->data; 292 } else { /* reuse skb */ 293 precvbuf->phead = precvbuf->pskb->head; 294 precvbuf->pdata = precvbuf->pskb->data; 295 precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); 296 precvbuf->pend = skb_end_pointer(precvbuf->pskb); 297 precvbuf->pbuf = precvbuf->pskb->data; 298 precvbuf->reuse = false; 299 } 300 purb = precvbuf->purb; 301 /* translate DMA FIFO addr to pipehandle */ 302 pipe = ffaddr2pipehdl(pdvobj, addr); 303 usb_fill_bulk_urb(purb, pusbd, pipe, 304 precvbuf->pbuf, MAX_RECVBUF_SZ, 305 r8712_usb_read_port_complete, 306 precvbuf); 307 err = usb_submit_urb(purb, GFP_ATOMIC); 308 if ((err) && (err != (-EPERM))) 309 ret = _FAIL; 310 } else 311 ret = _FAIL; 312 return ret; 313} 314 315void r8712_usb_read_port_cancel(struct _adapter *padapter) 316{ 317 int i; 318 struct recv_buf *precvbuf; 319 320 precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf; 321 for (i = 0; i < NR_RECVBUFF; i++) { 322 if (precvbuf->purb) 323 usb_kill_urb(precvbuf->purb); 324 precvbuf++; 325 } 326} 327 328void r8712_xmit_bh(void *priv) 329{ 330 int ret = false; 331 struct _adapter *padapter = (struct _adapter *)priv; 332 struct xmit_priv *pxmitpriv = &padapter->xmitpriv; 333 334 if ((padapter->bDriverStopped == true) || 335 (padapter->bSurpriseRemoved == true)) { 336 netdev_err(padapter->pnetdev, "xmit_bh => bDriverStopped or bSurpriseRemoved\n"); 337 return; 338 } 339 ret = r8712_xmitframe_complete(padapter, pxmitpriv, NULL); 340 if (ret == false) 341 return; 342 tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); 343} 344 345static void usb_write_port_complete(struct urb *purb) 346{ 347 int i; 348 struct xmit_frame *pxmitframe = (struct xmit_frame *)purb->context; 349 struct xmit_buf *pxmitbuf = pxmitframe->pxmitbuf; 350 struct _adapter *padapter = pxmitframe->padapter; 351 struct xmit_priv *pxmitpriv = &padapter->xmitpriv; 352 struct pkt_attrib *pattrib = &pxmitframe->attrib; 353 354 switch (pattrib->priority) { 355 case 1: 356 case 2: 357 pxmitpriv->bkq_cnt--; 358 break; 359 case 4: 360 case 5: 361 pxmitpriv->viq_cnt--; 362 break; 363 case 6: 364 case 7: 365 pxmitpriv->voq_cnt--; 366 break; 367 case 0: 368 case 3: 369 default: 370 pxmitpriv->beq_cnt--; 371 break; 372 } 373 pxmitpriv->txirp_cnt--; 374 for (i = 0; i < 8; i++) { 375 if (purb == pxmitframe->pxmit_urb[i]) { 376 pxmitframe->bpending[i] = false; 377 break; 378 } 379 } 380 if (padapter->bSurpriseRemoved) 381 return; 382 switch (purb->status) { 383 case 0: 384 break; 385 default: 386 netdev_warn(padapter->pnetdev, 387 "r8712u: pipe error: (%d)\n", purb->status); 388 break; 389 } 390 /* not to consider tx fragment */ 391 r8712_free_xmitframe_ex(pxmitpriv, pxmitframe); 392 r8712_free_xmitbuf(pxmitpriv, pxmitbuf); 393 tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); 394} 395 396u32 r8712_usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) 397{ 398 unsigned long irqL; 399 int i, status; 400 unsigned int pipe; 401 u32 ret, bwritezero; 402 struct urb *purb = NULL; 403 struct _adapter *padapter = (struct _adapter *)pintfhdl->adapter; 404 struct dvobj_priv *pdvobj = (struct dvobj_priv *)&padapter->dvobjpriv; 405 struct xmit_priv *pxmitpriv = &padapter->xmitpriv; 406 struct xmit_frame *pxmitframe = (struct xmit_frame *)wmem; 407 struct usb_device *pusbd = pdvobj->pusbdev; 408 struct pkt_attrib *pattrib = &pxmitframe->attrib; 409 410 if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) || 411 (padapter->pwrctrlpriv.pnp_bstop_trx)) 412 return _FAIL; 413 for (i = 0; i < 8; i++) { 414 if (pxmitframe->bpending[i] == false) { 415 spin_lock_irqsave(&pxmitpriv->lock, irqL); 416 pxmitpriv->txirp_cnt++; 417 pxmitframe->bpending[i] = true; 418 switch (pattrib->priority) { 419 case 1: 420 case 2: 421 pxmitpriv->bkq_cnt++; 422 break; 423 case 4: 424 case 5: 425 pxmitpriv->viq_cnt++; 426 break; 427 case 6: 428 case 7: 429 pxmitpriv->voq_cnt++; 430 break; 431 case 0: 432 case 3: 433 default: 434 pxmitpriv->beq_cnt++; 435 break; 436 } 437 spin_unlock_irqrestore(&pxmitpriv->lock, irqL); 438 pxmitframe->sz[i] = (u16)cnt; 439 purb = pxmitframe->pxmit_urb[i]; 440 break; 441 } 442 } 443 bwritezero = false; 444 if (pdvobj->ishighspeed) { 445 if (cnt > 0 && cnt % 512 == 0) 446 bwritezero = true; 447 } else { 448 if (cnt > 0 && cnt % 64 == 0) 449 bwritezero = true; 450 } 451 /* translate DMA FIFO addr to pipehandle */ 452 pipe = ffaddr2pipehdl(pdvobj, addr); 453 if (pxmitpriv->free_xmitbuf_cnt%NR_XMITBUFF == 0) 454 purb->transfer_flags &= (~URB_NO_INTERRUPT); 455 else 456 purb->transfer_flags |= URB_NO_INTERRUPT; 457 if (bwritezero) 458 cnt += 8; 459 usb_fill_bulk_urb(purb, pusbd, pipe, 460 pxmitframe->mem_addr, 461 cnt, usb_write_port_complete, 462 pxmitframe); /* context is xmit_frame */ 463 status = usb_submit_urb(purb, GFP_ATOMIC); 464 if (!status) 465 ret = _SUCCESS; 466 else 467 ret = _FAIL; 468 return ret; 469} 470 471void r8712_usb_write_port_cancel(struct _adapter *padapter) 472{ 473 int i, j; 474 struct xmit_buf *pxmitbuf = (struct xmit_buf *) 475 padapter->xmitpriv.pxmitbuf; 476 477 for (i = 0; i < NR_XMITBUFF; i++) { 478 for (j = 0; j < 8; j++) { 479 if (pxmitbuf->pxmit_urb[j]) 480 usb_kill_urb(pxmitbuf->pxmit_urb[j]); 481 } 482 pxmitbuf++; 483 } 484} 485 486int r8712_usbctrl_vendorreq(struct intf_priv *pintfpriv, u8 request, u16 value, 487 u16 index, void *pdata, u16 len, u8 requesttype) 488{ 489 unsigned int pipe; 490 int status; 491 u8 reqtype; 492 struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *) 493 pintfpriv->intf_dev; 494 struct usb_device *udev = pdvobjpriv->pusbdev; 495 /* For mstar platform, mstar suggests the address for USB IO 496 * should be 16 bytes alignment. Trying to fix it here. 497 */ 498 u8 *palloc_buf, *pIo_buf; 499 500 palloc_buf = kmalloc((u32)len + 16, GFP_ATOMIC); 501 if (palloc_buf == NULL) 502 return -ENOMEM; 503 pIo_buf = palloc_buf + 16 - ((addr_t)(palloc_buf) & 0x0f); 504 if (requesttype == 0x01) { 505 pipe = usb_rcvctrlpipe(udev, 0); /* read_in */ 506 reqtype = RTL871X_VENQT_READ; 507 } else { 508 pipe = usb_sndctrlpipe(udev, 0); /* write_out */ 509 reqtype = RTL871X_VENQT_WRITE; 510 memcpy(pIo_buf, pdata, len); 511 } 512 status = usb_control_msg(udev, pipe, request, reqtype, value, index, 513 pIo_buf, len, HZ / 2); 514 if (status > 0) { /* Success this control transfer. */ 515 if (requesttype == 0x01) { 516 /* For Control read transfer, we have to copy the read 517 * data from pIo_buf to pdata. 518 */ 519 memcpy(pdata, pIo_buf, status); 520 } 521 } 522 kfree(palloc_buf); 523 return status; 524} 525