📄 hci.c
字号:
/* * hci.c -- Implementation of Bluetooth Host Controller Interface * (UART transport layer) * * Copyright (C) 2000, 2001 Axis Communications AB * * Author: Mats Friden <mats.friden@axis.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Exceptionally, Axis Communications AB grants discretionary and * conditional permissions for additional use of the text contained * in the company's release of the AXIS OpenBT Stack under the * provisions set forth hereunder. * * Provided that, if you use the AXIS OpenBT Stack with other files, * that do not implement functionality as specified in the Bluetooth * System specification, to produce an executable, this does not by * itself cause the resulting executable to be covered by the GNU * General Public License. Your use of that executable is in no way * restricted on account of using the AXIS OpenBT Stack code with it. * * This exception does not however invalidate any other reasons why * the executable file might be covered by the provisions of the GNU * General Public License. * * $Id: hci.c,v 1.187 2001/10/16 14:57:10 pkj Exp $ * *//****************** INCLUDE FILES SECTION ***********************************/#define __NO_VERSION__ /* don't define kernel_version in module.h */#ifdef __KERNEL__#include <linux/config.h>#include <linux/bluetooth/sysdep-2.1.h>#include <linux/malloc.h>#include <linux/timer.h>#include <linux/bluetooth/hci.h>#include <linux/bluetooth/hci_internal.h>#include <linux/bluetooth/btdebug.h>#include <linux/bluetooth/bluetooth.h>#include <linux/bluetooth/l2cap.h>#include <linux/bluetooth/l2cap_con.h>#include <linux/bluetooth/tcs.h>#include <linux/bluetooth/btmem.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/bluetooth/sec_client.h>#include <asm/io.h>#include <asm/byteorder.h>#include <asm/unaligned.h>#else /* user mode */#include <stdlib.h>#include <string.h>#include <errno.h>#include <asm/unaligned.h>#include "include/bluetooth.h"#include "include/hci.h"#include "include/hci_internal.h"#include "include/btdebug.h"#include "include/l2cap.h"#include "include/l2cap_con.h"#include "include/btmem.h"#include "include/tcs.h"#include "include/sec_client.h"#include "include/local.h"#endif/****************** CONSTANT AND MACRO SECTION ******************************/#define ACL_LINK 1#define SCO_LINK 0#define HCI_BLOCK 1#define HCI_NON_BLOCK 0/* If using host flow control, this is what we can store in our inbuffers */#define HCI_ACL_LEN 500#define HCI_SCO_LEN 255#define HCI_ACL_NUM 4#define HCI_SCO_NUM 2/* Now we will define all the different packet types */#define DM1 0x0008#define DM3 0x0400#define DM5 0x4000#define DH1 0x0010#define DH3 0x0800#define DH5 0x8000/* master slave switch stuff */#define MS_SWITCH_BECOME_MASTER 0x00#define MS_SWITCH_REMAIN_SLAVE 0x01#define DONT_ALLOW_ROLE_SWITCH 0x00#define ALLOW_ROLE_SWITCH 0x01#define HCI_SYNC_FIX#ifdef HCI_EMULATION#define ACL_NUM 10#define ACL_LEN 800 #define SCO_NUM 2#define SCO_LEN 100#define HCI_HDL 0#define ACL_CON 0x1#endif#define USE_NCPTIMER #define NCP_TIMEOUT (2*HZ)/****************** TYPE DEFINITION SECTION *********************************//* cmd_t and cmd_buf are structures used to handle the queue of commands waiting to be sent on the serial port */typedef struct cmd_t { u8* data; u8 len; /* max 255 */} cmd_t;struct cmd_buf { u32 first_free; /* index in cmd_buf */ u32 next_to_send; /* index in cmd_buf */ u8 count; cmd_t buf[NBR_CMD_BUFS];};/* These are the states the state machine in hci_receive_data can be in */enum states { WAIT_FOR_PACKET_TYPE, WAIT_FOR_EVENT_TYPE, WAIT_FOR_EVENT_LENGTH, WAIT_FOR_EVENT_PARAM, WAIT_FOR_ACL_HDR, WAIT_FOR_ACL_DATA, WAIT_FOR_SCO_HDR, WAIT_FOR_SCO_DATA, WAIT_FOR_TIMEOUT };#ifdef HCI_EMULATION/* If we are using the HCI emulation, we need a definition of the event packet to, see part H:1 chapter 4.4.2 of the baseband core specification for a description of the HCI event packet. */typedef struct event_struct { u8 pkt_type; u8 event_type; u8 len; u8 data[0];} __attribute__ ((packed)) event_struct;#endif/****************** LOCAL FUNCTION DECLARATION SECTION **********************/static void process_event(u8 *buf, u32 len, u32 event_code);static void process_return_param(u8 *buf);static void process_acl_data(hci_in_buffer* in_buf, u32 pb_flag);static void process_sco_packet(u8 *data, u32 hci_hdl, u32 len);static hci_in_buffer* get_inbuffer(u32 hci_hdl);static hci_in_buffer* get_free_inbuffer(void);static u32 send_acl_packet(bt_tx_buf *tx_buf);static void set_acl_hdr(u8 *data, u32 len, u8 pb, u8 bc, u32 hci_hdl);static u16 hci_handle(void *data);static cmd_t* get_next_cmd(void); static s32 insert_cmd(u8* cmd, u8 len); static void init_cmd_buf(void);static void send_cmd_queue(void);static void update_nhcp(s32 nhcp);static s32 send_inq_cmd_block(u8 *cmd, u8 len, u8 inq_len);#ifdef CONFIG_BLUETOOTH_USE_SECURITY_MANAGERstatic u8* get_bd(u16 con_hdl);#endifstatic s32 get_con_hdl(u8 *bd);/* Link Control Commands */static s32 create_connection(u8 *bd, u32 pkt_type, u8 psrm, u8 psm, u32 c_off, u32 rol_sw);static s32 disconnect(u32 hdl, u8 reason);static s32 accept_connection_request(u8 bd_addr[], u8 role);static s32 reject_connection_request(u8 bd_addr[], u32 reason);static s32 change_connection_packet_type(u32 hci_hdl, u32 pkt_type);static s32 remote_name_request(u8 *bd);/* Link Policy Commands */static s32 role_discovery(u16 con_hdl);static s32 write_link_policy_settings(u16 con_hdl, u16 settings);/* Host Controller and Baseband Commands */static s32 write_inquiryscan_activity(u32 interval, u32 wind);static s32 write_automatic_flush_timeout(u16 con_hdl, u16 n);static s32 hci_set_host_controller_flow_control(u32 enable);static s32 hci_host_buffer_size(u16 acl_len, u8 sco_len, u16 acl_num, u16 sco_num);static s32 host_nbrcompleted_packets(u32 hci_hdl, u32 nbr_of_packets);/* Informational Parameters (HCI_IP) *//* Other functions */static s32 hci_update_load_factor(void);static s32 hci_read_buffer_size(s32 block); static void set_hci_con(u8 *bd, s32 con_hdl);static void set_hci_con_name(u8 *bd, u8 *name);static void reset_hci_con_bd(u16 con_hdl);#ifdef USE_NCPTIMERstatic void start_ncp_timer(void);static void release_ncp_timer(void);#endif#define USE_INQTIMER 1#ifdef USE_INQTIMERstatic void start_inq_timer(u8 inq_len);static void release_inq_timer(void);#endif#ifdef __KERNEL__#ifdef USE_NCPTIMERstatic void ncp_timeout(unsigned long ptr);#endifstatic void cmd_timeout(unsigned long ptr);#ifdef USE_INQTIMERstatic void inq_timeout(unsigned long ptr);#endif#endif#ifdef HCI_EMULATIONstatic void hci_emulator(u8 *data, u32 len);static void command_handler(u8 *data);static s32 set_cmd_status_event(event_struct *event, u8 *cmd);static s32 set_con_req_event(event_struct *event, u8 *bd, u8 con_type);static s32 set_con_cpl_event(event_struct *event, u8 status, u8 *bd, u16 hci_hdl,u8 con_type);static s32 set_discon_cpl_event(event_struct *event, u16 hci_hdl, u8 reason);#endifstatic void send_acl_data_task(void);/****************** LOCAL VARIABLE DECLARATION SECTION **********************/static struct cmd_buf cmd_buf;/* Struct used for sending command packets */cmd_pkt c_pkt;/* The states for the switch-statement in hci_receive_data fuction */static enum states state;/* General HCI controller struct, contains vital information about buffer sizes and connections */hci_controller hci_ctrl = {{0, 0, 0, 0, 0}}; #ifdef __KERNEL__#ifdef USE_NCPTIMERstatic struct timer_list hci_ncp_timer;#endifstatic struct timer_list hci_cmd_timer;#ifdef USE_INQTIMERstatic struct timer_list hci_inq_timer;#endif#ifdef USE_NCPTIMERstatic struct hw_info { u32 max_acl_num; u32 acl_num_count; /* since last timeout */} hw;#endif/* ================================= */static struct tq_struct send_cmd_task;static struct tq_struct send_data_task;/* semaphore for protecting shared data */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)static struct semaphore hci_cmd_semaphore = MUTEX;static struct semaphore hci_inq_semaphore = MUTEX;#elsestatic struct semaphore hci_cmd_semaphore;static struct semaphore hci_inq_semaphore;#endif /* LINUX_VERSION_CODE */#endif /* __KERNEL__ */static u32 hci_cmd_pending = 0;static u32 hci_inq_pending = 0;static u8 hci_inq_aborted = 0;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)struct wait_queue *hci_wq = NULL;struct wait_queue *inq_wq = NULL;struct wait_queue *set_baudrate_wq = NULL;struct wait_queue *test_wq = NULL;#elsewait_queue_head_t hci_wq;wait_queue_head_t inq_wq;wait_queue_head_t set_baudrate_wq;wait_queue_head_t test_wq;#endif /* LINUX_VERSION_CODE */static s32 test_wq_active = 0;static s32 result_param;static struct inquiry_results *inq_res = NULL;static s32 test_hci_hdl;/* temp solution to handle m/s switch */static s32 force_msswitch = 0;static s32 i_am_initiator = 0;/* In order to change load factor, store the other class of device parameters */static u8 class_of_device[3];/* If maximum BT connections is not set from above, use 7 as default */int bt_max_connections = 7;/****************** FUNCTION DEFINITION SECTION *****************************//* * Parses the serial data and sends it to either the parse_acl_packet, * parse_sco_packet or the parse_event_packet, depending on the packet type */voidhci_receive_data(u8* data, u32 count){ static u32 event_len; static u32 data_len; static u32 event_type; static u32 pb_flag; static u32 bc_flag; static u32 hci_hdl; static u8 event_buf[256]; static u8 hdr[4]; static hci_in_buffer *in_buf; static u32 tmp_pos; u32 c; /* Temporary variable for index calculations */ u8 *buf; /* Temporary pointer to the incoming data */ u32 tmp_data_len; PRINTPKT(__FUNCTION__ ": ", data, count); tmp_data_len = count; buf = data; /* Here we get a chunk of data from the serial port. When a complete packet is received it is copied into a buffer and sent to the processing function */ D_INDATA(__FUNCTION__ ": hci-%d\n", tmp_data_len); while (count > 0) { switch (state) { /* The first byte will tell us whether it is an event or a data packet */ case WAIT_FOR_PACKET_TYPE: D_STATE(__FUNCTION__ ": WAIT_FOR_PACKET_TYPE\n"); tmp_pos = 0; switch(*buf) { case EVENT_PKT: state = WAIT_FOR_EVENT_TYPE; break; case ACL_PKT: state = WAIT_FOR_ACL_HDR; break; case SCO_PKT: state = WAIT_FOR_SCO_HDR; break; default: D_ERR(__FUNCTION__ ": discarding %d bytes\n", count); /* An unrecognized HCI header type is usually a * sign of a problem with the lower level * driver. For example, if the UART drops some * bytes due to high interrupt latency. In this * case we'll try to resync by just dropping * this buffer and trying again at the start of * the next one. * --gmcnutt */ return; } buf++; count--; break; /* If it is an event packet we wait for the next byte which tell us which kind of event it is */ case WAIT_FOR_EVENT_TYPE: D_STATE(__FUNCTION__ ": WAIT_FOR_EVENT_TYPE\n"); event_type = *buf; state = WAIT_FOR_EVENT_LENGTH; buf++; count--; break; /* If it is an event the length-field is one byte */ case WAIT_FOR_EVENT_LENGTH: D_STATE(__FUNCTION__ ": WAIT_FOR_EVENT_LENGTH\n"); event_len = *buf; buf++; count--; /* If we don't check this and the lower level driver gives us some trashed values then we might write beyond the end of our event buffer in a memcpy below. --gmcnutt */ if (event_len > sizeof(event_buf)) { D_ERR(__FUNCTION__ ": %d is too big for our "\ "event buffer -- discarding buffer\n", event_len); state = WAIT_FOR_PACKET_TYPE; return; } if (event_len <= count) { process_event(buf, event_len, event_type); buf += event_len; count -= event_len; state = WAIT_FOR_PACKET_TYPE; } else { state = WAIT_FOR_EVENT_PARAM; } break; /* Before we can parse the event, we wait for the whole event */ case WAIT_FOR_EVENT_PARAM: D_STATE(__FUNCTION__ ": WAIT_FOR_EVENT_PARAM\n"); if (tmp_pos < event_len) { c = MIN(count, event_len - tmp_pos); memcpy(event_buf + tmp_pos, buf, c); tmp_pos += c; count -= c; buf += c; if (tmp_pos == event_len) { process_event(event_buf, event_len, event_type); state = WAIT_FOR_PACKET_TYPE; } } break; /* Here we wait for the whole data header, four bytes*/ case WAIT_FOR_ACL_HDR: D_STATE(__FUNCTION__ ": WAIT_FOR_ACL_HDR\n"); c = MIN(count, ACL_HDR_LEN - tmp_pos); memcpy(hdr + tmp_pos, buf, c); tmp_pos += c; buf += c; count -= c; if (tmp_pos == ACL_HDR_LEN) { u32 tmp_hdr = le32_to_cpuu(hdr); 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); /* 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); state = WAIT_FOR_PACKET_TYPE; return; } if (pb_flag == L2CAP_FRAME_START) { D_REC(__FUNCTION__ ": New 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 frame\n"); in_buf = get_inbuffer(hci_hdl); if (in_buf) { in_buf->nbr_of_hci_pkt++; } } host_nbrcompleted_packets(hci_hdl, 1); /* When we change state we reset data_index, because we are using separate buffers for
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -