📄 hci.c
字号:
case READ_LOCAL_VERSION_INFORMATION: D_CMD(__FUNCTION__ ": READ_LOCAL_VERSION_INFORMATION\n"); if (r_val[0]) { D_ERR(__FUNCTION__ ": READ_LOCAL_VERSION_INFORMATION: %s\n", get_err_msg(r_val[0])); break; } break; case READ_BUFFER_SIZE: D_CMD(__FUNCTION__ ": READ_BUFFER_SIZE\n"); if (r_val[0]) { D_ERR(__FUNCTION__ ": READ_BUFFER_SIZE: %s\n", get_err_msg(r_val[0])); break; } hci_ctrl.hc_buf.acl_len = le16_to_cpuu(&r_val[1]); hci_ctrl.hc_buf.sco_len = (u32) r_val[3]; hci_ctrl.hc_buf.acl_num = le16_to_cpuu(&r_val[4]); hci_ctrl.hc_buf.sco_num = le16_to_cpuu(&r_val[6]); printk("\nHW module contains...\n"); printk("%d ACL buffers at %d bytes\n%d SCO buffers at %d bytes\n\n", hci_ctrl.hc_buf.acl_num, hci_ctrl.hc_buf.acl_len, hci_ctrl.hc_buf.sco_num, hci_ctrl.hc_buf.sco_len);#ifdef __KERNEL__#ifdef USE_NCPTIMER hw.max_acl_num = hci_ctrl.hc_buf.acl_num;#endif#endif wake_up_interruptible(&hci_wq); break; case READ_BD_ADDR: D_CMD(__FUNCTION__ ": READ_BD_ADDR\n"); if (r_val[0]) { D_ERR(__FUNCTION__ ": READ_BD_ADDR: %s\n", get_err_msg(r_val[0])); break; } PRINTPKT(__FUNCTION__ ": READ_BD_ADDR : ", &r_val[1], 6); memcpy(hci_ctrl.local_bd, &r_val[1],6); break; default: D_CMD(__FUNCTION__ ": HCI_IP, ocf %d not recognised!\n", ocf); break; } wake_up_interruptible(&hci_wq); break; case HCI_TC: /* Test Commands */ release_cmd_timer(); switch (ocf) { case READ_LOOPBACK_MODE: D_ERR(__FUNCTION__ ": READ_LOOPBACK_MODE -- not impl\n"); break; case WRITE_LOOPBACK_MODE: D_ERR(__FUNCTION__ ": WRITE_LOOPBACK_MODE -- not impl\n"); break; case ENABLE_DEVICE_UNDER_TEST_MODE: DSYS(__FUNCTION__ ": ENABLE_DEVICE_UNDER_TEST_MODE\n"); if (r_val[0]) { D_ERR(__FUNCTION__ ": ENABLE_DEVICE_UNDER_TEST_MODE: %s\n", get_err_msg(r_val[0])); break; } printk(__FUNCTION__ ": *** Local device now under test\n***"); break; default: D_ERR(__FUNCTION__ ": HCI_TC, ocf %d not recognised!\n", ocf); break; } wake_up_interruptible(&hci_wq); break; case MANUFACTURER_SPEC: /* Manufacturer specific */ D_CMD(__FUNCTION__ ": MANUFACTURER_SPEC\n"); process_vendor_return_param(ocf, r_val); break; default: D_CMD(__FUNCTION__ ": ogf %d, not recognised! \n", ogf); break; }}/*Parses an ACL-data packet and copies it into the hci_in-buffer, data is a pointer to the data in the memory, pb_flag is the packet boundary flag which tells whether it is a beginning or a continuing fragment of an L2CAP-packet */void process_acl_data(hci_in_buffer *in_buf, u32 pb_flag){ D_REC(__FUNCTION__ ": in_buf->count:%d, in_buf->l2cap_len:%d\n", in_buf->count, in_buf->l2cap_len); if (pb_flag == L2CAP_FRAME_START) { in_buf->l2cap_len = 0; l2cap_receive_data(in_buf->buf, in_buf->count, in_buf->hci_hdl, &in_buf->l2cap_len); } else if (in_buf->count >= in_buf->l2cap_len) { l2cap_receive_data(in_buf->buf, in_buf->count, in_buf->hci_hdl, &in_buf->l2cap_len); }}/* Process an SCO-data packet, i.e. received audio from the Bluetooth module */voidprocess_sco_packet(u8 *data, u32 hci_hdl, u32 len){ hci_in_buffer *in_buf; if (!(in_buf = get_free_inbuffer())) { printk(__FUNCTION__ ": couldn't find free in buffer\n"); return; } memcpy(in_buf->buf_ptr, data, len); in_buf->hci_hdl = hci_hdl; in_buf->buf_ptr += len; in_buf->count += len; /* FIXME - Finish this function... */}voidset_hci_con(u8 *bd, s32 con_hdl){ s32 i; for (i = 0; i < MAX_NBR_OF_CONNECTIONS; i++) { if (hci_ctrl.con[i].state == NOT_CONNECTED) { memcpy(hci_ctrl.con[i].bd, bd, 6); hci_ctrl.con[i].con_hdl = con_hdl; hci_ctrl.con[i].state = UNIT_ACTIVE; return; } } D_ERR(__FUNCTION__ ": No free connection object\n");}void reset_hci_con_bd(u16 con_hdl){ s32 i; for (i = 0; i < MAX_NBR_OF_CONNECTIONS; i++) { if (hci_ctrl.con[i].con_hdl == con_hdl) { hci_ctrl.con[i].state = NOT_CONNECTED; hci_ctrl.con[i].con_hdl = -1; hci_ctrl.con[i].name[0] = 0; return; } } D_ERR(__FUNCTION__ ": Didn't find connection with con_hdl %d\n", con_hdl);}voidset_hci_con_name(u8 *bd, u8 *name){ s32 i; if (!name) { D_ERR(__FUNCTION__ ": set_hci_con_name: No name defined\n"); return; } for (i = 0; i < MAX_NBR_OF_CONNECTIONS; i++) { if (memcmp(hci_ctrl.con[i].bd, bd, 6) == 0) { strcpy(hci_ctrl.con[i].name, name); return; } } D_ERR(__FUNCTION__ ": Didn't fin connecton with BD adress 0x%02x:%02x:%02x:%02x:%02x:%02x\n", bd[5],bd[4],bd[3],bd[2],bd[1],bd[0]);}s32 hci_sprint_local_bd(u8 *buf){ return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", hci_ctrl.local_bd[5], hci_ctrl.local_bd[4], hci_ctrl.local_bd[3], hci_ctrl.local_bd[2], hci_ctrl.local_bd[1], hci_ctrl.local_bd[0]);} s32 hci_sprint_remote_info(u8 *buf){ s32 pos = 0; s32 i; pos += sprintf(buf + pos, "unit_id unit_bd_address unit_mode unit_name\n"); /* Then we printout the other connections bd addresses and their user friendly device names */ for (i = 0; i < MAX_NBR_OF_CONNECTIONS; i++) { if (hci_ctrl.con[i].state != NOT_CONNECTED) { pos += sprintf(buf + pos, "%d ", i); pos += sprintf(buf + pos,"%02X:%02X:%02X:%02X:%02X:%02X ", hci_ctrl.con[i].bd[5], hci_ctrl.con[i].bd[4], hci_ctrl.con[i].bd[3], hci_ctrl.con[i].bd[2], hci_ctrl.con[i].bd[1], hci_ctrl.con[i].bd[0]); if (hci_ctrl.con[i].state == UNIT_ACTIVE) { pos += sprintf(buf + pos, "active "); } else if (hci_ctrl.con[i].state == UNIT_PASSIVE) { pos += sprintf(buf + pos, "passive "); } else { pos += sprintf(buf + pos, "unknown "); } pos += sprintf(buf + pos, "%s\n", hci_ctrl.con[i].name); } } return pos;}s32 hci_sprint_local_info(u8 *buf){ s32 pos = 0; s32 i; pos += sprintf(buf + pos, "The connected hci handlers are:\n"); for (i = 0; i < MAX_NBR_OF_CONNECTIONS; i++) { if (hci_ctrl.con[i].state != NOT_CONNECTED) { pos += sprintf(buf + pos, "HCI handle:%d\n", hci_ctrl.con[i].con_hdl); } } pos += sprintf(buf + pos, "\nFree data buffers in HW : %d\n", hci_ctrl.hc_buf.acl_num); pos += sprintf(buf + pos, "Free command buffers in HW : %d\n", hci_ctrl.hc_buf.cmd_num); return pos;}/* Marks the buffer empty, so new hci data, from the same or another connection handler can be written in it */void hci_clear_buffer(u32 hci_hdl){ hci_in_buffer *in_buf = NULL; D_CTRL(__FUNCTION__ "\n"); if (!(in_buf = get_inbuffer(hci_hdl))) { printk(__FUNCTION__ ": couldn't find in buffer hci_hdl %d\n", hci_hdl); return; } in_buf->buf_ptr = in_buf->buf; in_buf->count = 0; in_buf->l2cap_len = 0; in_buf->empty = TRUE; in_buf->nbr_of_hci_pkt = 0;}/* Finds the in buffer for a given connection handler */ hci_in_buffer*get_inbuffer(u32 hci_hdl){ u32 i; for (i = 0 ; i < NBR_OF_HCI_INBUFFERS ; i ++) { if (hci_ctrl.hci_in_buf[i].hci_hdl == hci_hdl) { break; } } if (i >= NBR_OF_HCI_INBUFFERS) { D_ERR(__FUNCTION__ ": WARNING! No inbuffer with hci_hdl %d\n", hci_hdl); return NULL; } D_CTRL(__FUNCTION__ ": Found inbuffer for hci_hdl %d %p\n",hci_hdl, &hci_ctrl.hci_in_buf[i]); return &hci_ctrl.hci_in_buf[i];}/* Finds a free inbuffer */hci_in_buffer* get_free_inbuffer(void){ u32 i; for (i = 0 ; i < NBR_OF_HCI_INBUFFERS ; i ++) { if (hci_ctrl.hci_in_buf[i].empty) { break; } } if (i >= NBR_OF_HCI_INBUFFERS) { D_ERR(__FUNCTION__ ": No free buffer found, discarding data\n"); return NULL; } D_CTRL(__FUNCTION__ ": inbuffer %d was free\n",i); hci_ctrl.hci_in_buf[i].empty = FALSE; return &hci_ctrl.hci_in_buf[i];}s32hci_module_init(void){#ifdef __KERNEL__#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) init_waitqueue_head(&hci_wq); init_waitqueue_head(&inq_wq); init_waitqueue_head(&set_baudrate_wq); init_waitqueue_head(&test_wq); sema_init(&hci_cmd_semaphore, 1); sema_init(&hci_inq_semaphore, 1);#endif /* LINUX_VERSION_CODE */#endif /* __KERNEL__ */#ifdef CONFIG_BLUETOOTH_SUPPORT_BCSP hci_dfu_module_init();#endif return 0;}s32hci_init(void){ u32 i; DSYS("Initialising HCI\n");#ifdef HCI_EMULATION DSYS("*** HCI emulator on ***\n");#else DSYS("HCI emulator off\n");#endif DSYS("Initialising HCI inbuffers [%d]\n", HCI_IN_SIZE); /* Initiate the hci inbuffers */ for (i = 0; i < NBR_OF_HCI_INBUFFERS; i++) { hci_ctrl.hci_in_buf[i].buf_ptr = hci_ctrl.hci_in_buf[i].buf; hci_ctrl.hci_in_buf[i].count = 0; hci_ctrl.hci_in_buf[i].l2cap_len = 0; hci_ctrl.hci_in_buf[i].empty = TRUE; hci_ctrl.hci_in_buf[i].nbr_of_hci_pkt = 0; } for (i = 0; i < MAX_NBR_OF_CONNECTIONS; i ++) { hci_ctrl.con[i].state = NOT_CONNECTED; hci_ctrl.con[i].con_hdl = -1; } /* Here we set the buffer sizes to zero, just to avoid that they get undefined values if we fail to read the buffer sizes below */ hci_ctrl.hc_buf.acl_len = 0; hci_ctrl.hc_buf.sco_len = 0; hci_ctrl.hc_buf.acl_num = 0; hci_ctrl.hc_buf.sco_num = 0; init_cmd_buf(); hci_ctrl.nbr_of_connections = 0;#ifdef CONFIG_BLUETOOTH_SUPPORT_BCSP /* If we use bcsp cmd_num is set from command status event after syncronizing bcsp */ if (!bt_use_bcsp(-1)) { hci_ctrl.hc_buf.cmd_num = 1; }#else hci_ctrl.hc_buf.cmd_num = 1;#endif#ifdef __KERNEL__ send_data_task.routine = (void *)send_acl_data_task; send_data_task.data = NULL; if (bt_dfu_mode(-1)) return 0;#endif DSYS("Reading buffer sizes in HW module\n"); hci_read_buffer_size(HCI_BLOCK); DSYS("Reading firmware info in HW module\n"); hci_read_firmware_rev_info(); #ifdef HOST_FLOW_CTRL DSYS("Host flow control enabled\n"); hci_set_host_controller_flow_control(TRUE);#else DSYS("Host flow control not enabled\n");#endif hci_host_buffer_size(HCI_ACL_LEN,HCI_SCO_LEN,HCI_ACL_NUM,HCI_SCO_NUM);#ifdef USE_NCPTIMER start_ncp_timer(); #endif#ifdef CONFIG_BLUETOOTH_ENABLE_MSSWITCH DSYS("M/S switch enabled\n"); hci_force_msswitch(1);#else /* CONFIG_BLUETOOTH_ENABLE_MSSWITCH */ DSYS("M/S switch disabled\n"); hci_force_msswitch(0);#endif /* Check that hci initialized properly */ if (hci_ctrl.hc_buf.acl_num == 0) return -1; return 0;}void hci_shutdown(void){ /* take down any open acl links */ hci_ctrl.nbr_of_connections = 0;#ifdef USE_NCPTIMER release_ncp_timer();#endif#ifdef CONFIG_BLUETOOTH_SUPPORT_BCSP hci_shutdown_dfu();#endif}/* Start of the definition of the functions performing all the different HCI commands. The functions will be defined in the same order as they are described in the HCI specification, part H:1 of the bluetooh core specification. Functions that begins with hci_ can be reached from utside this file. *//* Definition of Link Control Commands *//* This function will cause the Bluetooth device to enter Inquiry Mode. Inquiry Mode is used to discover other nearby Bluetooth devices. The LAP input parameter contains the LAP from which the inquiry access code shall be derived when the inquiry procedure is made. The Inquiry_length parameter specifies the total duration of the Inquiry Mode and, when this time expires, Inquiry will be halted. The Num_Responses parameter specifies the number of responses that can be received before the Inquiry is halted.*/int hci_inquiry(u8 *lap, u8 inq_len, u8 num_resp, inquiry_results *results){ s32 tmp; D_CMD(__FUNCTION__ ": Sending inquiry()\n"); if (!results) return -EINVAL; inq_res = results; /* FIXME: Check if lap is valid first */ /* Set default lap */ lap[0] = 0x33; lap[1] = 0x8b; lap[2] = 0x9e; inq_res->nbr_of_units = 0; c_pkt.type = CMD_PKT; c_pkt.opcode = hci_put_opcode(INQUIRY, HCI_LC); memcpy(c_pkt.data, lap, 3); c_pkt.data[3] = inq_len; c_pkt.data[4] = num_resp; c_pkt.len = 5; print_data("hci_inquiry", (u8*) &c_pkt , c_pkt.len + CMD_HDR_LEN + HCI_HDR_LEN); tmp = send_inq_cmd_block((u8*) &c_pkt, c_pkt.len + CMD_HDR_LEN + HCI_HDR_LEN, inq_len); return tmp;}/* This function will cause the Link Manager to create a connection to the Bluetooth device with the BD_ADDR specified by the function parameters. This function causes the local Bluetooth device to begin the Page process to create a link level connection. The other parameters are psrm: Pagescan repetition mode; psm: Pagescan mode; c_off: Clock offset */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -