📄 hci.c
字号:
/*
* Copyright (c) 2003 EISLAB, Lulea University of Technology.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwBT Bluetooth stack.
*
* Author: Conny Ohult <conny@sm.luth.se>
*
*/
/*-----------------------------------------------------------------------------------*/
/* hci.c
*
* Implementation of the Host Controller Interface (HCI). A command interface to the
* baseband controller and link manager, and gives access to hardware status and
* control registers.
*
*/
/*-----------------------------------------------------------------------------------*/
#include "lwbtopts.h"
#include "phybusif.h"
#include "netif/lwbt/hci.h"
#include "netif/lwbt/l2cap.h"
#include "netif/lwbt/lwbt_memp.h"
#include "lwip/debug.h"
/* The HCI LINK lists. */
struct hci_link *hci_active_links; /* List of all active HCI LINKs */
struct hci_link *hci_tmp_link;
struct hci_pcb *pcb;
/*-----------------------------------------------------------------------------------*/
/*
* hci_init():
*
* Initializes the HCI layer.
*/
/*-----------------------------------------------------------------------------------*/
err_t
hci_init(void)
{
if((pcb = lwbt_memp_malloc(MEMP_HCI_PCB)) == NULL) {
LWIP_DEBUGF(HCI_DEBUG, ("hci_init: Could not allocate memory for pcb\n"));
return ERR_MEM;
}
memset(pcb, 0, sizeof(struct hci_pcb));
/* Clear globals */
hci_active_links = NULL;
hci_tmp_link = NULL;
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
/*
* hci_new():
*
* Creates a new HCI link control block
*/
/*-----------------------------------------------------------------------------------*/
struct hci_link *
hci_new(void)
{
struct hci_link *link;
link = lwbt_memp_malloc(MEMP_HCI_LINK);
if(link != NULL) {
memset(link, 0, sizeof(struct hci_link));
return link;
}
LWIP_DEBUGF(HCI_DEBUG, ("hci_new: Could not allocate memory for link\n"));
return NULL;
}
/*-----------------------------------------------------------------------------------*/
/*
* hci_close():
*
* Close the link control block.
*/
/*-----------------------------------------------------------------------------------*/
err_t
hci_close(struct hci_link *link)
{
#if RFCOMM_FLOW_QUEUEING
if(link->p != NULL) {
pbuf_free(link->p);
}
#endif
HCI_RMV(&(hci_active_links), link);
lwbt_memp_free(MEMP_HCI_LINK, link);
link = NULL;
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
/*
* hci_reset_all():
*
* Closes all active link control blocks.
*/
/*-----------------------------------------------------------------------------------*/
void
hci_reset_all(void)
{
struct hci_link *link, *tlink;
struct hci_inq_res *ires, *tires;
for(link = hci_active_links; link != NULL;) {
tlink = link->next;
hci_close(link);
link = tlink;
}
hci_active_links = NULL;
for(ires = pcb->ires; ires != NULL;) {
tires = ires->next;
lwbt_memp_free(MEMP_HCI_INQ, ires);
ires = tires;
}
lwbt_memp_free(MEMP_HCI_PCB, pcb);
hci_init();
}
/*-----------------------------------------------------------------------------------*/
/*
* hci_arg():
*
* Used to specify the argument that should be passed callback
* functions.
*/
/*-----------------------------------------------------------------------------------*/
void
hci_arg(void *arg)
{
pcb->callback_arg = arg;
}
/*-----------------------------------------------------------------------------------*/
/*
* hci_cmd_complete():
*
* Used to specify the function that should be called when HCI has received a
* command complete event.
*/
/*-----------------------------------------------------------------------------------*/
void
hci_cmd_complete(err_t (* cmd_complete)(void *arg, struct hci_pcb *pcb, u8_t ogf,
u8_t ocf, u8_t result))
{
pcb->cmd_complete = cmd_complete;
}
/*-----------------------------------------------------------------------------------*/
/*
* hci_pin_req():
*
* Used to specify the function that should be called when HCI has received a
* PIN code request event.
*/
/*-----------------------------------------------------------------------------------*/
void
hci_pin_req(err_t (* pin_req)(void *arg, struct bd_addr *bdaddr))
{
pcb->pin_req = pin_req;
}
/*-----------------------------------------------------------------------------------*/
/*
* hci_link_key_not():
*
* Used to specify the function that should be called when HCI has received a
* link key notification event.
*/
/*-----------------------------------------------------------------------------------*/
void
hci_link_key_not(err_t (* link_key_not)(void *arg, struct bd_addr *bdaddr, u8_t *key))
{
pcb->link_key_not = link_key_not;
}
/*-----------------------------------------------------------------------------------*/
/*
* hci_connection_complete():
*
* Used to specify the function that should be called when HCI has received a
* connection complete event.
*/
/*-----------------------------------------------------------------------------------*/
void
hci_connection_complete(err_t (* conn_complete)(void *arg, struct bd_addr *bdaddr))
{
pcb->conn_complete = conn_complete;
}
/*-----------------------------------------------------------------------------------*/
/*
* hci_wlp_complete():
*
* Used to specify the function that should be called when HCI has received a
* successful write link policy complete event.
*/
/*-----------------------------------------------------------------------------------*/
void
hci_wlp_complete(err_t (* wlp_complete)(void *arg, struct bd_addr *bdaddr))
{
pcb->wlp_complete = wlp_complete;
}
/*-----------------------------------------------------------------------------------*/
/*
* hci_get_link():
*
* Used to get the link structure for that represents an ACL connection.
*/
/*-----------------------------------------------------------------------------------*/
struct hci_link *
hci_get_link(struct bd_addr *bdaddr)
{
struct hci_link *link;
for(link = hci_active_links; link != NULL; link = link->next) {
if(bd_addr_cmp(&(link->bdaddr), bdaddr)) {
break;
}
}
return link;
}
/*-----------------------------------------------------------------------------------*/
/*
* hci_acl_input():
*
* Called by the physical bus interface. Handles host controller to host flow control,
* finds a bluetooth address that correspond to the connection handle and forward the
* packet to the L2CAP layer.
*/
/*-----------------------------------------------------------------------------------*/
void
hci_acl_input(struct pbuf *p)
{
struct hci_acl_hdr *aclhdr;
struct hci_link *link;
u16_t conhdl;
pbuf_header(p, HCI_ACL_HDR_LEN);
aclhdr = p->payload;
pbuf_header(p, -HCI_ACL_HDR_LEN);
conhdl = aclhdr->conhdl_pb_bc & 0x0FFF; /* Get the connection handle from the first
12 bits */
if(pcb->flow) {
//TODO: XXX??? DO WE SAVE NUMACL PACKETS COMPLETED IN LINKS LIST?? SHOULD WE CALL
//hci_host_num_comp_packets from the main loop when no data has been received from the
//serial port???
--pcb->host_num_acl;
if(pcb->host_num_acl == 0) {
hci_host_num_comp_packets(conhdl, HCI_HOST_MAX_NUM_ACL);
pcb->host_num_acl = HCI_HOST_MAX_NUM_ACL;
}
}
for(link = hci_active_links; link != NULL; link = link->next) {
if(link->conhdl == conhdl) {
break;
}
}
if(link != NULL) {
if(aclhdr->len) {
LWIP_DEBUGF(HCI_DEBUG, ("hci_acl_input: Forward ACL packet to higher layer p->tot_len = %d\n", p->tot_len));
l2cap_input(p, &(link->bdaddr));
} else {
pbuf_free(p); /* If length of ACL packet is zero, we silently discard it */
}
} else {
pbuf_free(p); /* If no acitve ACL link was found, we silently discard the packet */
}
}
/*-----------------------------------------------------------------------------------*/
#if HCI_EV_DEBUG
u8_t *
hci_get_error_code(u8_t code) {
switch(code) {
case HCI_SUCCESS:
return("Success");
case HCI_UNKNOWN_HCI_COMMAND:
return("Unknown HCI Command");
case HCI_NO_CONNECTION:
return("No Connection");
case HCI_HW_FAILURE:
return("Hardware Failure");
case HCI_PAGE_TIMEOUT:
return("Page Timeout");
case HCI_AUTHENTICATION_FAILURE:
return("Authentication Failure");
case HCI_KEY_MISSING:
return("Key Missing");
case HCI_MEMORY_FULL:
return("Memory Full");
case HCI_CONN_TIMEOUT:
return("Connection Timeout");
case HCI_MAX_NUMBER_OF_CONNECTIONS:
return("Max Number Of Connections");
case HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE:
return("Max Number Of SCO Connections To A Device");
case HCI_ACL_CONNECTION_EXISTS:
return("ACL connection already exists");
case HCI_COMMAND_DISSALLOWED:
return("Command Disallowed");
case HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES:
return("Host Rejected due to limited resources");
case HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS:
return("Host Rejected due to security reasons");
case HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE:
return("Host Rejected due to remote device is only a personal device");
case HCI_HOST_TIMEOUT:
return("Host Timeout");
case HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE:
return("Unsupported Feature or Parameter Value");
case HCI_INVALID_HCI_COMMAND_PARAMETERS:
return("Invalid HCI Command Parameters");
case HCI_OTHER_END_TERMINATED_CONN_USER_ENDED:
return("Other End Terminated Connection: User Ended Connection");
case HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES:
return("Other End Terminated Connection: Low Resources");
case HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF:
return("Other End Terminated Connection: About to Power Off");
case HCI_CONN_TERMINATED_BY_LOCAL_HOST:
return("Connection Terminated by Local Host");
case HCI_REPETED_ATTEMPTS:
return("Repeated Attempts");
case HCI_PAIRING_NOT_ALLOWED:
return("Pairing Not Allowed");
case HCI_UNKNOWN_LMP_PDU:
return("Unknown LMP PDU");
case HCI_UNSUPPORTED_REMOTE_FEATURE:
return("Unsupported Remote Feature");
case HCI_SCO_OFFSET_REJECTED:
return("SCO Offset Rejected");
case HCI_SCO_INTERVAL_REJECTED:
return("SCO Interval Rejected");
case HCI_SCO_AIR_MODE_REJECTED:
return("SCO Air Mode Rejected");
case HCI_INVALID_LMP_PARAMETERS:
return("Invalid LMP Parameters");
case HCI_UNSPECIFIED_ERROR:
return("Unspecified Error");
case HCI_UNSUPPORTED_LMP_PARAMETER_VALUE:
return("Unsupported LMP Parameter Value");
case HCI_ROLE_CHANGE_NOT_ALLOWED:
return("Role Change Not Allowed");
case HCI_LMP_RESPONSE_TIMEOUT:
return("LMP Response Timeout");
case HCI_LMP_ERROR_TRANSACTION_COLLISION:
return("LMP Error Transaction Collision");
case HCI_LMP_PDU_NOT_ALLOWED:
return("LMP PDU Not Allowed");
case HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE:
return("Encryption Mode Not Acceptable");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -