www.pudn.com > 蓝牙协议源代码.zip > 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  
 * 
 */ 
 
/*-----------------------------------------------------------------------------------*/ 
/* 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"); 
  case HCI_UNIT_KEY_USED: 
    return("Unit Key Used"); 
  case HCI_QOS_NOT_SUPPORTED: 
    return("QoS is Not Supported"); 
  case HCI_INSTANT_PASSED: 
    return("Instant Passed"); 
  case HCI_PAIRING_UNIT_KEY_NOT_SUPPORTED: 
    return("Pairing with Unit Key Not Supported"); 
  default: 
    return("Error code unknown"); 
  } 
} 
#else 
u8_t * 
hci_get_error_code(u8_t code)  
{ 
  return 0; 
} 
#endif /* HCI_EV_DEBUG */ 
/*-----------------------------------------------------------------------------------*/ 
/* hci_event_input(): 
 * 
 * Called by the physical bus interface. Parses the received event packet to determine  
 * which event occurred and handles it. 
 */ 
 /*-----------------------------------------------------------------------------------*/ 
void 
hci_event_input(struct pbuf *p) 
{ 
  struct hci_inq_res *inqres; 
  struct hci_event_hdr *evhdr; 
  struct hci_link *link; 
  u8_t i, j; 
  struct bd_addr *bdaddr; 
  u8_t resp_offset; 
  err_t ret; 
  u8_t ocf, ogf; 
 
  pbuf_header(p, HCI_EVENT_HDR_LEN); 
  evhdr = p->payload; 
  pbuf_header(p, -HCI_EVENT_HDR_LEN); 
 
  switch(evhdr->code) { 
  case HCI_INQUIRY_COMPLETE: 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Inquiry complete, 0x%x %s\n", ((u8_t *)p->payload)[0], hci_get_error_code(((u8_t *)p->payload)[0]))); 
    HCI_EVENT_INQ_COMPLETE(pcb,((u8_t *)p->payload)[0],ret); 
    break; 
  case HCI_INQUIRY_RESULT: 
    for(i=0;i<((u8_t *)p->payload)[0];i++) { 
      resp_offset = i*14; 
      LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Inquiry result %d\nBD_ADDR: 0x", i)); 
      for(i = 0; i < BD_ADDR_LEN; i++) { 
	LWIP_DEBUGF(HCI_EV_DEBUG, ("%x",((u8_t *)p->payload)[1+resp_offset+i])); 
      } 
      LWIP_DEBUGF(HCI_EV_DEBUG, ("\n")); 
      LWIP_DEBUGF(HCI_EV_DEBUG, ("Page_Scan_Rep_Mode: 0x%x\n",((u8_t *)p->payload)[7+resp_offset])); 
      LWIP_DEBUGF(HCI_EV_DEBUG, ("Page_Scan_Per_Mode: 0x%x\n",((u8_t *)p->payload)[8+resp_offset])); 
      LWIP_DEBUGF(HCI_EV_DEBUG, ("Page_Scan_Mode: 0x%x\n",((u8_t *)p->payload)[9+resp_offset])); 
      LWIP_DEBUGF(HCI_EV_DEBUG, ("Class_of_Dev: 0x%x 0x%x 0x%x\n",((u8_t *)p->payload)[10+resp_offset], 
	     ((u8_t *)p->payload)[11+resp_offset], ((u8_t *)p->payload)[12+resp_offset])); 
      LWIP_DEBUGF(HCI_EV_DEBUG, ("Clock_Offset: 0x%x%x\n",((u8_t *)p->payload)[13+resp_offset], 
	     ((u8_t *)p->payload)[14+resp_offset])); 
       
      bdaddr = (void *)(((u8_t *)p->payload)+(1+resp_offset)); 
      if((inqres = lwbt_memp_malloc(MEMP_HCI_INQ)) != NULL) { 
	bd_addr_set(&(inqres->bdaddr), bdaddr); 
	inqres->psrm = ((u8_t *)p->payload)[7+resp_offset]; 
	inqres->psm = ((u8_t *)p->payload)[9+resp_offset]; 
	memcpy(inqres->cod, ((u8_t *)p->payload)+10+resp_offset, 3); 
	inqres->co = *((u16_t *)(((u8_t *)p->payload)+13+resp_offset)); 
	HCI_REG(&(pcb->ires), inqres); 
      } else { 
        LWIP_DEBUGF(HCI_DEBUG, ("hci_event_input: Could not allocate memory for inquiry result\n")); 
      } 
    } 
    break; 
  case HCI_CONNECTION_COMPLETE: 
    bdaddr = (void *)(((u8_t *)p->payload)+3); /* Get the Bluetooth address */ 
    link = hci_get_link(bdaddr); 
    switch(((u8_t *)p->payload)[0]) { 
    case HCI_SUCCESS: 
      LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Conn successfully completed\n")); 
      if(link == NULL) { 
	if((link = hci_new()) == NULL) { 
	  /* Could not allocate memory for link. Disconnect */ 
	  LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Could not allocate memory for link. Disconnect\n")); 
	  hci_disconnect(bdaddr, HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES); 
	  /* Notify L2CAP */ 
	  lp_disconnect_ind(bdaddr); 
	  break; 
	} 
	bd_addr_set(&(link->bdaddr), bdaddr); 
	link->conhdl = *((u16_t *)(((u8_t *)p->payload)+1));  
	HCI_REG(&(hci_active_links), link); 
	HCI_EVENT_CONN_COMPLETE(pcb,bdaddr,ret); /* Allow applicaton to do optional configuration of link */ 
	LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Calling lp_connect_ind\n")); 
	lp_connect_ind(&(link->bdaddr)); /* Notify L2CAP */ 
      } else { 
	link->conhdl = *((u16_t *)(((u8_t *)p->payload)+1)); 
	HCI_EVENT_CONN_COMPLETE(pcb,bdaddr,ret); /* Allow applicaton to do optional configuration of link */ 
	LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Calling lp_connect_cfm\n")); 
	lp_connect_cfm(bdaddr, ((u8_t *)p->payload)[10], ERR_OK); /* Notify L2CAP */ 
      } 
      //TODO: MASTER SLAVE SWITCH?? 
      break; 
    default: 
      LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Conn failed to complete, 0x%x %s\n" 
			     , ((u8_t *)p->payload)[0], hci_get_error_code(((u8_t *)p->payload)[0]))); 
      if(link != NULL) { 
        LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Link exists. Notify upper layer\n")); 
	hci_close(link); 
	lp_connect_cfm(bdaddr, ((u8_t *)p->payload)[10], ERR_CONN); 
      } else { 
        /* silently discard */ 
        LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Silently discard. Link does not exist\n")); 
      } 
      break; 
    } /* switch */ 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("Conn_hdl: 0x%x 0x%x\n", ((u8_t *)p->payload)[1], ((u8_t *)p->payload)[2])); 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("BD_ADDR: 0x")); 
    for(j=0;jpayload)[3+j])); 
    } 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("\n")); 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("Link_type: 0x%x\n",((u8_t *)p->payload)[9])); 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("Encryption_Mode: 0x%x\n",((u8_t *)p->payload)[10])); 
    break; 
  case HCI_DISCONNECTION_COMPLETE: 
    switch(((u8_t *)p->payload)[0]) { 
    case HCI_SUCCESS: 
      LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Disconn has occurred\n")); 
      for(link = hci_active_links; link != NULL; link = link->next) { 
	if(link->conhdl == *((u16_t *)(((u8_t *)p->payload)+1))) { 
	  break; /* Found */ 
	} 
      } 
      if(link != NULL) { 
	lp_disconnect_ind(&(link->bdaddr)); /* Notify upper layer */ 
	hci_close(link); 
      } 
      /* else silently discard */ 
      break; 
    default: 
      LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Disconn failed to complete, 0x%x %s\n" 
			    , ((u8_t *)p->payload)[0], hci_get_error_code(((u8_t *)p->payload)[0]))); 
      return; 
    } 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("Conn_hdl: 0x%x%x\n", ((u8_t *)p->payload)[1], ((u8_t *)p->payload)[2])); 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("Reason: 0x%x %s\n", ((u8_t *)p->payload)[3], hci_get_error_code(((u8_t *)p->payload)[3]))); 
    break; 
  case HCI_ENCRYPTION_CHANGE: 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Encryption changed. Status = 0x%x, Encryption enable = 0x%x\n", ((u8_t *)p->payload)[0], ((u8_t *)p->payload)[3])); 
    break; 
  case HCI_QOS_SETUP_COMPLETE: 
     LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: QOS setup complete result = 0x%x\n", ((u8_t *)p->payload)[0])); 
    break; 
  case HCI_COMMAND_COMPLETE: 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Command Complete\n")); 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("Num_HCI_Command_Packets: 0x%x\n", ((u8_t *)p->payload)[0])); 
  
    pcb->numcmd += ((u8_t *)p->payload)[0]; /* Add number of completed command packets to the 
					       number of command packets that the BT module  
					       can buffer */ 
    pbuf_header(p, -1); /* Adjust payload pointer not to cover 
			 Num_HCI_Command_Packets parameter */ 
    ocf = *((u16_t *)p->payload) & 0x03FF; 
    ogf = *((u16_t *)p->payload) >> 10; 
     
    LWIP_DEBUGF(HCI_EV_DEBUG, ("OCF == 0x%x OGF == 0x%x\n", ocf, ogf)); 
     
    pbuf_header(p, -2); /* Adjust payload pointer not to cover Command_Opcode 
			   parameter */ 
    if(ogf == HCI_INFO_PARAM) { 
      if(ocf == HCI_READ_BUFFER_SIZE) { 
	if(((u8_t *)p->payload)[0] == HCI_SUCCESS) { 
	  LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Read_Buffer_Size command succeeded\n")); 
	  LWIP_DEBUGF(HCI_EV_DEBUG, ("HC_ACL_Data_Packet_Length: 0x%x%x\n", ((u8_t *)p->payload)[1], ((u8_t *)p->payload)[2])); 
	  LWIP_DEBUGF(HCI_EV_DEBUG, ("HC_SCO_Data_Packet_Length: 0x%x\n", ((u8_t *)p->payload)[3])); 
	  LWIP_DEBUGF(HCI_EV_DEBUG, ("HC_Total_Num_ACL_Data_Packets: %d\n", *((u16_t *)(((u8_t *)p->payload)+4)))); 
	  pcb->maxsize = *((u16_t *)(((u8_t *)p->payload)+1)); /* Maximum size of an ACL packet  
								  that the BT module is able to  
								  accept */ 
	  pcb->hc_num_acl = *((u16_t *)(((u8_t *)p->payload)+4)); /* Number of ACL packets that the  
								     BT module can buffer */ 
	  LWIP_DEBUGF(HCI_EV_DEBUG, ("HC_Total_Num_SCO_Data_Packets: 0x%x%x\n", ((u8_t *)p->payload)[6], ((u8_t *)p->payload)[7])); 
	} else { 
	  LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Read_Buffer_Size command failed, 0x%x %s\n", ((u8_t *)p->payload)[0], hci_get_error_code(((u8_t *)p->payload)[0]))); 
	  return; 
	} 
      } 
      if(ocf == HCI_READ_BD_ADDR) { 
	if(((u8_t *)p->payload)[0] == HCI_SUCCESS) { 
	  bdaddr = (void *)(((u8_t *)p->payload) + 1); /* Get the Bluetooth address */ 
	  HCI_EVENT_RBD_COMPLETE(pcb, bdaddr, ret); /* Notify application.*/ 
	} 
      } 
    } 
    if(ogf == HCI_HOST_C_N_BB && ocf == HCI_SET_HC_TO_H_FC) { 
      if(((u8_t *)p->payload)[0] == HCI_SUCCESS) { 
	pcb->flow = 1; 
      } 
    } 
    if(ogf == HCI_LINK_POLICY) { 
      if(ocf == HCI_W_LINK_POLICY) { 
	if(((u8_t *)p->payload)[0] == HCI_SUCCESS) { 
	  LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Successful HCI_W_LINK_POLICY.\n")); 
	  for(link = hci_active_links; link != NULL; link = link->next) { 
	    if(link->conhdl == *((u16_t *)(((u8_t *)p->payload)+1))) { 
	      break; 
	    } 
	  } 
	  if(link == NULL) { 
	    LWIP_DEBUGF(HCI_DEBUG, ("hci_event_input: Connection does not exist\n")); 
	    return; /* Connection does not exist */  
	  } 
	  HCI_EVENT_WLP_COMPLETE(pcb, &link->bdaddr, ret); /* Notify application.*/ 
	} else { 
	  LWIP_DEBUGF(HCI_EV_DEBUG, ("Unsuccessful HCI_W_LINK_POLICY.\n")); 
	  return; 
	} 
      } 
    } 
     
    HCI_EVENT_CMD_COMPLETE(pcb,ogf,ocf,((u8_t *)p->payload)[0],ret); 
    break; 
  case HCI_COMMAND_STATUS: 
    switch(((u8_t *)p->payload)[0]) { 
    case HCI_SUCCESS: 
      LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Command Status\n")); 
      break; 
    default: 
      LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Command failed, %s\n", hci_get_error_code(((u8_t *)p->payload)[0]))); 
      pbuf_header(p, -2); /* Adjust payload pointer not to cover 
			     Num_HCI_Command_Packets and status parameter */ 
      ocf = *((u16_t *)p->payload) & 0x03FF; 
      ogf = *((u16_t *)p->payload) >> 10; 
      pbuf_header(p, -2); /* Adjust payload pointer not to cover Command_Opcode 
			   parameter */ 
      HCI_EVENT_CMD_COMPLETE(pcb,ogf,ocf,((u8_t *)p->payload)[0],ret); 
      pbuf_header(p, 4); 
      break; 
    } 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("Num_HCI_Command_Packets: 0x%x\n", ((u8_t *)p->payload)[1])); 
    pcb->numcmd += ((u8_t *)p->payload)[1]; /* Add number of completed command packets to the  
					       number of command packets that the BT module  
					       can buffer */ 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("Command_Opcode: 0x%x 0x%x\n", ((u8_t *)p->payload)[2], ((u8_t *)p->payload)[3])); 
    break; 
  case HCI_HARDWARE_ERROR: 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Hardware Error\n")); 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("Hardware_code: 0x%x\n\n", ((u8_t *)p->payload)[0])); 
    //TODO: IS THIS FATAL?? 
    break;  
  case HCI_ROLE_CHANGE: 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Role change\n")); 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("Status: 0x%x\n", ((u8_t *)p->payload)[0])); 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("New Role: 0x%x\n", ((u8_t *)p->payload)[7])); 
    break; 
  case HCI_NBR_OF_COMPLETED_PACKETS: 
    LWIP_DEBUGF(DBG_OFF, ("hci_event_input: Number Of Completed Packets\n")); 
    LWIP_DEBUGF(DBG_OFF, ("Number_of_Handles: 0x%x\n", ((u8_t *)p->payload)[0])); 
    for(i=0;i<((u8_t *)p->payload)[0];i++) { 
      resp_offset = i*4; 
      LWIP_DEBUGF(DBG_OFF, ("Conn_hdl: 0x%x%x\n", ((u8_t *)p->payload)[1+resp_offset], ((u8_t *)p->payload)[2+resp_offset])); 
      LWIP_DEBUGF(DBG_OFF, ("HC_Num_Of_Completed_Packets: 0x%x\n",*((u16_t *)(((u8_t *)p->payload)+3+resp_offset)))); 
      /* Add number of completed ACL packets to the number of ACL packets that the  
	 BT module can buffer */ 
      pcb->hc_num_acl += *((u16_t *)(((u8_t *)p->payload) + 3 + resp_offset)); 
#if HCI_FLOW_QUEUEING 
      { 
	u16_t conhdl = *((u16_t *)(((u8_t *)p->payload) + 1 + resp_offset)); 
	struct pbuf *q; 
	for(link = hci_active_links; link != NULL; link = link->next) { 
	  if(link->conhdl == conhdl) { 
	    break; 
	  } 
	} 
	q = link->p; 
	/* Queued packet present? */ 
	if (q != NULL) { 
	  /* NULL attached buffer immediately */ 
	  link->p = NULL; 
	  LWIP_DEBUGF(RFCOMM_DEBUG, ("rfcomm_input: Sending queued packet.\n")); 
	  /* Send the queued packet */ 
	lp_acl_write(&link->bdaddr, q, link->len, link->pb);  
	/* Free the queued packet */ 
	pbuf_free(q); 
	} 
      } 
#endif /* RFCOMM_FLOW_QUEUEING */	 
    } 
    break; 
  case HCI_MODE_CHANGE: 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Mode change\n")); 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("Status: 0x%x\n", ((u8_t *)p->payload)[0])); 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("Conn_hdl: 0x%x\n", ((u16_t *)(((u8_t *)p->payload) + 1))[0])); 
    break; 
  case HCI_DATA_BUFFER_OVERFLOW: 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Data Buffer Overflow\n")); 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("Link_Type: 0x%x\n", ((u8_t *)p->payload)[0])); 
    //TODO: IS THIS FATAL???? 
    break; 
  case HCI_MAX_SLOTS_CHANGE: 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Max slots changed\n")); 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("Conn_hdl: 0x%x\n", ((u16_t *)p->payload)[0])); 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("LMP max slots: 0x%x\n", ((u8_t *)p->payload)[2])); 
    break;  
  case HCI_PIN_CODE_REQUEST: 
    bdaddr = (void *)((u8_t *)p->payload); /* Get the Bluetooth address */ 
    HCI_EVENT_PIN_REQ(pcb, bdaddr, ret); /* Notify application. If event is not registered,  
					    send a negative reply */ 
    break; 
  case HCI_LINK_KEY_NOTIFICATION: 
    bdaddr = (void *)((u8_t *)p->payload); /* Get the Bluetooth address */ 
     
    HCI_EVENT_LINK_KEY_NOT(pcb, bdaddr, ((u8_t *)p->payload) + 6, ret); /* Notify application.*/ 
    break; 
  default: 
    LWIP_DEBUGF(HCI_EV_DEBUG, ("hci_event_input: Undefined event code 0x%x\n", evhdr->code)); 
    break; 
  }/* switch */ 
} 
/*-----------------------------------------------------------------------------------*/ 
/* HCI Commands */  
/*-----------------------------------------------------------------------------------*/ 
/*-----------------------------------------------------------------------------------*/ 
/* hci_cmd_ass(): 
 * 
 * Assemble the command header. 
 */ 
 /*-----------------------------------------------------------------------------------*/ 
struct pbuf * 
hci_cmd_ass(struct pbuf *p, u8_t ocf, u8_t ogf, u8_t len)  
{ 
  ((u8_t *)p->payload)[0] = HCI_COMMAND_DATA_PACKET; /* cmd packet type */ 
  ((u8_t *)p->payload)[1] = (ocf & 0xff); /* OCF & OGF */ 
  ((u8_t *)p->payload)[2] = (ocf >> 8)|(ogf << 2); 
  ((u8_t *)p->payload)[3] = len-HCI_CMD_HDR_LEN-1; /* Param len = plen - cmd hdr - ptype */ 
  if(pcb->numcmd != 0) { 
    --pcb->numcmd; /* Reduce number of cmd packets that the host controller can buffer */ 
  } 
  return p; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* hci_inquiry(): 
 * 
 * Cause the Host contoller to enter inquiry mode to discovery other nearby Bluetooth  
 * devices. 
 */ 
 /*-----------------------------------------------------------------------------------*/ 
err_t 
hci_inquiry(u32_t lap, u8_t inq_len, u8_t num_resp,  
	    err_t (* inq_complete)(void *arg, struct hci_pcb *pcb,  
				   struct hci_inq_res *ires, u16_t result)) 
{ 
  struct pbuf *p; 
  struct hci_inq_res *tmpres; 
 
  /* Free any previous inquiry result list */ 
  while(pcb->ires != NULL) { 
    tmpres = pcb->ires; 
    pcb->ires = pcb->ires->next; 
    lwbt_memp_free(MEMP_HCI_INQ, tmpres); 
  } 
   
  pcb->inq_complete = inq_complete; 
   
  if((p = pbuf_alloc(PBUF_RAW, HCI_INQUIRY_PLEN, PBUF_RAM)) == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_inquiry: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; /* Could not allocate memory for pbuf */ 
  } 
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_INQUIRY_OCF, HCI_LINK_CTRL_OGF, HCI_INQUIRY_PLEN); 
  /* Assembling cmd prameters */ 
  ((u8_t *)p->payload)[4] = lap & 0xFF; 
  ((u8_t *)p->payload)[5] = lap >> 8; 
  ((u8_t *)p->payload)[6] = lap >> 16; 
  //memcpy(((u8_t *)p->payload)+4, inqres->cod, 3); 
  ((u8_t *)p->payload)[7] = inq_len; 
  ((u8_t *)p->payload)[8] = num_resp; 
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
   
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* hci_disconnect(): 
 * 
 * Used to terminate an existing connection. 
 */ 
 /*-----------------------------------------------------------------------------------*/ 
err_t 
hci_disconnect(struct bd_addr *bdaddr, u8_t reason) 
{ 
  struct pbuf *p; 
  struct hci_link *link; 
 
  link = hci_get_link(bdaddr); 
 
  if(link == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_disconnect: Connection does not exist\n")); 
    return ERR_CONN; /* Connection does not exist */  
  } 
  if((p = pbuf_alloc(PBUF_RAW, HCI_DISCONN_PLEN, PBUF_RAM)) == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_disconnect: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; /* Could not allocate memory for pbuf */ 
  } 
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_DISCONN_OCF, HCI_LINK_CTRL_OGF, HCI_DISCONN_PLEN); 
 
  /* Assembling cmd prameters */ 
  ((u16_t *)p->payload)[2] = link->conhdl; 
  ((u8_t *)p->payload)[6] = reason; 
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* hci_reject_connection_request(): 
 * 
 * Used to decline a new incoming connection request. 
 */ 
 /*-----------------------------------------------------------------------------------*/ 
err_t 
hci_reject_connection_request(struct bd_addr *bdaddr, u8_t reason) 
{ 
  struct pbuf *p; 
  if((p = pbuf_alloc(PBUF_RAW, HCI_REJECT_CONN_REQ_PLEN, PBUF_RAM)) == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_reject_connection_request: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; 
  } 
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_REJECT_CONN_REQ_OCF, HCI_LINK_CTRL_OGF, HCI_REJECT_CONN_REQ_PLEN); 
  /* Assembling cmd prameters */ 
  memcpy(((u8_t *)p->payload) + 4, bdaddr->addr, 6); 
  ((u8_t *)p->payload)[10] = reason; 
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* hci_pin_code_request_reply(): 
 * 
 * Used to reply to a PIN Code Request event from the Host Controller and specifies  
 * the PIN code to use for a connection. 
 */ 
 /*-----------------------------------------------------------------------------------*/ 
err_t 
hci_pin_code_request_reply(struct bd_addr *bdaddr, u8_t pinlen, u8_t *pincode) 
{ 
  struct pbuf *p; 
   
  if((p = pbuf_alloc(PBUF_RAW, HCI_PIN_CODE_REQ_REP_PLEN, PBUF_RAM)) == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_pin_code_request_reply: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; 
  } 
   
  /* Reset buffer content just to make sure */ 
  memset((u8_t *)p->payload, 0, HCI_PIN_CODE_REQ_REP_PLEN); 
   
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_PIN_CODE_REQ_REP, HCI_LINK_CTRL_OGF, HCI_PIN_CODE_REQ_REP_PLEN); 
  /* Assembling cmd prameters */ 
  memcpy(((u8_t *)p->payload) + 4, bdaddr->addr, 6); 
  ((u8_t *)p->payload)[10] = pinlen; 
  memcpy(((u8_t *)p->payload) + 11, pincode, pinlen); 
   
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* hci_pin_code_request_neg_reply(): 
 * 
 * Used to reply to a PIN Code Request event from the Host Controller when the Host  
 * cannot specify a PIN code to use for a connection. 
 */ 
 /*-----------------------------------------------------------------------------------*/ 
err_t 
hci_pin_code_request_neg_reply(struct bd_addr *bdaddr) 
{ 
  struct pbuf *p; 
  if((p = pbuf_alloc(PBUF_RAW, HCI_PIN_CODE_REQ_NEG_REP_PLEN, PBUF_RAM)) == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_pin_code_request_neg_reply: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; 
  } 
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_PIN_CODE_REQ_NEG_REP, HCI_LINK_CTRL_OGF, HCI_PIN_CODE_REQ_NEG_REP_PLEN); 
  /* Assembling cmd prameters */ 
  memcpy(((u8_t *)p->payload)+4, bdaddr->addr, 6); 
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* hci_sniff_mode(): 
 * 
 * Sets an ACL connection to low power Sniff mode. 
 */ 
/*-----------------------------------------------------------------------------------*/ 
err_t 
hci_sniff_mode(struct bd_addr *bdaddr, u16_t max_interval, u16_t min_interval,  
	       u16_t attempt, u16_t timeout) 
{ 
  struct pbuf *p; 
  struct hci_link *link; 
 
  /* Check if an ACL connection exists */  
  link = hci_get_link(bdaddr); 
 
  if(link == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_sniff_mode: ACL connection does not exist\n")); 
    return ERR_CONN; 
  } 
 
  if((p = pbuf_alloc(PBUF_TRANSPORT, HCI_SNIFF_PLEN, PBUF_RAM)) == NULL) { /* Alloc len of packet */ 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_sniff_mode: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; 
  } 
 
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_SNIFF_MODE, HCI_LINK_POLICY, HCI_SNIFF_PLEN); 
  /* Assembling cmd prameters */ 
  ((u16_t *)p->payload)[2] = link->conhdl; 
  ((u16_t *)p->payload)[3] = max_interval; 
  ((u16_t *)p->payload)[4] = min_interval; 
  ((u16_t *)p->payload)[5] = attempt; 
  ((u16_t *)p->payload)[6] = timeout; 
 
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* hci_write_link_policy_settings(): 
 * 
 * Control the modes (park, sniff, hold) that an ACL connection can take. 
 * 
 */ 
/*-----------------------------------------------------------------------------------*/ 
err_t 
hci_write_link_policy_settings(struct bd_addr *bdaddr, u16_t link_policy) 
{ 
  struct pbuf *p; 
  struct hci_link *link; 
 
  /* Check if an ACL connection exists */  
  link = hci_get_link(bdaddr); 
 
  if(link == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_write_link_policy_settings: ACL connection does not exist\n")); 
    return ERR_CONN; 
  } 
 
  if( (p = pbuf_alloc(PBUF_TRANSPORT, HCI_W_LINK_POLICY_PLEN, PBUF_RAM)) == NULL) { /* Alloc len of packet */ 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_write_link_policy_settings: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; 
  } 
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_W_LINK_POLICY, HCI_LINK_POLICY, HCI_W_LINK_POLICY_PLEN); 
 
  /* Assembling cmd prameters */ 
  ((u16_t *)p->payload)[2] = link->conhdl; 
  ((u16_t *)p->payload)[3] = link_policy; 
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* hci_reset(): 
 * 
 * Reset the Bluetooth host controller, link manager, and radio module. 
 */ 
 /*-----------------------------------------------------------------------------------*/ 
err_t 
hci_reset(void) 
{ 
  struct pbuf *p; 
  if((p = pbuf_alloc(PBUF_RAW, HCI_RESET_PLEN, PBUF_RAM)) == NULL) { 
   LWIP_DEBUGF(HCI_DEBUG, ("hci_reset: Could not allocate memory for pbuf\n"));  
    return ERR_MEM; 
  }  
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_RESET_OCF, HCI_HC_BB_OGF, HCI_RESET_PLEN); 
  /* Assembling cmd prameters */ 
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* hci_set_event_filter(): 
 * 
 * Used by the host to specify different event filters. 
 */ 
 /*-----------------------------------------------------------------------------------*/ 
err_t 
hci_set_event_filter(u8_t filter_type, u8_t filter_cond_type, u8_t* cond) 
{ 
  u8_t cond_len = 0x00; 
  struct pbuf *p; 
  switch(filter_type) { 
  case 0x00: 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_set_event_filter: Clearing all filters\n")); 
    cond_len = 0x00; 
    break; 
  case 0x01: 
    switch(filter_cond_type) { 
    case 0x00: 
      cond_len = 0x00; 
      break; 
    case 0x01: 
      cond_len = 0x06; 
      break; 
    case 0x02: 
      cond_len = 0x06; 
      break; 
    default: 
      LWIP_DEBUGF(HCI_DEBUG, ("hci_set_event_filter: Entered an unspecified filter condition type!\n")); 
      break; 
    } 
    break; 
  case 0x02: 
    switch(filter_cond_type) { 
    case 0x00: 
      cond_len = 0x01; 
      break; 
    case 0x01: 
      cond_len = 0x07; 
      break; 
    case 0x02: 
      cond_len = 0x07; 
      break; 
    default: 
      LWIP_DEBUGF(HCI_DEBUG, ("hci_set_event_filter: Entered an unspecified filter condition type!\n")); 
      break; 
    } 
    break; 
  default: 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_set_event_filter: Entered an unspecified filter type!\n")); 
    break; 
  } 
  if((p = pbuf_alloc(PBUF_RAW, HCI_SET_EV_FILTER_PLEN+cond_len, PBUF_RAM)) == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_set_event_filter: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; 
  } 
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_SET_EV_FILTER_OCF, HCI_HC_BB_OGF, HCI_SET_EV_FILTER_PLEN+cond_len); 
  ((u8_t *)p->payload)[4] = filter_type; 
  ((u8_t *)p->payload)[5] = filter_cond_type; 
  /* Assembling cmd prameters */ 
  if(cond_len) { 
    memcpy(((u8_t *)p->payload)+6, cond, cond_len); 
  } 
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* hci_write_stored_link_key(): 
 * 
 * Writes a link key to be stored in the Bluetooth host controller. 
 */ 
 /*-----------------------------------------------------------------------------------*/ 
err_t 
hci_write_stored_link_key(struct bd_addr *bdaddr, u8_t *link) 
{ 
  struct pbuf *p; 
  if((p = pbuf_alloc(PBUF_RAW, HCI_WRITE_STORED_LINK_KEY_PLEN, PBUF_RAM)) == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_write_stored_link_key: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; 
  } 
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_WRITE_STORED_LINK_KEY, HCI_HC_BB_OGF, HCI_WRITE_STORED_LINK_KEY_PLEN); 
  /* Assembling cmd prameters */ 
  ((u8_t *)p->payload)[4] = 0x01; 
  memcpy(((u8_t *)p->payload) + 5, bdaddr->addr, 6); 
  memcpy(((u8_t *)p->payload) + 11, link, 16); 
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* hci_change_local_name(): 
 * 
 * Writes a link key to be stored in the Bluetooth host controller. 
 */ 
 /*-----------------------------------------------------------------------------------*/ 
err_t 
hci_change_local_name(u8_t *name, u8_t len) 
{ 
  struct pbuf *p; 
  if((p = pbuf_alloc(PBUF_RAW, HCI_CHANGE_LOCAL_NAME_PLEN + len, PBUF_RAM)) == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_change_local_name: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; 
  } 
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_CHANGE_LOCAL_NAME, HCI_HC_BB_OGF, HCI_CHANGE_LOCAL_NAME_PLEN + len); 
  /* Assembling cmd prameters */ 
  memcpy(((u8_t *)p->payload) + 4, name, len); 
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* hci_write_page_timeout(): 
 * 
 * Define the amount of time a connection request will wait for the remote device 
 * to respond before the local device returns a connection failure. 
 */ 
 /*-----------------------------------------------------------------------------------*/ 
err_t 
hci_write_page_timeout(u16_t page_timeout) 
{ 
  struct pbuf *p; 
  if((p = pbuf_alloc(PBUF_RAW, HCI_W_PAGE_TIMEOUT_PLEN, PBUF_RAM)) == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_write_page_timeout: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; 
  }  
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_W_PAGE_TIMEOUT_OCF, HCI_HC_BB_OGF, HCI_W_PAGE_TIMEOUT_PLEN); 
  /* Assembling cmd prameters */ 
  ((u16_t *)p->payload)[2] = page_timeout; 
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* hci_write_scan_enable(): 
 * 
 * Controls whether or not the Bluetooth device will periodically scan for page  
 * attempts and/or inquiry requests from other Bluetooth devices. 
 */ 
 /*-----------------------------------------------------------------------------------*/ 
err_t 
hci_write_scan_enable(u8_t scan_enable) 
{ 
  struct pbuf *p; 
  if((p = pbuf_alloc(PBUF_RAW, HCI_W_SCAN_EN_PLEN, PBUF_RAM)) == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_write_scan_enable: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; 
  } 
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_W_SCAN_EN_OCF, HCI_HC_BB_OGF, HCI_W_SCAN_EN_PLEN); 
  /* Assembling cmd prameters */ 
  ((u8_t *)p->payload)[4] = scan_enable; 
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* hci_write_cod(): 
 * 
 * Write the value for the Class_of_Device parameter, which is used to indicate its  
 * capabilities to other devices. 
 */ 
 /*-----------------------------------------------------------------------------------*/ 
err_t 
hci_write_cod(u8_t *cod) 
{ 
  struct pbuf *p; 
  if((p = pbuf_alloc(PBUF_RAW, HCI_W_COD_PLEN, PBUF_RAM)) == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_write_cod: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; 
  }  
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_W_COD_OCF, HCI_HC_BB_OGF, HCI_W_COD_PLEN); 
  /* Assembling cmd prameters */ 
  memcpy(((u8_t *)p->payload)+4, cod, 3); 
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* hci_set_hc_to_h_fc(): 
 * 
 * Used by the Host to turn flow control on or off in the direction from the Host  
 * Controller to the Host. 
 */ 
 /*-----------------------------------------------------------------------------------*/ 
err_t 
hci_set_hc_to_h_fc(void) 
{ 
  struct pbuf *p; 
  if((p = pbuf_alloc(PBUF_RAW, HCI_SET_HC_TO_H_FC_PLEN, PBUF_RAM)) == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_set_hc_to_h_fc: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; 
  }  
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_SET_HC_TO_H_FC_OCF, HCI_HC_BB_OGF, HCI_SET_HC_TO_H_FC_PLEN); 
  /* Assembling cmd prameters */ 
  ((u8_t *)p->payload)[4] = 0x01; /* Flow control on for HCI ACL Data Packets and off for HCI  
				     SCO Data Packets in direction from Host Controller to  
				     Host */ 
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* hci_host_buffer_size(): 
 * 
 * Used by the Host to notify the Host Controller about the maximum size of the data  
 * portion of HCI ACL Data Packets sent from the Host Controller to the Host. 
 */ 
 /*-----------------------------------------------------------------------------------*/ 
err_t 
hci_host_buffer_size(void) 
{ 
  struct pbuf *p; 
  if((p = pbuf_alloc(PBUF_RAW, HCI_H_BUF_SIZE_PLEN, PBUF_RAM)) == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_host_buffer_size: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; 
  } 
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_H_BUF_SIZE_OCF, HCI_HC_BB_OGF, HCI_H_BUF_SIZE_PLEN);  
  ((u16_t *)p->payload)[2] = HCI_HOST_ACL_MAX_LEN; /* Host ACL data packet maximum length */ 
  ((u8_t *)p->payload)[6] = 255; /* Host SCO Data Packet Length */ 
  *((u16_t *)(((u8_t *)p->payload)+7)) = HCI_HOST_MAX_NUM_ACL; /* Host max total num ACL data packets */ 
  ((u16_t *)p->payload)[4] = 1; /* Host Total Num SCO Data Packets */ 
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
 
  pcb->host_num_acl = HCI_HOST_MAX_NUM_ACL; 
 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* hci_host_num_comp_packets(): 
 * 
 * Used by the Host to indicate to the Host Controller the number of HCI Data Packets  
 * that have been completed for each Connection Handle since the previous  
 * Host_Number_Of_Completed_Packets command was sent to the Host Controller. 
 */ 
 /*-----------------------------------------------------------------------------------*/ 
err_t 
hci_host_num_comp_packets(u16_t conhdl, u16_t num_complete) 
{ 
  struct pbuf *p; 
  if((p = pbuf_alloc(PBUF_RAW, HCI_H_NUM_COMPL_PLEN, PBUF_RAM)) == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_host_num_comp_packets: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; 
  } 
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_H_NUM_COMPL_OCF, HCI_HC_BB_OGF, HCI_H_NUM_COMPL_PLEN);  
  ((u16_t *)p->payload)[2] = conhdl; 
  ((u16_t *)p->payload)[3] = num_complete; /* Number of completed acl packets */ 
   
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
 
  pcb->host_num_acl += num_complete; 
 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* hci_read_buffer_size(): 
 * 
 * Used to read the maximum size of the data portion of HCI ACL packets sent from the  
 * Host to the Host Controller. 
 */ 
/*-----------------------------------------------------------------------------------*/ 
err_t 
hci_read_buffer_size(void) 
{ 
  struct pbuf *p; 
  if((p = pbuf_alloc(PBUF_RAW, HCI_R_BUF_SIZE_PLEN, PBUF_RAM)) == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_read_buffer_size: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; 
  }  
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_R_BUF_SIZE_OCF, HCI_INFO_PARAM_OGF, HCI_R_BUF_SIZE_PLEN); 
  /* Assembling cmd prameters */ 
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* hci_read_bd_addr(): 
 * 
 * Used to retreive the Bluetooth address of the host controller. 
 */ 
/*-----------------------------------------------------------------------------------*/ 
err_t 
hci_read_bd_addr(err_t (* rbd_complete)(void *arg, struct bd_addr *bdaddr)) 
{ 
  struct pbuf *p; 
 
  pcb->rbd_complete = rbd_complete; 
 
  if((p = pbuf_alloc(PBUF_RAW, HCI_R_BD_ADDR_PLEN, PBUF_RAM)) == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("hci_read_buffer_size: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; 
  }  
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_READ_BD_ADDR, HCI_INFO_PARAM_OGF, HCI_R_BD_ADDR_PLEN); 
  /* Assembling cmd prameters */ 
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* lp_write_flush_timeout(): 
 * 
 * Called by L2CAP to set the flush timeout for the ACL link. 
 */ 
/*-----------------------------------------------------------------------------------*/ 
err_t 
lp_write_flush_timeout(struct bd_addr *bdaddr, u16_t flushto) 
{ 
  struct hci_link *link; 
  struct pbuf *p; 
   
  /* Check if an ACL connection exists */  
  link = hci_get_link(bdaddr); 
 
  if(link == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("lp_write_flush_timeout: ACL connection does not exist\n")); 
    return ERR_CONN; 
  } 
   
  if((p = pbuf_alloc(PBUF_TRANSPORT, HCI_W_FLUSHTO_PLEN, PBUF_RAM)) == NULL) { /* Alloc len of packet */ 
    LWIP_DEBUGF(HCI_DEBUG, ("lp_write_flush_timeout: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; 
  } 
 
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_W_FLUSHTO, HCI_HC_BB_OGF, HCI_W_FLUSHTO_PLEN); 
  /* Assembling cmd prameters */ 
  ((u16_t *)p->payload)[2] = link->conhdl; 
  ((u16_t *)p->payload)[3] = flushto; 
 
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* lp_connect_req(): 
 * 
 * Called by L2CAP to cause the Link Manager to create a connection to the  
 * Bluetooth device with the BD_ADDR specified by the command parameters. 
 */ 
/*-----------------------------------------------------------------------------------*/ 
err_t 
lp_connect_req(struct bd_addr *bdaddr, u8_t allow_role_switch) 
{ 
  u8_t page_scan_repetition_mode, page_scan_mode; 
  u16_t clock_offset; 
  struct pbuf *p; 
  struct hci_link *link = hci_new(); 
  struct hci_inq_res *inqres; 
 
  if(link == NULL) { 
   LWIP_DEBUGF(HCI_DEBUG, ("lp_connect_req: Could not allocate memory for link\n"));  
    return ERR_MEM; /* Could not allocate memory for link */ 
  } 
   
  bd_addr_set(&(link->bdaddr), bdaddr); 
  HCI_REG(&(hci_active_links), link); 
 
 
  /* Check if module has been discovered in a recent inquiry */ 
  for(inqres = pcb->ires; inqres != NULL; inqres = inqres->next) { 
    if(bd_addr_cmp(&inqres->bdaddr, bdaddr)) { 
      page_scan_repetition_mode = inqres->psrm; 
      page_scan_mode = inqres->psm; 
      clock_offset = inqres->co; 
      break; 
    } 
  } 
  if(inqres == NULL) { 
    /* No information on parameters from an inquiry. Using default values */ 
    page_scan_repetition_mode = 0x01; /* Assuming worst case: time between 
					 successive page scans starting  
					 <= 2.56s */ 
    page_scan_mode = 0x00; /* Assumes the device uses mandatory scanning, most 
			      devices use this. If no conn is established, try 
			      again w this parm set to optional page scanning */ 
    clock_offset = 0x00; /* If the device was not found in a recent inquiry 
			    this  information is irrelevant */ 
  }     
    
  if((p = pbuf_alloc(PBUF_RAW, HCI_CREATE_CONN_PLEN, PBUF_RAM)) == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("lp_connect_req: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; /* Could not allocate memory for pbuf */ 
  } 
 
  /* Assembling command packet */ 
  p = hci_cmd_ass(p, HCI_CREATE_CONN_OCF, HCI_LINK_CTRL_OGF, HCI_CREATE_CONN_PLEN); 
  /* Assembling cmd prameters */ 
  memcpy(((u8_t *)p->payload)+4, bdaddr->addr, 6); 
   
  ((u16_t *)p->payload)[5] = HCI_PACKET_TYPE; 
  ((u8_t *)p->payload)[12] = page_scan_repetition_mode; 
  ((u8_t *)p->payload)[13] = page_scan_mode; 
  ((u16_t *)p->payload)[7] = clock_offset; 
  ((u8_t *)p->payload)[16] = allow_role_switch; 
  phybusif_output(p, p->tot_len); 
  pbuf_free(p); 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* lp_acl_write(): 
 * 
 * Called by L2CAP to send data to the Host Controller that will be transfered over 
 * the ACL link from there. 
 */ 
/*-----------------------------------------------------------------------------------*/ 
err_t 
lp_acl_write(struct bd_addr *bdaddr, struct pbuf *p, u16_t len, u8_t pb) 
{ 
  struct hci_link *link; 
  static struct hci_acl_hdr *aclhdr; 
  struct pbuf *q; 
   
  /* Check if an ACL connection exists */  
  link = hci_get_link(bdaddr); 
 
  if(link == NULL) { 
    LWIP_DEBUGF(HCI_DEBUG, ("lp_acl_write: ACL connection does not exist\n")); 
    return ERR_CONN; 
  } 
 
  LWIP_DEBUGF(HCI_DEBUG, ("lp_acl_write: HC num ACL %d\n", pcb->hc_num_acl)); 
  if(pcb->hc_num_acl == 0) { 
    LWIP_DEBUGF(HCI_DEBUG, ("lp_acl_write: HC out of buffer space\n")); 
#if HCI_FLOW_QUEUEING 
    if(p != NULL) { 
      /* Packet can be queued? */ 
      if(link->p != NULL) { 
	LWIP_DEBUGF(HCI_DEBUG, ("lp_acl_write: Host buffer full. Dropped packet\n")); 
	return ERR_OK; /* Drop packet */ 
      } else { 
	/* Copy PBUF_REF referenced payloads into PBUF_RAM */ 
	p = pbuf_take(p); 
	/* Remember pbuf to queue, if any */ 
	link->p = p; 
	link->len = len; 
	link->pb = pb; 
	/* Pbufs are queued, increase the reference count */ 
	pbuf_ref(p); 
	LWIP_DEBUGF(HCI_DEBUG, ("lp_acl_write: Host queued packet %p\n", (void *)p)); 
      } 
    } 
#else 
    LWIP_DEBUGF(HCI_DEBUG, ("lp_acl_write: Dropped packet\n")); 
#endif 
    return ERR_OK; 
  } 
 
  if((q = pbuf_alloc(PBUF_RAW, 1+HCI_ACL_HDR_LEN, PBUF_RAM)) == NULL) { 
    /* Could not allocate memory for pbuf */ 
    LWIP_DEBUGF(HCI_DEBUG, ("lp_acl_write: Could not allocate memory for pbuf\n")); 
    return ERR_MEM; 
  } 
  pbuf_chain(q, p); 
 
  ((u8_t*)q->payload)[0] = HCI_ACL_DATA_PACKET; 
  aclhdr = (void *)(((u8_t*)q->payload)+1); 
  aclhdr->conhdl_pb_bc = link->conhdl; /* Received from connection complete event */ 
  aclhdr->conhdl_pb_bc |= pb << 12; /* Packet boundary flag */ 
  aclhdr->conhdl_pb_bc &= 0x3FFF; /* Point-to-point */ 
  aclhdr->len = len; 
   
  LWIP_DEBUGF(HCI_DEBUG, ("lp_acl_write: q->tot_len = %d aclhdr->len + q->len = %d\n", q->tot_len, aclhdr->len + q->len)); 
 
  phybusif_output(q, aclhdr->len + q->len); 
 
  --pcb->hc_num_acl; 
 
  /* Free ACL header. Upper layers will handle rest of packet */ 
  p = pbuf_dechain(q); 
  pbuf_free(q); 
  return ERR_OK; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* lp_is_connected(): 
 * 
 * Called by L2CAP to check if an active ACL connection exists for the specified  
 * Bluetooth address. 
 */ 
/*-----------------------------------------------------------------------------------*/ 
u8_t 
lp_is_connected(struct bd_addr *bdaddr) 
{ 
  struct hci_link *link; 
 
  link = hci_get_link(bdaddr); 
 
  if(link == NULL) { 
    return 0; 
  } 
  return 1; 
} 
/*-----------------------------------------------------------------------------------*/ 
/* lp_pdu_maxsize(): 
 * 
 * Called by L2CAP to check the maxsize of the PDU. In this case it is the largest 
 * ACL packet that the Host Controller can buffer. 
 */ 
/*-----------------------------------------------------------------------------------*/ 
u16_t 
lp_pdu_maxsize(void) 
{ 
  return pcb->maxsize; 
} 
/*-----------------------------------------------------------------------------------*/