📄 hci.c
字号:
the HCI header and the HCI data */ tmp_pos = 0; state = WAIT_FOR_ACL_DATA; } else if (tmp_pos < ACL_HDR_LEN) { D_REC(__FUNCTION__ ": Didn't got whole header length, waiting for more\n"); } else { D_ERR(__FUNCTION__ ": incorredt ACL header length\n"); } break; /* Finally we process the data, i.e we wait for the whole data packet and then we send it to a higher protocol layer, in this case the L2CAP-layer */ case WAIT_FOR_ACL_DATA: D_STATE(__FUNCTION__ ": WAIT_FOR_ACL_DATA\n"); /* Find out how much data we can copy, don't copy more than one HCI packet at time */ c = MIN(count, data_len - tmp_pos); if (in_buf) { memcpy(in_buf->buf_ptr, buf, c); in_buf->buf_ptr += c; in_buf->count += c; D_REC(__FUNCTION__ ": in_buf->count = %d\n",in_buf->count); } /* Increase the data_index and decrease the amount of data */ tmp_pos += c; count -= c; D_REC(__FUNCTION__ ": Copied %d bytes into inbuffer\n",c); if (tmp_pos == data_len) { if (in_buf) { process_acl_data(in_buf, pb_flag); } else { D_ERR("invalid inbuffer\n"); } state = WAIT_FOR_PACKET_TYPE; } buf += c; break; /* wait for the SCO header, three bytes */ case WAIT_FOR_SCO_HDR: D_STATE(__FUNCTION__ ": WAIT_FOR_SCO_HDR\n"); if (tmp_pos < SCO_HDR_LEN) { c = MIN(count,SCO_HDR_LEN - tmp_pos); memcpy(hdr + tmp_pos, buf, c); tmp_pos += c; buf += c; count -= c; if (tmp_pos == SCO_HDR_LEN) { hci_hdl = hci_handle(hdr); data_len = hdr[2]; tmp_pos = 0; state = WAIT_FOR_SCO_DATA; } } break; /* Wait for the rest of the SCO packet and send it to the tty */ case WAIT_FOR_SCO_DATA: D_STATE(__FUNCTION__ ": WAIT_FOR_SCO_DATA\n"); c = MIN(count, data_len - tmp_pos); process_sco_packet(buf, hci_hdl, c); tmp_pos += c; buf += c; count -= c; if (tmp_pos == data_len) { state = WAIT_FOR_PACKET_TYPE; /* FIXME - Send the data to the audio tty */ } break; default: D_ERR(__FUNCTION__ ": Oops shouldn't be possible...\n"); break; } }}#ifdef CONFIG_BLUETOOTH_SUPPORT_BCSPvoidhci_receive_event(u8 *data, s32 count){ u8 event_type, event_len; u8 *tmp_buf; tmp_buf = data; while (count > 0) { event_type = tmp_buf[0]; event_len = tmp_buf[1]; tmp_buf += EVENT_HDR_LEN; count -= EVENT_HDR_LEN; D_REC(__FUNCTION__ ": Received event 0x%02x with len:%d\n", event_type, event_len); process_event(tmp_buf, event_len, event_type); tmp_buf += event_len; count -= event_len; }}voidhci_receive_acl(u8 *data, s32 count){ u8 *tmp_buf; u16 hci_hdl; u8 pb_flag; u8 bc_flag; u16 data_len; hci_in_buffer *in_buf; tmp_buf = data; while (count > 0) { u32 tmp_hdr = le32_to_cpuu(tmp_buf); /* Parse the ACL header */ hci_hdl = GET_BITS(tmp_hdr, 0, 12); pb_flag = GET_BITS(tmp_hdr, 12, 2); bc_flag = GET_BITS(tmp_hdr, 14, 2); data_len = GET_BITS(tmp_hdr, 16, 16); tmp_buf += ACL_HDR_LEN; count -= ACL_HDR_LEN; /* Check the length to make sure we won't overrun in_buf->buf_ptr in a memcpy later. --gmcnutt */ if (data_len > HCI_IN_SIZE) { D_ERR(__FUNCTION__ ": %d is too big "\ "for our HCI input buffers -- "\ "discarding buffer\n", data_len); return; } if (pb_flag == L2CAP_FRAME_START) { D_REC(__FUNCTION__ ": New L2CAP frame\n"); in_buf = get_free_inbuffer(); if (in_buf) { in_buf->nbr_of_hci_pkt = 1; in_buf->hci_hdl = hci_hdl; } } else { D_REC(__FUNCTION__ ": Cont L2CAP frame\n"); in_buf = get_inbuffer(hci_hdl); if (in_buf) { in_buf->nbr_of_hci_pkt++; } } if (in_buf) { memcpy(in_buf->buf_ptr, tmp_buf, data_len); D_REC(__FUNCTION__ ": Copied %d bytes into inbuffer\n", data_len); in_buf->buf_ptr += data_len; in_buf->count += data_len; D_REC(__FUNCTION__ ": in_buf->count: %d\n", in_buf->count); } else { D_ERR(__FUNCTION__ ": No inbuffer was found, "\ "discarding data\n"); return; } /* Decrease the amount of remaining data */ count -= data_len; process_acl_data(in_buf, pb_flag); tmp_buf += data_len; }}#endifs32hci_trig_send(void){#ifdef __KERNEL__ if (buf_count() && (hci_ctrl.hc_buf.acl_num > 0)) {#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) queue_task(&send_data_task, &tq_scheduler);#else queue_task(&send_data_task, &tq_immediate); mark_bh(IMMEDIATE_BH);#endif return TRUE; } else { return FALSE; }#else /* FIXME? */ return FALSE;#endif}s32hci_acl_num_cnt(void){ return hci_ctrl.hc_buf.acl_num;}voidupdate_ncp(u8 nbr_of_hdl, u8 *pkt){ s32 i;#ifdef __KERNEL__ unsigned long flags; save_flags(flags); cli();#endif D_REC(__FUNCTION__ ": acl_num before: %d\n", hci_ctrl.hc_buf.acl_num); /* FIXME */ /* Check if we have to register which connection handlers that have been sent, or if we just need to know how many packets that have been sent */ for (i = 0; i < 4 * nbr_of_hdl; i += 4) { hci_ctrl.hc_buf.acl_num += le16_to_cpuu(&pkt[i+2]); } D_QUEUE("<NCP:%d>\n", hci_ctrl.hc_buf.acl_num); D_REC(__FUNCTION__ ": acl_num after: %d\n", hci_ctrl.hc_buf.acl_num); /* We've just been notified that the hardware has free buffers. If we have any outstanding packets, send_acl_data_task will try to send as many packets as possible. */#ifdef __KERNEL__ if (buf_count()) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) queue_task(&send_data_task, &tq_scheduler);#else queue_task(&send_data_task, &tq_immediate); mark_bh(IMMEDIATE_BH);#endif }#ifdef USE_NCPTIMER hw.acl_num_count += hci_ctrl.hc_buf.acl_num;#endif bt_feedstack(); restore_flags(flags);#else if (buf_count()) send_acl_data_task();#endif }/* * Parses an eventpacket, buf is the event parameters, length the event length * and event_code is the event's opcode */voidprocess_event(u8 *buf, u32 len, u32 event_code){ u16 hci_hdl; s32 i; PRINTPKT(__FUNCTION__, buf, len); switch (event_code) { case INQUIRY_COMPLETE: D_CMD("INQUIRY_COMPLETE\n"); hci_inq_pending = 0;#if USE_INQTIMER release_inq_timer();#endif wake_up_interruptible(&inq_wq);#ifndef __KERNEL__ for (i = 0; i < inq_res->nbr_of_units; i++) { D_CMD(__FUNCTION__ ": BD %d: %02x:%02x:%02x:%02x:%02x:%02x\n",i, inq_res->bd_addr[0+6*i],inq_res->bd_addr[1+6*i], inq_res->bd_addr[2+6*i],inq_res->bd_addr[3+6*i], inq_res->bd_addr[4+6*i],inq_res->bd_addr[5+6*i]); }#endif break; case INQUIRY_RESULT: { s32 j; u8 tmp_bd[6]; D_CMD(__FUNCTION__ ": INQUIRY_RESULT\n"); for(i = 1; i < (buf[0] * 14) + 1; i += 14) { printk("BD addr %d\n", i % 14); for (j = 0; j < 6; j++) { tmp_bd[5-j] = buf[i + j]; } print_data("BD", tmp_bd, 6); for (j = 0; j < inq_res->nbr_of_units; j++) { if (!memcmp(inq_res->bd_addr + j * 6, tmp_bd, 6)) { break; } } if (j >= inq_res->nbr_of_units) { memcpy(inq_res->bd_addr + inq_res->nbr_of_units * 6, tmp_bd, 6); inq_res->nbr_of_units++; } } break; } case CONNECTION_COMPLETE: { u8 link_type; D_CMD(__FUNCTION__ ": CONNECTION_COMPLETE: %s\n", get_err_msg(buf[0])); link_type = buf[9]; hci_hdl = hci_handle(&buf[1]); test_hci_hdl = hci_hdl; if (link_type == ACL_LINK) { if (lp_connect_cfm(buf + 3, (u32) buf[0], hci_hdl)) { hci_ctrl.nbr_of_connections++; hci_update_load_factor(); }#ifndef HCI_EMULATION if (buf[0]) { /* remove hci handle if connection failed */ DSYS(__FUNCTION__ ": CONNECTION_COMPLETE %s\n", get_err_msg(buf[0])); reset_hci_con_bd(hci_hdl); } else { DSYS(__FUNCTION__ ": ACL link is up\n");#ifdef CONFIG_BLUETOOTH_ERICSSON change_connection_packet_type(hci_hdl, DM3|DH3|DM5|DH5);#else change_connection_packet_type(hci_hdl, DM1|DH1|DM3|DH3|DM5|DH5);#endif set_hci_con(buf + 3, hci_hdl); remote_name_request(buf + 3); /* enable m/s switch */ write_link_policy_settings(hci_hdl, 0x01); /* we demand role switch as server */ if (force_msswitch && !i_am_initiator) { /* FIXME -- check return code */#ifndef CONFIG_BLUETOOTH_EARLY_MSSWITCH hci_switch_role(buf + 3, 0);#endif } /* reset variable again */ i_am_initiator = 0; }#endif /* HCI_EMULATION */ if (test_wq_active) { test_wq_active = 0; wake_up_interruptible(&test_wq); } } else { hci_ctrl.nbr_of_connections++; hci_update_load_factor(); tcs_add_sco_link(buf[0], hci_hdl); } break; } case CONNECTION_REQUEST: D_CMD(__FUNCTION__ ": CONNECTION_REQUEST\n"); if (buf[9] == ACL_LINK) { lp_connect_ind(buf); /* BD_ADDRESS */ } else { printk(__FUNCTION__ ": CONNECTION_REQUEST for SCO LINK"); accept_connection_request(buf, 0x01); /* role ignored for SCO */ } break; case DISCONNECTION_COMPLETE: DSYS(__FUNCTION__ ": DISCONNECTION_COMPLETE %s\n", get_err_msg(buf[3])); release_cmd_timer(); wake_up_interruptible(&hci_wq); if (lp_disconnect_ind(hci_handle(&buf[1]))) if (hci_ctrl.nbr_of_connections > 0) { hci_ctrl.nbr_of_connections--; hci_update_load_factor(); } /* FIXME: No more NBR_OF_COMPLETE_PACKETS will arrive for this connection handle, if we only support point-to-point connections we can acl_num by reading the buffersizes again, but this will not work in a multipoint connection. */ reset_hci_con_bd(hci_handle(&buf[1])); if (hci_ctrl.nbr_of_connections <= 0) { hci_read_buffer_size(HCI_NON_BLOCK); } break; case AUTHENTICATION_COMPLETE: DSYS(__FUNCTION__ ": AUTHENTICATION_COMPLETE\n"); release_cmd_timer(); #ifdef CONFIG_BLUETOOTH_USE_SECURITY_MANAGER if (buf[0]) { D_ERR(__FUNCTION__ ": AUTHENTICATION_COMPLETE: %s\n", get_err_msg(buf[0])); } sec_man_event(HCI, get_bd(hci_handle(&buf[1])), AUTHENTICATION_COMPLETE, buf, 1);#endif wake_up_interruptible(&hci_wq); break; case REMOTE_NAME_REQUEST_COMPLETE: D_CMD(__FUNCTION__ ": REMOTE_NAME_REQUEST_COMPLETE %s\n", buf + 7); if (buf[0]) { D_ERR(__FUNCTION__ ": REMOTE_NAME_REQUEST_COMPLETE: %s\n", get_err_msg(buf[0])); } else { if (strlen(buf + 7) > 248) { D_ERR(__FUNCTION__ ": REMOTE_NAME_REQUEST_COMPLETE: too long name length %d\n", (int)strlen(buf + 7)); break; } set_hci_con_name(buf + 1, buf + 7); } break; case ENCRYPTION_CHANGE: DSYS(__FUNCTION__ ": ENCRYPTION_CHANGE\n"); release_cmd_timer();#ifdef CONFIG_BLUETOOTH_USE_SECURITY_MANAGER if (buf[0]) { D_ERR(__FUNCTION__ ": ENCRYPTION_CHANGE: %s\n", get_err_msg(buf[0])); } { u8 tmp[2]; tmp[0] = buf[0]; tmp[1] = buf[3]; sec_man_event(HCI, get_bd(hci_handle(&buf[1])), ENCRYPTION_CHANGE, tmp, 2); }#endif wake_up_interruptible(&hci_wq); break; case CHANGE_CONNECTION_LINK_KEY_COMPLETE: DSYS(__FUNCTION__ ": CHANGE_CONNECTION_LINK_KEY_COMPLETE Not implemented!\n"); break; case MASTER_LINK_KEY_COMPLETE: DSYS(__FUNCTION__ ": MASTER_LINK_KEY_COMPLETE Not implemented!\n"); break; case READ_REMOTE_SUPPORTED_FEATURES_COMPLETE: DSYS(__FUNCTION__ ": READ_REMOTE_SUPPORTED_FEATURES_COMPLETE Not implemented!\n"); break; case READ_REMOTE_VERSION_INFORMATION_COMPLETE: DSYS(__FUNCTION__ ": READ_REMOTE_VERSION_INFORMATION_COMPLETE Not implemented!\n"); break; case QOS_SETUP_COMPLETE: DSYS(__FUNCTION__ ": QOS_SETUP_COMPLETE\n"); break; case COMMAND_COMPLETE: D_CMD(__FUNCTION__ ": COMMAND_COMPLETE\n"); /* FIXME - stop any outstanding send timers if cmd_num is > 0*/ D_QUEUE("<CC>\n"); process_return_param(buf); update_nhcp(buf[0]); break; /* used to prevent host from waiting on reply when a command has been received in HW and is currently performing the task for this command */ case COMMAND_STATUS: release_cmd_timer();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -