#include #include #include #include #include #include #include #include "bt.h" #include "bte.h" #include "hci.h" #include "l2cap.h" #include "btmemb.h" #include "physbusif.h" #define STACKSIZE 32768 #define MQ_BOX_SIZE 256 /* Vendor specific OGF */ #define HCI_VENDOR_OGF 0x3f /* Vendor specific OCF */ #define HCI_VENDOR_PATCH_START_OCF 0x4f #define HCI_VENDOR_PATCH_CONT_OCF 0x4c #define HCI_VENDOR_PATCH_END_OCF 0x4f enum bte_state { STATE_NOTREADY = -1, STATE_READY = 0, STATE_CONNECTING, STATE_CONNECTED, STATE_DISCONNECTING, STATE_DISCONNECTED, STATE_SENDING, STATE_SENT, STATE_RECEIVING, STATE_RECEIVED, STATE_FAILED }; struct bt_state { err_t last_err; syswd_t timer_svc; lwpq_t hci_cmdq; u8_t hci_cmddone; u8_t hci_inited; u8_t num_maxdevs; u8_t num_founddevs; struct inquiry_info_ex *info; btecallback cb; void *usrdata; }; struct ctrl_req_t { u8 err; struct pbuf *p; struct bte_pcb *pcb; enum bte_state state; s32 (*sent)(void *arg,struct bte_pcb *pcb,u8 err); struct ctrl_req_t *next; }; static struct bt_state btstate; static u8_t bte_patch0[184] = { 0x70,0x99,0x08,0x00,0x88,0x43,0xd1,0x07,0x09,0x0c,0x08,0x43,0xa0,0x62,0x19,0x23, 0xdb,0x01,0x33,0x80,0x7c,0xf7,0x88,0xf8,0x28,0x76,0x80,0xf7,0x17,0xff,0x43,0x78, 0xeb,0x70,0x19,0x23,0xdb,0x01,0x33,0x87,0x7c,0xf7,0xbc,0xfb,0x0b,0x60,0xa3,0x7b, 0x01,0x49,0x0b,0x60,0x90,0xf7,0x96,0xfb,0xd8,0x1d,0x08,0x00,0x00,0xf0,0x04,0xf8, 0x00,0x23,0x79,0xf7,0xe3,0xfa,0x00,0x00,0x00,0xb5,0x00,0x23,0x11,0x49,0x0b,0x60, 0x1d,0x21,0xc9,0x03,0x0b,0x60,0x7d,0x20,0x80,0x01,0x01,0x38,0xfd,0xd1,0x0e,0x4b, 0x0e,0x4a,0x13,0x60,0x47,0x20,0x00,0x21,0x96,0xf7,0x96,0xff,0x46,0x20,0x00,0x21, 0x96,0xf7,0x92,0xff,0x0a,0x4a,0x13,0x68,0x0a,0x48,0x03,0x40,0x13,0x60,0x0a,0x4a, 0x13,0x68,0x0a,0x48,0x03,0x40,0x13,0x60,0x09,0x4a,0x13,0x68,0x09,0x48,0x03,0x40, 0x13,0x60,0x00,0xbd,0x24,0x80,0x0e,0x00,0x81,0x03,0x0f,0xfe,0x5c,0x00,0x0f,0x00, 0x60,0xfc,0x0e,0x00,0xfe,0xff,0x00,0x00,0xfc,0xfc,0x0e,0x00,0xff,0x9f,0x00,0x00, 0x30,0xfc,0x0e,0x00,0x7f,0xff,0x00,0x00 }; static u8_t bte_patch1[92] = { 0x07,0x20,0xbc,0x65,0x01,0x00,0x84,0x42,0x09,0xd2,0x84,0x42,0x09,0xd1,0x21,0x84, 0x5a,0x00,0x00,0x83,0xf0,0x74,0xff,0x09,0x0c,0x08,0x43,0x22,0x00,0x61,0x00,0x00, 0x83,0xf0,0x40,0xfc,0x00,0x00,0x00,0x00,0x23,0xcc,0x9f,0x01,0x00,0x6f,0xf0,0xe4, 0xfc,0x03,0x28,0x7d,0xd1,0x24,0x3c,0x62,0x01,0x00,0x28,0x20,0x00,0xe0,0x60,0x8d, 0x23,0x68,0x25,0x04,0x12,0x01,0x00,0x20,0x1c,0x20,0x1c,0x24,0xe0,0xb0,0x21,0x26, 0x74,0x2f,0x00,0x00,0x86,0xf0,0x18,0xfd,0x21,0x4f,0x3b,0x60 }; static u8 ppc_stack[STACKSIZE] ATTRIBUTE_ALIGN(8); err_t acl_wlp_completed(void *arg,struct bd_addr *bdaddr); err_t link_key_not(void *arg,struct bd_addr *bdaddr,u8_t *key); err_t pin_req(void *arg,struct bd_addr *bdaddr); err_t l2cap_connected(void *arg,struct l2cap_pcb *l2cappcb,u16_t result,u16_t status); err_t l2cap_accepted(void *arg,struct l2cap_pcb *l2cappcb,err_t err); err_t acl_conn_complete(void *arg,struct bd_addr *bdaddr); err_t l2cap_disconnect_cfm(void *arg, struct l2cap_pcb *pcb); err_t l2cap_disconnected_ind(void *arg, struct l2cap_pcb *pcb, err_t err); err_t bte_input(void *arg,struct l2cap_pcb *pcb,struct pbuf *p,err_t err); err_t bte_callback(void (*f)(void*),void *ctx); err_t bte_hci_apply_patch_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result); err_t bte_hci_patch_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result); err_t bte_hci_initcore_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result); err_t bte_hci_initsub_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result); err_t bte_inquiry_complete(void *arg,struct hci_pcb *pcb,struct hci_inq_res *ires,u16_t result); err_t bte_read_stored_link_key_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result); err_t bte_read_bd_addr_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result); MEMB(bte_pcbs,sizeof(struct bte_pcb),MEMP_NUM_BTE_PCB); MEMB(bte_ctrl_reqs,sizeof(struct ctrl_req_t),MEMP_NUM_BTE_CTRLS); static void bte_reset_all() { btmemb_init(&bte_pcbs); btmemb_init(&bte_ctrl_reqs); if(btstate.info!=NULL) free(btstate.info); btstate.info = NULL; btstate.hci_inited = 0; btstate.hci_cmddone = 0; btstate.num_founddevs = 0; btstate.last_err = ERR_OK; } static void bt_alarmhandler(syswd_t alarm,void *cbarg) { __lwp_thread_dispatchdisable(); SYS_SwitchFiber(0,0,0,0,(u32)l2cap_tmr,(u32)(&ppc_stack[STACKSIZE])); __lwp_thread_dispatchunnest(); } static inline s32 __bte_waitcmdfinish(struct bt_state *state) { u32 level; s32 ret; if(!state) return ERR_VAL; _CPU_ISR_Disable(level); while(!state->hci_cmddone) LWP_ThreadSleep(state->hci_cmdq); ret = state->last_err; _CPU_ISR_Restore(level); return ret; } static inline s32 __bte_cmdfinish(struct bt_state *state,err_t err) { u32 level; if(!state) return ERR_VAL; _CPU_ISR_Disable(level); state->last_err = err; state->hci_cmddone = 1; if(state->cb!=NULL) state->cb(err,state->usrdata); else LWP_ThreadSignal(state->hci_cmdq); _CPU_ISR_Restore(level); return err; } static inline s32 __bte_waitrequest(struct ctrl_req_t *req) { s32 err; u32 level; if(!req || !req->pcb) return ERR_VAL; _CPU_ISR_Disable(level); while(req->state!=STATE_SENT && req->state!=STATE_FAILED) { LWP_ThreadSleep(req->pcb->cmdq); } err = req->err; _CPU_ISR_Restore(level); return err; } static inline void __bte_close_ctrl_queue(struct bte_pcb *pcb) { struct ctrl_req_t *req; while(pcb->ctrl_req_head!=NULL) { req = pcb->ctrl_req_head; req->err = ERR_CLSD; req->state = STATE_DISCONNECTED; if(req->sent!=NULL) { req->sent(pcb->cbarg,pcb,ERR_CLSD); btmemb_free(&bte_ctrl_reqs,req); } else LWP_ThreadSignal(pcb->cmdq); pcb->ctrl_req_head = req->next; } pcb->ctrl_req_tail = NULL; } static s32 __bte_send_pending_request(struct bte_pcb *pcb) { s32 err; struct ctrl_req_t *req; if(pcb->ctrl_req_head==NULL) return ERR_OK; if(pcb->state==STATE_DISCONNECTING || pcb->state==STATE_DISCONNECTED) return ERR_CLSD; req = pcb->ctrl_req_head; req->state = STATE_SENDING; err = l2ca_datawrite(pcb->ctl_pcb,req->p); btpbuf_free(req->p); if(err!=ERR_OK) { pcb->ctrl_req_head = req->next; req->err = err; req->state = STATE_FAILED; if(req->sent) { req->sent(pcb->cbarg,pcb,err); btmemb_free(&bte_ctrl_reqs,req); } else LWP_ThreadSignal(pcb->cmdq); } return err; } static s32 __bte_send_request(struct ctrl_req_t *req) { s32 err; u32 level; req->next = NULL; req->err = ERR_VAL; req->state = STATE_READY; _CPU_ISR_Disable(level); if(req->pcb->ctrl_req_head==NULL) { req->pcb->ctrl_req_head = req->pcb->ctrl_req_tail = req; err = __bte_send_pending_request(req->pcb); } else { req->pcb->ctrl_req_tail->next = req; req->pcb->ctrl_req_tail = req; err = ERR_OK; } _CPU_ISR_Restore(level); return err; } static err_t __bte_shutdown_finished(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result) { err_t err; struct bt_state *state = (struct bt_state*)arg; if(state==NULL) return ERR_OK; state->hci_inited = 0; hci_cmd_complete(NULL); if(result==HCI_SUCCESS) err = ERR_OK; else err = ERR_CONN; physbusif_close(); return __bte_cmdfinish(state,err); } static void bte_process_handshake(struct bte_pcb *pcb,u8_t param,void *buf,u16_t len) { struct ctrl_req_t *req; LOG("bte_process_handshake(%p)\n",pcb); switch(param) { case HIDP_HSHK_SUCCESSFULL: req = pcb->ctrl_req_head; pcb->ctrl_req_head = req->next; req->err = ERR_OK; req->state = STATE_SENT; if(req->sent) { req->sent(pcb->cbarg,pcb,ERR_OK); btmemb_free(&bte_ctrl_reqs,req); } else LWP_ThreadSignal(pcb->cmdq); __bte_send_pending_request(pcb); break; case HIDP_HSHK_NOTREADY: case HIDP_HSHK_INV_REPORTID: case HIDP_HSHK_NOTSUPPORTED: case HIDP_HSHK_IVALIDPARAM: case HIDP_HSHK_UNKNOWNERROR: break; case HIDP_HSHK_FATALERROR: break; default: break; } } static void bte_process_data(struct bte_pcb *pcb,u8_t param,void *buf,u16_t len) { LOG("bte_process_data(%p)\n",pcb); switch(param) { case HIDP_DATA_RTYPE_INPUT: if(pcb->recv!=NULL) pcb->recv(pcb->cbarg,buf,len); break; case HIDP_DATA_RTYPE_OTHER: case HIDP_DATA_RTYPE_OUPUT: case HIDP_DATA_RTYPE_FEATURE: break; default: break; } } static err_t bte_process_input(void *arg,struct l2cap_pcb *pcb,struct pbuf *p,err_t err) { u8 *buf; u16 len; u8 hdr,type,param; struct bte_pcb *bte = (struct bte_pcb*)arg; LOG("bte_process_input(%p,%p)\n",bte,p); if(bte->state==STATE_DISCONNECTING || bte->state==STATE_DISCONNECTED) return ERR_CLSD; buf = p->payload; len = p->tot_len; len--; hdr = *buf++; type = (hdr&HIDP_HDR_TRANS_MASK); param = (hdr&HIDP_HDR_PARAM_MASK); switch(type) { case HIDP_TRANS_HANDSHAKE: bte_process_handshake(bte,param,buf,len); break; case HIDP_TRANS_HIDCONTROL: break; case HIDP_TRANS_DATA: bte_process_data(bte,param,buf,len); break; default: break; } return ERR_OK; } void BTE_Init() { u32 level; struct timespec tb; LOG("BTE_Init()\n"); memset(&btstate,0,sizeof(struct bt_state)); hci_init(); l2cap_init(); physbusif_init(); LWP_InitQueue(&btstate.hci_cmdq); SYS_CreateAlarm(&btstate.timer_svc); _CPU_ISR_Disable(level); bte_reset_all(); hci_reset_all(); l2cap_reset_all(); physbusif_reset_all(); hci_wlp_complete(acl_wlp_completed); hci_connection_complete(acl_conn_complete); _CPU_ISR_Restore(level); tb.tv_sec = 1; tb.tv_nsec = 0; SYS_SetPeriodicAlarm(btstate.timer_svc,&tb,&tb,bt_alarmhandler, NULL); } void BTE_Shutdown() { u32 level; if(btstate.hci_inited==0) return; LOG("BTE_Shutdown()\n"); _CPU_ISR_Disable(level); SYS_RemoveAlarm(btstate.timer_svc); btstate.cb = NULL; btstate.usrdata = NULL; btstate.hci_cmddone = 0; hci_arg(&btstate); hci_cmd_complete(__bte_shutdown_finished); hci_reset(); __bte_waitcmdfinish(&btstate); _CPU_ISR_Restore(level); physbusif_shutdown(); } s32 BTE_InitCore(btecallback cb) { u32 level; _CPU_ISR_Disable(level); btstate.cb = cb; btstate.usrdata = NULL; btstate.hci_cmddone = 0; hci_arg(&btstate); hci_cmd_complete(bte_hci_initcore_complete); hci_reset(); _CPU_ISR_Restore(level); return ERR_OK; } s32 BTE_ApplyPatch(btecallback cb) { u32 level; u8 kick = 0; _CPU_ISR_Disable(level); btstate.cb = cb; btstate.usrdata = NULL; btstate.hci_cmddone = 0; hci_arg(&btstate); hci_cmd_complete(bte_hci_apply_patch_complete); hci_vendor_specific_command(HCI_VENDOR_PATCH_START_OCF,HCI_VENDOR_OGF,&kick,1); _CPU_ISR_Restore(level); return ERR_OK; } s32 BTE_InitSub(btecallback cb) { u32 level; _CPU_ISR_Disable(level); btstate.cb = cb; btstate.usrdata = NULL; btstate.hci_cmddone = 0; hci_arg(&btstate); hci_cmd_complete(bte_hci_initsub_complete); hci_write_inquiry_mode(0x01); _CPU_ISR_Restore(level); return ERR_OK; } s32 BTE_ReadStoredLinkKey(struct linkkey_info *keys,u8 max_cnt,btecallback cb) { u32 level; _CPU_ISR_Disable(level); btstate.cb = cb; btstate.usrdata = keys; btstate.num_maxdevs = max_cnt; btstate.hci_cmddone = 0; hci_arg(&btstate); hci_cmd_complete(bte_read_stored_link_key_complete); hci_read_stored_link_key(); _CPU_ISR_Restore(level); return ERR_OK; } s32 BTE_ReadBdAddr(struct bd_addr *bdaddr, btecallback cb) { u32 level; _CPU_ISR_Disable(level); btstate.cb = cb; btstate.usrdata = bdaddr; btstate.hci_cmddone = 0; hci_arg(&btstate); hci_cmd_complete(bte_read_bd_addr_complete); hci_read_bd_addr(); _CPU_ISR_Restore(level); return ERR_OK; } void (*BTE_SetDisconnectCallback(void (*callback)(struct bd_addr *bdaddr,u8 reason)))(struct bd_addr *bdaddr,u8 reason) { return l2cap_disconnect_bb(callback); } struct bte_pcb* bte_new() { struct bte_pcb *pcb; if((pcb=btmemb_alloc(&bte_pcbs))==NULL) return NULL; memset(pcb,0,sizeof(struct bte_pcb)); pcb->state = (u32)STATE_NOTREADY; LWP_InitQueue(&(pcb->cmdq)); return pcb; } s32 bte_registerdeviceasync(struct bte_pcb *pcb,struct bd_addr *bdaddr,s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err)) { u32 level; s32 err = ERR_OK; struct l2cap_pcb *l2capcb = NULL; //printf("bte_registerdeviceasync()\n"); _CPU_ISR_Disable(level); pcb->err = ERR_USE; pcb->data_pcb = NULL; pcb->ctl_pcb = NULL; pcb->conn_cfm = conn_cfm; pcb->state = (u32)STATE_CONNECTING; bd_addr_set(&(pcb->bdaddr),bdaddr); if((l2capcb=l2cap_new())==NULL) { err = ERR_MEM; goto error; } l2cap_arg(l2capcb,pcb); err = l2cap_connect_ind(l2capcb,bdaddr,HIDP_CONTROL_CHANNEL,l2cap_accepted); if(err!=ERR_OK) { l2cap_close(l2capcb); err = ERR_CONN; goto error; } if((l2capcb=l2cap_new())==NULL) { err = ERR_MEM; goto error; } l2cap_arg(l2capcb,pcb); err = l2cap_connect_ind(l2capcb,bdaddr,HIDP_DATA_CHANNEL,l2cap_accepted); if(err!=ERR_OK) { l2cap_close(l2capcb); err = ERR_CONN; } error: _CPU_ISR_Restore(level); //printf("bte_registerdeviceasync(%02x)\n",err); return err; } s32 bte_inquiry(struct inquiry_info *info,u8 max_cnt,u8 flush) { s32_t i; u32 level,fnd; err_t last_err; struct inquiry_info_ex *pinfo; last_err = ERR_OK; _CPU_ISR_Disable(level); if(btstate.num_founddevs==0 || flush==1) { btstate.hci_cmddone = 0; btstate.num_maxdevs = max_cnt; hci_inquiry(0x009E8B33,0x03,max_cnt,bte_inquiry_complete); last_err = __bte_waitcmdfinish(&btstate); } fnd = btstate.num_founddevs; pinfo = btstate.info; _CPU_ISR_Restore(level); if(last_err==ERR_OK) { for(i=0;istate = (u32)STATE_DISCONNECTING; if(pcb->data_pcb!=NULL ) err = l2ca_disconnect_req(pcb->data_pcb,l2cap_disconnect_cfm); else if(pcb->ctl_pcb!=NULL) err = l2ca_disconnect_req(pcb->ctl_pcb,l2cap_disconnect_cfm); _CPU_ISR_Restore(level); return err; } /* s32 bte_connect(struct bte_pcb *pcb,struct bd_addr *bdaddr,u8 psm,s32 (*recv)(void *arg,void *buffer,u16 len)) { u32 level; err_t err = ERR_OK; if(pcb==NULL) return ERR_VAL; if((pcb->l2capcb=l2cap_new())==NULL) return ERR_MEM; pcb->psm = psm; pcb->recv = recv; bd_addr_set(&(pcb->bdaddr),bdaddr); _CPU_ISR_Disable(level); pcb->err = ERR_CONN; l2cap_arg(pcb->l2capcb,pcb); err = l2ca_connect_req(pcb->l2capcb,bdaddr,psm,HCI_ALLOW_ROLE_SWITCH,l2cap_connected); if(err==ERR_OK) { LWP_ThreadSleep(pcb->cmdq); err = pcb->err; } _CPU_ISR_Restore(level); return err; } s32 bte_connect_ex(struct bte_pcb *pcb,struct inquiry_info_ex *info,u8 psm,s32 (*recv)(void *arg,void *buffer,u16 len)) { err_t err; if((err=hci_reg_dev_info(&(info->bdaddr),info->cod,info->psrm,info->psm,info->co))!=ERR_OK) return err; return bte_connect(pcb,&(info->bdaddr),psm,recv); } s32 bte_listen(struct bte_pcb *pcb,struct bd_addr *bdaddr,u8 psm) { s32 err; u32 level; struct l2cap_pcb *l2capcb = NULL; if(pcb==NULL) return ERR_VAL; if((l2capcb=l2cap_new())==NULL) return ERR_MEM; pcb->l2capcb = NULL; pcb->psm = psm; pcb->recv = NULL; bd_addr_set(&(pcb->bdaddr),bdaddr); _CPU_ISR_Disable(level); pcb->err = ERR_CONN; l2cap_arg(l2capcb,pcb); err = l2cap_connect_ind(l2capcb,psm,l2cap_accepted); if(err!=ERR_OK) l2cap_close(l2capcb); _CPU_ISR_Restore(level); return err; } s32 bte_accept(struct bte_pcb *pcb,s32 (*recv)(void *arg,void *buffer,u16 len)) { u32 level; err_t err = ERR_OK; if(pcb==NULL) return ERR_VAL; _CPU_ISR_Disable(level); pcb->recv = recv; while(pcb->l2capcb==NULL) LWP_ThreadSleep(pcb->cmdq); err = pcb->err; _CPU_ISR_Restore(level); return err; } */ s32 bte_senddata(struct bte_pcb *pcb,void *message,u16 len) { err_t err; struct pbuf *p; if(pcb==NULL || message==NULL || len==0) return ERR_VAL; if(pcb->state==STATE_DISCONNECTING || pcb->state==STATE_DISCONNECTED) return ERR_CLSD; if((p=btpbuf_alloc(PBUF_RAW,(1 + len),PBUF_RAM))==NULL) { ERROR("bte_senddata: Could not allocate memory for pbuf\n"); return ERR_MEM; } ((u8*)p->payload)[0] = (HIDP_TRANS_DATA|HIDP_DATA_RTYPE_OUPUT); memcpy(p->payload+1,message,len); err = l2ca_datawrite(pcb->data_pcb,p); btpbuf_free(p); return err; } s32 bte_sendmessageasync(struct bte_pcb *pcb,void *message,u16 len,s32 (*sent)(void *arg,struct bte_pcb *pcb,u8 err)) { struct pbuf *p; struct ctrl_req_t *req; //printf("bte_sendmessageasync()\n"); if(pcb==NULL || message==NULL || len==0) return ERR_VAL; if(pcb->state==STATE_DISCONNECTING || pcb->state==STATE_DISCONNECTED) return ERR_CLSD; if((req=btmemb_alloc(&bte_ctrl_reqs))==NULL) { ERROR("bte_sendmessageasync: Could not allocate memory for request\n"); return ERR_MEM; } if((p=btpbuf_alloc(PBUF_RAW,(1 + len),PBUF_RAM))==NULL) { ERROR("bte_sendmessageasync: Could not allocate memory for pbuf\n"); btmemb_free(&bte_ctrl_reqs,req); return ERR_MEM; } ((u8*)p->payload)[0] = (HIDP_TRANS_SETREPORT|HIDP_DATA_RTYPE_OUPUT); memcpy(p->payload+1,message,len); req->p = p; req->pcb = pcb; req->sent = sent; return __bte_send_request(req); } s32 bte_sendmessage(struct bte_pcb *pcb,void *message,u16 len) { s32 err = ERR_VAL; struct pbuf *p; struct ctrl_req_t *req; //printf("bte_sendmessage()\n"); if(pcb==NULL || message==NULL || len==0) return ERR_VAL; if(pcb->state==STATE_DISCONNECTING || pcb->state==STATE_DISCONNECTED) return ERR_CLSD; if((req=btmemb_alloc(&bte_ctrl_reqs))==NULL) { ERROR("bte_sendmessage: Could not allocate memory for request\n"); return ERR_MEM; } if((p=btpbuf_alloc(PBUF_RAW,(1 + len),PBUF_RAM))==NULL) { ERROR("bte_sendmessage: Could not allocate memory for pbuf\n"); btmemb_free(&bte_ctrl_reqs,req); return ERR_MEM; } ((u8*)p->payload)[0] = (HIDP_TRANS_SETREPORT|HIDP_DATA_RTYPE_OUPUT); memcpy(p->payload+1,message,len); req->p = p; req->pcb = pcb; req->sent = NULL; err = __bte_send_request(req); if(err==ERR_OK) err = __bte_waitrequest(req); btmemb_free(&bte_ctrl_reqs,req); return err; } void bte_arg(struct bte_pcb *pcb,void *arg) { u32 level; _CPU_ISR_Disable(level); pcb->cbarg = arg; _CPU_ISR_Restore(level); } void bte_received(struct bte_pcb *pcb, s32 (*recv)(void *arg,void *buffer,u16 len)) { u32 level; _CPU_ISR_Disable(level); pcb->recv = recv; _CPU_ISR_Restore(level); } void bte_disconnected(struct bte_pcb *pcb,s32 (disconn_cfm)(void *arg,struct bte_pcb *pcb,u8 err)) { u32 level; _CPU_ISR_Disable(level); pcb->disconn_cfm = disconn_cfm; _CPU_ISR_Restore(level); } err_t acl_wlp_completed(void *arg,struct bd_addr *bdaddr) { //hci_sniff_mode(bdaddr,200,100,10,10); return ERR_OK; } err_t acl_conn_complete(void *arg,struct bd_addr *bdaddr) { //printf("acl_conn_complete\n"); //memcpy(&(btstate.acl_bdaddr),bdaddr,6); hci_write_link_policy_settings(bdaddr,0x0005); return ERR_OK; } err_t pin_req(void *arg,struct bd_addr *bdaddr) { //printf("pin_req\n"); return ERR_OK; } err_t l2cap_disconnected_ind(void *arg, struct l2cap_pcb *pcb, err_t err) { struct bte_pcb *bte = (struct bte_pcb*)arg; if(bte==NULL) return ERR_OK; bte->state = (u32)STATE_DISCONNECTING; switch(l2cap_psm(pcb)) { case HIDP_CONTROL_CHANNEL: l2cap_close(bte->ctl_pcb); bte->ctl_pcb = NULL; break; case HIDP_DATA_CHANNEL: l2cap_close(bte->data_pcb); bte->data_pcb = NULL; break; } if(bte->data_pcb==NULL && bte->ctl_pcb==NULL) { bte->err = ERR_OK; bte->state = (u32)STATE_DISCONNECTED; __bte_close_ctrl_queue(bte); if(bte->disconn_cfm!=NULL) bte->disconn_cfm(bte->cbarg,bte,ERR_OK); } return ERR_OK; } err_t l2cap_disconnect_cfm(void *arg, struct l2cap_pcb *pcb) { struct bte_pcb *bte = (struct bte_pcb*)arg; if(bte==NULL) return ERR_OK; switch(l2cap_psm(pcb)) { case HIDP_CONTROL_CHANNEL: l2cap_close(bte->ctl_pcb); bte->ctl_pcb = NULL; if(bte->data_pcb!=NULL) l2ca_disconnect_req(bte->data_pcb,l2cap_disconnect_cfm); break; case HIDP_DATA_CHANNEL: l2cap_close(bte->data_pcb); bte->data_pcb = NULL; if(bte->ctl_pcb!=NULL) l2ca_disconnect_req(bte->ctl_pcb,l2cap_disconnect_cfm); break; } if(bte->data_pcb==NULL && bte->ctl_pcb==NULL) { bte->err = ERR_OK; bte->state = (u32)STATE_DISCONNECTED; __bte_close_ctrl_queue(bte); if(bte->disconn_cfm!=NULL) bte->disconn_cfm(bte->cbarg,bte,ERR_OK); hci_cmd_complete(NULL); hci_disconnect(&(bte->bdaddr),HCI_OTHER_END_TERMINATED_CONN_USER_ENDED); } return ERR_OK; } err_t link_key_not(void *arg,struct bd_addr *bdaddr,u8_t *key) { //printf("link_key_not\n"); return hci_write_stored_link_key(bdaddr,key); } /* err_t l2cap_connected(void *arg,struct l2cap_pcb *l2cappcb,u16_t result,u16_t status) { struct bte_pcb *btepcb = (struct bte_pcb*)arg; printf("l2cap_connected(%02x)\n",result); if(result==L2CAP_CONN_SUCCESS) { l2cap_recv(l2cappcb,bte_input); l2cap_disconnect_ind(l2cappcb,l2cap_disconnected_ind); btepcb->err = ERR_OK; } else { l2cap_close(l2cappcb); btepcb->err = ERR_CONN; } if(btepcb->conn_cfm) btepcb->conn_cfm(btepcb->cbarg,btepcb,btepcb->err); LWP_ThreadSignal(btepcb->cmdq); return ERR_OK; } */ err_t l2cap_accepted(void *arg,struct l2cap_pcb *l2cappcb,err_t err) { struct bte_pcb *btepcb = (struct bte_pcb*)arg; //printf("l2cap_accepted(%02x)\n",err); if(err==ERR_OK) { l2cap_recv(l2cappcb,bte_process_input); l2cap_disconnect_ind(l2cappcb,l2cap_disconnected_ind); switch(l2cap_psm(l2cappcb)) { case HIDP_CONTROL_CHANNEL: btepcb->ctl_pcb = l2cappcb; break; case HIDP_DATA_CHANNEL: btepcb->data_pcb = l2cappcb; break; } if(btepcb->data_pcb && btepcb->ctl_pcb) { btepcb->err = ERR_OK; btepcb->state = (u32)STATE_CONNECTED; if(btepcb->conn_cfm) btepcb->conn_cfm(btepcb->cbarg,btepcb,ERR_OK); } } else { l2cap_close(l2cappcb); btepcb->err = ERR_CONN; btepcb->conn_cfm(btepcb->cbarg,btepcb,ERR_CONN); } return ERR_OK; } err_t bte_inquiry_complete(void *arg,struct hci_pcb *pcb,struct hci_inq_res *ires,u16_t result) { u8_t i; struct hci_inq_res *p; struct bt_state *state = (struct bt_state*)arg; if(result==HCI_SUCCESS) { if(ires!=NULL) { if(btstate.info!=NULL) free(btstate.info); btstate.info = NULL; btstate.num_maxdevs = 0; btstate.num_founddevs = 0; p = ires; while(p!=NULL) { btstate.num_founddevs++; p = p->next; } p = ires; btstate.info = (struct inquiry_info_ex*)malloc(sizeof(struct inquiry_info_ex)*btstate.num_founddevs); for(i=0;ibdaddr)); memcpy(btstate.info[i].cod,p->cod,3); btstate.info[i].psrm = p->psrm; btstate.info[i].psm = p->psm; btstate.info[i].co = p->co; printf("bdaddr: %02x:%02x:%02x:%02x:%02x:%02x\n",p->bdaddr.addr[0],p->bdaddr.addr[1],p->bdaddr.addr[2],p->bdaddr.addr[3],p->bdaddr.addr[4],p->bdaddr.addr[5]); printf("cod: %02x%02x%02x\n",p->cod[0],p->cod[1],p->cod[2]); printf("psrm: %02x\n",p->psrm); printf("psm: %02x\n",p->psm); printf("co: %04x\n",p->co); p = p->next; } __bte_cmdfinish(state,ERR_OK); } else hci_inquiry(0x009E8B33,0x03,btstate.num_maxdevs,bte_inquiry_complete); } return ERR_OK; } err_t bte_read_stored_link_key_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result) { u8_t i = 0; struct hci_link_key *p; struct linkkey_info *keys; struct bt_state *state = (struct bt_state*)arg; if(!pcb) return ERR_CONN; LOG("bte_read_stored_link_key_complete(%02x,%p)\n",result,pcb->keyres); if(state==NULL) return ERR_VAL; if(!(ogf==HCI_HC_BB_OGF && ocf==HCI_R_STORED_LINK_KEY_OCF)) return __bte_cmdfinish(state,ERR_CONN); if(result==HCI_SUCCESS) { keys = (struct linkkey_info*)state->usrdata; if(pcb->keyres!=NULL && keys!=NULL) { for(i=0,p=pcb->keyres;inum_maxdevs && p!=NULL;i++) { bd_addr_set(&(keys[i].bdaddr),&(p->bdaddr)); memcpy(keys[i].key,p->key,16); p = p->next; } } LOG("bte_read_stored_link_key_complete(%02x,%p,%d)\n",result,pcb->keyres,i); __bte_cmdfinish(state,i); return ERR_OK; } return __bte_cmdfinish(state,ERR_VAL); } err_t bte_read_bd_addr_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result) { struct bd_addr *bdaddr; struct bt_state *state = (struct bt_state*)arg; if(!pcb) return ERR_CONN; LOG("bte_read_bd_addr_complete(%02x,%p)\n", result, &pcb->bdaddr); if(state==NULL) return ERR_VAL; if(!(ogf==HCI_INFO_PARAM_OGF && ocf==HCI_R_BD_ADDR_OCF)) return __bte_cmdfinish(state,ERR_CONN); if(result == HCI_SUCCESS) { bdaddr = (struct bd_addr *)state->usrdata; if (bdaddr != NULL) { bdaddr->addr[0] = pcb->bdaddr.addr[5]; bdaddr->addr[1] = pcb->bdaddr.addr[4]; bdaddr->addr[2] = pcb->bdaddr.addr[3]; bdaddr->addr[3] = pcb->bdaddr.addr[2]; bdaddr->addr[4] = pcb->bdaddr.addr[1]; bdaddr->addr[5] = pcb->bdaddr.addr[0]; } LOG("bte_read_bd_addr_complete(%02x,%p,%d)\n",result,bdaddr,i); __bte_cmdfinish(state,ERR_OK); return ERR_OK; } return __bte_cmdfinish(state,ERR_VAL); } /* new init with patching */ err_t bte_hci_initcore_complete2(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result) { err_t err = ERR_OK; u8_t dev_cod[] = {0x04, 0x02,0x40}; struct bt_state *state = (struct bt_state*)arg; LOG("bte_hci_initcore_complete2(%02x,%02x)\n",ogf,ocf); switch(ogf) { case HCI_HC_BB_OGF: if(ocf==HCI_WRITE_INQUIRY_MODE) { if(result==HCI_SUCCESS) { hci_write_page_scan_type(0x01); } else err = ERR_CONN; } else if(ocf==HCI_WRITE_PAGE_SCAN_TYPE) { if(result==HCI_SUCCESS) { hci_write_inquiry_scan_type(0x01); } else err = ERR_CONN; } else if(ocf==HCI_WRITE_INQUIRY_SCAN_TYPE) { if(result==HCI_SUCCESS) { hci_write_cod(dev_cod); } else err = ERR_CONN; } else if(ocf==HCI_WRITE_COD) { if(result==HCI_SUCCESS) { hci_write_page_timeout(0x2000); } else err = ERR_CONN; } else if(ocf==HCI_WRITE_PAGE_TIMEOUT) { if(result==HCI_SUCCESS) { state->hci_inited = 1; hci_cmd_complete(NULL); return __bte_cmdfinish(state,ERR_OK); } else err = ERR_CONN; } break; default: LOG("Unknown command complete event. OGF = 0x%x OCF = 0x%x\n", ogf, ocf); err = ERR_CONN; break; } if(err!=ERR_OK) __bte_cmdfinish(state,err); return err; } err_t bte_hci_initcore_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result) { err_t err = ERR_OK; u8_t dev_cod[] = {0x00, 0x1f,0x00}; struct bt_state *state = (struct bt_state*)arg; LOG("bte_hci_initcore_complete(%02x,%02x)\n",ogf,ocf); switch(ogf) { case HCI_INFO_PARAM: if(ocf==HCI_READ_BUFFER_SIZE) { if(result==HCI_SUCCESS) { hci_write_cod(dev_cod); } else err = ERR_CONN; } else if(ocf==HCI_READ_LOCAL_VERSION) { if(result==HCI_SUCCESS) { hci_read_bd_addr(); } else err = ERR_CONN; } else if(ocf==HCI_READ_BD_ADDR) { if(result==HCI_SUCCESS) { hci_read_local_features(); } else err = ERR_CONN; } else if(ocf==HCI_READ_LOCAL_FEATURES) { if(result==HCI_SUCCESS) { hci_cmd_complete(bte_hci_initcore_complete2); hci_write_inquiry_mode(0x01); } else err = ERR_CONN; } break; case HCI_HC_BB_OGF: if(ocf==HCI_RESET) { if(result==HCI_SUCCESS) { hci_read_buffer_size(); } else err = ERR_CONN; } else if(ocf==HCI_WRITE_COD) { if(result==HCI_SUCCESS) { hci_write_local_name((u8_t*)"",1); } else err = ERR_CONN; } else if(ocf==HCI_WRITE_LOCAL_NAME) { if(result==HCI_SUCCESS) { hci_write_pin_type(0x00); } else err = ERR_CONN; } else if(ocf==HCI_WRITE_PIN_TYPE) { if(result==HCI_SUCCESS) { hci_host_buffer_size(); } else err = ERR_CONN; } else if(ocf==HCI_HOST_BUF_SIZE) { if(result==HCI_SUCCESS) { hci_read_local_version(); } else err = ERR_CONN; } break; default: LOG("Unknown command complete event. OGF = 0x%x OCF = 0x%x\n", ogf, ocf); err = ERR_CONN; break; } if(err!=ERR_OK) __bte_cmdfinish(state,err); return err; } err_t bte_hci_apply_patch_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result) { err_t err = ERR_OK; struct bt_state *state = (struct bt_state*)arg; LOG("bte_hci_apply_patch_complete(%02x,%02x,%02x)\n",ogf,ocf,result); switch(ogf) { case HCI_VENDOR_OGF: if(ocf==HCI_VENDOR_PATCH_START_OCF) { if(result==HCI_SUCCESS) { err = hci_vendor_specific_command(HCI_VENDOR_PATCH_CONT_OCF,HCI_VENDOR_OGF,bte_patch0,184); } else err = ERR_CONN; } else if(ocf==HCI_VENDOR_PATCH_CONT_OCF) { if(result==HCI_SUCCESS) { hci_cmd_complete(bte_hci_patch_complete); err = hci_vendor_specific_command(HCI_VENDOR_PATCH_END_OCF,HCI_VENDOR_OGF,bte_patch1,92); } else err = ERR_CONN; } break; default: LOG("Unknown command complete event. OGF = 0x%x OCF = 0x%x\n", ogf, ocf); err = ERR_CONN; break; } if(err!=ERR_OK) __bte_cmdfinish(state,err); return err; } err_t bte_hci_patch_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result) { err_t err = ERR_OK; u8_t dev_cod[] = {0x04, 0x02,0x40}; struct bt_state *state = (struct bt_state*)arg; LOG("bte_hci_patch_complete(%02x,%02x,%02x)\n",ogf,ocf,result); switch(ogf) { case HCI_INFO_PARAM: if(ocf==HCI_READ_BUFFER_SIZE) { if(result==HCI_SUCCESS) { hci_write_cod(dev_cod); } else err = ERR_CONN; } else if(ocf==HCI_READ_LOCAL_VERSION) { if(result==HCI_SUCCESS) { hci_read_bd_addr(); } else err = ERR_CONN; } else if(ocf==HCI_READ_BD_ADDR) { if(result==HCI_SUCCESS) { hci_read_local_features(); } else err = ERR_CONN; } else if(ocf==HCI_READ_LOCAL_FEATURES) { if(result==HCI_SUCCESS) { hci_cmd_complete(NULL); return __bte_cmdfinish(state,ERR_OK); } else err = ERR_CONN; } break; case HCI_HC_BB_OGF: if(ocf==HCI_RESET) { if(result==HCI_SUCCESS) { hci_read_buffer_size(); } else err = ERR_CONN; } else if(ocf==HCI_WRITE_COD) { if(result==HCI_SUCCESS) { hci_write_local_name((u8_t*)"",1); } else err = ERR_CONN; } else if(ocf==HCI_WRITE_LOCAL_NAME) { if(result==HCI_SUCCESS) { hci_write_pin_type(0x00); } else err = ERR_CONN; } else if(ocf==HCI_WRITE_PIN_TYPE) { if(result==HCI_SUCCESS) { hci_host_buffer_size(); } else err = ERR_CONN; } else if(ocf==HCI_HOST_BUF_SIZE) { if(result==HCI_SUCCESS) { hci_read_local_version(); } else err = ERR_CONN; } break; case HCI_VENDOR_OGF: if(ocf==HCI_VENDOR_PATCH_END_OCF) { if(result==HCI_SUCCESS) { err = hci_reset(); } else err = ERR_CONN; } break; default: LOG("Unknown command complete event. OGF = 0x%x OCF = 0x%x\n", ogf, ocf); err = ERR_CONN; break; } if(err!=ERR_OK) __bte_cmdfinish(state,err); return err; } err_t bte_hci_initsub_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result) { err_t err = ERR_OK; u8_t dev_cod[] = {0x00, 0x04,0x48}; struct bt_state *state = (struct bt_state*)arg; LOG("bte_hci_initsub_complete(%02x,%02x)\n",ogf,ocf); switch(ogf) { case HCI_HC_BB_OGF: if(ocf==HCI_WRITE_INQUIRY_MODE) { if(result==HCI_SUCCESS) { hci_write_page_scan_type(0x01); } else err = ERR_CONN; } else if(ocf==HCI_WRITE_PAGE_SCAN_TYPE) { if(result==HCI_SUCCESS) { hci_write_inquiry_scan_type(0x01); } else err = ERR_CONN; } else if(ocf==HCI_WRITE_INQUIRY_SCAN_TYPE) { if(result==HCI_SUCCESS) { hci_write_cod(dev_cod); } else err = ERR_CONN; } else if(ocf==HCI_WRITE_COD) { if(result==HCI_SUCCESS) { hci_write_page_timeout(0x8000); } else err = ERR_CONN; } else if(ocf==HCI_WRITE_PAGE_TIMEOUT) { if(result==HCI_SUCCESS) { hci_write_local_name((u8_t*)"Wii",4); } else err = ERR_CONN; } else if(ocf==HCI_WRITE_LOCAL_NAME) { if(result==HCI_SUCCESS) { hci_write_scan_enable(0x02); } else err = ERR_CONN; } else if(ocf==HCI_WRITE_SCAN_ENABLE) { if(result==HCI_SUCCESS) { hci_cmd_complete(NULL); return __bte_cmdfinish(state,ERR_OK); } else err = ERR_CONN; } break; default: LOG("Unknown command complete event. OGF = 0x%x OCF = 0x%x\n", ogf, ocf); err = ERR_CONN; break; } if(err!=ERR_OK) __bte_cmdfinish(state,err); return err; }