OLD | NEW |
(Empty) | |
| 1 //------------------------------------------------------------------------------ |
| 2 // Copyright (c) 2004-2010 Atheros Communications Inc. |
| 3 // All rights reserved. |
| 4 // |
| 5 // |
| 6 // |
| 7 // Permission to use, copy, modify, and/or distribute this software for any |
| 8 // purpose with or without fee is hereby granted, provided that the above |
| 9 // copyright notice and this permission notice appear in all copies. |
| 10 // |
| 11 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 12 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 13 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 14 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 15 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 16 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 17 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 18 // |
| 19 // |
| 20 // |
| 21 // Author(s): ="Atheros" |
| 22 //------------------------------------------------------------------------------ |
| 23 |
| 24 #include "ar6000_drv.h" |
| 25 #ifdef AR6K_ENABLE_HCI_PAL |
| 26 #include <net/bluetooth/bluetooth.h> |
| 27 #include <net/bluetooth/hci_core.h> |
| 28 #include <ar6k_pal.h> |
| 29 |
| 30 extern unsigned int setupbtdev; |
| 31 #define bt_check_bit(val, bit) (val & bit) |
| 32 #define bt_set_bit(val, bit) (val |= bit) |
| 33 #define bt_clear_bit(val, bit) (val &= ~bit) |
| 34 |
| 35 /* export ATH_AR6K_DEBUG_HCI_PAL=yes in host/localmake.linux.inc |
| 36 * to enable debug information */ |
| 37 #ifdef HCIPAL_DEBUG |
| 38 #define PRIN_LOG(format, args...) printk(KERN_ALERT "%s:%d - %s Msg:" format "\n
",__FUNCTION__, __LINE__, __FILE__, ## args) |
| 39 #else |
| 40 #define PRIN_LOG(format, args...) |
| 41 #endif |
| 42 |
| 43 /********************************** |
| 44 * HCI PAL private info structure |
| 45 *********************************/ |
| 46 typedef struct ar6k_hci_pal_info_s{ |
| 47 |
| 48 unsigned long ulFlags; |
| 49 #define HCI_NORMAL_MODE (1) |
| 50 #define HCI_REGISTERED (1<<1) |
| 51 struct hci_dev *hdev; /* BT Stack HCI dev */ |
| 52 AR_SOFTC_T *ar; |
| 53 |
| 54 }ar6k_hci_pal_info_t; |
| 55 |
| 56 /*** BT Stack Entrypoints *******/ |
| 57 /*************************************** |
| 58 * bt_open - open a handle to the device |
| 59 ***************************************/ |
| 60 static int bt_open(struct hci_dev *hdev) |
| 61 { |
| 62 PRIN_LOG("HCI PAL: bt_open - enter - x\n"); |
| 63 set_bit(HCI_RUNNING, &hdev->flags); |
| 64 set_bit(HCI_UP, &hdev->flags); |
| 65 set_bit(HCI_INIT, &hdev->flags); |
| 66 return 0; |
| 67 } |
| 68 |
| 69 /*************************************** |
| 70 * bt_close - close handle to the device |
| 71 ***************************************/ |
| 72 static int bt_close(struct hci_dev *hdev) |
| 73 { |
| 74 PRIN_LOG("HCI PAL: bt_close - enter\n"); |
| 75 clear_bit(HCI_RUNNING, &hdev->flags); |
| 76 return 0; |
| 77 } |
| 78 |
| 79 /***************************** |
| 80 * bt_ioctl - ioctl processing |
| 81 *****************************/ |
| 82 static int bt_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) |
| 83 { |
| 84 PRIN_LOG("HCI PAL: bt_ioctl - enter\n"); |
| 85 return -ENOIOCTLCMD; |
| 86 } |
| 87 |
| 88 /************************************** |
| 89 * bt_flush - flush outstanding packets |
| 90 **************************************/ |
| 91 static int bt_flush(struct hci_dev *hdev) |
| 92 { |
| 93 PRIN_LOG("HCI PAL: bt_flush - enter\n"); |
| 94 return 0; |
| 95 } |
| 96 |
| 97 /*************** |
| 98 * bt_destruct |
| 99 ***************/ |
| 100 static void bt_destruct(struct hci_dev *hdev) |
| 101 { |
| 102 PRIN_LOG("HCI PAL: bt_destruct - enter\n"); |
| 103 /* nothing to do here */ |
| 104 } |
| 105 |
| 106 /**************************************************** |
| 107 * Invoked from bluetooth stack via hdev->send() |
| 108 * to send the packet out via ar6k to PAL firmware. |
| 109 * |
| 110 * For HCI command packet wmi_send_hci_cmd() is invoked. |
| 111 * wmi_send_hci_cmd adds WMI_CMD_HDR and sends the packet |
| 112 * to PAL firmware. |
| 113 * |
| 114 * For HCI ACL data packet wmi_data_hdr_add is invoked |
| 115 * to add WMI_DATA_HDR to the packet. ar6000_acl_data_tx |
| 116 * is then invoked to send the packet to PAL firmware. |
| 117 ******************************************************/ |
| 118 static int btpal_send_frame(struct sk_buff *skb) |
| 119 { |
| 120 struct hci_dev *hdev = (struct hci_dev *)skb->dev; |
| 121 HCI_TRANSPORT_PACKET_TYPE type; |
| 122 ar6k_hci_pal_info_t *pHciPalInfo; |
| 123 A_STATUS status = A_OK; |
| 124 struct sk_buff *txSkb = NULL; |
| 125 AR_SOFTC_T *ar; |
| 126 |
| 127 if (!hdev) { |
| 128 PRIN_LOG("HCI PAL: btpal_send_frame - no device\n"); |
| 129 return -ENODEV; |
| 130 } |
| 131 |
| 132 if (!test_bit(HCI_RUNNING, &hdev->flags)) { |
| 133 PRIN_LOG("HCI PAL: btpal_send_frame - not open\n"); |
| 134 return -EBUSY; |
| 135 } |
| 136 |
| 137 pHciPalInfo = (ar6k_hci_pal_info_t *)hdev->driver_data; |
| 138 A_ASSERT(pHciPalInfo != NULL); |
| 139 ar = pHciPalInfo->ar; |
| 140 |
| 141 PRIN_LOG("+btpal_send_frame type: %d \n",bt_cb(skb)->pkt_type); |
| 142 type = HCI_COMMAND_TYPE; |
| 143 |
| 144 switch (bt_cb(skb)->pkt_type) { |
| 145 case HCI_COMMAND_PKT: |
| 146 type = HCI_COMMAND_TYPE; |
| 147 hdev->stat.cmd_tx++; |
| 148 break; |
| 149 |
| 150 case HCI_ACLDATA_PKT: |
| 151 type = HCI_ACL_TYPE; |
| 152 hdev->stat.acl_tx++; |
| 153 break; |
| 154 |
| 155 case HCI_SCODATA_PKT: |
| 156 /* we don't support SCO over the pal */ |
| 157 kfree_skb(skb); |
| 158 return 0; |
| 159 default: |
| 160 A_ASSERT(FALSE); |
| 161 kfree_skb(skb); |
| 162 return 0; |
| 163 } |
| 164 |
| 165 if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_HCI_DUMP)) { |
| 166 A_PRINTF(">>> Send HCI %s packet len: %d\n", |
| 167 (type == HCI_COMMAND_TYPE) ? "COMMAND" : "ACL", |
| 168 skb->len); |
| 169 if (type == HCI_COMMAND_TYPE) { |
| 170 PRIN_LOG(" HCI Command: OGF:0x%X OCF:0x%X \r\n", |
| 171 HCI_GET_OP_CODE(skb-data) >> 10, HCI_GET
_OP_CODE(skb-data) & 0x3FF); |
| 172 } |
| 173 AR_DEBUG_PRINTBUF(skb->data,skb->len,"BT HCI SEND Packet Dump"); |
| 174 } |
| 175 |
| 176 do { |
| 177 if(type == HCI_COMMAND_TYPE) |
| 178 { |
| 179 PRIN_LOG("HCI command"); |
| 180 |
| 181 if (ar->arWmiReady == FALSE) |
| 182 { |
| 183 PRIN_LOG("WMI not ready "); |
| 184 break; |
| 185 } |
| 186 |
| 187 if (wmi_send_hci_cmd(ar->arWmi, skb->data, skb->len) !=
A_OK) |
| 188 { |
| 189 PRIN_LOG("send hci cmd error"); |
| 190 break; |
| 191 } |
| 192 } |
| 193 else if(type == HCI_ACL_TYPE) |
| 194 { |
| 195 void *osbuf; |
| 196 |
| 197 PRIN_LOG("ACL data"); |
| 198 if (ar->arWmiReady == FALSE) |
| 199 { |
| 200 PRIN_LOG("WMI not ready"); |
| 201 break; |
| 202 } |
| 203 |
| 204 /* need to add WMI header so allocate a skb with more sp
ace */ |
| 205 txSkb = bt_skb_alloc(TX_PACKET_RSV_OFFSET + WMI_MAX_TX_M
ETA_SZ + |
| 206 sizeof(WMI_DATA_HDR) + skb->len, |
| 207 GFP_ATOMIC); |
| 208 |
| 209 if (txSkb == NULL) { |
| 210 status = A_NO_MEMORY; |
| 211 PRIN_LOG("No memory"); |
| 212 break; |
| 213 } |
| 214 |
| 215 bt_cb(txSkb)->pkt_type = bt_cb(skb)->pkt_type; |
| 216 txSkb->dev = (void *)pHciPalInfo->hdev; |
| 217 skb_reserve(txSkb, TX_PACKET_RSV_OFFSET + WMI_MAX_TX_MET
A_SZ + sizeof(WMI_DATA_HDR)); |
| 218 A_MEMCPY(txSkb->data, skb->data, skb->len); |
| 219 skb_put(txSkb,skb->len); |
| 220 /* Add WMI packet type */ |
| 221 osbuf = (void *)txSkb; |
| 222 |
| 223 if (wmi_data_hdr_add(ar->arWmi, osbuf, DATA_MSGTYPE, 0,
WMI_DATA_HDR_DATA_TYPE_ACL,0,NULL) != A_OK) { |
| 224 PRIN_LOG("XIOCTL_ACL_DATA - wmi_data_hdr_add fai
led\n"); |
| 225 } else { |
| 226 /* Send data buffer over HTC */ |
| 227 PRIN_LOG("acl data tx"); |
| 228 ar6000_acl_data_tx(osbuf, ar->arNetDev); |
| 229 } |
| 230 txSkb = NULL; |
| 231 } |
| 232 } while (FALSE); |
| 233 |
| 234 if (txSkb != NULL) { |
| 235 PRIN_LOG("Free skb"); |
| 236 kfree_skb(txSkb); |
| 237 } |
| 238 kfree_skb(skb); |
| 239 return 0; |
| 240 } |
| 241 |
| 242 |
| 243 /*********************************************** |
| 244 * Unregister HCI device and free HCI device info |
| 245 ***********************************************/ |
| 246 static void bt_cleanup_hci_pal(ar6k_hci_pal_info_t *pHciPalInfo) |
| 247 { |
| 248 int err; |
| 249 |
| 250 if (bt_check_bit(pHciPalInfo->ulFlags, HCI_REGISTERED)) { |
| 251 bt_clear_bit(pHciPalInfo->ulFlags, HCI_REGISTERED); |
| 252 clear_bit(HCI_RUNNING, &pHciPalInfo->hdev->flags); |
| 253 clear_bit(HCI_UP, &pHciPalInfo->hdev->flags); |
| 254 clear_bit(HCI_INIT, &pHciPalInfo->hdev->flags); |
| 255 A_ASSERT(pHciPalInfo->hdev != NULL); |
| 256 /* unregister */ |
| 257 PRIN_LOG("Unregister PAL device"); |
| 258 if ((err = hci_unregister_dev(pHciPalInfo->hdev)) < 0) { |
| 259 PRIN_LOG("HCI PAL: failed to unregister with bluetooth %
d\n",err); |
| 260 } |
| 261 } |
| 262 |
| 263 if (pHciPalInfo->hdev != NULL) { |
| 264 kfree(pHciPalInfo->hdev); |
| 265 pHciPalInfo->hdev = NULL; |
| 266 } |
| 267 } |
| 268 |
| 269 /********************************************************* |
| 270 * Allocate HCI device and store in PAL private info structure. |
| 271 *********************************************************/ |
| 272 static A_STATUS bt_setup_hci_pal(ar6k_hci_pal_info_t *pHciPalInfo) |
| 273 { |
| 274 A_STATUS status = A_OK; |
| 275 struct hci_dev *pHciDev = NULL; |
| 276 |
| 277 if (!setupbtdev) { |
| 278 return A_OK; |
| 279 } |
| 280 |
| 281 do { |
| 282 /* allocate a BT HCI struct for this device */ |
| 283 pHciDev = hci_alloc_dev(); |
| 284 if (NULL == pHciDev) { |
| 285 PRIN_LOG("HCI PAL driver - failed to allocate BT HCI str
uct \n"); |
| 286 status = A_NO_MEMORY; |
| 287 break; |
| 288 } |
| 289 |
| 290 /* save the device, we'll register this later */ |
| 291 pHciPalInfo->hdev = pHciDev; |
| 292 SET_HCI_BUS_TYPE(pHciDev, HCI_VIRTUAL, HCI_80211); |
| 293 pHciDev->driver_data = pHciPalInfo; |
| 294 pHciDev->open = bt_open; |
| 295 pHciDev->close = bt_close; |
| 296 pHciDev->send = btpal_send_frame; |
| 297 pHciDev->ioctl = bt_ioctl; |
| 298 pHciDev->flush = bt_flush; |
| 299 pHciDev->destruct = bt_destruct; |
| 300 pHciDev->owner = THIS_MODULE; |
| 301 /* driver is running in normal BT mode */ |
| 302 PRIN_LOG("Normal mode enabled"); |
| 303 bt_set_bit(pHciPalInfo->ulFlags, HCI_NORMAL_MODE); |
| 304 |
| 305 } while (FALSE); |
| 306 |
| 307 if (A_FAILED(status)) { |
| 308 bt_cleanup_hci_pal(pHciPalInfo); |
| 309 } |
| 310 return status; |
| 311 } |
| 312 |
| 313 /********************************************** |
| 314 * Cleanup HCI device and free HCI PAL private info |
| 315 *********************************************/ |
| 316 void ar6k_cleanup_hci_pal(void *ar_p) |
| 317 { |
| 318 AR_SOFTC_T *ar = (AR_SOFTC_T *)ar_p; |
| 319 ar6k_hci_pal_info_t *pHciPalInfo = (ar6k_hci_pal_info_t *)ar->hcipal_inf
o; |
| 320 |
| 321 if (pHciPalInfo != NULL) { |
| 322 bt_cleanup_hci_pal(pHciPalInfo); |
| 323 A_FREE(pHciPalInfo); |
| 324 ar->hcipal_info = NULL; |
| 325 } |
| 326 } |
| 327 |
| 328 /**************************** |
| 329 * Register HCI device |
| 330 ****************************/ |
| 331 static A_BOOL ar6k_pal_transport_ready(void *pHciPal) |
| 332 { |
| 333 ar6k_hci_pal_info_t *pHciPalInfo = (ar6k_hci_pal_info_t *)pHciPal; |
| 334 |
| 335 PRIN_LOG("HCI device transport ready"); |
| 336 if(pHciPalInfo == NULL) |
| 337 return FALSE; |
| 338 |
| 339 if (hci_register_dev(pHciPalInfo->hdev) < 0) { |
| 340 PRIN_LOG("Can't register HCI device"); |
| 341 hci_free_dev(pHciPalInfo->hdev); |
| 342 return FALSE; |
| 343 } |
| 344 PRIN_LOG("HCI device registered"); |
| 345 pHciPalInfo->ulFlags |= HCI_REGISTERED; |
| 346 return TRUE; |
| 347 } |
| 348 |
| 349 /************************************************** |
| 350 * Called from ar6k driver when command or ACL data |
| 351 * packet is received. Pass the packet to bluetooth |
| 352 * stack via hci_recv_frame. |
| 353 **************************************************/ |
| 354 A_BOOL ar6k_pal_recv_pkt(void *pHciPal, void *osbuf) |
| 355 { |
| 356 struct sk_buff *skb = (struct sk_buff *)osbuf; |
| 357 ar6k_hci_pal_info_t *pHciPalInfo; |
| 358 A_BOOL success = FALSE; |
| 359 A_UINT8 btType = 0; |
| 360 pHciPalInfo = (ar6k_hci_pal_info_t *)pHciPal; |
| 361 |
| 362 do { |
| 363 |
| 364 /* if normal mode is not enabled pass on to the stack |
| 365 * by returning failure */ |
| 366 if(!(pHciPalInfo->ulFlags & HCI_NORMAL_MODE)) |
| 367 { |
| 368 PRIN_LOG("Normal mode not enabled"); |
| 369 break; |
| 370 } |
| 371 |
| 372 if (!test_bit(HCI_RUNNING, &pHciPalInfo->hdev->flags)) { |
| 373 PRIN_LOG("HCI PAL: HCI - not running\n"); |
| 374 break; |
| 375 } |
| 376 |
| 377 if(*((short *)A_NETBUF_DATA(skb)) == WMI_ACL_DATA_EVENTID) |
| 378 btType = HCI_ACLDATA_PKT; |
| 379 else |
| 380 btType = HCI_EVENT_PKT; |
| 381 /* pull 4 bytes which contains WMI packet type */ |
| 382 A_NETBUF_PULL(skb, sizeof(int)); |
| 383 bt_cb(skb)->pkt_type = btType; |
| 384 skb->dev = (void *)pHciPalInfo->hdev; |
| 385 |
| 386 /* pass the received event packet up the stack */ |
| 387 if (hci_recv_frame(skb) != 0) { |
| 388 PRIN_LOG("HCI PAL: hci_recv_frame failed \n"); |
| 389 break; |
| 390 } else { |
| 391 PRIN_LOG("HCI PAL: Indicated RCV of type:%d, Length:%d \
n",HCI_EVENT_PKT, skb->len); |
| 392 } |
| 393 PRIN_LOG("hci recv success"); |
| 394 success = TRUE; |
| 395 }while(FALSE); |
| 396 return success; |
| 397 } |
| 398 |
| 399 /********************************************************** |
| 400 * HCI PAL init function called from ar6k when it is loaded.. |
| 401 * Allocates PAL private info, stores the same in ar6k private info. |
| 402 * Registers a HCI device. |
| 403 * Registers packet receive callback function with ar6k |
| 404 **********************************************************/ |
| 405 A_STATUS ar6k_setup_hci_pal(void *ar_p) |
| 406 { |
| 407 A_STATUS status = A_OK; |
| 408 ar6k_hci_pal_info_t *pHciPalInfo; |
| 409 ar6k_pal_config_t ar6k_pal_config; |
| 410 AR_SOFTC_T *ar = (AR_SOFTC_T *)ar_p; |
| 411 |
| 412 do { |
| 413 |
| 414 pHciPalInfo = (ar6k_hci_pal_info_t *)A_MALLOC(sizeof(ar6k_hci_pa
l_info_t)); |
| 415 |
| 416 if (NULL == pHciPalInfo) { |
| 417 status = A_NO_MEMORY; |
| 418 break; |
| 419 } |
| 420 |
| 421 A_MEMZERO(pHciPalInfo, sizeof(ar6k_hci_pal_info_t)); |
| 422 ar->hcipal_info = pHciPalInfo; |
| 423 pHciPalInfo->ar = ar; |
| 424 |
| 425 status = bt_setup_hci_pal(pHciPalInfo); |
| 426 if (A_FAILED(status)) { |
| 427 break; |
| 428 } |
| 429 |
| 430 if(bt_check_bit(pHciPalInfo->ulFlags, HCI_NORMAL_MODE)) |
| 431 PRIN_LOG("HCI PAL: running in normal mode... \n"); |
| 432 else |
| 433 PRIN_LOG("HCI PAL: running in test mode... \n"); |
| 434 |
| 435 ar6k_pal_config.fpar6k_pal_recv_pkt = ar6k_pal_recv_pkt; |
| 436 register_pal_cb(&ar6k_pal_config); |
| 437 ar6k_pal_transport_ready(ar->hcipal_info); |
| 438 } while (FALSE); |
| 439 |
| 440 if (A_FAILED(status)) { |
| 441 ar6k_cleanup_hci_pal(ar); |
| 442 } |
| 443 return status; |
| 444 } |
| 445 #else /* AR6K_ENABLE_HCI_PAL */ |
| 446 A_STATUS ar6k_setup_hci_pal(void *ar_p) |
| 447 { |
| 448 return A_OK; |
| 449 } |
| 450 void ar6k_cleanup_hci_pal(void *ar_p) |
| 451 { |
| 452 } |
| 453 #endif /* AR6K_ENABLE_HCI_PAL */ |
| 454 |
| 455 #ifdef EXPORT_HCI_PAL_INTERFACE |
| 456 /***************************************************** |
| 457 * Register init and callback function with ar6k |
| 458 * when PAL driver is a separate kernel module. |
| 459 ****************************************************/ |
| 460 A_STATUS ar6k_register_hci_pal(HCI_TRANSPORT_CALLBACKS *hciTransCallbacks); |
| 461 static int __init pal_init_module(void) |
| 462 { |
| 463 HCI_TRANSPORT_CALLBACKS hciTransCallbacks; |
| 464 |
| 465 hciTransCallbacks.setupTransport = ar6k_setup_hci_pal; |
| 466 hciTransCallbacks.cleanupTransport = ar6k_cleanup_hci_pal; |
| 467 |
| 468 if(ar6k_register_hci_pal(&hciTransCallbacks) != A_OK) |
| 469 return -ENODEV; |
| 470 |
| 471 return 0; |
| 472 } |
| 473 |
| 474 static void __exit pal_cleanup_module(void) |
| 475 { |
| 476 } |
| 477 |
| 478 module_init(pal_init_module); |
| 479 module_exit(pal_cleanup_module); |
| 480 MODULE_LICENSE("Dual BSD/GPL"); |
| 481 #endif |
OLD | NEW |