diff --git a/gc/bte/bd_addr.h b/gc/bte/bd_addr.h index 87faf9267..90f6614c1 100644 --- a/gc/bte/bd_addr.h +++ b/gc/bte/bd_addr.h @@ -39,12 +39,12 @@ extern "C" { #endif /* __cplusplus */ +#define BD_ADDR_LEN 6 + struct bd_addr { - u8 addr[6]; + u8 addr[BD_ADDR_LEN]; }; -#define BD_ADDR_LEN 6 - #define BD_ADDR_ANY (&(struct bd_addr){{0,0,0,0,0,0}}) #define BD_ADDR_LOCAL (&(struct bd_addr){{0,0,0,0xff,0xff,0xff}}) @@ -55,6 +55,23 @@ struct bd_addr { (bdaddr)->addr[3] = d; \ (bdaddr)->addr[4] = e; \ (bdaddr)->addr[5] = f; }while(0) + +#define BD_ADDR_FROM_BYTES(bdaddr, bytes) do{ \ + (bdaddr)->addr[0] = bytes[5]; \ + (bdaddr)->addr[1] = bytes[4]; \ + (bdaddr)->addr[2] = bytes[3]; \ + (bdaddr)->addr[3] = bytes[2]; \ + (bdaddr)->addr[4] = bytes[1]; \ + (bdaddr)->addr[5] = bytes[0]; }while(0) + +#define BYTES_FROM_BD_ADDR(bytes, bdaddr) do{ \ + bytes[0] = (bdaddr)->addr[5]; \ + bytes[1] = (bdaddr)->addr[4]; \ + bytes[2] = (bdaddr)->addr[3]; \ + bytes[3] = (bdaddr)->addr[2]; \ + bytes[4] = (bdaddr)->addr[1]; \ + bytes[5] = (bdaddr)->addr[0]; }while(0) + //TODO: USE memcmp???? #define bd_addr_cmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ ((addr1)->addr[1] == (addr2)->addr[1]) && \ diff --git a/gc/bte/bte.h b/gc/bte/bte.h index 3a181613d..012315e21 100644 --- a/gc/bte/bte.h +++ b/gc/bte/bte.h @@ -56,18 +56,27 @@ #define HIDP_CTRL_VC_UNPLUG 0x05 /* HIDP data transaction headers */ -#define HIDP_DATA_RTYPE_MASK 0x03 -#define HIDP_DATA_RSRVD_MASK 0x0c -#define HIDP_DATA_RTYPE_OTHER 0x00 -#define HIDP_DATA_RTYPE_INPUT 0x01 -#define HIDP_DATA_RTYPE_OUPUT 0x02 -#define HIDP_DATA_RTYPE_FEATURE 0x03 +#define HIDP_DATA_RTYPE_MASK 0x03 +#define HIDP_DATA_RSRVD_MASK 0x0c +#define HIDP_DATA_RTYPE_OTHER 0x00 +#define HIDP_DATA_RTYPE_INPUT 0x01 +#define HIDP_DATA_RTYPE_OUPUT 0x02 +#define HIDP_DATA_RTYPE_FEATURE 0x03 #define HIDP_PROTO_BOOT 0x00 #define HIDP_PROTO_REPORT 0x01 +#define BD_LINK_KEY_LEN 16 +#define BD_NAME_LEN 248 +#define BD_MAX_INQUIRY_DEVS 255 + +enum pair_mode { + PAIR_MODE_NORMAL, + PAIR_MODE_TEMPORARY +}; + #ifdef __cplusplus - extern "C" { + extern "C" { #endif /* __cplusplus */ struct l2cap_pcb; @@ -88,10 +97,22 @@ struct inquiry_info_ex u16 co; }; +struct bte_inquiry_res +{ + u8 count; + struct inquiry_info_ex *info; +}; + struct linkkey_info { struct bd_addr bdaddr; - u8 key[16]; + u8 key[BD_LINK_KEY_LEN]; +}; + +struct pad_name_info +{ + struct bd_addr bdaddr; + u8 name[BD_NAME_LEN]; }; struct bte_pcb @@ -112,6 +133,7 @@ struct bte_pcb s32 (*recv)(void *arg,void *buffer,u16 len); + s32 (*conn_req)(void *arg,struct bte_pcb *pcb,struct bd_addr *bdaddr,u8 *cod,u8 link_type,u8 err); s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err); s32 (*disconn_cfm)(void *arg,struct bte_pcb *pcb,u8 err); }; @@ -120,34 +142,47 @@ typedef s32 (*btecallback)(s32 result,void *userdata); void BTE_Init(void); void BTE_Shutdown(void); +void BTE_Close(void); s32 BTE_InitCore(btecallback cb); s32 BTE_ApplyPatch(btecallback cb); s32 BTE_InitSub(btecallback cb); s32 BTE_ReadStoredLinkKey(struct linkkey_info *keys,u8 max_cnt,btecallback cb); s32 BTE_ReadBdAddr(struct bd_addr *bdaddr, btecallback cb); +s32 BTE_SetEvtFilter(u8 filter_type,u8 filter_cond_type,u8 *cond, btecallback cb); +s32 BTE_ReadRemoteName(struct pad_name_info *padinfo, btecallback cb); +s32 BTE_Inquiry(u8 max_cnt,u8 flush, btecallback cb); +s32 BTE_PeriodicInquiry(u8 max_cnt,u8 flush,btecallback cb); +s32 BTE_ExitPeriodicInquiry(void); +s32 BTE_LinkKeyRequestReply(struct bd_addr *bdaddr,u8 *key); +s32 BTE_LinkKeyRequestNegativeReply(struct bd_addr *bdaddr); void (*BTE_SetDisconnectCallback(void (*callback)(struct bd_addr *bdaddr,u8 reason)))(struct bd_addr *bdaddr,u8 reason); +void BTE_SetHostSyncButtonCallback(void (*callback)(u32 held)); +void BTE_SetConnectionRequestCallback(s8 (*callback)(void *arg,struct bd_addr *bdaddr,u8 *cod,u8 link_type)); +void BTE_SetLinkKeyRequestCallback(s8 (*callback)(void *arg,struct bd_addr *bdaddr)); +void BTE_SetLinkKeyNotificationCallback(s8 (*callback)(void *arg,struct bd_addr *bdaddr,u8 *key)); +u8 BTE_GetPairMode(void); +s32 BTE_WriteStoredLinkKey(struct bd_addr *bdaddr,u8 *key); +s32 BTE_ClearStoredLinkKeys(void); +s32 BTE_DeleteStoredLinkKey(struct bd_addr *bdaddr); struct bte_pcb* bte_new(void); +void bte_free(struct bte_pcb *pcb); void bte_arg(struct bte_pcb *pcb,void *arg); void bte_received(struct bte_pcb *pcb, s32 (*recv)(void *arg,void *buffer,u16 len)); void bte_disconnected(struct bte_pcb *pcb,s32 (disconn_cfm)(void *arg,struct bte_pcb *pcb,u8 err)); -s32 bte_registerdeviceasync(struct bte_pcb *pcb,struct bd_addr *bdaddr,s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err)); - s32 bte_disconnect(struct bte_pcb *pcb); -//s32 bte_listen(struct bte_pcb *pcb,struct bd_addr *bdaddr,u8 psm); -//s32 bte_accept(struct bte_pcb *pcb,s32 (*recv)(void *arg,void *buffer,u16 len)); -s32 bte_inquiry(struct inquiry_info *info,u8 max_cnt,u8 flush); -s32 bte_inquiry_ex(struct inquiry_info_ex *info,u8 max_cnt,u8 flush); -//s32 bte_connect(struct bte_pcb *pcb,struct bd_addr *bdaddr,u8 psm,s32 (*recv)(void *arg,void *buffer,u16 len)); -//s32 bte_connect_ex(struct bte_pcb *pcb,struct inquiry_info_ex *info,u8 psm,s32 (*recv)(void *arg,void *buffer,u16 len)); +s32 bte_listenasync(struct bte_pcb *pcb,struct bd_addr *bdaddr,s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err)); +s32 bte_listenasync_step2(struct bte_pcb *pcb,s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err)); +s32 bte_connectasync(struct bte_pcb *pcb,struct bd_addr *bdaddr,s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err)); +s32 bte_connectasync_step2(struct bte_pcb *pcb,s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err)); s32 bte_senddata(struct bte_pcb *pcb,void *message,u16 len); s32 bte_sendmessage(struct bte_pcb *pcb,void *message,u16 len); s32 bte_sendmessageasync(struct bte_pcb *pcb,void *message,u16 len,s32 (*sent)(void *arg,struct bte_pcb *pcb,u8 err)); #ifdef __cplusplus - } + } #endif /* __cplusplus */ #endif diff --git a/gc/ogc/conf.h b/gc/ogc/conf.h index 4cdf2962a..8564b5736 100644 --- a/gc/ogc/conf.h +++ b/gc/ogc/conf.h @@ -128,6 +128,8 @@ enum { #define CONF_PAD_MAX_REGISTERED 10 #define CONF_PAD_MAX_ACTIVE 4 +#define CONF_PAD_ACTIVE_AND_OTHER (CONF_PAD_MAX_ACTIVE + 2) +#define CONF_PAD_TOTAL (CONF_PAD_MAX_REGISTERED + CONF_PAD_ACTIVE_AND_OTHER) typedef struct _conf_pad_device conf_pad_device; @@ -146,7 +148,24 @@ struct _conf_pads { conf_pad_device unknown; } ATTRIBUTE_PACKED; +typedef struct _conf_pad_guest_device conf_pad_guest_device; + +struct _conf_pad_guest_device { + u8 bdaddr[6]; + char name[0x40]; + u8 link_key[16]; +} ATTRIBUTE_PACKED; + +typedef struct _conf_pad_guests conf_pad_guests; + +struct _conf_pad_guests { + u8 num_guests; + conf_pad_guest_device guests[CONF_PAD_MAX_ACTIVE]; + conf_pad_guest_device unknown[2]; // Balance Board can't be set as guest... +} ATTRIBUTE_PACKED; + s32 CONF_Init(void); +s32 CONF_SaveChanges(void); s32 CONF_GetLength(const char *name); s32 CONF_GetType(const char *name); s32 CONF_Get(const char *name, void *buffer, u32 length); @@ -164,6 +183,9 @@ s32 CONF_GetCounterBias(u32 *bias); s32 CONF_GetScreenSaverMode(void); s32 CONF_GetDisplayOffsetH(s8 *offset); s32 CONF_GetPadDevices(conf_pads *pads); +s32 CONF_SetPadDevices(const conf_pads *pads); +s32 CONF_GetPadGuestDevices(conf_pad_guests *pads); +s32 CONF_SetPadGuestDevices(const conf_pad_guests *pads); s32 CONF_GetNickName(u8 *nickname); s32 CONF_GetAspectRatio(void); s32 CONF_GetEULA(void); diff --git a/gc/ogc/system.h b/gc/ogc/system.h index 5493ed8a6..329d3190e 100644 --- a/gc/ogc/system.h +++ b/gc/ogc/system.h @@ -286,7 +286,7 @@ void SYS_ResetPMC(void); \brief Create/initialize sysalarm structure \param[in] thealarm pointer to the handle to store the created alarm context identifier -\return 0 on succuess, non-zero on error +\return 0 on success, non-zero on error */ s32 SYS_CreateAlarm(syswd_t *thealarm); @@ -297,7 +297,7 @@ s32 SYS_CreateAlarm(syswd_t *thealarm); \param[in] tp pointer to timespec structure holding the time to fire the alarm \param[in] cb pointer to callback which is called when the alarm fires. -\return 0 on succuess, non-zero on error +\return 0 on success, non-zero on error */ s32 SYS_SetAlarm(syswd_t thealarm,const struct timespec *tp,alarmcallback cb,void *cbarg); @@ -305,11 +305,11 @@ s32 SYS_SetAlarm(syswd_t thealarm,const struct timespec *tp,alarmcallback cb,voi /*! \fn s32 SYS_SetPeriodicAlarm(syswd_t thealarm,const struct timespec *tp_start,const struct timespec *tp_period,alarmcallback cb) \brief Set the alarm parameters for a periodioc alarm, add to the list of alarms and start. The alarm and interval persists as long as SYS_CancelAlarm() isn't called. \param[in] thealarm identifier to the alarm context to be initialized for a periodic alarm -\param[in] tp_start pointer to timespec structure holding the time to fire first time the alarm +\param[in] tp_start pointer to timespec structure holding the time to fire the alarm for first time \param[in] tp_period pointer to timespec structure holding the interval for all following alarm triggers. \param[in] cb pointer to callback which is called when the alarm fires. -\return 0 on succuess, non-zero on error +\return 0 on success, non-zero on error */ s32 SYS_SetPeriodicAlarm(syswd_t thealarm,const struct timespec *tp_start,const struct timespec *tp_period,alarmcallback cb,void *cbarg); @@ -318,15 +318,15 @@ s32 SYS_SetPeriodicAlarm(syswd_t thealarm,const struct timespec *tp_start,const \brief Remove the given alarm context from the list of contexts and destroy it \param[in] thealarm identifier to the alarm context to be removed and destroyed -\return 0 on succuess, non-zero on error +\return 0 on success, non-zero on error */ s32 SYS_RemoveAlarm(syswd_t thealarm); /*! \fn s32 SYS_CancelAlarm(syswd_t thealarm) \brief Cancel the alarm, but do not remove from the list of contexts. -\param[in] thealarm identifier to the alram context to be canceled +\param[in] thealarm identifier to the alarm context to be cancelled -\return 0 on succuess, non-zero on error +\return 0 on success, non-zero on error */ s32 SYS_CancelAlarm(syswd_t thealarm); @@ -391,6 +391,7 @@ void* SYS_GetArena2Hi(void); void SYS_SetArena2Hi(void *newHi); u32 SYS_GetArena2Size(void); powercallback SYS_SetPowerCallback(powercallback cb); +void SYS_DoPowerCB(void); #endif /* \fn u64 SYS_Time(void) diff --git a/gc/wiiuse/wiiuse.h b/gc/wiiuse/wiiuse.h index 61369db0f..49ed06282 100644 --- a/gc/wiiuse/wiiuse.h +++ b/gc/wiiuse/wiiuse.h @@ -242,7 +242,8 @@ typedef enum cmd_blk_s { CMD_READY = 0, CMD_SENT, - CMD_DONE + CMD_DONE, + CMD_FAILED } cmd_blk_s; struct cmd_blk_t @@ -660,9 +661,10 @@ typedef struct wiimote_t { * @brief Wiimote listen structure. */ typedef struct wiimote_listen_t { + WCONST u8 name[0x40]; WCONST struct bd_addr bdaddr; WCONST struct bte_pcb *sock; - WCONST struct wiimote_t *(*assign_cb)(struct bd_addr *bdaddr); + WCONST struct wiimote_t *(*assign_cb)(struct wiimote_listen_t *wml, u8 err); WCONST struct wiimote_t *wm; } wiimote_listen; #endif @@ -697,7 +699,8 @@ WIIUSE_EXPORT extern const char* wiiuse_version(); #ifndef GEKKO WIIUSE_EXPORT extern struct wiimote_t** wiiuse_init(int wiimotes); #else -WIIUSE_EXPORT extern int wiiuse_register(struct wiimote_listen_t *wml, struct bd_addr *bdaddr, struct wiimote_t *(*assign_cb)(struct bd_addr *bdaddr)); +WIIUSE_EXPORT extern int wiiuse_accept(struct wiimote_listen_t *wml, struct bd_addr *bdaddr, u8 *name, struct wiimote_t *(*assign_cb)(wiimote_listen *wml, u8 err)); +WIIUSE_EXPORT extern int wiiuse_connect(struct wiimote_listen_t *wml, struct bd_addr *bdaddr, u8 *name, struct wiimote_t *(*assign_cb)(wiimote_listen *wml, u8 err)); WIIUSE_EXPORT extern struct wiimote_t** wiiuse_init(int wiimotes, wii_event_cb event_cb); WIIUSE_EXPORT extern void wiiuse_sensorbar_enable(int enable); #endif @@ -721,7 +724,6 @@ WIIUSE_EXPORT extern int wiiuse_write_streamdata(struct wiimote_t *wm,ubyte *dat /* connect.c */ WIIUSE_EXPORT extern int wiiuse_find(struct wiimote_t** wm, int max_wiimotes, int timeout); -WIIUSE_EXPORT extern int wiiuse_connect(struct wiimote_t** wm, int wiimotes); WIIUSE_EXPORT extern void wiiuse_disconnect(struct wiimote_t* wm); /* events.c */ diff --git a/gc/wiiuse/wpad.h b/gc/wiiuse/wpad.h index 952d9d62b..daddd9a2d 100644 --- a/gc/wiiuse/wpad.h +++ b/gc/wiiuse/wpad.h @@ -43,8 +43,12 @@ enum { WPAD_CHAN_2, WPAD_CHAN_3, WPAD_BALANCE_BOARD, - WPAD_MAX_WIIMOTES, + WPAD_CHAN_UNKNOWN, + WPAD_MAX_DEVICES, }; + +// Compatibility with old apps +#define WPAD_MAX_WIIMOTES WPAD_MAX_DEVICES #define WPAD_BUTTON_2 0x0001 #define WPAD_BUTTON_1 0x0002 @@ -136,6 +140,14 @@ enum { #define WPAD_THRESH_DEFAULT_BALANCEBOARD 60 #define WPAD_THRESH_DEFAULT_MOTION_PLUS 100 +#define WPAD_DISCON_AUTH_FAILURE 0x05 /* HCI_AUTHENTICATION_FAILURE */ +#define WPAD_DISCON_TIMEOUT 0x08 /* HCI_CONN_TIMEOUT */ +#define WPAD_DISCON_SYNC_PRESSED 0x13 /* HCI_OTHER_END_TERMINATED_CONN_USER_ENDED */ +#define WPAD_DISCON_BATTERY_DIED 0x14 /* HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES */ +#define WPAD_DISCON_POWER_OFF 0x15 /* HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF */ +#define WPAD_DISCON_IDLE_TIMEOUT 0x16 /* HCI_CONN_TERMINATED_BY_LOCAL_HOST */ +#define WPAD_DISCON_REPEATED_ATTEMPTS 0x17 /* HCI_REPEATED_ATTEMPTS */ + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -166,6 +178,9 @@ typedef struct _wpad_encstatus typedef void (*WPADDataCallback)(s32 chan, const WPADData *data); typedef void (*WPADShutdownCallback)(s32 chan); +typedef void (*WPADDisconnectCallback)(s32 chan, u8 reason); +typedef void (*WPADStatusCallback)(s32 chan); +typedef void (*WPADHostSyncBtnCallback)(u32 held); s32 WPAD_Init(void); s32 WPAD_ControlSpeaker(s32 chan,s32 enable); @@ -182,10 +197,17 @@ s32 WPAD_SetEventBufs(s32 chan, WPADData *bufs, u32 cnt); s32 WPAD_Disconnect(s32 chan); s32 WPAD_IsSpeakerEnabled(s32 chan); s32 WPAD_SendStreamData(s32 chan,void *buf,u32 len); -void WPAD_Shutdown(void); +s32 WPAD_Search(void); +s32 WPAD_StopSearch(void); +s32 WPAD_StartPairing(void); +s32 WPAD_WipeSavedControllers(void); +s32 WPAD_Shutdown(void); void WPAD_SetIdleTimeout(u32 seconds); void WPAD_SetPowerButtonCallback(WPADShutdownCallback cb); void WPAD_SetBatteryDeadCallback(WPADShutdownCallback cb); +void WPAD_SetDisconnectCallback(WPADDisconnectCallback cb); +void WPAD_SetHostSyncButtonCallback(WPADHostSyncBtnCallback cb); +void WPAD_SetStatusCallback(WPADStatusCallback cb); s32 WPAD_ScanPads(void); s32 WPAD_Rumble(s32 chan, int status); s32 WPAD_SetIdleThresholds(s32 chan, s32 btns, s32 ir, s32 accel, s32 js, s32 wb, s32 mp); @@ -200,6 +222,8 @@ void WPAD_Orientation(int chan, struct orient_t *orient); void WPAD_GForce(int chan, struct gforce_t *gforce); void WPAD_Accel(int chan, struct vec3w_t *accel); void WPAD_Expansion(int chan, struct expansion_t *exp); +void WPAD_PadStatus(int chan); +bool WPAD_IsBatteryCritical(int chan); #ifdef __cplusplus } diff --git a/libogc/conf.c b/libogc/conf.c index 2492e45c8..c35b40765 100644 --- a/libogc/conf.c +++ b/libogc/conf.c @@ -1,9 +1,11 @@ /*------------------------------------------------------------- -conf.c -- SYSCONF support +conf.c -- SYSCONF & setting.txt support -Copyright (C) 2008 +Copyright (C) 2008-2025 Hector Martin (marcan) +tona +Zarithya This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -36,10 +38,13 @@ distribution. #include "processor.h" #include "conf.h" +#define CONF_FILE_SIZE 0x4000 +#define CONF_TXT_FILE_SIZE 0x100 static int __conf_inited = 0; -static u8 __conf_buffer[0x4000] ATTRIBUTE_ALIGN(32); -static char __conf_txt_buffer[0x101] ATTRIBUTE_ALIGN(32); +static u8 __conf_buffer[CONF_FILE_SIZE] ATTRIBUTE_ALIGN(32); +static char __conf_txt_buffer[CONF_TXT_FILE_SIZE + 1] ATTRIBUTE_ALIGN(32); +static int __conf_buffer_dirty = false; static const char __conf_file[] ATTRIBUTE_ALIGN(32) = "/shared2/sys/SYSCONF"; static const char __conf_txt_file[] ATTRIBUTE_ALIGN(32) = "/title/00000001/00000002/data/setting.txt"; @@ -49,7 +54,7 @@ void __CONF_DecryptTextBuffer(void) u32 key = 0x73B5DBFA; int i; - for(i=0; i<0x100; i++) { + for(i=0; i>31); } @@ -65,19 +70,19 @@ s32 CONF_Init(void) fd = IOS_Open(__conf_file,1); if(fd < 0) return fd; - memset(__conf_buffer,0,0x4000); - memset(__conf_txt_buffer,0,0x101); + memset(__conf_buffer,0,CONF_FILE_SIZE); + memset(__conf_txt_buffer,0,CONF_TXT_FILE_SIZE + 1); - ret = IOS_Read(fd, __conf_buffer, 0x4000); + ret = IOS_Read(fd, __conf_buffer, CONF_FILE_SIZE); IOS_Close(fd); - if(ret != 0x4000) return CONF_EBADFILE; + if(ret != CONF_FILE_SIZE) return CONF_EBADFILE; fd = IOS_Open(__conf_txt_file,1); if(fd < 0) return fd; - ret = IOS_Read(fd, __conf_txt_buffer, 0x100); + ret = IOS_Read(fd, __conf_txt_buffer, CONF_TXT_FILE_SIZE); IOS_Close(fd); - if(ret != 0x100) return CONF_EBADFILE; + if(ret != CONF_TXT_FILE_SIZE) return CONF_EBADFILE; if(memcmp(__conf_buffer, "SCv0", 4)) return CONF_EBADFILE; @@ -96,7 +101,7 @@ int __CONF_GetTxt(const char *name, char *buf, int length) if(!__conf_inited) return CONF_ENOTINIT; - while(line < (__conf_txt_buffer+0x100) ) { + while(line < (__conf_txt_buffer+CONF_TXT_FILE_SIZE) ) { delim = strchr(line, '='); if(delim && ((delim - line) == nlen) && !memcmp(name, line, nlen)) { delim++; @@ -115,7 +120,7 @@ int __CONF_GetTxt(const char *name, char *buf, int length) } // skip to line end - while(line < (__conf_txt_buffer+0x100) && *line++ != '\n'); + while(line < (__conf_txt_buffer+CONF_TXT_FILE_SIZE) && *line++ != '\n'); } return CONF_ENOENT; } @@ -207,6 +212,74 @@ s32 CONF_Get(const char *name, void *buffer, u32 length) return len; } +s32 CONF_Set(const char *name, const void *buffer, u32 length) +{ + u8 *entry; + s32 len; + if(!__conf_inited) return CONF_ENOTINIT; + + entry = __CONF_Find(name); + if(!entry) return CONF_ENOENT; + + len = CONF_GetLength(name); + if(len<0) return len; + if(len!=length) return CONF_EBADVALUE; + + switch(*entry>>5) { + case CONF_BIGARRAY: + memcpy(&entry[strlen(name)+3], buffer, len); + break; + case CONF_SMALLARRAY: + memcpy(&entry[strlen(name)+2], buffer, len); + break; + case CONF_BYTE: + case CONF_SHORT: + case CONF_LONG: + case CONF_BOOL: + memcpy(&entry[strlen(name)+1], buffer, len); + break; + default: + return CONF_ENOTIMPL; + } + __conf_buffer_dirty = true; + return len; +} + +int __CONF_WriteBuffer(void) +{ + int ret, fd; + + if (!__conf_inited) + return CONF_ENOTINIT; + + if (!__conf_buffer_dirty) + return 0; + + fd = IOS_Open(__conf_file, 2); + if (fd < 0) + return fd; + + ret = IOS_Write(fd, __conf_buffer, CONF_FILE_SIZE); + IOS_Close(fd); + if (ret != CONF_FILE_SIZE) + return CONF_EBADFILE; + + __conf_buffer_dirty = false; + return 0; +} + +s32 CONF_SaveChanges(void) +{ + s32 ret; + if (!__conf_inited) + return CONF_ENOTINIT; + ret = __CONF_WriteBuffer(); + if (ret < 0) + return ret; + + return CONF_ERR_OK; +} + s32 CONF_GetShutdownMode(void) { u8 idleconf[2] = {0,0}; @@ -346,6 +419,37 @@ s32 CONF_GetPadDevices(conf_pads *pads) return 0; } +s32 CONF_SetPadDevices(const conf_pads *pads) +{ + u8 count; + + if (!pads) return CONF_EBADVALUE; + count = pads->num_registered; + if (count > CONF_PAD_MAX_REGISTERED) return CONF_EBADVALUE; + return CONF_Set("BT.DINF", pads, sizeof(conf_pads)); +} + +s32 CONF_GetPadGuestDevices(conf_pad_guests *pads) +{ + int res; + + res = CONF_Get("BT.CDIF", pads, sizeof(conf_pad_guests)); + if(res < 0) return res; + if(res < sizeof(conf_pad_guests)) return CONF_EBADVALUE; + return 0; +} + +s32 CONF_SetPadGuestDevices(const conf_pad_guests *pads) +{ + u8 count; + conf_pad_guests empty = {0}; + + if (!pads) pads = ∅ + count = pads->num_guests; + if (count > CONF_PAD_MAX_ACTIVE) return CONF_EBADVALUE; + return CONF_Set("BT.CDIF", pads, sizeof(conf_pad_guests)); +} + s32 CONF_GetNickName(u8 *nickname) { int i, res; diff --git a/libogc/system.c b/libogc/system.c index 504625e1b..41bff36c7 100644 --- a/libogc/system.c +++ b/libogc/system.c @@ -156,6 +156,7 @@ static void __POWDefaultHandler(void); static powercallback __POWCallback = NULL; static u32 __sys_resetdown = 0; +static u64 __sys_powerenabletime = 0; #endif static vu64* const _bootTime = (u64*)0x800030d8; @@ -456,7 +457,7 @@ static void __STMEventHandler(u32 event) if(event==STM_EVENT_POWER) { _CPU_ISR_Disable(level); - __POWCallback(); + SYS_DoPowerCB(); _CPU_ISR_Restore(level); } } @@ -1019,16 +1020,23 @@ void _V_EXPORTNAME(void) { __sys_versionbuild = _V_STRING; __sys_versiondate = _V_DATE_; } #if defined(HW_RVL) -void __SYS_DoPowerCB(void) +void SYS_DoPowerCB(void) { u32 level; - powercallback powcb; - _CPU_ISR_Disable(level); - powcb = __POWCallback; - __POWCallback = __POWDefaultHandler; - powcb(); - _CPU_ISR_Restore(level); + // Power button events fire repeatedly for one second after button is pressed + // Throttle events so only one callback gets called per button press + if(gettime() >= __sys_powerenabletime) { + _CPU_ISR_Disable(level); + __POWCallback(); + _CPU_ISR_Restore(level); + } + __sys_powerenabletime = gettime() + millisecs_to_ticks(50); +} + +void __SYS_DisablePowerButton(u32 disableTime) +{ + __sys_powerenabletime = gettime() + millisecs_to_ticks(disableTime); } #endif diff --git a/lwbt/btarch.h b/lwbt/btarch.h index 7697f32b2..9abf7ba61 100644 --- a/lwbt/btarch.h +++ b/lwbt/btarch.h @@ -137,19 +137,19 @@ static __inline__ void __memset(void *dest,s32_t c,s32_t len) #define MEMSET memset #endif -#if LOGGING == 1 +#if BT_LOGGING == 1 #include #define LOG(fmt, ...) fprintf(stderr, "[BTLOG] " __FILE__ ":%i: " fmt "\n", __LINE__, ##__VA_ARGS__) #else #define LOG(fmt, ...) -#endif /* LOGGING == 1 */ +#endif /* BT_LOGGING == 1 */ -#if ERRORING == 1 +#if BT_ERRORING == 1 #include #define ERROR(fmt,...) fprintf(stderr, "[BTERR] " __FILE__ ":%i: " fmt "\n", __LINE__, ##__VA_ARGS__) #else #define ERROR(fmt, ...) -#endif /* ERRORING == 1 */ +#endif /* BT_ERRORING == 1 */ /** @} */ diff --git a/lwbt/bte.c b/lwbt/bte.c index 76d276f55..7c50f436a 100644 --- a/lwbt/bte.c +++ b/lwbt/bte.c @@ -17,14 +17,6 @@ #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, @@ -49,10 +41,13 @@ struct bt_state u8_t hci_inited; u8_t num_maxdevs; - u8_t num_founddevs; - struct inquiry_info_ex *info; + + u8_t pair_mode; + + struct bte_inquiry_res inq_res; btecallback cb; + btecallback inq_complete_cb; void *usrdata; }; @@ -94,11 +89,11 @@ static u8_t bte_patch1[92] = { 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 acl_auth_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); @@ -111,6 +106,8 @@ err_t bte_hci_initsub_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u 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); +err_t bte_set_evt_filter_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result); +err_t bte_read_remote_name_complete(void *arg,struct bd_addr *bdaddr,u8_t *name, u8_t result); MEMB(bte_pcbs,sizeof(struct bte_pcb),MEMP_NUM_BTE_PCB); @@ -121,12 +118,12 @@ static void bte_reset_all() btmemb_init(&bte_pcbs); btmemb_init(&bte_ctrl_reqs); - if(btstate.info!=NULL) free(btstate.info); + if(btstate.inq_res.info!=NULL) free(btstate.inq_res.info); - btstate.info = NULL; + btstate.inq_res.count = 0; + btstate.inq_res.info = NULL; btstate.hci_inited = 0; btstate.hci_cmddone = 0; - btstate.num_founddevs = 0; btstate.last_err = ERR_OK; } @@ -163,9 +160,15 @@ static inline s32 __bte_cmdfinish(struct bt_state *state,err_t err) state->last_err = err; state->hci_cmddone = 1; if(state->cb!=NULL) - state->cb(err,state->usrdata); + { + btecallback cb = state->cb; + state->cb = NULL; + cb(err,state->usrdata); + } else + { LWP_ThreadSignal(state->hci_cmdq); + } _CPU_ISR_Restore(level); return err; @@ -387,6 +390,9 @@ void BTE_Init(void) hci_wlp_complete(acl_wlp_completed); hci_connection_complete(acl_conn_complete); + hci_auth_complete(acl_auth_complete); + hci_remote_name_req_complete(bte_read_remote_name_complete); + hci_pin_req(pin_req); _CPU_ISR_Restore(level); tb.tv_sec = 1; @@ -394,6 +400,15 @@ void BTE_Init(void) SYS_SetPeriodicAlarm(btstate.timer_svc,&tb,&tb,bt_alarmhandler, NULL); } +void BTE_Close(void) +{ + u32 level; + + _CPU_ISR_Disable(level); + hci_cmd_complete(NULL); + _CPU_ISR_Restore(level); +} + void BTE_Shutdown(void) { u32 level; @@ -411,6 +426,7 @@ void BTE_Shutdown(void) hci_cmd_complete(__bte_shutdown_finished); hci_reset(); __bte_waitcmdfinish(&btstate); + LWP_CloseQueue(btstate.hci_cmdq); _CPU_ISR_Restore(level); physbusif_shutdown(); @@ -484,144 +500,255 @@ s32 BTE_ReadStoredLinkKey(struct linkkey_info *keys,u8 max_cnt,btecallback cb) s32 BTE_ReadBdAddr(struct bd_addr *bdaddr, btecallback cb) { - u32 level; + 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; +} + +s32 BTE_SetEvtFilter(u8 filter_type,u8 filter_cond_type,u8 *cond, 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); + _CPU_ISR_Disable(level); + btstate.cb = cb; + btstate.usrdata = NULL; + btstate.hci_cmddone = 0; + hci_arg(&btstate); + hci_cmd_complete(bte_set_evt_filter_complete); + hci_set_event_filter(filter_type,filter_cond_type,cond); + _CPU_ISR_Restore(level); - return ERR_OK; + return ERR_OK; } -void (*BTE_SetDisconnectCallback(void (*callback)(struct bd_addr *bdaddr,u8 reason)))(struct bd_addr *bdaddr,u8 reason) +s32 BTE_ReadRemoteName(struct pad_name_info *padinfo, btecallback cb) { - return l2cap_disconnect_bb(callback); + u32 level; + err_t last_err = ERR_OK; + + _CPU_ISR_Disable(level); + btstate.cb = cb; + btstate.usrdata = padinfo; + btstate.hci_cmddone = 0; + hci_arg(&btstate); + hci_read_remote_name(&padinfo->bdaddr); + _CPU_ISR_Restore(level); + + return last_err; } -struct bte_pcb* bte_new(void) +s32 BTE_LinkKeyRequestReply(struct bd_addr *bdaddr,u8 *key) { - struct bte_pcb *pcb; + u32 level; + err_t last_err = ERR_OK; - if((pcb=btmemb_alloc(&bte_pcbs))==NULL) return NULL; + LOG("BTE_LinkKeyRequestReply\n"); - memset(pcb,0,sizeof(struct bte_pcb)); + _CPU_ISR_Disable(level); + btstate.cb = NULL; + btstate.usrdata = NULL; + btstate.hci_cmddone = 0; + hci_arg(&btstate); + hci_link_key_req_reply(bdaddr, key); + _CPU_ISR_Restore(level); - pcb->state = (u32)STATE_NOTREADY; - LWP_InitQueue(&(pcb->cmdq)); + return last_err; +} - return pcb; +s32 BTE_LinkKeyRequestNegativeReply(struct bd_addr *bdaddr) +{ + u32 level; + err_t last_err = ERR_OK; + + LOG("BTE_LinkKeyRequestNegativeReply\n"); + + _CPU_ISR_Disable(level); + btstate.cb = NULL; + btstate.usrdata = NULL; + btstate.hci_cmddone = 0; + hci_arg(&btstate); + hci_link_key_req_neg_reply(bdaddr); + _CPU_ISR_Restore(level); + + return last_err; +} + +u8 BTE_GetPairMode(void) +{ + return btstate.pair_mode; } -s32 bte_registerdeviceasync(struct bte_pcb *pcb,struct bd_addr *bdaddr,s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err)) +void (*BTE_SetDisconnectCallback(void (*callback)(struct bd_addr *bdaddr,u8 reason)))(struct bd_addr *bdaddr,u8 reason) +{ + return l2cap_disconnect_bb(callback); +} + +void BTE_SetHostSyncButtonCallback(void (*callback)(u32 held)) { u32 level; - s32 err = ERR_OK; - struct l2cap_pcb *l2capcb = NULL; + + _CPU_ISR_Disable(level); + hci_sync_btn(callback); + _CPU_ISR_Restore(level); +} - //printf("bte_registerdeviceasync()\n"); +void BTE_SetConnectionRequestCallback(err_t (*callback)(void *arg,struct bd_addr *bdaddr,u8 *cod,u8 link_type)) +{ + u32 level; + _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; + hci_conn_req(callback); + _CPU_ISR_Restore(level); +} - bd_addr_set(&(pcb->bdaddr),bdaddr); - if((l2capcb=l2cap_new())==NULL) { - err = ERR_MEM; - goto error; - } - l2cap_arg(l2capcb,pcb); +void BTE_SetLinkKeyRequestCallback(err_t (*callback)(void *arg,struct bd_addr *bdaddr)) +{ + u32 level; + + _CPU_ISR_Disable(level); + hci_link_key_req(callback); + _CPU_ISR_Restore(level); +} - err = l2cap_connect_ind(l2capcb,bdaddr,HIDP_CONTROL_CHANNEL,l2cap_accepted); - if(err!=ERR_OK) { - l2cap_close(l2capcb); - err = ERR_CONN; - goto error; - } +void BTE_SetLinkKeyNotificationCallback(err_t (*callback)(void *arg,struct bd_addr *bdaddr,u8 *key)) +{ + u32 level; - if((l2capcb=l2cap_new())==NULL) { - err = ERR_MEM; - goto error; - } - l2cap_arg(l2capcb,pcb); + _CPU_ISR_Disable(level); + hci_link_key_not(callback); + _CPU_ISR_Restore(level); +} - err = l2cap_connect_ind(l2capcb,bdaddr,HIDP_DATA_CHANNEL,l2cap_accepted); - if(err!=ERR_OK) { - l2cap_close(l2capcb); - err = ERR_CONN; - } +s32 BTE_WriteStoredLinkKey(struct bd_addr *bdaddr,u8_t *key) +{ + u32 level; + err_t last_err = ERR_OK; -error: + LOG("BTE_WriteStoredLinkKey\n"); + + _CPU_ISR_Disable(level); + btstate.cb = NULL; + btstate.usrdata = NULL; + btstate.hci_cmddone = 0; + hci_arg(&btstate); + hci_write_stored_link_key(bdaddr,key); _CPU_ISR_Restore(level); - //printf("bte_registerdeviceasync(%02x)\n",err); - return err; + + return last_err; } -s32 bte_inquiry(struct inquiry_info *info,u8 max_cnt,u8 flush) +s32 BTE_ClearStoredLinkKeys(void) { - s32_t i; - u32 level,fnd; - err_t last_err; - struct inquiry_info_ex *pinfo; + u32 level; + err_t last_err = ERR_OK; - last_err = ERR_OK; + LOG("BTE_ClearStoredLinkKeys\n"); _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; + btstate.cb = NULL; + btstate.usrdata = NULL; + btstate.hci_cmddone = 0; + hci_arg(&btstate); + hci_delete_stored_link_key(NULL); _CPU_ISR_Restore(level); - if(last_err==ERR_OK) { - for(i=0;istate = (u32)STATE_NOTREADY; + LWP_InitQueue(&(pcb->cmdq)); + + return pcb; +} + +void bte_free(struct bte_pcb *pcb) +{ + if(pcb==NULL) return; + + LWP_CloseQueue(pcb->cmdq); + btmemb_free(&bte_pcbs, pcb); +} + +s32 BTE_Inquiry(u8 max_cnt,u8 flush,btecallback cb) +{ + u32 level; _CPU_ISR_Disable(level); - if(btstate.num_founddevs==0 || flush==1) { - btstate.hci_cmddone = 0; + if(btstate.inq_res.count==0 || flush==1) { + btstate.inq_complete_cb = cb; + btstate.pair_mode = PAIR_MODE_NORMAL; btstate.num_maxdevs = max_cnt; - hci_inquiry(0x009E8B33,0x03,max_cnt,bte_inquiry_complete); - last_err = __bte_waitcmdfinish(&btstate); + hci_arg(&btstate); + // Use Limited Dedicated Inquiry Access Code (LIAC) to query, since third-party Wiimotes + // cannot be discovered without it. + hci_inquiry(0x009E8B00,0x03,max_cnt,bte_inquiry_complete); } - fnd = btstate.num_founddevs; - pinfo = btstate.info; _CPU_ISR_Restore(level); + return ERR_OK; +} - if(last_err==ERR_OK) { - for(i=0;istate = (u32)STATE_DISCONNECTING; - if(pcb->data_pcb!=NULL ) + 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); + bte_free(pcb); _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)) +s32 bte_connectasync(struct bte_pcb *pcb,struct bd_addr *bdaddr,s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err)) { u32 level; - err_t err = ERR_OK; - - if(pcb==NULL) return ERR_VAL; - - if((pcb->l2capcb=l2cap_new())==NULL) return ERR_MEM; + s32 err = ERR_OK; + struct l2cap_pcb *l2capcb = NULL; + + _CPU_ISR_Disable(level); + LOG("bte_connectasync()\n"); + if(lp_is_connected(bdaddr)) { + ERROR("bdaddr already exists: %02x:%02x:%02x:%02x:%02x:%02x\n",bdaddr->addr[5],bdaddr->addr[4],bdaddr->addr[3],bdaddr->addr[2],bdaddr->addr[1],bdaddr->addr[0]); + err = ERR_CONN; + goto error; + } + pcb->err = ERR_USE; + pcb->data_pcb = NULL; + pcb->ctl_pcb = NULL; + pcb->conn_cfm = conn_cfm; + pcb->state = (u32)STATE_CONNECTING; - pcb->psm = psm; - pcb->recv = recv; bd_addr_set(&(pcb->bdaddr),bdaddr); + if((l2capcb=l2cap_new())==NULL) { + err = ERR_MEM; + goto error; + } + l2cap_arg(l2capcb,pcb); - _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; + err = l2ca_connect_req(l2capcb,bdaddr,HIDP_CONTROL_CHANNEL,HCI_ALLOW_ROLE_SWITCH,l2cap_connected); + if(err!=ERR_OK) { + l2cap_close(l2capcb); + err = ERR_CONN; } - _CPU_ISR_Restore(level); +error: + _CPU_ISR_Restore(level); + LOG("bte_connectasync(%02x)\n",err); 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)) +s32 bte_connectasync_step2(struct bte_pcb *pcb,s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err)) { - err_t err; + u32 level; + s32 err = ERR_OK; + struct l2cap_pcb *l2capcb = NULL; + + _CPU_ISR_Disable(level); + LOG("bte_connectasync_step2()\n"); + + if(!lp_is_connected(&(pcb->bdaddr))) { + ERROR("bdaddr not connected: %02x:%02x:%02x:%02x:%02x:%02x\n",pcb->bdaddr.addr[5],pcb->bdaddr.addr[4],pcb->bdaddr.addr[3],pcb->bdaddr.addr[2],pcb->bdaddr.addr[1],pcb->bdaddr.addr[0]); + err = ERR_CONN; + goto error; + } + + pcb->conn_cfm = conn_cfm; - 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); + if((l2capcb=l2cap_new())==NULL) { + err = ERR_MEM; + goto error; + } + l2cap_arg(l2capcb,pcb); + + err = l2ca_connect_req(l2capcb,&(pcb->bdaddr),HIDP_DATA_CHANNEL,HCI_ALLOW_ROLE_SWITCH,l2cap_connected); + if(err!=ERR_OK) { + l2cap_close(l2capcb); + err = ERR_CONN; + } + +error: + _CPU_ISR_Restore(level); + LOG("bte_connectasync_step2(%02x)\n",err); + return err; } -s32 bte_listen(struct bte_pcb *pcb,struct bd_addr *bdaddr,u8 psm) +s32 bte_listenasync(struct bte_pcb *pcb,struct bd_addr *bdaddr,s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err)) { - s32 err; u32 level; + s32 err = ERR_OK; struct l2cap_pcb *l2capcb = NULL; - if(pcb==NULL) return ERR_VAL; + LOG("bte_listenasync()\n"); + _CPU_ISR_Disable(level); - if((l2capcb=l2cap_new())==NULL) return ERR_MEM; - pcb->l2capcb = NULL; + pcb->err = ERR_USE; + pcb->data_pcb = NULL; + pcb->ctl_pcb = NULL; + pcb->conn_cfm = conn_cfm; + pcb->state = (u32)STATE_CONNECTING; - pcb->psm = psm; - pcb->recv = NULL; bd_addr_set(&(pcb->bdaddr),bdaddr); - - _CPU_ISR_Disable(level); - pcb->err = ERR_CONN; + if((l2capcb=l2cap_new())==NULL) { + err = ERR_MEM; + goto error; + } l2cap_arg(l2capcb,pcb); - err = l2cap_connect_ind(l2capcb,psm,l2cap_accepted); - if(err!=ERR_OK) l2cap_close(l2capcb); + err = l2cap_connect_ind(l2capcb,bdaddr,HIDP_CONTROL_CHANNEL,l2cap_accepted); + if(err!=ERR_OK) { + l2cap_close(l2capcb); + err = ERR_CONN; + } + +error: _CPU_ISR_Restore(level); + LOG("bte_listenasync(%02x)\n",err); return err; } -s32 bte_accept(struct bte_pcb *pcb,s32 (*recv)(void *arg,void *buffer,u16 len)) +s32 bte_listenasync_step2(struct bte_pcb *pcb,s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err)) { u32 level; - err_t err = ERR_OK; - - if(pcb==NULL) return ERR_VAL; + s32 err = ERR_OK; + struct l2cap_pcb *l2capcb = NULL; + LOG("bte_listenasync_step2()\n"); _CPU_ISR_Disable(level); - pcb->recv = recv; - while(pcb->l2capcb==NULL) - LWP_ThreadSleep(pcb->cmdq); - err = pcb->err; - _CPU_ISR_Restore(level); + if(!lp_is_connected(&(pcb->bdaddr))) { + ERROR("bdaddr not connected: %02x:%02x:%02x:%02x:%02x:%02x\n",pcb->bdaddr.addr[5],pcb->bdaddr.addr[4],pcb->bdaddr.addr[3],pcb->bdaddr.addr[2],pcb->bdaddr.addr[1],pcb->bdaddr.addr[0]); + err = ERR_CONN; + goto error; + } + + pcb->conn_cfm = conn_cfm; + + if((l2capcb=l2cap_new())==NULL) { + err = ERR_MEM; + goto error; + } + l2cap_arg(l2capcb,pcb); + + err = l2cap_connect_ind(l2capcb,&(pcb->bdaddr),HIDP_DATA_CHANNEL,l2cap_accepted); + if(err!=ERR_OK) { + l2cap_close(l2capcb); + err = ERR_CONN; + } +error: + _CPU_ISR_Restore(level); + LOG("bte_listenasync_step2(%02x)\n",err); return err; } -*/ s32 bte_senddata(struct bte_pcb *pcb,void *message,u16 len) { @@ -747,7 +938,7 @@ s32 bte_sendmessageasync(struct bte_pcb *pcb,void *message,u16 len,s32 (*sent)(v struct pbuf *p; struct ctrl_req_t *req; - //printf("bte_sendmessageasync()\n"); + LOG("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; @@ -778,7 +969,7 @@ s32 bte_sendmessage(struct bte_pcb *pcb,void *message,u16 len) struct pbuf *p; struct ctrl_req_t *req; - //printf("bte_sendmessage()\n"); + LOG("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; @@ -839,8 +1030,15 @@ err_t acl_wlp_completed(void *arg,struct bd_addr *bdaddr) err_t acl_conn_complete(void *arg,struct bd_addr *bdaddr) { - //printf("acl_conn_complete\n"); - //memcpy(&(btstate.acl_bdaddr),bdaddr,6); + LOG("acl_conn_complete\n"); + + hci_auth_req(bdaddr); + return ERR_OK; +} + +err_t acl_auth_complete(void *arg,struct bd_addr *bdaddr) +{ + LOG("acl_auth_complete\n"); hci_write_link_policy_settings(bdaddr,0x0005); return ERR_OK; @@ -848,7 +1046,20 @@ err_t acl_conn_complete(void *arg,struct bd_addr *bdaddr) err_t pin_req(void *arg,struct bd_addr *bdaddr) { - //printf("pin_req\n"); + struct bd_addr addr; + LOG("pin_req\n"); + + if (btstate.pair_mode == PAIR_MODE_NORMAL) + { + // Pairing from sync button (permanent) + hci_get_bd_addr(&addr); + } + else + { + // Pairing from 1+2 (guest/temporary) + bd_addr_set(&addr, bdaddr); + } + hci_pin_code_request_reply(bdaddr, sizeof(addr.addr), addr.addr); return ERR_OK; } @@ -911,22 +1122,24 @@ err_t l2cap_disconnect_cfm(void *arg, struct l2cap_pcb *pcb) 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); + LOG("l2cap_connected(%02x)\n",result); if(result==L2CAP_CONN_SUCCESS) { - l2cap_recv(l2cappcb,bte_input); + 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; + } btepcb->err = ERR_OK; + btepcb->state = (u32)STATE_CONNECTED; } else { l2cap_close(l2cappcb); btepcb->err = ERR_CONN; @@ -936,12 +1149,12 @@ err_t l2cap_connected(void *arg,struct l2cap_pcb *l2cappcb,u16_t result,u16_t st 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); + LOG("l2cap_accepted(%02x)\n",err); if(err==ERR_OK) { l2cap_recv(l2cappcb,bte_process_input); l2cap_disconnect_ind(l2cappcb,l2cap_disconnected_ind); @@ -953,59 +1166,60 @@ err_t l2cap_accepted(void *arg,struct l2cap_pcb *l2cappcb,err_t err) 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); - } + btepcb->err = ERR_OK; + btepcb->state = (u32)STATE_CONNECTED; } else { l2cap_close(l2cappcb); btepcb->err = ERR_CONN; - btepcb->conn_cfm(btepcb->cbarg,btepcb,ERR_CONN); } - + + if(btepcb->conn_cfm) btepcb->conn_cfm(btepcb->cbarg,btepcb,btepcb->err); return ERR_OK; } err_t bte_inquiry_complete(void *arg,struct hci_pcb *pcb,struct hci_inq_res *ires,u16_t result) { + u32 level; u8_t i; struct hci_inq_res *p; struct bt_state *state = (struct bt_state*)arg; + struct bte_inquiry_res *inq_res = &btstate.inq_res; if(result==HCI_SUCCESS) { if(ires!=NULL) { - if(btstate.info!=NULL) free(btstate.info); - btstate.info = NULL; + if(inq_res->info!=NULL) free(inq_res->info); + inq_res->info = NULL; + inq_res->count = 0; btstate.num_maxdevs = 0; - btstate.num_founddevs = 0; p = ires; while(p!=NULL) { - btstate.num_founddevs++; + inq_res->count++; 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); + inq_res->info = (struct inquiry_info_ex*)malloc(sizeof(struct inquiry_info_ex)*inq_res->count); + for(i=0;icount && p!=NULL;i++) { + bd_addr_set(&(inq_res->info[i].bdaddr),&(p->bdaddr)); + memcpy(inq_res->info[i].cod,p->cod,3); + inq_res->info[i].psrm = p->psrm; + inq_res->info[i].psm = p->psm; + inq_res->info[i].co = p->co; + p = p->next; } - __bte_cmdfinish(state,ERR_OK); - } else - hci_inquiry(0x009E8B33,0x03,btstate.num_maxdevs,bte_inquiry_complete); + // Can't use __bte_cmdfinish here because we need to run a different callback. + // Commands may have run during inquiry which overwrote state->cb. + //__bte_cmdfinish(state,ERR_OK); + _CPU_ISR_Disable(level); + state->last_err = ERR_OK; + state->hci_cmddone = 1; + state->inq_complete_cb(ERR_OK,&state->inq_res); + _CPU_ISR_Restore(level); + } else if (state->pair_mode == PAIR_MODE_NORMAL) + hci_inquiry(0x009E8B00,0x03,btstate.num_maxdevs,bte_inquiry_complete); } return ERR_OK; } @@ -1029,7 +1243,7 @@ err_t bte_read_stored_link_key_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u 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); + memcpy(keys[i].key,p->key,HCI_LINK_KEY_LEN); p = p->next; } @@ -1044,33 +1258,75 @@ err_t bte_read_stored_link_key_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u 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; + struct bd_addr *bdaddr; + struct bt_state *state = (struct bt_state*)arg; - if(!pcb) return ERR_CONN; + if(!pcb) return ERR_CONN; - LOG("bte_read_bd_addr_complete(%02x,%p)\n", result, &pcb->bdaddr); + LOG("bte_read_bd_addr_complete(%02x,%p)\n", result, &pcb->bdaddr); - if(state==NULL) return ERR_VAL; + 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(!(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)\n",result,bdaddr); + __bte_cmdfinish(state,ERR_OK); + return ERR_OK; + } - 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); +} + +err_t bte_read_remote_name_complete(void *arg,struct bd_addr *bdaddr,u8_t *name,u8_t result) +{ + struct pad_name_info *info; + struct bt_state *state = (struct bt_state*)arg; - return __bte_cmdfinish(state,ERR_VAL); + LOG("bte_read_remote_name_complete(%02x,%p)\n", result, bdaddr); + + if(state==NULL) return ERR_VAL; + + if(result == HCI_SUCCESS) { + info = (struct pad_name_info *)state->usrdata; + bd_addr_set(&info->bdaddr, bdaddr); + memcpy(info->name, name, BD_NAME_LEN); + LOG("bte_read_remote_name_complete(%02x,%s)\n",result,name); + __bte_cmdfinish(state,ERR_OK); + return ERR_OK; + } + + return __bte_cmdfinish(state,ERR_VAL); +} + +err_t bte_set_evt_filter_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result) +{ + struct bt_state *state = (struct bt_state*)arg; + + if(!pcb) return ERR_CONN; + + LOG("bte_set_evt_filter_complete(%02x)\n", result); + + if(state==NULL) return ERR_VAL; + + if(!(ogf==HCI_HC_BB_OGF && ocf==HCI_SET_EV_FILTER_OCF)) return __bte_cmdfinish(state,ERR_CONN); + + if(result == HCI_SUCCESS) { + LOG("bte_set_evt_filter_complete(%02x)\n",result); + __bte_cmdfinish(state,ERR_OK); + return ERR_OK; + } + + return __bte_cmdfinish(state,ERR_VAL); } /* new init with patching */ @@ -1083,27 +1339,27 @@ static err_t bte_hci_initcore_complete2(void *arg,struct hci_pcb *pcb,u8_t ogf,u LOG("bte_hci_initcore_complete2(%02x,%02x)\n",ogf,ocf); switch(ogf) { case HCI_HC_BB_OGF: - if(ocf==HCI_WRITE_INQUIRY_MODE) { + if(ocf==HCI_W_INQUIRY_MODE_OCF) { if(result==HCI_SUCCESS) { hci_write_page_scan_type(0x01); } else err = ERR_CONN; - } else if(ocf==HCI_WRITE_PAGE_SCAN_TYPE) { + } else if(ocf==HCI_W_PAGE_SCAN_TYPE_OCF) { if(result==HCI_SUCCESS) { hci_write_inquiry_scan_type(0x01); } else err = ERR_CONN; - } else if(ocf==HCI_WRITE_INQUIRY_SCAN_TYPE) { + } else if(ocf==HCI_W_INQUIRY_SCAN_TYPE_OCF) { if(result==HCI_SUCCESS) { hci_write_cod(dev_cod); } else err = ERR_CONN; - } else if(ocf==HCI_WRITE_COD) { + } else if(ocf==HCI_W_COD_OCF) { if(result==HCI_SUCCESS) { hci_write_page_timeout(0x2000); } else err = ERR_CONN; - } else if(ocf==HCI_WRITE_PAGE_TIMEOUT) { + } else if(ocf==HCI_W_PAGE_TIMEOUT_OCF) { if(result==HCI_SUCCESS) { state->hci_inited = 1; hci_cmd_complete(NULL); @@ -1130,23 +1386,23 @@ err_t bte_hci_initcore_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf, LOG("bte_hci_initcore_complete(%02x,%02x)\n",ogf,ocf); switch(ogf) { - case HCI_INFO_PARAM: - if(ocf==HCI_READ_BUFFER_SIZE) { + case HCI_INFO_PARAM_OGF: + if(ocf==HCI_R_BUF_SIZE_OCF) { if(result==HCI_SUCCESS) { hci_write_cod(dev_cod); } else err = ERR_CONN; - } else if(ocf==HCI_READ_LOCAL_VERSION) { + } else if(ocf==HCI_R_LOC_VERS_INFO_OCF) { if(result==HCI_SUCCESS) { hci_read_bd_addr(); } else err = ERR_CONN; - } else if(ocf==HCI_READ_BD_ADDR) { + } else if(ocf==HCI_R_BD_ADDR_OCF) { if(result==HCI_SUCCESS) { hci_read_local_features(); } else err = ERR_CONN; - } else if(ocf==HCI_READ_LOCAL_FEATURES) { + } else if(ocf==HCI_R_LOC_FEAT_OCF) { if(result==HCI_SUCCESS) { hci_cmd_complete(bte_hci_initcore_complete2); hci_write_inquiry_mode(0x01); @@ -1155,27 +1411,27 @@ err_t bte_hci_initcore_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf, } break; case HCI_HC_BB_OGF: - if(ocf==HCI_RESET) { + if(ocf==HCI_RESET_OCF) { if(result==HCI_SUCCESS) { hci_read_buffer_size(); } else err = ERR_CONN; - } else if(ocf==HCI_WRITE_COD) { + } else if(ocf==HCI_W_COD_OCF) { if(result==HCI_SUCCESS) { hci_write_local_name((u8_t*)"",1); } else err = ERR_CONN; - } else if(ocf==HCI_WRITE_LOCAL_NAME) { + } else if(ocf==HCI_W_LOCAL_NAME_OCF) { if(result==HCI_SUCCESS) { hci_write_pin_type(0x00); } else err = ERR_CONN; - } else if(ocf==HCI_WRITE_PIN_TYPE) { + } else if(ocf==HCI_W_PIN_TYPE_OCF) { if(result==HCI_SUCCESS) { hci_host_buffer_size(); } else err = ERR_CONN; - } else if(ocf==HCI_HOST_BUF_SIZE) { + } else if(ocf==HCI_HOST_BUF_SIZE_OCF) { if(result==HCI_SUCCESS) { hci_read_local_version(); } else @@ -1231,23 +1487,23 @@ err_t bte_hci_patch_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_ LOG("bte_hci_patch_complete(%02x,%02x,%02x)\n",ogf,ocf,result); switch(ogf) { - case HCI_INFO_PARAM: - if(ocf==HCI_READ_BUFFER_SIZE) { + case HCI_INFO_PARAM_OGF: + if(ocf==HCI_R_BUF_SIZE_OCF) { if(result==HCI_SUCCESS) { hci_write_cod(dev_cod); } else err = ERR_CONN; - } else if(ocf==HCI_READ_LOCAL_VERSION) { + } else if(ocf==HCI_R_LOC_VERS_INFO_OCF) { if(result==HCI_SUCCESS) { hci_read_bd_addr(); } else err = ERR_CONN; - } else if(ocf==HCI_READ_BD_ADDR) { + } else if(ocf==HCI_R_BD_ADDR_OCF) { if(result==HCI_SUCCESS) { hci_read_local_features(); } else err = ERR_CONN; - } else if(ocf==HCI_READ_LOCAL_FEATURES) { + } else if(ocf==HCI_R_LOC_FEAT_OCF) { if(result==HCI_SUCCESS) { hci_cmd_complete(NULL); return __bte_cmdfinish(state,ERR_OK); @@ -1256,27 +1512,27 @@ err_t bte_hci_patch_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_ } break; case HCI_HC_BB_OGF: - if(ocf==HCI_RESET) { + if(ocf==HCI_RESET_OCF) { if(result==HCI_SUCCESS) { hci_read_buffer_size(); } else err = ERR_CONN; - } else if(ocf==HCI_WRITE_COD) { + } else if(ocf==HCI_W_COD_OCF) { if(result==HCI_SUCCESS) { hci_write_local_name((u8_t*)"",1); } else err = ERR_CONN; - } else if(ocf==HCI_WRITE_LOCAL_NAME) { + } else if(ocf==HCI_W_LOCAL_NAME_OCF) { if(result==HCI_SUCCESS) { hci_write_pin_type(0x00); } else err = ERR_CONN; - } else if(ocf==HCI_WRITE_PIN_TYPE) { + } else if(ocf==HCI_W_PIN_TYPE_OCF) { if(result==HCI_SUCCESS) { hci_host_buffer_size(); } else err = ERR_CONN; - } else if(ocf==HCI_HOST_BUF_SIZE) { + } else if(ocf==HCI_HOST_BUF_SIZE_OCF) { if(result==HCI_SUCCESS) { hci_read_local_version(); } else @@ -1310,37 +1566,37 @@ err_t bte_hci_initsub_complete(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u LOG("bte_hci_initsub_complete(%02x,%02x)\n",ogf,ocf); switch(ogf) { case HCI_HC_BB_OGF: - if(ocf==HCI_WRITE_INQUIRY_MODE) { + if(ocf==HCI_W_INQUIRY_MODE_OCF) { if(result==HCI_SUCCESS) { hci_write_page_scan_type(0x01); } else err = ERR_CONN; - } else if(ocf==HCI_WRITE_PAGE_SCAN_TYPE) { + } else if(ocf==HCI_W_PAGE_SCAN_TYPE_OCF) { if(result==HCI_SUCCESS) { hci_write_inquiry_scan_type(0x01); } else err = ERR_CONN; - } else if(ocf==HCI_WRITE_INQUIRY_SCAN_TYPE) { + } else if(ocf==HCI_W_INQUIRY_SCAN_TYPE_OCF) { if(result==HCI_SUCCESS) { hci_write_cod(dev_cod); } else err = ERR_CONN; - } else if(ocf==HCI_WRITE_COD) { + } else if(ocf==HCI_W_COD_OCF) { if(result==HCI_SUCCESS) { hci_write_page_timeout(0x8000); } else err = ERR_CONN; - } else if(ocf==HCI_WRITE_PAGE_TIMEOUT) { + } else if(ocf==HCI_W_PAGE_TIMEOUT_OCF) { if(result==HCI_SUCCESS) { hci_write_local_name((u8_t*)"Wii",4); } else err = ERR_CONN; - } else if(ocf==HCI_WRITE_LOCAL_NAME) { + } else if(ocf==HCI_W_LOCAL_NAME_OCF) { if(result==HCI_SUCCESS) { hci_write_scan_enable(0x02); } else err = ERR_CONN; - } else if(ocf==HCI_WRITE_SCAN_ENABLE) { + } else if(ocf==HCI_W_SCAN_EN_OCF) { if(result==HCI_SUCCESS) { hci_cmd_complete(NULL); return __bte_cmdfinish(state,ERR_OK); diff --git a/lwbt/btopt.h b/lwbt/btopt.h index 28485f10b..4e94d4f5c 100644 --- a/lwbt/btopt.h +++ b/lwbt/btopt.h @@ -169,7 +169,7 @@ typedef s8 err_t; * * \hideinitializer */ -#define STATISTICS 0 +#define STATISTICS 0 /** * Determines if logging of certain events should be compiled in. @@ -180,8 +180,8 @@ typedef s8 err_t; * * \hideinitializer */ -#define LOGGING 0 -#define ERRORING 0 +#define BT_LOGGING 0 +#define BT_ERRORING 0 /** * Print out a uIP log message. @@ -200,7 +200,7 @@ void bt_log(const char *filename,int line_nb,char *msg); * * \hideinitializer */ -#define LL_HLEN 16 +#define LL_HLEN 16 #define TCPIP_HLEN 40 /** @} */ @@ -216,10 +216,10 @@ void bt_log(const char *filename,int line_nb,char *msg); * reflect the CPU architecture on which uIP is to be run. */ #ifndef LITTLE_ENDIAN -#define LITTLE_ENDIAN 3412 +#define LITTLE_ENDIAN 3412 #endif /* LITTLE_ENDIAN */ #ifndef BIG_ENDIAN -#define BIG_ENDIAN 1234 +#define BIG_ENDIAN 1234 #endif /* BIGE_ENDIAN */ /** @@ -231,7 +231,7 @@ void bt_log(const char *filename,int line_nb,char *msg); * \hideinitializer */ #ifndef BYTE_ORDER -#define BYTE_ORDER BIG_ENDIAN +#define BYTE_ORDER BIG_ENDIAN #endif /* BYTE_ORDER */ /** @} */ @@ -241,7 +241,7 @@ void bt_log(const char *filename,int line_nb,char *msg); /* ---------- Memory options ---------- */ #define MAX_NUM_CLIENTS 6 /* Maximum number of connected Bluetooth clients. No more than 6 */ -#define MAX_NUM_OPT_CLIENTS 10 /* Maximum number of possible Bluetooth clients we might listen to */ +#define MAX_NUM_OPT_CLIENTS 10 /* Maximum number of possible Bluetooth clients we might listen to */ #define MEMB_NUM_HCI_PCB 1 /* Always set to one */ #define MEMB_NUM_HCI_LINK MAX_NUM_CLIENTS /* One for DT + One per ACL connection */ diff --git a/lwbt/hci.c b/lwbt/hci.c index acb7de8da..fbe8c2e4c 100644 --- a/lwbt/hci.c +++ b/lwbt/hci.c @@ -27,6 +27,7 @@ * This file is part of the lwBT Bluetooth stack. * * Author: Conny Ohult + * Modified in 2025 by Zarithya. * */ @@ -54,16 +55,24 @@ #include "btpbuf.h" #include "physbusif.h" -struct hci_pcb *hci_dev = NULL; -struct hci_link *hci_active_links = NULL; +/* The HCI LINK lists. */ +struct hci_link *hci_active_links = NULL; /* List of all active HCI LINKs */ struct hci_link *hci_tmp_link = NULL; -struct hci_link_key *hci_tmp_key = NULL; + +struct hci_pcb *hci_dev = NULL; MEMB(hci_pcbs,sizeof(struct hci_pcb),MEMB_NUM_HCI_PCB); MEMB(hci_links,sizeof(struct hci_link),MEMB_NUM_HCI_LINK); MEMB(hci_inq_results,sizeof(struct hci_inq_res),MEMB_NUM_HCI_INQ); MEMB(hci_link_key_results,sizeof(struct hci_link_key),MEMB_NUM_HCI_LINK_KEY); +/*-----------------------------------------------------------------------------------*/ +/* + * hci_init(): + * + * Initializes the HCI layer. + */ +/*-----------------------------------------------------------------------------------*/ err_t hci_init(void) { btmemr_init(); @@ -80,12 +89,20 @@ err_t hci_init(void) } memset(hci_dev,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; @@ -97,16 +114,6 @@ struct hci_link* hci_new(void) return link; } -static 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_close(): @@ -154,7 +161,7 @@ void hci_reset_all(void) for(ikeys=hci_dev->keyres;ikeys!=NULL;) { tikeys = ikeys->next; - btmemb_free(&hci_inq_results,ikeys); + btmemb_free(&hci_link_key_results,ikeys); ikeys = tikeys; } btmemb_free(&hci_pcbs,hci_dev); @@ -162,11 +169,27 @@ void hci_reset_all(void) hci_init(); } +/*-----------------------------------------------------------------------------------*/ +/* + * hci_arg(): + * + * Used to specify the argument that should be passed to callback + * functions. + */ +/*-----------------------------------------------------------------------------------*/ void hci_arg(void *arg) { hci_dev->cbarg = 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)) { hci_dev->cmd_complete = cmd_complete; @@ -184,6 +207,33 @@ void hci_pin_req(err_t (* pin_req)(void *arg, struct bd_addr *bdaddr)) { hci_dev->pin_req = pin_req; } + +/*-----------------------------------------------------------------------------------*/ +/* + * hci_sync_btn(): + * + * Used to specify the function that should be called when HCI has received a + * sync button event. + */ +/*-----------------------------------------------------------------------------------*/ +void hci_sync_btn(void (* sync_btn)(u32_t held)) +{ + hci_dev->sync_btn = sync_btn; +} + +/*-----------------------------------------------------------------------------------*/ +/* + * hci_remote_name_req_complete(): + * + * Used to specify the function that should be called when HCI has received a + * remote name request complete event. + */ +/*-----------------------------------------------------------------------------------*/ +void hci_remote_name_req_complete(err_t (* remote_name_req_complete)(void *arg, struct bd_addr *bdaddr, u8_t *name, u8_t result)) +{ + hci_dev->remote_name_req_complete = remote_name_req_complete; +} + /*-----------------------------------------------------------------------------------*/ /* * hci_link_key_req(): @@ -196,6 +246,7 @@ void hci_link_key_req(err_t (* link_key_req)(void *arg, struct bd_addr *bdaddr)) { hci_dev->link_key_req = link_key_req; } + /*-----------------------------------------------------------------------------------*/ /* * hci_link_key_not(): @@ -222,6 +273,19 @@ void hci_connection_complete(err_t (* conn_complete)(void *arg, struct bd_addr * hci_dev->conn_complete = conn_complete; } +/*-----------------------------------------------------------------------------------*/ +/* + * hci_auth_complete(): + * + * Used to specify the function that should be called when HCI has received an + * authentication complete event. + */ +/*-----------------------------------------------------------------------------------*/ +void hci_auth_complete(err_t (* auth_complete)(void *arg, struct bd_addr *bdaddr)) +{ + hci_dev->auth_complete = auth_complete; +} + /*-----------------------------------------------------------------------------------*/ /* * hci_wlp_complete(): @@ -230,11 +294,36 @@ void hci_connection_complete(err_t (* conn_complete)(void *arg, struct bd_addr * * successful write link policy complete event. */ /*-----------------------------------------------------------------------------------*/ -void hci_wlp_complete(err_t (* wlp_complete)(void *arg, struct bd_addr *bdaddr)) +void hci_wlp_complete(err_t (* wlp_complete)(void *arg, struct bd_addr *bdaddr)) { hci_dev->wlp_complete = wlp_complete; } +/*-----------------------------------------------------------------------------------*/ +/* + * hci_get_link(): + * + * Used to get the link structure that represents an ACL connection. + */ +/*-----------------------------------------------------------------------------------*/ +static 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_conn_req(): + * + * Used to specify the function that should be called when HCI has received a + * connection request event. + */ +/*-----------------------------------------------------------------------------------*/ void hci_conn_req(err_t (*conn_req)(void *arg,struct bd_addr *bdaddr,u8_t *cod,u8_t link_type)) { hci_dev->conn_req = conn_req; @@ -260,8 +349,15 @@ err_t hci_reg_dev_info(struct bd_addr *bdaddr,u8_t *cod,u8_t psrm,u8_t psm,u16_t return ERR_MEM; } +/*-----------------------------------------------------------------------------------*/ +/* hci_cmd_ass(): + * + * Assemble the command header. + */ +/*-----------------------------------------------------------------------------------*/ static struct pbuf* hci_cmd_ass(struct pbuf *p,u8_t ocf,u8_t ogf,u8_t len) { + memset(p->payload, 0, 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)); @@ -271,6 +367,12 @@ static struct pbuf* hci_cmd_ass(struct pbuf *p,u8_t ocf,u8_t ogf,u8_t len) return p; } +/*-----------------------------------------------------------------------------------*/ +/* hci_reset(): + * + * Reset the Bluetooth host controller, link manager, and radio module. + */ +/*-----------------------------------------------------------------------------------*/ err_t hci_reset(void) { struct pbuf *p = NULL; @@ -288,6 +390,13 @@ err_t hci_reset(void) 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 = NULL; @@ -305,6 +414,12 @@ err_t hci_read_buffer_size(void) return ERR_OK; } +/*-----------------------------------------------------------------------------------*/ +/* hci_read_bd_addr(): + * + * Used to retreive the Bluetooth address of the host controller. + */ +/*-----------------------------------------------------------------------------------*/ err_t hci_read_bd_addr(void) { struct pbuf *p = NULL; @@ -326,12 +441,12 @@ err_t hci_read_local_version(void) { struct pbuf *p = NULL; - if((p=btpbuf_alloc(PBUF_RAW,HCI_R_LOC_VERS_SIZE_PLEN,PBUF_RAM))==NULL) { + if((p=btpbuf_alloc(PBUF_RAW,HCI_R_LOC_VERS_INFO_PLEN,PBUF_RAM))==NULL) { ERROR("hci_read_local_version: Could not allocate memory for pbuf\n"); return ERR_MEM; } - p = hci_cmd_ass(p,HCI_R_LOC_VERSION_OCF,HCI_INFO_PARAM_OGF,HCI_R_LOC_VERS_SIZE_PLEN); + p = hci_cmd_ass(p,HCI_R_LOC_VERS_INFO_OCF,HCI_INFO_PARAM_OGF,HCI_R_LOC_VERS_INFO_PLEN); physbusif_output(p,p->tot_len); btpbuf_free(p); @@ -339,16 +454,22 @@ err_t hci_read_local_version(void) return ERR_OK; } +/*-----------------------------------------------------------------------------------*/ +/* hci_read_local_features() + * + * Read the features of the connected module + */ +/*-----------------------------------------------------------------------------------*/ err_t hci_read_local_features(void) { struct pbuf *p = NULL; - if((p=btpbuf_alloc(PBUF_RAW,HCI_R_LOC_FEAT_SIZE_PLEN,PBUF_RAM))==NULL) { + if((p=btpbuf_alloc(PBUF_RAW,HCI_R_LOC_FEAT_PLEN,PBUF_RAM))==NULL) { ERROR("hci_read_local_features: Could not allocate memory for pbuf\n"); return ERR_MEM; } - p = hci_cmd_ass(p,HCI_R_LOC_FEATURES_OCF,HCI_INFO_PARAM_OGF,HCI_R_LOC_FEAT_SIZE_PLEN); + p = hci_cmd_ass(p,HCI_R_LOC_FEAT_OCF,HCI_INFO_PARAM_OGF,HCI_R_LOC_FEAT_PLEN); physbusif_output(p,p->tot_len); btpbuf_free(p); @@ -367,7 +488,6 @@ err_t hci_read_stored_link_key(void) hci_dev->keyres = hci_dev->keyres->next; btmemb_free(&hci_link_key_results,tmpres); } - if((p=btpbuf_alloc(PBUF_RAW,HCI_R_STORED_LINK_KEY_PLEN,PBUF_RAM))==NULL) { ERROR("hci_read_stored_link_keys: Could not allocate memory for pbuf\n"); @@ -385,6 +505,12 @@ err_t hci_read_stored_link_key(void) 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) { u32 cond_len = 0; @@ -437,13 +563,20 @@ err_t hci_set_event_filter(u8_t filter_type,u8_t filter_cond_type,u8_t *cond) ((u8_t*)p->payload)[4] = filter_type; ((u8_t*)p->payload)[5] = filter_cond_type; if(cond_len>0) memcpy(p->payload+6,cond,cond_len); - + physbusif_output(p,p->tot_len); btpbuf_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 timeout) { struct pbuf *p = NULL; @@ -462,6 +595,13 @@ err_t hci_write_page_timeout(u16_t timeout) 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 = NULL; @@ -480,6 +620,13 @@ err_t hci_write_scan_enable(u8_t scan_enable) return ERR_OK; } +/*-----------------------------------------------------------------------------------*/ +/* hci_inquiry(): + * + * Cause the Host contoller to enter inquiry mode to discover 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 = NULL; @@ -512,6 +659,13 @@ err_t hci_inquiry(u32_t lap,u8_t inq_len,u8_t num_resp,err_t (*inq_complete)(voi return ERR_OK; } +/*-----------------------------------------------------------------------------------*/ +/* hci_periodic_inquiry(): + * + * Cause the Host contoller to enter periodic inquiry mode to discover other nearby + * Bluetooth devices. + */ +/*-----------------------------------------------------------------------------------*/ err_t hci_periodic_inquiry(u32_t lap,u16_t min_period,u16_t max_period,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 = NULL; @@ -533,7 +687,7 @@ err_t hci_periodic_inquiry(u32_t lap,u16_t min_period,u16_t max_period,u8_t inq_ /* Assembling command packet */ p = hci_cmd_ass(p,HCI_PERIODIC_INQUIRY_OCF,HCI_LINK_CTRL_OGF,HCI_PERIODIC_INQUIRY_PLEN); - /* Assembling cmd prameters */ + /* Assembling cmd parameters */ ((u16_t*)p->payload)[2] = htole16(max_period); ((u16_t*)p->payload)[3] = htole16(min_period); ((u8_t*)p->payload)[8] = (lap&0xff); @@ -549,6 +703,12 @@ err_t hci_periodic_inquiry(u32_t lap,u16_t min_period,u16_t max_period,u8_t inq_ return ERR_OK; } +/*-----------------------------------------------------------------------------------*/ +/* hci_periodic_inquiry(): + * + * Cause the Host contoller to exit periodic inquiry mode. + */ +/*-----------------------------------------------------------------------------------*/ err_t hci_exit_periodic_inquiry(void) { struct pbuf *p = NULL; @@ -567,7 +727,13 @@ err_t hci_exit_periodic_inquiry(void) return ERR_OK; } -err_t hci_accecpt_conn_request(struct bd_addr *bdaddr,u8_t role) +/*-----------------------------------------------------------------------------------*/ +/* hci_accept_conn_request(): + * + * Accept a connection request. + */ +/*-----------------------------------------------------------------------------------*/ +err_t hci_accept_conn_request(struct bd_addr *bdaddr,u8_t role) { struct pbuf *p = NULL; @@ -579,7 +745,7 @@ err_t hci_accecpt_conn_request(struct bd_addr *bdaddr,u8_t role) /* Assembling command packet */ p = hci_cmd_ass(p,HCI_ACCEPT_CONN_REQ_OCF,HCI_LINK_CTRL_OGF,HCI_ACCEPT_CONN_REQ_PLEN); - /* Assembling cmd prameters */ + /* Assembling cmd parameters */ memcpy((void*)(((u8_t*)p->payload)+4),bdaddr,6); ((u8_t*)p->payload)[10] = role; @@ -589,6 +755,12 @@ err_t hci_accecpt_conn_request(struct bd_addr *bdaddr,u8_t role) return ERR_OK; } +/*-----------------------------------------------------------------------------------*/ +/* hci_set_event_mask(): + * + * Sets the Host Controller's event mask. + */ +/*-----------------------------------------------------------------------------------*/ err_t hci_set_event_mask(u64_t ev_mask) { u64_t mask; @@ -611,6 +783,12 @@ err_t hci_set_event_mask(u64_t ev_mask) return ERR_OK; } +/*-----------------------------------------------------------------------------------*/ +/* hci_write_local_name(): + * + * Sets the Host Controller's name. + */ +/*-----------------------------------------------------------------------------------*/ err_t hci_write_local_name(u8_t *name,u8_t len) { struct pbuf *p = NULL; @@ -622,7 +800,7 @@ err_t hci_write_local_name(u8_t *name,u8_t len) /* Assembling command packet */ p = hci_cmd_ass(p,HCI_W_LOCAL_NAME_OCF,HCI_HC_BB_OGF,HCI_W_LOCAL_NAME_PLEN); - /* Assembling cmd prameters */ + /* Assembling cmd parameters */ memcpy(((u8_t *)p->payload) + 4, name, len); physbusif_output(p, p->tot_len); @@ -631,6 +809,12 @@ err_t hci_write_local_name(u8_t *name,u8_t len) return ERR_OK; } +/*-----------------------------------------------------------------------------------*/ +/* hci_write_inquiry_mode(): + * + * Sets the Host Controller's PIN type. + */ +/*-----------------------------------------------------------------------------------*/ err_t hci_write_pin_type(u8_t type) { struct pbuf *p = NULL; @@ -642,7 +826,7 @@ err_t hci_write_pin_type(u8_t type) /* Assembling command packet */ p = hci_cmd_ass(p,HCI_W_PIN_TYPE_OCF,HCI_HC_BB_OGF,HCI_W_PIN_TYPE_PLEN); - /* Assembling cmd prameters */ + /* Assembling cmd parameters */ ((u8_t *)p->payload)[4] = type; physbusif_output(p, p->tot_len); @@ -651,6 +835,12 @@ err_t hci_write_pin_type(u8_t type) return ERR_OK; } +/*-----------------------------------------------------------------------------------*/ +/* hci_read_remote_name(): + * + * Read the remote name of a device. + */ +/*-----------------------------------------------------------------------------------*/ err_t hci_read_remote_name(struct bd_addr *bdaddr) { u16_t clock_offset; @@ -680,7 +870,7 @@ err_t hci_read_remote_name(struct bd_addr *bdaddr) /* Assembling command packet */ p = hci_cmd_ass(p,HCI_R_REMOTE_NAME_OCF,HCI_LINK_CTRL_OGF,HCI_R_REMOTE_NAME_PLEN); - /* Assembling cmd prameters */ + /* Assembling cmd parameters */ memcpy(((u8_t *)p->payload+4),bdaddr->addr,6); ((u8_t*)p->payload)[10] = page_scan_repetition_mode; ((u8_t*)p->payload)[11] = page_scan_mode; @@ -690,9 +880,101 @@ err_t hci_read_remote_name(struct bd_addr *bdaddr) btpbuf_free(p); return ERR_OK; +} + +/*-----------------------------------------------------------------------------------*/ +/* hci_read_clock_offset(): + * + * Read clock offset from an ACL connection. + */ +/*-----------------------------------------------------------------------------------*/ +err_t hci_read_clock_offset(struct bd_addr *bdaddr) +{ + struct pbuf *p = NULL; + struct hci_link *link; + + /* Check if an ACL connection exists */ + link = hci_get_link(bdaddr); + + if(link == NULL) { + ERROR("hci_read_clock_offset: ACL connection does not exist\n"); + return ERR_CONN; + } + + if((p=btpbuf_alloc(PBUF_RAW,HCI_R_CLOCK_OFFSET_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_read_clock_offset: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + /* Assembling command packet */ + p = hci_cmd_ass(p,HCI_R_CLOCK_OFFSET_OCF,HCI_LINK_CTRL_OGF,HCI_R_CLOCK_OFFSET_PLEN); + /* Assembling cmd parameters */ + ((u16_t *)p->payload)[2] = htole16(link->connhdl); + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +/*-----------------------------------------------------------------------------------*/ +/* hci_read_remote_version_info(): + * + * Read remote version info from an ACL connection. + */ +/*-----------------------------------------------------------------------------------*/ +err_t hci_read_remote_version_info(u16_t connhdl) +{ + struct pbuf *p = NULL; + + if((p=btpbuf_alloc(PBUF_RAW,HCI_R_REMOTE_VERSION_INFO_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_read_remote_version_info: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + /* Assembling command packet */ + p = hci_cmd_ass(p,HCI_R_REMOTE_VERSION_INFO_OCF,HCI_LINK_CTRL_OGF,HCI_R_REMOTE_VERSION_INFO_PLEN); + /* Assembling cmd parameters */ + ((u16_t *)p->payload)[2] = htole16(connhdl); + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + +/*-----------------------------------------------------------------------------------*/ +/* hci_read_remote_features(): + * + * Read remote features from an ACL connection. + */ +/*-----------------------------------------------------------------------------------*/ +err_t hci_read_remote_features(u16_t connhdl) +{ + struct pbuf *p = NULL; + if((p=btpbuf_alloc(PBUF_RAW,HCI_R_REMOTE_FEATURES_PLEN,PBUF_RAM))==NULL) { + ERROR("hci_read_remote_features: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + + /* Assembling command packet */ + p = hci_cmd_ass(p,HCI_R_REMOTE_FEATURES_OCF,HCI_LINK_CTRL_OGF,HCI_R_REMOTE_FEATURES_PLEN); + /* Assembling cmd parameters */ + ((u16_t *)p->payload)[2] = htole16(connhdl); + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; } +/*-----------------------------------------------------------------------------------*/ +/* hci_write_inquiry_mode(): + * + * Sets the Host Controller's inquiry mode. + */ +/*-----------------------------------------------------------------------------------*/ err_t hci_write_inquiry_mode(u8_t mode) { struct pbuf *p = NULL; @@ -704,7 +986,7 @@ err_t hci_write_inquiry_mode(u8_t mode) /* Assembling command packet */ p = hci_cmd_ass(p,HCI_W_INQUIRY_MODE_OCF,HCI_HC_BB_OGF,HCI_W_INQUIRY_MODE_PLEN); - /* Assembling cmd prameters */ + /* Assembling cmd parameters */ ((u8_t*)p->payload)[4] = mode; physbusif_output(p, p->tot_len); @@ -713,18 +995,24 @@ err_t hci_write_inquiry_mode(u8_t mode) return ERR_OK; } +/*-----------------------------------------------------------------------------------*/ +/* hci_write_page_scan_type(): + * + * Sets the Host Controller's page scan type. + */ +/*-----------------------------------------------------------------------------------*/ err_t hci_write_page_scan_type(u8_t type) { struct pbuf *p = NULL; if((p=btpbuf_alloc(PBUF_RAW,HCI_W_PAGE_SCAN_TYPE_PLEN,PBUF_RAM))==NULL) { - ERROR("hci_write_inquiry_mode: Could not allocate memory for pbuf\n"); + ERROR("hci_write_page_scan_type: Could not allocate memory for pbuf\n"); return ERR_MEM; } /* Assembling command packet */ p = hci_cmd_ass(p,HCI_W_PAGE_SCAN_TYPE_OCF,HCI_HC_BB_OGF,HCI_W_PAGE_SCAN_TYPE_PLEN); - /* Assembling cmd prameters */ + /* Assembling cmd parameters */ ((u8_t*)p->payload)[4] = type; physbusif_output(p, p->tot_len); @@ -733,18 +1021,24 @@ err_t hci_write_page_scan_type(u8_t type) return ERR_OK; } +/*-----------------------------------------------------------------------------------*/ +/* hci_write_inquiry_scan_type(): + * + * Sets the Host Controller's inquiry scan type. + */ +/*-----------------------------------------------------------------------------------*/ err_t hci_write_inquiry_scan_type(u8_t type) { struct pbuf *p = NULL; if((p=btpbuf_alloc(PBUF_RAW,HCI_W_INQUIRY_SCAN_TYPE_PLEN,PBUF_RAM))==NULL) { - ERROR("hci_write_inquiry_mode: Could not allocate memory for pbuf\n"); + ERROR("hci_write_inquiry_scan_type: Could not allocate memory for pbuf\n"); return ERR_MEM; } /* Assembling command packet */ p = hci_cmd_ass(p,HCI_W_INQUIRY_SCAN_TYPE_OCF,HCI_HC_BB_OGF,HCI_W_INQUIRY_SCAN_TYPE_PLEN); - /* Assembling cmd prameters */ + /* Assembling cmd parameters */ ((u8_t*)p->payload)[4] = type; physbusif_output(p, p->tot_len); @@ -753,18 +1047,24 @@ err_t hci_write_inquiry_scan_type(u8_t type) return ERR_OK; } +/*-----------------------------------------------------------------------------------*/ +/* hci_vendor_specific_command(): + * + * Sends a vendor specific command to the Host Controller. + */ +/*-----------------------------------------------------------------------------------*/ err_t hci_vendor_specific_command(u8_t ocf,u8_t ogf,void *data,u8_t len) { struct pbuf *p = NULL; if((p=btpbuf_alloc(PBUF_RAW,HCI_W_VENDOR_CMD_PLEN + len,PBUF_RAM))==NULL) { - ERROR("hci_vendor_specific_patch: Could not allocate memory for pbuf\n"); + ERROR("hci_vendor_specific_command: Could not allocate memory for pbuf\n"); return ERR_MEM; } /* Assembling command packet */ p = hci_cmd_ass(p,ocf,ogf,HCI_W_VENDOR_CMD_PLEN + len); - /* Assembling cmd prameters */ + /* Assembling cmd parameters */ memcpy(((u8_t*)p->payload + 4),data,len); physbusif_output(p, p->tot_len); @@ -772,6 +1072,7 @@ err_t hci_vendor_specific_command(u8_t ocf,u8_t ogf,void *data,u8_t len) return ERR_OK; } + /*-----------------------------------------------------------------------------------*/ /* hci_sniff_mode(): * @@ -791,14 +1092,14 @@ err_t hci_sniff_mode(struct bd_addr *bdaddr, u16_t max_interval, u16_t min_inter return ERR_CONN; } - if((p = btpbuf_alloc(PBUF_TRANSPORT, HCI_SNIFF_PLEN, PBUF_RAM)) == NULL) { /* Alloc len of packet */ + if((p = btpbuf_alloc(PBUF_TRANSPORT, HCI_SNIFF_MODE_PLEN, PBUF_RAM)) == NULL) { /* Alloc len of packet */ ERROR("hci_sniff_mode: Could not allocate memory for pbuf\n"); return ERR_MEM; } /* Assembling command packet */ - p = hci_cmd_ass(p, HCI_SNIFF_MODE_OCF, HCI_LINK_POLICY_OGF, HCI_SNIFF_PLEN); - /* Assembling cmd prameters */ + p = hci_cmd_ass(p, HCI_SNIFF_MODE_OCF, HCI_LINK_POLICY_OGF, HCI_SNIFF_MODE_PLEN); + /* Assembling cmd parameters */ ((u16_t *)p->payload)[2] = htole16(link->connhdl); ((u16_t *)p->payload)[3] = htole16(max_interval); ((u16_t *)p->payload)[4] = htole16(min_interval); @@ -810,6 +1111,42 @@ err_t hci_sniff_mode(struct bd_addr *bdaddr, u16_t max_interval, u16_t min_inter return ERR_OK; } + +/*-----------------------------------------------------------------------------------*/ +/* hci_auth_req(): + * + * Request authentication from an ACL connection. + * + */ +/*-----------------------------------------------------------------------------------*/ +err_t hci_auth_req(struct bd_addr *bdaddr) +{ + struct pbuf *p; + struct hci_link *link; + + /* Check if an ACL connection exists */ + link = hci_get_link(bdaddr); + + if(link == NULL) { + ERROR("hci_auth_req: ACL connection does not exist\n"); + return ERR_CONN; + } + + if( (p = btpbuf_alloc(PBUF_TRANSPORT, HCI_AUTH_REQUESTED_PLEN, PBUF_RAM)) == NULL) { /* Alloc len of packet */ + ERROR("hci_auth_req: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + /* Assembling command packet */ + p = hci_cmd_ass(p, HCI_AUTH_REQUESTED_OCF, HCI_LINK_CTRL_OGF, HCI_AUTH_REQUESTED_PLEN); + + /* Assembling cmd parameters */ + ((u16_t *)p->payload)[2] = htole16(link->connhdl); + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + return ERR_OK; +} + /*-----------------------------------------------------------------------------------*/ /* hci_write_link_policy_settings(): * @@ -837,7 +1174,7 @@ err_t hci_write_link_policy_settings(struct bd_addr *bdaddr, u16_t link_policy) /* Assembling command packet */ p = hci_cmd_ass(p, HCI_W_LINK_POLICY_OCF, HCI_LINK_POLICY_OGF, HCI_W_LINK_POLICY_PLEN); - /* Assembling cmd prameters */ + /* Assembling cmd parameters */ ((u16_t *)p->payload)[2] = htole16(link->connhdl); ((u16_t *)p->payload)[3] = htole16(link_policy); @@ -846,6 +1183,32 @@ err_t hci_write_link_policy_settings(struct bd_addr *bdaddr, u16_t link_policy) return ERR_OK; } +/*-----------------------------------------------------------------------------------*/ +/* hci_write_authentication_enable(): + * + * Control the authentication enable for the Host Controller. + * + */ +/*-----------------------------------------------------------------------------------*/ +err_t hci_write_authentication_enable(u8_t auth_enable) +{ + struct pbuf *p; + + if( (p = btpbuf_alloc(PBUF_TRANSPORT, HCI_W_AUTH_ENABLE_PLEN, PBUF_RAM)) == NULL) { /* Alloc len of packet */ + ERROR("hci_write_authentication_enable: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + /* Assembling command packet */ + p = hci_cmd_ass(p, HCI_W_AUTH_ENABLE_OCF, HCI_HC_BB_OGF, HCI_W_AUTH_ENABLE_PLEN); + + /* Assembling cmd parameters */ + ((u8_t *)p->payload)[4] = auth_enable; + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + return ERR_OK; +} + /*-----------------------------------------------------------------------------------*/ /* hci_pin_code_request_reply(): * @@ -866,8 +1229,8 @@ err_t hci_pin_code_request_reply(struct bd_addr *bdaddr, u8_t pinlen, u8_t *pinc 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 */ + p = hci_cmd_ass(p, HCI_PIN_CODE_REQ_REP_OCF, HCI_LINK_CTRL_OGF, HCI_PIN_CODE_REQ_REP_PLEN); + /* Assembling cmd parameters */ memcpy(((u8_t *)p->payload) + 4, bdaddr->addr, 6); ((u8_t *)p->payload)[10] = pinlen; memcpy(((u8_t *)p->payload) + 11, pincode, pinlen); @@ -887,24 +1250,23 @@ err_t hci_pin_code_request_reply(struct bd_addr *bdaddr, u8_t pinlen, u8_t *pinc /*-----------------------------------------------------------------------------------*/ err_t hci_link_key_req_reply(struct bd_addr *bdaddr, unsigned char *link_key) { - struct pbuf *p; - if ((p = btpbuf_alloc(PBUF_RAW, HCI_LINK_KEY_REQ_REP_PLEN, PBUF_RAM)) == NULL) { - ERROR("hci_link_key_req_reply: Could not allocate memory for pbuf\n"); - return ERR_MEM; - } - - p = hci_cmd_ass(p, HCI_LINK_KEY_REQ_REP, HCI_LINK_CTRL_OGF, HCI_LINK_KEY_REQ_REP_PLEN); - //copy bdaddr to offset 0x4 - memcpy(((u8_t *)p->payload)+4, bdaddr->addr, 6); - //copy Link Key (16 bytes long) to offset 10 (0xA) - memcpy(((u8_t *)p->payload)+10, link_key, 16); - //send command - physbusif_output(p,p->tot_len); - btpbuf_free(p); - - return ERR_OK; -} + struct pbuf *p; + if ((p = btpbuf_alloc(PBUF_RAW, HCI_LINK_KEY_REQ_REP_PLEN, PBUF_RAM)) == NULL) { + ERROR("hci_link_key_req_reply: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + p = hci_cmd_ass(p, HCI_LINK_KEY_REQ_REP_OCF, HCI_LINK_CTRL_OGF, HCI_LINK_KEY_REQ_REP_PLEN); + //copy bdaddr to offset 0x4 + memcpy(((u8_t *)p->payload)+4, bdaddr->addr, 6); + //copy Link Key (16 bytes long) to offset 10 (0xA) + memcpy(((u8_t *)p->payload)+10, link_key, 16); + //send command + physbusif_output(p,p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} /*-----------------------------------------------------------------------------------*/ /* hci_pin_code_request_neg_reply(): @@ -922,7 +1284,7 @@ err_t hci_pin_code_request_neg_reply(struct bd_addr *bdaddr) return ERR_MEM; } - p = hci_cmd_ass(p,HCI_PIN_CODE_REQ_NEG_REP,HCI_LINK_CTRL_OGF,HCI_PIN_CODE_REQ_NEG_REP_PLEN); + p = hci_cmd_ass(p,HCI_PIN_CODE_REQ_NEG_REP_OCF,HCI_LINK_CTRL_OGF,HCI_PIN_CODE_REQ_NEG_REP_PLEN); memcpy(((u8_t *)p->payload)+4, bdaddr->addr, 6); physbusif_output(p,p->tot_len); @@ -942,12 +1304,12 @@ err_t hci_link_key_req_neg_reply(struct bd_addr *bdaddr) { struct pbuf *p; - if ((p = btpbuf_alloc(PBUF_RAW, HCI_LINK_KEY_REQ_REP_NEG_PLEN, PBUF_RAM)) == NULL) { + if ((p = btpbuf_alloc(PBUF_RAW, HCI_LINK_KEY_REQ_NEG_REP_PLEN, PBUF_RAM)) == NULL) { ERROR("hci_link_key_req_neg_repl: Could not allocate memory for pbuf\n"); return ERR_MEM; } - p = hci_cmd_ass(p, HCI_LINK_KEY_REQ_REP_NEG, HCI_LINK_CTRL_OGF, HCI_LINK_KEY_REQ_REP_NEG_PLEN); + p = hci_cmd_ass(p, HCI_LINK_KEY_REQ_NEG_REP_OCF, HCI_LINK_CTRL_OGF, HCI_LINK_KEY_REQ_NEG_REP_PLEN); memcpy(((u8_t *)p->payload)+4, bdaddr->addr, 6); physbusif_output(p,p->tot_len); @@ -980,7 +1342,7 @@ err_t hci_disconnect(struct bd_addr *bdaddr, u8_t reason) /* Assembling command packet */ p = hci_cmd_ass(p, HCI_DISCONN_OCF, HCI_LINK_CTRL_OGF, HCI_DISCONN_PLEN); - /* Assembling cmd prameters */ + /* Assembling cmd parameters */ ((u16_t *)p->payload)[2] = htole16(link->connhdl); ((u8_t *)p->payload)[6] = reason; @@ -1006,7 +1368,7 @@ err_t hci_reject_connection_request(struct bd_addr *bdaddr, u8_t reason) } /* 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 */ + /* Assembling cmd parameters */ memcpy(((u8_t *)p->payload) + 4, bdaddr->addr, 6); ((u8_t *)p->payload)[10] = reason; @@ -1024,15 +1386,15 @@ err_t hci_reject_connection_request(struct bd_addr *bdaddr, u8_t reason) /*-----------------------------------------------------------------------------------*/ err_t hci_write_stored_link_key(struct bd_addr *bdaddr, u8_t *link) { - struct pbuf *p; + struct pbuf *p; - if((p = btpbuf_alloc(PBUF_RAW, HCI_WRITE_STORED_LINK_KEY_PLEN, PBUF_RAM)) == NULL) { + if((p = btpbuf_alloc(PBUF_RAW, HCI_W_STORED_LINK_KEY_PLEN, PBUF_RAM)) == NULL) { ERROR("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 */ + p = hci_cmd_ass(p, HCI_W_STORED_LINK_KEY_OCF, HCI_HC_BB_OGF, HCI_W_STORED_LINK_KEY_PLEN); + /* Assembling cmd parameters */ ((u8_t *)p->payload)[4] = 0x01; memcpy(((u8_t *)p->payload) + 5, bdaddr->addr, 6); memcpy(((u8_t *)p->payload) + 11, link, 16); @@ -1043,6 +1405,39 @@ err_t hci_write_stored_link_key(struct bd_addr *bdaddr, u8_t *link) return ERR_OK; } +/*-----------------------------------------------------------------------------------*/ +/* hci_delete_stored_link_key(): + * + * Deletes a link key from the Bluetooth host controller. + * If bdaddr == NULL, deletes all keys. + */ + /*-----------------------------------------------------------------------------------*/ +err_t hci_delete_stored_link_key(struct bd_addr *bdaddr) +{ + struct pbuf *p; + + if((p = btpbuf_alloc(PBUF_RAW, HCI_D_STORED_LINK_KEY_PLEN, PBUF_RAM)) == NULL) { + ERROR("hci_write_stored_link_key: Could not allocate memory for pbuf\n"); + return ERR_MEM; + } + /* Assembling command packet */ + p = hci_cmd_ass(p, HCI_D_STORED_LINK_KEY_OCF, HCI_HC_BB_OGF, HCI_D_STORED_LINK_KEY_PLEN); + /* Assembling cmd parameters */ + if (bdaddr) { + memcpy(((u8_t *)p->payload) + 4, bdaddr->addr, 6); + ((u8_t *)p->payload)[10] = 0; + } + else { + memset(((u8_t *)p->payload) + 4, 0, 6); + ((u8_t *)p->payload)[10] = 1; + } + + physbusif_output(p, p->tot_len); + btpbuf_free(p); + + return ERR_OK; +} + /*-----------------------------------------------------------------------------------*/ /* hci_write_cod(): * @@ -1060,7 +1455,7 @@ err_t hci_write_cod(u8_t *cod) } /* Assembling command packet */ p = hci_cmd_ass(p, HCI_W_COD_OCF, HCI_HC_BB_OGF, HCI_W_COD_PLEN); - /* Assembling cmd prameters */ + /* Assembling cmd parameters */ memcpy(((u8_t *)p->payload)+4, cod, 3); physbusif_output(p, p->tot_len); @@ -1103,7 +1498,7 @@ err_t hci_set_hc_to_h_fc(void) } /* 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 */ + /* Assembling cmd parameters */ ((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 */ @@ -1123,12 +1518,12 @@ err_t hci_set_hc_to_h_fc(void) err_t hci_host_buffer_size(void) { struct pbuf *p; - if((p = btpbuf_alloc(PBUF_RAW, HCI_H_BUF_SIZE_PLEN, PBUF_RAM)) == NULL) { + if((p = btpbuf_alloc(PBUF_RAW, HCI_HOST_BUF_SIZE_PLEN, PBUF_RAM)) == NULL) { ERROR("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); + p = hci_cmd_ass(p, HCI_HOST_BUF_SIZE_OCF, HCI_HC_BB_OGF, HCI_HOST_BUF_SIZE_PLEN); ((u16_t *)p->payload)[2] = htole16(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)) = htole16(HCI_HOST_MAX_NUM_ACL); /* Host max total num ACL data packets */ @@ -1158,7 +1553,7 @@ err_t hci_host_num_comp_packets(u16_t conhdl, u16_t num_complete) 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); + p = hci_cmd_ass(p, HCI_HOST_NUM_COMPL_OCF, HCI_HC_BB_OGF, HCI_H_NUM_COMPL_PLEN); ((u8_t*)p->payload)[4] = 1; *(u16_t*)(p->payload+5) = htole16(conhdl); *(u16_t*)(p->payload+7) = htole16(num_complete); /* Number of completed acl packets */ @@ -1183,6 +1578,19 @@ u16_t lp_pdu_maxsize(void) return hci_dev->acl_mtu; } +/*-----------------------------------------------------------------------------------*/ +/* hci_get_bd_addr(): + * + * 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. + */ +/*-----------------------------------------------------------------------------------*/ +void hci_get_bd_addr(struct bd_addr *bdaddr) +{ + if (bdaddr) + bd_addr_set(bdaddr, &hci_dev->bdaddr); +} + /*-----------------------------------------------------------------------------------*/ /* lp_is_connected(): * @@ -1291,8 +1699,8 @@ err_t lp_write_flush_timeout(struct bd_addr *bdaddr, u16_t flushto) } /* Assembling command packet */ - p = hci_cmd_ass(p, HCI_W_FLUSHTO, HCI_HC_BB_OGF, HCI_W_FLUSHTO_PLEN); - /* Assembling cmd prameters */ + p = hci_cmd_ass(p, HCI_W_FLUSHTO_OCF, HCI_HC_BB_OGF, HCI_W_FLUSHTO_PLEN); + /* Assembling cmd parameters */ ((u16_t *)p->payload)[2] = htole16(link->connhdl); ((u16_t *)p->payload)[3] = htole16(flushto); @@ -1353,7 +1761,7 @@ err_t lp_connect_req(struct bd_addr *bdaddr, u8_t allow_role_switch) /* Assembling command packet */ p = hci_cmd_ass(p, HCI_CREATE_CONN_OCF, HCI_LINK_CTRL_OGF, HCI_CREATE_CONN_PLEN); - /* Assembling cmd prameters */ + /* Assembling cmd parameters */ memcpy(((u8_t *)p->payload)+4, bdaddr->addr, 6); ((u16_t *)p->payload)[5] = htole16(hci_dev->pkt_type); ((u8_t *)p->payload)[12] = page_scan_repetition_mode; @@ -1372,17 +1780,17 @@ static void hci_cc_info_param(u8_t ocf,struct pbuf *p) struct bd_addr *bdaddr; switch(ocf) { - case HCI_READ_LOCAL_VERSION: + case HCI_R_LOC_VERS_INFO_OCF: if(((u8_t*)p->payload)[0]==HCI_SUCCESS) { hci_dev->info.hci_version = *((u8_t*)p->payload + 1); hci_dev->info.hci_revision = le16toh(*(u16_t*)((u8_t*)p->payload + 2)); hci_dev->info.lmp_version = *((u8_t*)p->payload + 4); hci_dev->info.manufacturer = le16toh(*(u16_t*)((u8_t*)p->payload + 5)); hci_dev->info.lmp_subversion = le16toh(*(u16_t*)((u8_t*)p->payload + 7)); - LOG("hci_cc_info_param(HCI_READ_LOCAL_VERSION): hci_version = %02x, hci_revision = %04x, lmp_version = %02x, manufacturer = %04x, lmp_suversion = %04x\n",hci_dev->info.hci_version,hci_dev->info.hci_revision,hci_dev->info.lmp_version,hci_dev->info.manufacturer,hci_dev->info.lmp_subversion); + LOG("hci_cc_info_param(HCI_R_LOC_VERS_INFO_OCF): hci_version = %02x, hci_revision = %04x, lmp_version = %02x, manufacturer = %04x, lmp_suversion = %04x\n",hci_dev->info.hci_version,hci_dev->info.hci_revision,hci_dev->info.lmp_version,hci_dev->info.manufacturer,hci_dev->info.lmp_subversion); } break; - case HCI_READ_LOCAL_FEATURES: + case HCI_R_LOC_FEAT_OCF: if(((u8_t*)p->payload)[0]==HCI_SUCCESS) { memcpy(hci_dev->features,(void*)((u8_t*)p->payload+1),sizeof(hci_dev->features)); @@ -1394,23 +1802,23 @@ static void hci_cc_info_param(u8_t ocf,struct pbuf *p) hci_dev->pkt_type |= HCI_HV2; if(hci_dev->features[1]&LMP_HV3) hci_dev->pkt_type |= HCI_HV3; - LOG("hci_cc_info_param(HCI_READ_LOCAL_FEATURES): %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",hci_dev->features[0],hci_dev->features[1],hci_dev->features[2],hci_dev->features[3], + LOG("hci_cc_info_param(HCI_R_LOC_FEAT_OCF): %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",hci_dev->features[0],hci_dev->features[1],hci_dev->features[2],hci_dev->features[3], hci_dev->features[4],hci_dev->features[5],hci_dev->features[6],hci_dev->features[7]); } break; - case HCI_READ_BUFFER_SIZE: + case HCI_R_BUF_SIZE_OCF: if(((u8_t*)p->payload)[0]==HCI_SUCCESS) { hci_dev->acl_mtu = le16toh(*(u16_t*)(((u8_t*)p->payload)+1)); hci_dev->sco_mtu = *((u8_t*)p->payload+3); hci_dev->acl_max_pkt = le16toh(*(u16_t*)(((u8_t*)p->payload)+4)); hci_dev->sco_max_pkt = le16toh(*(u16_t*)(((u8_t*)p->payload)+5)); - LOG("hci_cc_info_param(HCI_READ_BUFFER_SIZE): acl_mt = %d, sco_mt = %d, acl_max_pkt = %d, sco_max_pkt = %d\n",hci_dev->acl_mtu,hci_dev->sco_mtu,hci_dev->acl_max_pkt,hci_dev->sco_max_pkt); + LOG("hci_cc_info_param(HCI_R_BUF_SIZE_OCF): acl_mt = %d, sco_mt = %d, acl_max_pkt = %d, sco_max_pkt = %d\n",hci_dev->acl_mtu,hci_dev->sco_mtu,hci_dev->acl_max_pkt,hci_dev->sco_max_pkt); } break; - case HCI_READ_BD_ADDR: + case HCI_R_BD_ADDR_OCF: if(((u8_t*)p->payload)[0]==HCI_SUCCESS) { bdaddr = (void*)((u8_t*)p->payload+1); - LOG("hci_cc_info_param(HCI_READ_BD_ADDR): %02x:%02x:%02x:%02x:%02x:%02x",bdaddr->addr[0],bdaddr->addr[1],bdaddr->addr[2],bdaddr->addr[3],bdaddr->addr[4],bdaddr->addr[5]); + LOG("hci_cc_info_param(HCI_R_BD_ADDR_OCF): %02x:%02x:%02x:%02x:%02x:%02x",bdaddr->addr[0],bdaddr->addr[1],bdaddr->addr[2],bdaddr->addr[3],bdaddr->addr[4],bdaddr->addr[5]); bd_addr_set(&(hci_dev->bdaddr),bdaddr); } break; @@ -1422,12 +1830,12 @@ static void hci_cc_host_ctrl(u8_t ocf,struct pbuf *p) u8_t *lap; u8_t i,resp_off; - //printf("hci_cc_host_ctrl(%02x)\n",ocf); + LOG("hci_cc_host_ctrl(%02x)\n",ocf); switch(ocf) { - case HCI_SET_HC_TO_H_FC: + case HCI_SET_HC_TO_H_FC_OCF: if(((u8_t*)p->payload)[0]==HCI_SUCCESS) hci_dev->flow = 1; break; - case HCI_READ_CUR_IACLAP: + case HCI_R_CUR_IACLAP_OCF: if(((u8_t*)p->payload)[0]==HCI_SUCCESS) { for(i=0;i<((u8_t*)p->payload)[1];i++) { resp_off = (i*3); @@ -1447,7 +1855,7 @@ static void hci_cc_link_policy(u8_t ocf,struct pbuf *p) (void)ret; switch(ocf) { - case HCI_W_LINK_POLICY: + case HCI_W_LINK_POLICY_OCF: if(((u8_t*)p->payload)[0]==HCI_SUCCESS) { for(link=hci_active_links;link!=NULL;link=link->next) { if(link->connhdl==le16toh(*((u16_t*)(((u8_t*)p->payload)+1)))) break; @@ -1489,8 +1897,9 @@ static void hci_conn_request_evt(struct pbuf *p) bd_addr_set(&(link->bdaddr),bdaddr); HCI_REG(&(hci_active_links),link); } - hci_accecpt_conn_request(bdaddr,0x00); + hci_accept_conn_request(bdaddr,0x00); } else { + hci_reject_connection_request(bdaddr, HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS); } } @@ -1504,7 +1913,7 @@ static void hci_conn_complete_evt(struct pbuf *p) bdaddr = (void*)(((u8_t*)p->payload)+3); link = hci_get_link(bdaddr); - LOG("hci_conn_complete_evt(%p,%02x - %02x:%02x:%02x:%02x:%02x:%02x)\n",link,((u8_t*)p->payload)[0],bdaddr->addr[0],bdaddr->addr[1],bdaddr->addr[2],bdaddr->addr[3],bdaddr->addr[4],bdaddr->addr[5]); + LOG("hci_conn_complete_evt(%p,%02x - %02x:%02x:%02x:%02x:%02x:%02x)\n",link,((u8_t*)p->payload)[0],bdaddr->addr[5],bdaddr->addr[4],bdaddr->addr[3],bdaddr->addr[2],bdaddr->addr[1],bdaddr->addr[0]); switch(((u8_t*)p->payload)[0]) { case HCI_SUCCESS: if(link==NULL) { @@ -1526,8 +1935,35 @@ static void hci_conn_complete_evt(struct pbuf *p) } break; case HCI_PAGE_TIMEOUT: + ERROR("hci_conn_complete_evt: Page timeout\n"); + if(link!=NULL) { + hci_close(link); + lp_connect_cfm(bdaddr,((u8_t*)p->payload)[10],ERR_CONN); + } + break; + case HCI_CONN_TIMEOUT: + ERROR("hci_conn_complete_evt: Timeout\n"); + if(link!=NULL) { + hci_close(link); + lp_connect_cfm(bdaddr,((u8_t*)p->payload)[10],ERR_CONN); + } + break; + case HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS: + LOG("hci_conn_complete_evt: Device not paired\n"); + if(link!=NULL) { + hci_close(link); + lp_connect_cfm(bdaddr,((u8_t*)p->payload)[10],ERR_CONN); + } + break; + case HCI_PAIRING_NOT_ALLOWED: + ERROR("hci_conn_complete_evt: Pairing not allowed\n"); + if(link!=NULL) { + hci_close(link); + lp_connect_cfm(bdaddr,((u8_t*)p->payload)[10],ERR_CONN); + } break; default: + ERROR("hci_conn_complete_evt: Unknown error %d\n", ((u8_t*)p->payload)[0]); if(link!=NULL) { hci_close(link); lp_connect_cfm(bdaddr,((u8_t*)p->payload)[10],ERR_CONN); @@ -1538,13 +1974,15 @@ static void hci_conn_complete_evt(struct pbuf *p) static void hci_inquiry_result_evt(struct pbuf *p) { + // TODO: implement inquiries like the SM does (canceling inquiry after first valid result) + // Need to research what SM deems "valid" (it cancels inquiry before checking for name...) u8_t num_resp; u32_t i,resp_off; struct bd_addr *bdaddr; struct hci_inq_res *ires; num_resp = ((u8_t*)p->payload)[0]; - //printf("hci_inquriy_result_evt(%d)\n",num_resp); + LOG("hci_inquiry_result_evt(%d)\n",num_resp); for(i=0;ipayload)+(1+resp_off)); @@ -1558,7 +1996,36 @@ static void hci_inquiry_result_evt(struct pbuf *p) HCI_REG(&(hci_dev->ires),ires); } else - ERROR("hci_inquriy_result_evt: Could not allocate memory for inquiry result\n"); + ERROR("hci_inquiry_result_evt: Could not allocate memory for inquiry result\n"); + } + +} + +static void hci_inquiry_result_with_rssi_evt(struct pbuf *p) +{ + // TODO: implement inquiries like the SM does (canceling inquiry after first valid result) + // Need to research what SM deems "valid" (it cancels inquiry before checking for name...) + u8_t num_resp; + u32_t i,resp_off; + struct bd_addr *bdaddr; + struct hci_inq_res *ires; + + num_resp = ((u8_t*)p->payload)[0]; + LOG("hci_inquiry_result_with_rssi_evt(%d)\n",num_resp); + for(i=0;ipayload)+(1+resp_off)); + if((ires=btmemb_alloc(&hci_inq_results))!=NULL) { + bd_addr_set(&(ires->bdaddr),bdaddr); + ires->psrm = ((u8_t*)p->payload)[7+resp_off]; + ires->psm = ((u8_t*)p->payload)[8+resp_off]; + memcpy(ires->cod,((u8_t*)p->payload)+9+resp_off,3); + ires->co = le16toh(*((u16_t*)(((u8_t*)p->payload)+12+resp_off))); + ires->next = NULL; + + HCI_REG(&(hci_dev->ires),ires); + } else + ERROR("hci_inquiry_result_with_rssi_evt: Could not allocate memory for inquiry result\n"); } } @@ -1571,7 +2038,7 @@ static void hci_return_link_key_evt(struct pbuf *p) struct hci_link_key *keyres; num_keys = ((u8_t*)p->payload)[0]; - //printf("hci_return_link_key_evt(%d)\n",num_keys); + LOG("hci_return_link_key_evt(%d)\n",num_keys); for(i=0;ipayload)+1+resp_off); @@ -1588,6 +2055,23 @@ static void hci_return_link_key_evt(struct pbuf *p) } +static void hci_inquiry_complete_evt(struct pbuf *p) +{ + err_t ret; + struct hci_inq_res *tmpres; + + (void)ret; + + HCI_EVENT_INQ_COMPLETE(hci_dev,((u8_t*)p->payload)[0],ret); + + // After event completes, clear the list (in case periodic scan is ongoing) + while(hci_dev->ires != NULL) { + tmpres = hci_dev->ires; + hci_dev->ires = hci_dev->ires->next; + btmemb_free(&hci_inq_results,tmpres); + } +} + void hci_event_handler(struct pbuf *p) { err_t ret; @@ -1606,12 +2090,14 @@ void hci_event_handler(struct pbuf *p) switch(evthdr->code) { case HCI_INQUIRY_COMPLETE: - //printf("HCI_INQUIRY_COMPLETE\n"); - HCI_EVENT_INQ_COMPLETE(hci_dev,((u8_t*)p->payload)[0],ret); + hci_inquiry_complete_evt(p); break; case HCI_INQUIRY_RESULT: hci_inquiry_result_evt(p); break; + case HCI_INQUIRY_RESULT_WITH_RSSI: + hci_inquiry_result_with_rssi_evt(p); + break; case HCI_CONNECTION_COMPLETE: hci_conn_complete_evt(p); break; @@ -1633,9 +2119,35 @@ void hci_event_handler(struct pbuf *p) return; } break; + case HCI_AUTH_COMPLETE: + switch(((u8_t*)p->payload)[0]) { + case HCI_SUCCESS: + for(link=hci_active_links;link!=NULL;link=link->next) { + if(link->connhdl==le16toh(*((u16_t*)(((u8_t*)p->payload)+1)))) break; + } + if(link!=NULL) { + HCI_EVENT_AUTH_COMPLETE(hci_dev,&(link->bdaddr),ret); + } + break; + default: + return; + } + break; + case HCI_REMOTE_NAME_REQ_COMPLETE: + bdaddr = (void *)(((u8_t *)p->payload)+1); /* Get the Bluetooth address */ + HCI_EVENT_REMOTE_NAME_REQ_COMPLETE(hci_dev,bdaddr,(((u8_t*)p->payload)+7),((u8_t*)p->payload)[0],ret); + break; case HCI_ENCRYPTION_CHANGE: + LOG("HCI_ENCRYPTION_CHANGE\n"); + break; + case HCI_READ_REMOTE_FEATURES_COMPLETE: + LOG("HCI_READ_REMOTE_FEATURES_COMPLETE\n"); + break; + case HCI_READ_REMOTE_VERSION_COMPLETE: + LOG("HCI_READ_REMOTE_VERSION_COMPLETE\n"); break; case HCI_QOS_SETUP_COMPLETE: + LOG("HCI_QOS_SETUP_COMPLETE\n"); break; case HCI_COMMAND_COMPLETE: hci_dev->num_cmd += ((u8_t*)p->payload)[0]; @@ -1647,13 +2159,13 @@ void hci_event_handler(struct pbuf *p) btpbuf_header(p,-2); switch(ogf) { - case HCI_INFO_PARAM: + case HCI_INFO_PARAM_OGF: hci_cc_info_param(ocf,p); break; - case HCI_HOST_C_N_BB: + case HCI_HC_BB_OGF: hci_cc_host_ctrl(ocf,p); break; - case HCI_LINK_POLICY: + case HCI_LINK_POLICY_OGF: hci_cc_link_policy(ocf,p); break; } @@ -1674,9 +2186,11 @@ void hci_event_handler(struct pbuf *p) hci_dev->num_cmd += ((u8_t*)p->payload)[1]; break; case HCI_HARDWARE_ERROR: + LOG("HCI_HARDWARE_ERROR\n"); //TODO: IS THIS FATAL?? break; case HCI_ROLE_CHANGE: + LOG("HCI_ROLE_CHANGE\n"); break; case HCI_NBR_OF_COMPLETED_PACKETS: for(i=0;i<((u8_t *)p->payload)[0];i++) { @@ -1701,13 +2215,18 @@ void hci_event_handler(struct pbuf *p) } break; case HCI_MODE_CHANGE: - printf("HCI_MODE_CHANGE\n"); + LOG("HCI_MODE_CHANGE\n"); break; case HCI_DATA_BUFFER_OVERFLOW: + LOG("HCI_DATA_BUFFER_OVERFLOW\n"); //TODO: IS THIS FATAL???? break; case HCI_MAX_SLOTS_CHANGE: - break; + LOG("HCI_MAX_SLOTS_CHANGE\n"); + break; + case HCI_READ_CLOCK_OFFSET_COMPLETE: + LOG("HCI_READ_CLOCK_OFFSET_COMPLETE\n"); + break; case HCI_RETURN_LINK_KEYS: hci_return_link_key_evt(p); break; @@ -1725,8 +2244,21 @@ void hci_event_handler(struct pbuf *p) HCI_EVENT_LINK_KEY_NOT(hci_dev, bdaddr, ((u8_t *)p->payload) + 6, ret); /* Notify application.*/ break; + case HCI_VENDOR_SPECIFIC_EVENT: + switch (((u8_t *)p->payload)[0]) { + case HCI_VENDOR_BEGIN_PAIRING: + HCI_EVENT_SYNC_BTN(hci_dev, FALSE); + break; + case HCI_VENDOR_CLEAR_PAIRED_DEVICES: + HCI_EVENT_SYNC_BTN(hci_dev, TRUE); + break; + default: + LOG("hci_event_input: Undefined vendor event code 0x%x, length %d\n", ((u8_t *)p->payload)[0], evthdr->len); + break; + } + break; default: - LOG("hci_event_input: Undefined event code 0x%x\n", evthdr->code); + LOG("hci_event_input: Undefined event code 0x%x, length %d\n", evthdr->code, evthdr->len); break; } } diff --git a/lwbt/hci.h b/lwbt/hci.h index be0d8905b..230d0f95f 100644 --- a/lwbt/hci.h +++ b/lwbt/hci.h @@ -1,3 +1,36 @@ +/* + * 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, modified for use in libogc. + * + * Author: Conny Ohult + * Modified in 2025 by Zarithya. + * + */ + #ifndef __HCI_H__ #define __HCI_H__ @@ -9,7 +42,7 @@ #define HCI_ACL_DATA_PACKET 0x02 #define HCI_SCO_DATA_PACKET 0x03 #define HCI_EVENT_PACKET 0x04 -#define HCI_VENDOR_PACKET 0xff +#define HCI_VENDOR_PACKET 0xFF /* HCI packet types */ #define HCI_DM1 0x0008 @@ -31,6 +64,11 @@ #define HCI_SCO_HDR_LEN 3 #define HCI_CMD_HDR_LEN 3 +/* Specification defined parameters */ +#define HCI_BD_ADDR_LEN 6 +#define HCI_LINK_KEY_LEN 16 +#define HCI_LMP_FEAT_LEN 8 + /* LMP features */ #define LMP_3SLOT 0x01 #define LMP_5SLOT 0x02 @@ -55,261 +93,282 @@ #define LMP_PCONTROL 0x04 /* Opcode Group Field (OGF) values */ -#define HCI_LINK_CONTROL 0x01 /* Link Control Commands */ -#define HCI_LINK_POLICY 0x02 /* Link Policy Commands */ -#define HCI_HOST_C_N_BB 0x03 /* Host Controller & Baseband Commands */ -#define HCI_INFO_PARAM 0x04 /* Informational Parameters */ -#define HCI_STATUS_PARAM 0x05 /* Status Parameters */ -#define HCI_TESTING 0x06 /* Testing Commands */ +#define HCI_LINK_CTRL_OGF 0x01 /* Link Control Commands */ +#define HCI_LINK_POLICY_OGF 0x02 /* Link Policy Commands */ +#define HCI_HC_BB_OGF 0x03 /* Host Controller & Baseband Commands */ +#define HCI_INFO_PARAM_OGF 0x04 /* Informational Parameters */ +#define HCI_STATUS_PARAM_OGF 0x05 /* Status Parameters */ +#define HCI_TESTING_OGF 0x06 /* Testing Commands */ +#define HCI_VENDOR_OGF 0x3F /* Vendor-Specific Commands */ /* Opcode Command Field (OCF) values */ /* Link control commands */ -#define HCI_INQUIRY 0x01 -#define HCI_PERIODIC_INQUIRY 0x03 -#define HCI_CREATE_CONNECTION 0x05 -#define HCI_REJECT_CONNECTION_REQUEST 0x0A -#define HCI_DISCONNECT 0x06 -#define HCI_PIN_CODE_REQ_REP 0x0D -#define HCI_PIN_CODE_REQ_NEG_REP 0x0E -#define HCI_LINK_KEY_REQ_REP 0x0B -#define HCI_LINK_KEY_REQ_REP_NEG 0x0C -#define HCI_SET_CONN_ENCRYPT 0x13 +#define HCI_INQUIRY_OCF 0x01 +#define HCI_INQUIRY_CANCEL_OCF 0x02 +#define HCI_PERIODIC_INQUIRY_OCF 0x03 +#define HCI_EXIT_PERIODIC_INQUIRY_OCF 0x04 +#define HCI_CREATE_CONN_OCF 0x05 +#define HCI_DISCONN_OCF 0x06 +#define HCI_ACCEPT_CONN_REQ_OCF 0x09 +#define HCI_REJECT_CONN_REQ_OCF 0x0A +#define HCI_LINK_KEY_REQ_REP_OCF 0x0B +#define HCI_LINK_KEY_REQ_NEG_REP_OCF 0x0C +#define HCI_PIN_CODE_REQ_REP_OCF 0x0D +#define HCI_PIN_CODE_REQ_NEG_REP_OCF 0x0E +#define HCI_CHANGE_CONN_PACKET_TYPE_OCF 0x0F +#define HCI_AUTH_REQUESTED_OCF 0x11 +#define HCI_SET_CONN_ENCRYPT_OCF 0x13 +#define HCI_R_REMOTE_NAME_OCF 0x19 +#define HCI_R_REMOTE_FEATURES_OCF 0x1B +#define HCI_R_REMOTE_VERSION_INFO_OCF 0x1D +#define HCI_R_CLOCK_OFFSET_OCF 0x1F /* Link Policy commands */ -#define HCI_HOLD_MODE 0x01 -#define HCI_SNIFF_MODE 0x03 -#define HCI_EXIT_SNIFF_MODE 0x04 -#define HCI_PARK_MODE 0x05 -#define HCI_EXIT_PARK_MODE 0x06 -#define HCI_W_LINK_POLICY 0x0D +#define HCI_HOLD_MODE_OCF 0x01 +#define HCI_SNIFF_MODE_OCF 0x03 +#define HCI_EXIT_SNIFF_MODE_OCF 0x04 +#define HCI_PARK_MODE_OCF 0x05 +#define HCI_EXIT_PARK_MODE_OCF 0x06 +#define HCI_W_LINK_POLICY_OCF 0x0D /* Host-Controller and Baseband Commands */ -#define HCI_SET_EVENT_MASK 0x01 -#define HCI_RESET 0x03 -#define HCI_SET_EVENT_FILTER 0x05 -#define HCI_WRITE_STORED_LINK_KEY 0x11 -#define HCI_ROLE_CHANGE 0x12 -#define HCI_WRITE_LOCAL_NAME 0x13 - -#define HCI_WRITE_PAGE_TIMEOUT 0x18 -#define HCI_WRITE_SCAN_ENABLE 0x1A -#define HCI_WRITE_COD 0x24 -#define HCI_W_FLUSHTO 0x28 -#define HCI_SET_HC_TO_H_FC 0x31 -#define HCI_READ_CUR_IACLAP 0x39 -#define HCI_WRITE_PIN_TYPE 0x0A -#define HCI_R_STORED_LINK_KEY 0x0D -#define HCI_HOST_BUF_SIZE 0x33 -#define HCI_WRITE_INQUIRY_SCAN_TYPE 0x43 -#define HCI_WRITE_INQUIRY_MODE 0x45 -#define HCI_WRITE_PAGE_SCAN_TYPE 0x47 +#define HCI_SET_EV_MASK_OCF 0x01 +#define HCI_RESET_OCF 0x03 +#define HCI_SET_EV_FILTER_OCF 0x05 +#define HCI_W_PIN_TYPE_OCF 0x0A +#define HCI_R_STORED_LINK_KEY_OCF 0x0D +#define HCI_W_STORED_LINK_KEY_OCF 0x11 +#define HCI_D_STORED_LINK_KEY_OCF 0x12 +#define HCI_W_LOCAL_NAME_OCF 0x13 +#define HCI_W_PAGE_TIMEOUT_OCF 0x18 +#define HCI_W_SCAN_EN_OCF 0x1A +#define HCI_W_AUTH_ENABLE_OCF 0x20 +#define HCI_R_COD_OCF 0x23 +#define HCI_W_COD_OCF 0x24 +#define HCI_W_FLUSHTO_OCF 0x28 +#define HCI_SET_HC_TO_H_FC_OCF 0x31 +#define HCI_HOST_BUF_SIZE_OCF 0x33 +#define HCI_HOST_NUM_COMPL_OCF 0x35 +#define HCI_W_LINK_SUP_TIMEOUT_OCF 0x37 +#define HCI_R_CUR_IACLAP_OCF 0x39 +#define HCI_W_INQUIRY_SCAN_TYPE_OCF 0x43 +#define HCI_W_INQUIRY_MODE_OCF 0x45 +#define HCI_W_PAGE_SCAN_TYPE_OCF 0x47 /* Informational Parameters */ -#define HCI_READ_LOCAL_VERSION 0x01 -#define HCI_READ_LOCAL_FEATURES 0x03 -#define HCI_READ_BUFFER_SIZE 0x05 -#define HCI_READ_BD_ADDR 0x09 +#define HCI_R_LOC_VERS_INFO_OCF 0x01 +#define HCI_R_LOC_FEAT_OCF 0x03 +#define HCI_R_BUF_SIZE_OCF 0x05 +#define HCI_R_BD_ADDR_OCF 0x09 /* Status Parameters */ -#define HCI_READ_FAILED_CONTACT_COUNTER 0x01 -#define HCI_RESET_FAILED_CONTACT_COUNTER 0x02 -#define HCI_GET_LINK_QUALITY 0x03 -#define HCI_READ_RSSI 0x05 +#define HCI_READ_FAILED_CONTACT_COUNTER 0x01 +#define HCI_RESET_FAILED_CONTACT_COUNTER 0x02 +#define HCI_GET_LINK_QUALITY 0x03 +#define HCI_READ_RSSI 0x05 -/* Testing commands */ - -/* Possible event codes */ -#define HCI_INQUIRY_COMPLETE 0x01 -#define HCI_INQUIRY_RESULT 0x02 -#define HCI_CONNECTION_COMPLETE 0x03 -#define HCI_CONNECTION_REQUEST 0x04 -#define HCI_DISCONNECTION_COMPLETE 0x05 -#define HCI_ENCRYPTION_CHANGE 0x08 -#define HCI_QOS_SETUP_COMPLETE 0x0D -#define HCI_COMMAND_COMPLETE 0x0E -#define HCI_COMMAND_STATUS 0x0F -#define HCI_HARDWARE_ERROR 0x10 -#define HCI_ROLE_CHANGE 0x12 -#define HCI_NBR_OF_COMPLETED_PACKETS 0x13 -#define HCI_MODE_CHANGE 0x14 -#define HCI_RETURN_LINK_KEYS 0x15 -#define HCI_PIN_CODE_REQUEST 0x16 -#define HCI_LINK_KEY_REQUEST 0x17 -#define HCI_LINK_KEY_NOTIFICATION 0x18 -#define HCI_DATA_BUFFER_OVERFLOW 0x1A -#define HCI_MAX_SLOTS_CHANGE 0x1B +/* Testing Commands */ -/* Success code */ -#define HCI_SUCCESS 0x00 -/* Possible error codes */ -#define HCI_UNKNOWN_HCI_COMMAND 0x01 -#define HCI_NO_CONNECTION 0x02 -#define HCI_HW_FAILURE 0x03 -#define HCI_PAGE_TIMEOUT 0x04 -#define HCI_AUTHENTICATION_FAILURE 0x05 -#define HCI_KEY_MISSING 0x06 -#define HCI_MEMORY_FULL 0x07 -#define HCI_CONN_TIMEOUT 0x08 -#define HCI_MAX_NUMBER_OF_CONNECTIONS 0x09 -#define HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE 0x0A -#define HCI_ACL_CONNECTION_EXISTS 0x0B -#define HCI_COMMAND_DISSALLOWED 0x0C -#define HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES 0x0D -#define HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS 0x0E -#define HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE 0x0F -#define HCI_HOST_TIMEOUT 0x10 -#define HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE 0x11 -#define HCI_INVALID_HCI_COMMAND_PARAMETERS 0x12 -#define HCI_OTHER_END_TERMINATED_CONN_USER_ENDED 0x13 -#define HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES 0x14 -#define HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF 0x15 -#define HCI_CONN_TERMINATED_BY_LOCAL_HOST 0x16 -#define HCI_REPETED_ATTEMPTS 0x17 -#define HCI_PAIRING_NOT_ALLOWED 0x18 -#define HCI_UNKNOWN_LMP_PDU 0x19 -#define HCI_UNSUPPORTED_REMOTE_FEATURE 0x1A -#define HCI_SCO_OFFSET_REJECTED 0x1B -#define HCI_SCO_INTERVAL_REJECTED 0x1C -#define HCI_SCO_AIR_MODE_REJECTED 0x1D -#define HCI_INVALID_LMP_PARAMETERS 0x1E -#define HCI_UNSPECIFIED_ERROR 0x1F -#define HCI_UNSUPPORTED_LMP_PARAMETER_VALUE 0x20 -#define HCI_ROLE_CHANGE_NOT_ALLOWED 0x21 -#define HCI_LMP_RESPONSE_TIMEOUT 0x22 -#define HCI_LMP_ERROR_TRANSACTION_COLLISION 0x23 -#define HCI_LMP_PDU_NOT_ALLOWED 0x24 -#define HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE 0x25 -#define HCI_UNIT_KEY_USED 0x26 -#define HCI_QOS_NOT_SUPPORTED 0x27 -#define HCI_INSTANT_PASSED 0x28 -#define HCI_PAIRING_UNIT_KEY_NOT_SUPPORTED 0x29 - -/* Specification specific parameters */ -#define HCI_BD_ADDR_LEN 6 -#define HCI_LMP_FEATURES_LEN 8 -#define HCI_LINK_KEY_LEN 16 -#define HCI_LMP_FEAT_LEN 8 - -/* Command OGF */ -#define HCI_LINK_CTRL_OGF 0x01 /* Link ctrl cmds */ -#define HCI_LINK_POLICY_OGF 0x02 /* Link Policy Commands */ -#define HCI_HC_BB_OGF 0x03 /* Host controller and baseband commands */ -#define HCI_INFO_PARAM_OGF 0x04 /* Informal parameters */ - -/* Command OCF */ -#define HCI_INQUIRY_OCF 0x01 -#define HCI_SNIFF_MODE_OCF 0x03 -#define HCI_EXIT_SNIFF_MODE_OCF 0x04 -#define HCI_PARK_MODE_OCF 0x05 -#define HCI_EXIT_PARK_MODE_OCF 0x06 -#define HCI_PERIODIC_INQUIRY_OCF 0x03 -#define HCI_EXIT_PERIODIC_INQUIRY_OCF 0x04 -#define HCI_CREATE_CONN_OCF 0x05 -#define HCI_DISCONN_OCF 0x06 -#define HCI_W_LOCAL_NAME_OCF 0x13 -#define HCI_W_LINK_POLICY_OCF 0x0D -#define HCI_ACCEPT_CONN_REQ_OCF 0x09 -#define HCI_REJECT_CONN_REQ_OCF 0x0A -#define HCI_SET_EV_MASK_OCF 0x01 -#define HCI_RESET_OCF 0x03 -#define HCI_SET_EV_FILTER_OCF 0x05 -#define HCI_R_STORED_LINK_KEY_OCF 0x0D -#define HCI_W_PAGE_TIMEOUT_OCF 0x18 -#define HCI_W_SCAN_EN_OCF 0x1A -#define HCI_R_COD_OCF 0x23 -#define HCI_W_COD_OCF 0x24 -#define HCI_SET_HC_TO_H_FC_OCF 0x31 -#define HCI_H_BUF_SIZE_OCF 0x33 -#define HCI_H_NUM_COMPL_OCF 0x35 -#define HCI_R_CUR_IACLAP_OCF 0x39 -#define HCI_R_LOC_VERSION_OCF 0x01 -#define HCI_R_LOC_FEATURES_OCF 0x03 -#define HCI_R_BUF_SIZE_OCF 0x05 -#define HCI_R_BD_ADDR_OCF 0x09 -#define HCI_R_REMOTE_NAME_OCF 0x19 -#define HCI_W_PIN_TYPE_OCF 0x0A -#define HCI_W_INQUIRY_SCAN_TYPE_OCF 0x43 -#define HCI_W_INQUIRY_MODE_OCF 0x45 -#define HCI_W_PAGE_SCAN_TYPE_OCF 0x47 -#define HCI_W_PAGE_SCAN_TYPE_OCF 0x47 +/* Vendor-Specific Commands*/ +#define HCI_VENDOR_PATCH_START_OCF 0x4F +#define HCI_VENDOR_PATCH_CONT_OCF 0x4C +#define HCI_VENDOR_PATCH_END_OCF 0x4F /* Command packet length (including ACL header)*/ + +/* Link Control Commands */ #define HCI_INQUIRY_PLEN 9 #define HCI_PERIODIC_INQUIRY_PLEN 13 #define HCI_EXIT_PERIODIC_INQUIRY_PLEN 4 #define HCI_CREATE_CONN_PLEN 17 #define HCI_DISCONN_PLEN 7 -#define HCI_REJECT_CONN_REQ_PLEN 11 #define HCI_ACCEPT_CONN_REQ_PLEN 11 +#define HCI_REJECT_CONN_REQ_PLEN 11 +#define HCI_LINK_KEY_REQ_REP_PLEN 26 +#define HCI_LINK_KEY_REQ_NEG_REP_PLEN 10 #define HCI_PIN_CODE_REQ_REP_PLEN 27 #define HCI_PIN_CODE_REQ_NEG_REP_PLEN 10 -#define HCI_LINK_KEY_REQ_REP_PLEN 26 -#define HCI_LINK_KEY_REQ_REP_NEG_PLEN 10 +#define HCI_AUTH_REQUESTED_PLEN 6 #define HCI_SET_CONN_ENCRYPT_PLEN 7 -#define HCI_WRITE_STORED_LINK_KEY_PLEN 27 -#define HCI_SET_EV_MASK_PLEN 12 -#define HCI_SNIFF_PLEN 14 +#define HCI_R_REMOTE_NAME_PLEN 14 +#define HCI_R_REMOTE_FEATURES_PLEN 6 +#define HCI_R_REMOTE_VERSION_INFO_PLEN 6 +#define HCI_R_CLOCK_OFFSET_PLEN 6 + +/* Link Policy Commands */ +#define HCI_SNIFF_MODE_PLEN 14 #define HCI_W_LINK_POLICY_PLEN 8 + +/* Host-Controller and Baseband Commands */ +#define HCI_SET_EV_MASK_PLEN 12 #define HCI_RESET_PLEN 4 #define HCI_SET_EV_FILTER_PLEN 6 +#define HCI_W_PIN_TYPE_PLEN 5 +#define HCI_R_STORED_LINK_KEY_PLEN 11 +#define HCI_W_STORED_LINK_KEY_PLEN 27 +#define HCI_D_STORED_LINK_KEY_PLEN 11 +#define HCI_W_LOCAL_NAME_PLEN 252 #define HCI_W_PAGE_TIMEOUT_PLEN 6 #define HCI_W_SCAN_EN_PLEN 5 +#define HCI_W_AUTH_ENABLE_PLEN 5 #define HCI_R_COD_PLEN 4 #define HCI_W_COD_PLEN 7 #define HCI_W_FLUSHTO_PLEN 8 -#define HCI_W_LOCAL_NAME_PLEN 252 #define HCI_SET_HC_TO_H_FC_PLEN 5 -#define HCI_H_BUF_SIZE_PLEN 11 +#define HCI_HOST_BUF_SIZE_PLEN 11 #define HCI_H_NUM_COMPL_PLEN 9 -#define HCI_R_LOC_FEAT_SIZE_PLEN 4 -#define HCI_R_LOC_VERS_SIZE_PLEN 4 -#define HCI_R_BUF_SIZE_PLEN 4 -#define HCI_R_BD_ADDR_PLEN 4 #define HCI_R_CUR_IACLAP_PLEN 4 -#define HCI_R_STORED_LINK_KEY_PLEN 11 -#define HCI_R_REMOTE_NAME_PLEN 14 -#define HCI_W_PIN_TYPE_PLEN 5 -#define HCI_W_INQUIRY_MODE_PLEN 5 #define HCI_W_INQUIRY_SCAN_TYPE_PLEN 5 +#define HCI_W_INQUIRY_MODE_PLEN 5 #define HCI_W_PAGE_SCAN_TYPE_PLEN 5 + +/* Informational Parameters */ +#define HCI_R_LOC_VERS_INFO_PLEN 4 +#define HCI_R_LOC_FEAT_PLEN 4 +#define HCI_R_BUF_SIZE_PLEN 4 +#define HCI_R_BD_ADDR_PLEN 4 + +/* Testing Commands */ + +/* Vendor-Specific Commands*/ #define HCI_W_VENDOR_CMD_PLEN 4 -struct hci_evt_hdr -{ - u8_t code; - u8_t len; +/* Possible event codes */ +#define HCI_INQUIRY_COMPLETE 0x01 +#define HCI_INQUIRY_RESULT 0x02 +#define HCI_CONNECTION_COMPLETE 0x03 +#define HCI_CONNECTION_REQUEST 0x04 +#define HCI_DISCONNECTION_COMPLETE 0x05 +#define HCI_AUTH_COMPLETE 0x06 +#define HCI_REMOTE_NAME_REQ_COMPLETE 0x07 +#define HCI_ENCRYPTION_CHANGE 0x08 +#define HCI_CHANGE_CONN_LINK_KEY_COMPLETE 0x09 +#define HCI_MASTER_LINK_KEY_COMPLETE 0x0A +#define HCI_READ_REMOTE_FEATURES_COMPLETE 0x0B +#define HCI_READ_REMOTE_VERSION_COMPLETE 0x0C +#define HCI_QOS_SETUP_COMPLETE 0x0D +#define HCI_COMMAND_COMPLETE 0x0E +#define HCI_COMMAND_STATUS 0x0F +#define HCI_HARDWARE_ERROR 0x10 +#define HCI_FLUSH_OCCURRED 0x11 +#define HCI_ROLE_CHANGE 0x12 +#define HCI_NBR_OF_COMPLETED_PACKETS 0x13 +#define HCI_MODE_CHANGE 0x14 +#define HCI_RETURN_LINK_KEYS 0x15 +#define HCI_PIN_CODE_REQUEST 0x16 +#define HCI_LINK_KEY_REQUEST 0x17 +#define HCI_LINK_KEY_NOTIFICATION 0x18 +#define HCI_LOOPBACK_COMMAND 0x19 +#define HCI_DATA_BUFFER_OVERFLOW 0x1A +#define HCI_MAX_SLOTS_CHANGE 0x1B +#define HCI_READ_CLOCK_OFFSET_COMPLETE 0x1C +#define HCI_CONN_PTYPE_CHANGED 0x1D +#define HCI_QOS_VIOLATION 0x1E +#define HCI_PSCAN_REP_MODE_CHANGE 0x20 +#define HCI_FLOW_SPEC_COMPLETE 0x21 +#define HCI_INQUIRY_RESULT_WITH_RSSI 0x22 +#define HCI_READ_REMOTE_EXT_FEATURES_COMPLETE 0x23 +#define HCI_SYNC_CONN_COMPLETE 0x2C +#define HCI_SYNC_CONN_CHANGED 0x2D +#define HCI_SNIFF_SUBRATING 0x2E +#define HCI_EXTENDED_INQUIRY_RESULT 0x2F +#define HCI_ENCRYPTION_KEY_REFRESH_COMPLETE 0x30 +#define HCI_IO_CAPABILITY_REQUEST 0x31 +#define HCI_IO_CAPABILITY_RESPONSE 0x32 +#define HCI_USER_CONFIRM_REQUEST 0x33 +#define HCI_USER_PASSKEY_REQUEST 0x34 +#define HCI_REMOTE_OOB_DATA_REQUEST 0x35 +#define HCI_SIMPLE_PAIRING_COMPLETE 0x36 +#define HCI_LINK_SUPERVISION_TIMEOUT_CHANGED 0x38 +#define HCI_ENHANCED_FLUSH_COMPLETE 0x39 +#define HCI_USER_PASSKEY_NOTIFY 0x3B +#define HCI_KEYPRESS_NOTIFY 0x3C +#define HCI_REMOTE_HOST_FEATURES_NOTIFY 0x3D +#define HCI_VENDOR_SPECIFIC_EVENT 0xFF + +/* Vendor specific event codes */ +#define HCI_VENDOR_BEGIN_PAIRING 0x08 +#define HCI_VENDOR_CLEAR_PAIRED_DEVICES 0x09 + +/* Success code */ +#define HCI_SUCCESS 0x00 +/* Possible error codes */ +#define HCI_UNKNOWN_HCI_COMMAND 0x01 +#define HCI_NO_CONNECTION 0x02 +#define HCI_HW_FAILURE 0x03 +#define HCI_PAGE_TIMEOUT 0x04 +#define HCI_AUTHENTICATION_FAILURE 0x05 +#define HCI_KEY_MISSING 0x06 +#define HCI_MEMORY_FULL 0x07 +#define HCI_CONN_TIMEOUT 0x08 +#define HCI_MAX_NUMBER_OF_CONNECTIONS 0x09 +#define HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE 0x0A +#define HCI_ACL_CONNECTION_EXISTS 0x0B +#define HCI_COMMAND_DISSALLOWED 0x0C +#define HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES 0x0D +#define HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS 0x0E +#define HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE 0x0F +#define HCI_HOST_TIMEOUT 0x10 +#define HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE 0x11 +#define HCI_INVALID_HCI_COMMAND_PARAMETERS 0x12 +#define HCI_OTHER_END_TERMINATED_CONN_USER_ENDED 0x13 +#define HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES 0x14 +#define HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF 0x15 +#define HCI_CONN_TERMINATED_BY_LOCAL_HOST 0x16 +#define HCI_REPEATED_ATTEMPTS 0x17 +#define HCI_PAIRING_NOT_ALLOWED 0x18 +#define HCI_UNKNOWN_LMP_PDU 0x19 +#define HCI_UNSUPPORTED_REMOTE_FEATURE 0x1A +#define HCI_SCO_OFFSET_REJECTED 0x1B +#define HCI_SCO_INTERVAL_REJECTED 0x1C +#define HCI_SCO_AIR_MODE_REJECTED 0x1D +#define HCI_INVALID_LMP_PARAMETERS 0x1E +#define HCI_UNSPECIFIED_ERROR 0x1F +#define HCI_UNSUPPORTED_LMP_PARAMETER_VALUE 0x20 +#define HCI_ROLE_CHANGE_NOT_ALLOWED 0x21 +#define HCI_LMP_RESPONSE_TIMEOUT 0x22 +#define HCI_LMP_ERROR_TRANSACTION_COLLISION 0x23 +#define HCI_LMP_PDU_NOT_ALLOWED 0x24 +#define HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE 0x25 +#define HCI_UNIT_KEY_USED 0x26 +#define HCI_QOS_NOT_SUPPORTED 0x27 +#define HCI_INSTANT_PASSED 0x28 +#define HCI_PAIRING_UNIT_KEY_NOT_SUPPORTED 0x29 + +struct hci_evt_hdr { + u8_t code; /* Event code */ + u8_t len; /* Parameter total length */ } ATTRIBUTE_PACKED; -struct hci_acl_hdr -{ - u16_t connhdl_pb_bc; - u16_t len; +struct hci_acl_hdr { + u16_t connhdl_pb_bc; /* Connection handle, packet boundary and broadcast flag + flag */ + u16_t len; /* length of data */ } ATTRIBUTE_PACKED; -struct hci_inq_res -{ - struct hci_inq_res *next; - struct bd_addr bdaddr; - u8_t cod[3]; - u8_t psrm; - u8_t psm; - u16_t co; +struct hci_inq_res { + struct hci_inq_res *next; /* For the linked list */ + + struct bd_addr bdaddr; /* Bluetooth address of a device found in an inquiry */ + u8_t cod[3]; /* Class of the remote device */ + u8_t psrm; /* Page scan repetition mode */ + u8_t psm; /* Page scan mode */ + u16_t co; /* Clock offset */ }; -struct hci_link_key -{ - struct bd_addr bdaddr; - u8_t key[16]; +struct hci_link_key { + struct hci_link_key *next; /* For the linked list */ - struct hci_link_key *next; + struct bd_addr bdaddr; /* The remote peer's Bluetooth address for this connection */ + u8_t key[HCI_LINK_KEY_LEN]; /* The connection's link key */ }; -struct hci_link -{ - struct hci_link *next; - struct bd_addr bdaddr; - u16_t connhdl; +struct hci_link { + struct hci_link *next; /* For the linked list */ + + struct bd_addr bdaddr; /* The remote peers Bluetooth address for this connection */ + u16_t connhdl; /* Connection handle */ struct pbuf *p; u16_t len; u8_t pb; @@ -328,7 +387,10 @@ struct hci_version_info struct hci_pcb { void *cbarg; - s8_t num_cmd; + + /* Host to host controller flow control */ + s8_t num_cmd; /* Number of command packets that the host controller (Bluetooth + module) can buffer */ u16_t acl_mtu; u8_t sco_mtu; @@ -337,29 +399,36 @@ struct hci_pcb u32_t flags; - u8_t flow; - u16_t host_num_acl; + /* Host controller to host flow control */ + u8_t flow; /* Indicates if host controller to host flow control is on */ + u16_t host_num_acl; /* Number of ACL packets that we (the host) can buffer */ u16_t pkt_type; u8_t features[8]; - struct bd_addr bdaddr; - struct hci_version_info info; + struct bd_addr bdaddr; /* Host controller address */ + struct hci_version_info info; /* Host controller version info */ - struct hci_inq_res *ires; + struct hci_inq_res *ires; /* Results of an inquiry */ struct hci_link_key *keyres; err_t (*pin_req)(void *arg,struct bd_addr *bdaddr); + err_t (*inq_complete)(void *arg,struct hci_pcb *pcb,struct hci_inq_res *ires,u16_t result); + err_t (*conn_req)(void *arg,struct bd_addr *bdaddr,u8_t *cod,u8_t link_type); err_t (*link_key_req)(void *arg,struct bd_addr *bdaddr); - err_t (*cmd_complete)(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result); err_t (*link_key_not)(void *arg, struct bd_addr *bdaddr, u8_t *key); - err_t (*conn_complete)(void *arg,struct bd_addr *bdaddr); - err_t (*inq_complete)(void *arg,struct hci_pcb *pcb,struct hci_inq_res *ires,u16_t result); + err_t (*auth_complete)(void *arg,struct bd_addr *bdaddr); err_t (*wlp_complete)(void *arg, struct bd_addr *bdaddr); - err_t (*conn_req)(void *arg,struct bd_addr *bdaddr,u8_t *cod,u8_t link_type); + err_t (*conn_complete)(void *arg,struct bd_addr *bdaddr); + err_t (*cmd_complete)(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result); + err_t (*remote_name_req_complete)(void *arg,struct bd_addr *bdaddr,u8_t *name,u8_t result); + void (*sync_btn)(u32_t held); }; -err_t hci_init(void); +/* Functions for interfacing with HCI */ +err_t hci_init(void); /* Must be called first to initialize HCI */ + +/* Application program's interface: */ struct hci_link* hci_new(void); void hci_reset_all(void); void hci_event_handler(struct pbuf *p); @@ -381,6 +450,7 @@ err_t hci_reject_connection_request(struct bd_addr *bdaddr, u8_t reason); err_t hci_pin_code_request_reply(struct bd_addr *bdaddr, u8_t pinlen, u8_t *pincode); err_t hci_link_key_req_reply(struct bd_addr *bdaddr, u8_t *link_key); err_t hci_write_stored_link_key(struct bd_addr *bdaddr, u8_t *link); +err_t hci_delete_stored_link_key(struct bd_addr *bdaddr); err_t hci_set_event_filter(u8_t filter_type,u8_t filter_cond_type,u8_t *cond); err_t hci_write_page_timeout(u16_t timeout); 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)); @@ -389,10 +459,12 @@ err_t hci_link_key_req_neg_reply(struct bd_addr *bdaddr); err_t hci_write_scan_enable(u8_t scan_enable); err_t hci_host_num_comp_packets(u16_t conhdl, u16_t num_complete); err_t hci_sniff_mode(struct bd_addr *bdaddr, u16_t max_interval, u16_t min_interval, u16_t attempt, u16_t timeout); +err_t hci_auth_req(struct bd_addr *bdaddr); err_t hci_write_link_policy_settings(struct bd_addr *bdaddr, u16_t link_policy); +err_t hci_write_authentication_enable(u8_t auth_enable); err_t hci_periodic_inquiry(u32_t lap,u16_t min_period,u16_t max_period,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)); err_t hci_exit_periodic_inquiry(void); -err_t hci_accecpt_conn_request(struct bd_addr *bdaddr,u8_t role); +err_t hci_accept_conn_request(struct bd_addr *bdaddr,u8_t role); err_t hci_set_event_mask(u64_t ev_mask); err_t hci_read_local_version(void); err_t hci_read_local_features(void); @@ -400,6 +472,9 @@ err_t hci_write_local_name(u8_t *name,u8_t len); err_t hci_write_pin_type(u8_t type); err_t hci_read_stored_link_key(void); err_t hci_read_remote_name(struct bd_addr *bdaddr); +err_t hci_read_clock_offset(struct bd_addr *bdaddr); +err_t hci_read_remote_version_info(u16_t connhdl); +err_t hci_read_remote_features(u16_t connhdl); err_t hci_vendor_specific_command(u8_t ocf,u8_t ogf,void *data,u8_t len); err_t hci_reg_dev_info(struct bd_addr *bdaddr,u8_t *cod,u8_t psrm,u8_t psm,u16_t co); @@ -407,76 +482,88 @@ err_t hci_reg_dev_info(struct bd_addr *bdaddr,u8_t *cod,u8_t psrm,u8_t psm,u16_t void hci_arg(void *arg); void hci_cmd_complete(err_t (*cmd_complete)(void *arg,struct hci_pcb *pcb,u8_t ogf,u8_t ocf,u8_t result)); void hci_connection_complete(err_t (* conn_complete)(void *arg, struct bd_addr *bdaddr)); +void hci_auth_complete(err_t (* auth_complete)(void *arg, struct bd_addr *bdaddr)); void hci_pin_req(err_t (* pin_req)(void *arg, struct bd_addr *bdaddr)); void hci_link_key_req(err_t (* link_key_req)(void *arg, struct bd_addr *bdaddr)); void hci_link_key_not(err_t (* link_key_not)(void *arg, struct bd_addr *bdaddr, u8_t *key)); void hci_wlp_complete(err_t (* wlp_complete)(void *arg, struct bd_addr *bdaddr)); void hci_conn_req(err_t (*conn_req)(void *arg,struct bd_addr *bdaddr,u8_t *cod,u8_t link_type)); +void hci_remote_name_req_complete(err_t (*remote_name_req_complete)(void *arg,struct bd_addr *bdaddr,u8_t *name,u8_t result)); +void hci_sync_btn(void (*sync_btn)(u32_t held)); +void hci_get_bd_addr(struct bd_addr *bdaddr); +/* L2CAP interface */ u16_t lp_pdu_maxsize(void); u8_t lp_is_connected(struct bd_addr *bdaddr); err_t lp_acl_write(struct bd_addr *bdaddr,struct pbuf *p,u16_t len,u8_t pb); err_t lp_connect_req(struct bd_addr *bdaddr, u8_t allow_role_switch); err_t lp_write_flush_timeout(struct bd_addr *bdaddr, u16_t flushto); - #define HCI_EVENT_PIN_REQ(pcb,bdaddr,ret) \ - if((pcb)->pin_req != NULL) { \ - (ret = (pcb)->pin_req((pcb)->cbarg,(bdaddr))); \ - } else { \ - ret = hci_pin_code_request_neg_reply(bdaddr); \ + if((pcb)->pin_req != NULL) { \ + (ret = (pcb)->pin_req((pcb)->cbarg,(bdaddr))); \ + } else { \ + ret = hci_pin_code_request_neg_reply(bdaddr); \ } #define HCI_EVENT_LINK_KEY_REQ(pcb,bdaddr,ret) \ - if((pcb)->link_key_req != NULL) { \ - (ret = (pcb)->link_key_req((pcb)->cbarg,(bdaddr))); \ - } else { \ - ret = hci_link_key_req_neg_reply(bdaddr); \ + if((pcb)->link_key_req != NULL) { \ + (ret = (pcb)->link_key_req((pcb)->cbarg,(bdaddr))); \ + } else { \ + ret = hci_link_key_req_neg_reply(bdaddr); \ } #define HCI_EVENT_CONN_REQ(pcb,bdaddr,cod,linktype,ret) \ if((pcb)->conn_req!=NULL) \ (ret = (pcb)->conn_req((pcb)->cbarg,(bdaddr),(cod),(linktype))) #define HCI_EVENT_LINK_KEY_NOT(pcb,bdaddr,key,ret) \ - if((pcb)->link_key_not != NULL) { \ - (ret = (pcb)->link_key_not((pcb)->cbarg,(bdaddr),(key))); \ - } + if((pcb)->link_key_not != NULL) { \ + (ret = (pcb)->link_key_not((pcb)->cbarg,(bdaddr),(key))); \ + } #define HCI_EVENT_INQ_COMPLETE(pcb,result,ret) \ - if((pcb)->inq_complete != NULL) \ - (ret = (pcb)->inq_complete((pcb)->cbarg,(pcb),(pcb)->ires,(result))) + if((pcb)->inq_complete != NULL) \ + (ret = (pcb)->inq_complete((pcb)->cbarg,(pcb),(pcb)->ires,(result))) #define HCI_EVENT_WLP_COMPLETE(pcb,bdaddr,ret) \ - if((pcb)->wlp_complete != NULL) \ - (ret = (pcb)->wlp_complete((pcb)->cbarg,(bdaddr))); + if((pcb)->wlp_complete != NULL) \ + (ret = (pcb)->wlp_complete((pcb)->cbarg,(bdaddr))); #define HCI_EVENT_CONN_COMPLETE(pcb,bdaddr,ret) \ - if((pcb)->conn_complete != NULL) \ - (ret = (pcb)->conn_complete((pcb)->cbarg,(bdaddr))); + if((pcb)->conn_complete != NULL) \ + (ret = (pcb)->conn_complete((pcb)->cbarg,(bdaddr))); +#define HCI_EVENT_AUTH_COMPLETE(pcb,bdaddr,ret) \ + if((pcb)->auth_complete != NULL) \ + (ret = (pcb)->auth_complete((pcb)->cbarg,(bdaddr))); #define HCI_EVENT_CMD_COMPLETE(pcb,ogf,ocf,result,ret) \ - if((pcb)->cmd_complete != NULL) \ - (ret = (pcb)->cmd_complete((pcb)->cbarg,(pcb),(ogf),(ocf),(result))) + if((pcb)->cmd_complete != NULL) \ + (ret = (pcb)->cmd_complete((pcb)->cbarg,(pcb),(ogf),(ocf),(result))) +#define HCI_EVENT_REMOTE_NAME_REQ_COMPLETE(pcb,bdaddr,name,result,ret) \ + if((pcb)->remote_name_req_complete != NULL) \ + (ret = (pcb)->remote_name_req_complete((pcb)->cbarg,(bdaddr),(name),(result))) +#define HCI_EVENT_SYNC_BTN(pcb, held) \ + if((pcb)->sync_btn != NULL) \ + ((pcb)->sync_btn(held)) /* The HCI LINK lists. */ extern struct hci_link *hci_active_links; /* List of all active HCI LINKs */ extern struct hci_link *hci_tmp_link; /* Only used for temporary storage. */ -extern struct hci_link_key *hci_tmp_key; #define HCI_REG(links, nlink) do { \ u32 level; \ _CPU_ISR_Disable(level); \ - nlink->next = *links; \ - *links = nlink; \ + nlink->next = *links; \ + *links = nlink; \ _CPU_ISR_Restore(level); \ - } while(0) + } while(0) #define HCI_RMV(links, nlink) do { \ u32 level; \ _CPU_ISR_Disable(level);\ - if(*links == nlink) { \ - *links = (*links)->next; \ - } else for(hci_tmp_link = *links; hci_tmp_link != NULL; hci_tmp_link = hci_tmp_link->next) { \ - if(hci_tmp_link->next != NULL && hci_tmp_link->next == nlink) { \ - hci_tmp_link->next = nlink->next; \ - break; \ - } \ - } \ - nlink->next = NULL; \ + if(*links == nlink) { \ + *links = (*links)->next; \ + } else for(hci_tmp_link = *links; hci_tmp_link != NULL; hci_tmp_link = hci_tmp_link->next) { \ + if(hci_tmp_link->next != NULL && hci_tmp_link->next == nlink) { \ + hci_tmp_link->next = nlink->next; \ + break; \ + } \ + } \ + nlink->next = NULL; \ _CPU_ISR_Restore(level); \ - } while(0) + } while(0) #endif diff --git a/lwbt/l2cap.c b/lwbt/l2cap.c index 799cba7d6..b26a6c528 100644 --- a/lwbt/l2cap.c +++ b/lwbt/l2cap.c @@ -342,6 +342,9 @@ void l2cap_process_sig(struct pbuf *q, struct l2cap_hdr *l2caphdr, struct bd_add pcb->state = L2CAP_CONFIG; L2CAP_REG(&l2cap_active_pcbs, pcb); + + /* Free the listening pcb, don't need it anymore */ + l2cap_close((struct l2cap_pcb *)lpcb); LOG("l2cap_process_sig: A connection request was received. Send a response\n"); data = btpbuf_alloc(PBUF_RAW, L2CAP_CONN_RSP_SIZE, PBUF_RAM); @@ -1398,7 +1401,7 @@ void lp_connect_cfm(struct bd_addr *bdaddr, u8_t encrypt_mode, err_t err) L2CA_ACTION_CONN_CFM(pcb,L2CAP_CONN_REF_RES,0x0000,ret); /* No resources available */ } } else { - ERROR("lp_connect_cfm: Connection falied\n"); + ERROR("lp_connect_cfm: Connection failed(%d)\n", err); L2CA_ACTION_CONN_CFM(pcb,L2CAP_CONN_REF_RES,0x0000,ret); /* No resources available */ } } diff --git a/lwbt/physbusif.c b/lwbt/physbusif.c index 88e9be76e..5960ff00f 100644 --- a/lwbt/physbusif.c +++ b/lwbt/physbusif.c @@ -47,12 +47,6 @@ static s32 __issue_intrread(void); extern u32 __IPC_ClntInit(void); -static s32 __usb_closeCB(s32 result,void *usrdata) -{ - __usbdev.fd = -1; - return result; -} - static s32 __writectrlmsgCB(s32 result,void *usrdata) { if(usrdata!=NULL) btmemb_free(&ctrlbufs,usrdata); @@ -299,7 +293,7 @@ void physbusif_close(void) void physbusif_shutdown(void) { if(__usbdev.openstate!=0x0004) return; - USB_CloseDeviceAsync(&__usbdev.fd,__usb_closeCB,NULL); + USB_CloseDevice(&__usbdev.fd); } void physbusif_reset_all(void) diff --git a/wiiuse/definitions.h b/wiiuse/definitions.h index 04dc5be6d..979b2fd33 100644 --- a/wiiuse/definitions.h +++ b/wiiuse/definitions.h @@ -7,14 +7,30 @@ //#define WITH_WIIUSE_DEBUG +#define WIIUSE_LOGGING 0 +#define WIIUSE_ERRORING 0 + /* Error output macros */ -#define WIIUSE_ERROR(fmt, ...) fprintf(stderr, "[ERROR] " fmt "\n", ##__VA_ARGS__) +#if WIIUSE_ERRORING == 1 + #define WIIUSE_ERROR(fmt, ...) fprintf(stderr, "[ERROR] " fmt "\n", ##__VA_ARGS__) +#else + #define WIIUSE_ERROR(fmt, ...) +#endif /* WIIUSE_ERRORING == 1 */ /* Warning output macros */ -#define WIIUSE_WARNING(fmt, ...) fprintf(stderr, "[WARNING] " fmt "\n", ##__VA_ARGS__) +#if WIIUSE_ERRORING == 1 + #define WIIUSE_WARNING(fmt, ...) fprintf(stderr, "[WARNING] " fmt "\n", ##__VA_ARGS__) +#else + #define WIIUSE_WARNING(fmt, ...) +#endif /* WIIUSE_ERRORING == 1 */ + /* Information output macros */ -#define WIIUSE_INFO(fmt, ...) fprintf(stderr, "[INFO] " fmt "\n", ##__VA_ARGS__) +#if WIIUSE_LOGGING == 1 + #define WIIUSE_INFO(fmt, ...) fprintf(stderr, "[INFO] " fmt "\n", ##__VA_ARGS__) +#else + #define WIIUSE_INFO(fmt, ...) +#endif /* WIIUSE_LOGGING == 1 */ #ifdef WITH_WIIUSE_DEBUG #ifdef WIN32 diff --git a/wiiuse/events.c b/wiiuse/events.c index 3dc05649a..fbf30369a 100644 --- a/wiiuse/events.c +++ b/wiiuse/events.c @@ -88,7 +88,7 @@ static void event_ack(struct wiimote_t *wm,ubyte *msg) return; } if(msg[3]) { - WIIUSE_WARNING("Command %02x %02x failed: status %02x", cmd->data[0], cmd->data[1], msg[3]); + WIIUSE_WARNING("Command %02x %02x%02x%02x%02x failed: status %02x", cmd->data[0], cmd->data[1], cmd->data[2], cmd->data[3], cmd->data[4], msg[3]); return; } @@ -106,9 +106,10 @@ static void event_ack(struct wiimote_t *wm,ubyte *msg) static void event_status(struct wiimote_t *wm,ubyte *msg) { - int ir = 0; + int critical = 0; int attachment = 0; int speaker = 0; + int ir = 0; //int led[4]= {0}; struct cmd_blk_t *cmd = wm->cmd_head; @@ -120,12 +121,16 @@ static void event_status(struct wiimote_t *wm,ubyte *msg) //if(msg[2]&WM_CTRL_STATUS_BYTE1_LED_3) led[2] = 1; //if(msg[2]&WM_CTRL_STATUS_BYTE1_LED_4) led[3] = 1; + if((msg[2]&WM_CTRL_STATUS_BYTE1_BATTERY_CRITICAL)==WM_CTRL_STATUS_BYTE1_BATTERY_CRITICAL) critical = 1; if((msg[2]&WM_CTRL_STATUS_BYTE1_ATTACHMENT)==WM_CTRL_STATUS_BYTE1_ATTACHMENT) attachment = 1; if((msg[2]&WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED)==WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED) speaker = 1; if((msg[2]&WM_CTRL_STATUS_BYTE1_IR_ENABLED)==WM_CTRL_STATUS_BYTE1_IR_ENABLED) ir = 1; wm->battery_level = msg[5]; + if(critical && !WIIMOTE_IS_SET(wm,WIIMOTE_STATE_BATTERY_CRITICAL)) WIIMOTE_ENABLE_STATE(wm,WIIMOTE_STATE_BATTERY_CRITICAL); + else if(!critical && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_BATTERY_CRITICAL)) WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_BATTERY_CRITICAL); + if(!ir && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_IR_INIT)) { WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR_INIT); wiiuse_set_ir(wm, 1); diff --git a/wiiuse/io.c b/wiiuse/io.c index 57bd09de0..a01074795 100644 --- a/wiiuse/io.c +++ b/wiiuse/io.c @@ -102,11 +102,18 @@ void wiiuse_handshake_expansion(struct wiimote_t *wm,ubyte *data,uword len) case 3: if(!data || !len) return; id = BIG_ENDIAN_LONG(*(int*)(&data[220])); + //printf("New exp type: %d\n", id); switch(id) { case EXP_ID_CODE_NUNCHUK: if(!nunchuk_handshake(wm,&wm->exp.nunchuk,data,len)) return; break; + case EXP_ID_CODE_GUITAR: + if(!guitar_hero_3_handshake(wm,&wm->exp.gh3,data,len)) return; + break; + case EXP_ID_CODE_WIIBOARD: + if(!wii_board_handshake(wm,&wm->exp.wb,data,len)) return; + break; case EXP_ID_CODE_CLASSIC_CONTROLLER: case EXP_ID_CODE_CLASSIC_CONTROLLER_NYKOWING: case EXP_ID_CODE_CLASSIC_CONTROLLER_NYKOWING2: @@ -117,21 +124,9 @@ void wiiuse_handshake_expansion(struct wiimote_t *wm,ubyte *data,uword len) case EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC4: case EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC5: case EXP_ID_CODE_CLASSIC_WIIU_PRO: - if(!classic_ctrl_handshake(wm,&wm->exp.classic,data,len)) return; - break; - case EXP_ID_CODE_GUITAR: - if(!guitar_hero_3_handshake(wm,&wm->exp.gh3,data,len)) return; - break; - case EXP_ID_CODE_WIIBOARD: - if(!wii_board_handshake(wm,&wm->exp.wb,data,len)) return; - break; default: if(!classic_ctrl_handshake(wm,&wm->exp.classic,data,len)) return; - /*WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_EXP_HANDSHAKE); - WIIMOTE_ENABLE_STATE(wm,WIIMOTE_STATE_EXP_FAILED); - __lwp_wkspace_free(data); - wiiuse_status(wm,NULL); - return;*/ + break; } __lwp_wkspace_free(data); diff --git a/wiiuse/io_wii.c b/wiiuse/io_wii.c index a1e50a6b3..5cea497a8 100644 --- a/wiiuse/io_wii.c +++ b/wiiuse/io_wii.c @@ -22,6 +22,8 @@ extern void parse_event(struct wiimote_t *wm); extern void idle_cycle(struct wiimote_t* wm); extern void hexdump(void *d, int len); +extern void __SYS_DisablePowerButton(u32 duration); + static __inline__ u32 ACR_ReadReg(u32 reg) { return _ipcReg[reg>>2]; @@ -39,7 +41,14 @@ static s32 __wiiuse_disconnected(void *arg,struct bte_pcb *pcb,u8 err) if(!wm) return ERR_OK; - //printf("wiimote disconnected\n"); + // Disable system power button events for a bit after Wiimote disconnection + // BT module hardware will trigger power button press in GPIO just like front panel + // if auth'd Wiimote power button pressed, so this is the only way to disambiguate + // It sends power button events for ~1s, but if we disable for 200ms, we can get + // power button event throttling to take care of the rest + __SYS_DisablePowerButton(200); + + WIIMOTE_DISABLE_STATE(wm, (WIIMOTE_STATE_BATTERY_CRITICAL)); WIIMOTE_DISABLE_STATE(wm, (WIIMOTE_STATE_IR|WIIMOTE_STATE_IR_INIT)); WIIMOTE_DISABLE_STATE(wm, (WIIMOTE_STATE_SPEAKER|WIIMOTE_STATE_SPEAKER_INIT)); WIIMOTE_DISABLE_STATE(wm, (WIIMOTE_STATE_EXP|WIIMOTE_STATE_EXP_HANDSHAKE|WIIMOTE_STATE_EXP_FAILED)); @@ -54,6 +63,9 @@ static s32 __wiiuse_disconnected(void *arg,struct bte_pcb *pcb,u8 err) if(wm->event_cb) wm->event_cb(wm,WIIUSE_DISCONNECT); wml->wm = NULL; + + bte_free(wml->sock); + wml->sock = NULL; return ERR_OK; } @@ -64,7 +76,7 @@ static s32 __wiiuse_receive(void *arg,void *buffer,u16 len) if(!wm || !buffer || len==0) return ERR_OK; - //printf("__wiiuse_receive[%02x]\n",*(char*)buffer); + WIIUSE_DEBUG("__wiiuse_receive[%02x]",*(char*)buffer); wm->event = WIIUSE_NONE; memcpy(wm->event_buf,buffer,len); @@ -83,10 +95,12 @@ static s32 __wiiuse_connected(void *arg,struct bte_pcb *pcb,u8 err) struct wiimote_listen_t *wml = (struct wiimote_listen_t*)arg; struct wiimote_t *wm; - wm = wml->assign_cb(&wml->bdaddr); - + WIIUSE_DEBUG("__wiiuse_connected(%d)", err); + wm = wml->assign_cb(wml, err); + if(!wm) { bte_disconnect(wml->sock); + wml->sock = NULL; return ERR_OK; } @@ -95,7 +109,6 @@ static s32 __wiiuse_connected(void *arg,struct bte_pcb *pcb,u8 err) wm->sock = wml->sock; wm->bdaddr = wml->bdaddr; - //printf("__wiiuse_connected()\n"); WIIMOTE_ENABLE_STATE(wm,(WIIMOTE_STATE_CONNECTED|WIIMOTE_STATE_HANDSHAKE)); wm->handshake_state = 0; @@ -104,6 +117,38 @@ static s32 __wiiuse_connected(void *arg,struct bte_pcb *pcb,u8 err) return ERR_OK; } +static s32 __wiiuse_connect_step2(void *arg,struct bte_pcb *pcb,u8 err) +{ + WIIUSE_DEBUG("__wiiuse_connect_step2(%d)", err); + if (err!=ERR_OK) { + bte_disconnect(pcb); + return ERR_OK; + } + + err = bte_connectasync_step2(pcb,__wiiuse_connected); + + if(err==ERR_OK) return ERR_OK; + + WIIUSE_ERROR("__wiiuse_connect_step2: bte_connectasync_step2 failed(%d)", err); + return err; +} + +static s32 __wiiuse_accept_step2(void *arg,struct bte_pcb *pcb,u8 err) +{ + WIIUSE_DEBUG("__wiiuse_accept_step2(%d)", err); + if (err!=ERR_OK) { + bte_disconnect(pcb); + return ERR_OK; + } + + err = bte_listenasync_step2(pcb,__wiiuse_connected); + + if(err==ERR_OK) return ERR_OK; + + WIIUSE_ERROR("__wiiuse_accept_step2: bte_listenasync_step2 failed(%d)", err); + return err; +} + void __wiiuse_sensorbar_enable(int enable) { u32 val; @@ -116,34 +161,103 @@ void __wiiuse_sensorbar_enable(int enable) IRQ_Restore(level); } -int wiiuse_register(struct wiimote_listen_t *wml, struct bd_addr *bdaddr, struct wiimote_t *(*assign_cb)(struct bd_addr *bdaddr)) +int wiiuse_accept(struct wiimote_listen_t *wml, struct bd_addr *bdaddr, u8 *name, struct wiimote_t *(*assign_cb)(wiimote_listen *wml, u8 err)) { s32 err; if(!wml || !bdaddr || !assign_cb) return 0; + WIIUSE_DEBUG("wiiuse_accept %p, bdaddr: %02x:%02x:%02x:%02x:%02x:%02x",wml,bdaddr->addr[5],bdaddr->addr[4],bdaddr->addr[3],bdaddr->addr[2],bdaddr->addr[1],bdaddr->addr[0]); + + if(wml->sock!=NULL) { + WIIUSE_ERROR("wiiuse_accept: wml->sock was not NULL!"); + return 0; + } + wml->wm = NULL; - wml->bdaddr = *bdaddr; - wml->sock = bte_new(); + bd_addr_set(&(wml->bdaddr),bdaddr); + if(name) { + strncpy((char *)wml->name, (char *)name, sizeof(wml->name)); + wml->name[sizeof(wml->name) - 1] = 0x00; + } else { + memset(wml->name, 0, sizeof(wml->name)); + } wml->assign_cb = assign_cb; - if(wml->sock==NULL) return 0; + wml->sock = bte_new(); + if (wml->sock==NULL) + { + WIIUSE_ERROR("wiiuse_accept: bte_new failed to alloc new sock"); + return 0; + } + bte_arg(wml->sock,wml); bte_received(wml->sock,__wiiuse_receive); bte_disconnected(wml->sock,__wiiuse_disconnected); - err = bte_registerdeviceasync(wml->sock,bdaddr,__wiiuse_connected); + err = bte_listenasync(wml->sock,bdaddr,__wiiuse_accept_step2); + if(err==ERR_OK) return 1; + + WIIUSE_ERROR("wiiuse_accept: bte_listenasync failed(%d)", err); + + bte_free(wml->sock); + wml->sock = NULL; + return 0; +} + +int wiiuse_connect(struct wiimote_listen_t *wml, struct bd_addr *bdaddr, u8 *name, struct wiimote_t *(*assign_cb)(wiimote_listen *wml, u8 err)) +{ + s32 err; + + if(!wml || !bdaddr|| !assign_cb) return 0; + + WIIUSE_DEBUG("wiiuse_connect %p, bdaddr: %02x:%02x:%02x:%02x:%02x:%02x",wml,bdaddr->addr[5],bdaddr->addr[4],bdaddr->addr[3],bdaddr->addr[2],bdaddr->addr[1],bdaddr->addr[0]); + + if(wml->sock!=NULL) { + WIIUSE_ERROR("wiiuse_connect: wml->sock was not NULL!"); + return 0; + } + + wml->wm = NULL; + bd_addr_set(&(wml->bdaddr),bdaddr); + if(name) { + strncpy((char *)wml->name, (char *)name, sizeof(wml->name)); + wml->name[sizeof(wml->name) - 1] = 0x00; + } else { + memset(wml->name, 0, sizeof(wml->name)); + } + wml->assign_cb = assign_cb; + + wml->sock = bte_new(); + if (wml->sock==NULL) + { + WIIUSE_ERROR("wiiuse_connect: bte_new failed to alloc new sock"); + return 0; + } + + bte_arg(wml->sock,wml); + bte_received(wml->sock,__wiiuse_receive); + bte_disconnected(wml->sock,__wiiuse_disconnected); + + err = bte_connectasync(wml->sock,bdaddr,__wiiuse_connect_step2); if(err==ERR_OK) return 1; + + WIIUSE_ERROR("wiiuse_connect: bte_connectasync failed(%d)", err); + bte_free(wml->sock); + wml->sock = NULL; return 0; } void wiiuse_disconnect(struct wiimote_t *wm) { + WIIUSE_DEBUG("wiiuse_disconnect"); + if(wm==NULL || wm->sock==NULL) return; WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_CONNECTED); bte_disconnect(wm->sock); + wm->sock = NULL; } void wiiuse_sensorbar_enable(int enable) @@ -151,7 +265,6 @@ void wiiuse_sensorbar_enable(int enable) __wiiuse_sensorbar_enable(enable); } - void wiiuse_init_cmd_queue(struct wiimote_t *wm) { u32 size; diff --git a/wiiuse/wiiboard.c b/wiiuse/wiiboard.c index 5ee0ccad6..cca1a1567 100644 --- a/wiiuse/wiiboard.c +++ b/wiiuse/wiiboard.c @@ -95,7 +95,7 @@ int wii_board_handshake(struct wiimote_t* wm, struct wii_board_t* wb, ubyte* dat /** * @brief The wii board disconnected. * - * @param cc A pointer to a classic_ctrl_t structure. + * @param cc A pointer to a wii_board_t structure. */ void wii_board_disconnected(struct wii_board_t* wb) { diff --git a/wiiuse/wiiuse_internal.h b/wiiuse/wiiuse_internal.h index 17892f970..9c0013b1b 100644 --- a/wiiuse/wiiuse_internal.h +++ b/wiiuse/wiiuse_internal.h @@ -143,7 +143,7 @@ #define WM_IR_TYPE_FULL 0x05 /* controller status flags for the first message byte */ -/* bit 1 is unknown */ +#define WM_CTRL_STATUS_BYTE1_BATTERY_CRITICAL 0x01 #define WM_CTRL_STATUS_BYTE1_ATTACHMENT 0x02 #define WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED 0x04 #define WM_CTRL_STATUS_BYTE1_IR_ENABLED 0x08 @@ -174,7 +174,7 @@ #define EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC3 0xa0a1a000 #define EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC4 0x8d8d8e00 #define EXP_ID_CODE_CLASSIC_CONTROLLER_GENERIC5 0x93949400 -#define EXP_ID_CODE_CLASSIC_WIIU_PRO 0xa4200120 +#define EXP_ID_CODE_CLASSIC_WIIU_PRO 0xa4200120 #define EXP_ID_CODE_GUITAR 0xa4200103 #define EXP_ID_CODE_WIIBOARD 0xa4200402 #define EXP_ID_CODE_MOTION_PLUS 0xa4200405 @@ -189,7 +189,7 @@ /* wiimote state flags - (some duplicated in wiiuse.h)*/ #define WIIMOTE_STATE_DEV_FOUND 0x000001 -//#define WIIMOTE_STATE_DEV_REGISTER 0x000002 +#define WIIMOTE_STATE_BATTERY_CRITICAL 0x000002 #define WIIMOTE_STATE_HANDSHAKE 0x000004 /* actual connection exists but no handshake yet */ #define WIIMOTE_STATE_HANDSHAKE_COMPLETE 0x000008 /* actual connection exists but no handshake yet */ #define WIIMOTE_STATE_CONNECTED 0x000010 diff --git a/wiiuse/wpad.c b/wiiuse/wpad.c index a0cb3169a..d09d4a67f 100644 --- a/wiiuse/wpad.c +++ b/wiiuse/wpad.c @@ -2,10 +2,11 @@ wpad.c -- Wiimote Application Programmers Interface -Copyright (C) 2008 +Copyright (C) 2008-2025 Michael Wiedenbauer (shagkur) Dave Murphy (WinterMute) Hector Martin (marcan) +Zarithya This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -50,13 +51,10 @@ distribution. #include "lwp_threads.inl" -#define MAX_STREAMDATA_LEN 20 -#define EVENTQUEUE_LENGTH 16 +#define MAX_STREAMDATA_LEN 20 +#define EVENTQUEUE_LENGTH 16 -#define DISCONNECT_BATTERY_DIED 0x14 -#define DISCONNECT_POWER_OFF 0x15 - -struct _wpad_thresh{ +struct _wpad_thresh { s32 btns; s32 ir; s32 js; @@ -89,27 +87,40 @@ struct _wpad_cb { static syswd_t __wpad_timer; static vu32 __wpads_inited = 0; -static vs32 __wpads_ponded = 0; +static vs32 __wpads_bonded = 0; static u32 __wpad_idletimeout = 300; static vu32 __wpads_active = 0; static vu32 __wpads_used = 0; static wiimote **__wpads = NULL; -static wiimote_listen __wpads_listen[CONF_PAD_MAX_REGISTERED]; -static WPADData wpaddata[WPAD_MAX_WIIMOTES]; -static struct _wpad_cb __wpdcb[WPAD_MAX_WIIMOTES]; +static wiimote_listen __wpads_listen[WPAD_MAX_DEVICES]; +static WPADData wpaddata[WPAD_MAX_DEVICES]; +static struct _wpad_cb __wpdcb[WPAD_MAX_DEVICES]; static conf_pads __wpad_devs; -static struct linkkey_info __wpad_keys[WPAD_MAX_WIIMOTES]; +static conf_pad_guests __wpad_guests; +static struct linkkey_info __wpad_keys[CONF_PAD_MAX_REGISTERED]; +static struct linkkey_info __wpad_guest_keys[CONF_PAD_ACTIVE_AND_OTHER]; + +static sem_t __wpad_confsave_sem; +static bool __wpad_confsave_thread_running = false; +static void* __wpad_confsave_thread_func(void *); +static lwp_t __wpad_confsave_thread = LWP_THREAD_NULL; static s32 __wpad_onreset(s32 final); static s32 __wpad_disconnect(struct _wpad_cb *wpdcb); static void __wpad_eventCB(struct wiimote_t *wm,s32 event); +static s32 GetGuestSlot(struct bd_addr *pad_addr); +static s32 GetRegisteredSlot(struct bd_addr *pad_addr); + static void __wpad_def_powcb(s32 chan); +static void __wpad_def_hostsynccb(u32 held); static WPADShutdownCallback __wpad_batcb = NULL; static WPADShutdownCallback __wpad_powcb = __wpad_def_powcb; +static WPADDisconnectCallback __wpad_disconncb = NULL; +static WPADHostSyncBtnCallback __wpad_hostsynccb = __wpad_def_hostsynccb; +static WPADStatusCallback __wpad_statuscb = NULL; extern void __wiiuse_sensorbar_enable(int enable); -extern void __SYS_DoPowerCB(void); static sys_resetinfo __wpad_resetinfo = { {}, @@ -119,7 +130,7 @@ static sys_resetinfo __wpad_resetinfo = { static s32 __wpad_onreset(s32 final) { - //printf("__wpad_onreset(%d)\n",final); + WIIUSE_DEBUG("__wpad_onreset(%d)",final); if(final==FALSE) { WPAD_Shutdown(); } @@ -128,7 +139,7 @@ static s32 __wpad_onreset(s32 final) static void __wpad_def_powcb(s32 chan) { - __SYS_DoPowerCB(); + SYS_DoPowerCB(); } static void __wpad_timeouthandler(syswd_t alarm,void *cbarg) @@ -140,7 +151,7 @@ static void __wpad_timeouthandler(syswd_t alarm,void *cbarg) if(!__wpads_active) return; __lwp_thread_dispatchdisable(); - for(i=0;iwm; if(wm && WIIMOTE_IS_SET(wm,WIIMOTE_STATE_CONNECTED)) { @@ -201,97 +212,217 @@ static void __wpad_setfmt(s32 chan) } } -wiimote *__wpad_assign_slot(struct bd_addr *pad_addr) +wiimote *__wpad_assign_slot(wiimote_listen *wml, u8 err) { - u32 i, level; - struct bd_addr bdaddr; - //printf("WPAD Assigning slot (active: 0x%02x)\n", __wpads_used); - _CPU_ISR_Disable(level); + u32 i, level; - // check for balance board - BD_ADDR(&(bdaddr),__wpad_devs.balance_board.bdaddr[5],__wpad_devs.balance_board.bdaddr[4],__wpad_devs.balance_board.bdaddr[3],__wpad_devs.balance_board.bdaddr[2],__wpad_devs.balance_board.bdaddr[1],__wpad_devs.balance_board.bdaddr[0]); - if(bd_addr_cmp(pad_addr,&bdaddr)) { - if(!(__wpads_used&(1<= WPAD_MAX_DEVICES) + { + WIIUSE_ERROR("WPAD Slot %d Not Valid\n", i); + _CPU_ISR_Restore(level); + return NULL; + } + + if (err) { + WIIUSE_ERROR("WPAD Connection Error %d\n", (s8)err); + __wpads_used &= ~(0x01<=WPAD_BALANCE_BOARD) { + BYTES_FROM_BD_ADDR(__wpad_devs.balance_board.bdaddr, &wml->bdaddr); + memcpy(__wpad_devs.balance_board.name, wml->name, sizeof(__wpad_devs.balance_board.name)); + } else { + BYTES_FROM_BD_ADDR(__wpad_devs.active[i].bdaddr, &wml->bdaddr); + } + LWP_SemPost(__wpad_confsave_sem); + _CPU_ISR_Restore(level); + return __wpads[i]; } -static s32 __wpad_init_finished(s32 result,void *usrdata) +static void* __wpad_confsave_thread_func(void *) { - u32 i; - struct bd_addr bdaddr; + __wpad_confsave_thread_running = true; + + while (__wpad_confsave_thread_running) + { + CONF_SetPadDevices(&__wpad_devs); + CONF_SaveChanges(); + LWP_SemWait(__wpad_confsave_sem); + } - //printf("__wpad_init_finished(%d)\n",result); + return NULL; +} - if(result==ERR_OK) { - for(i=0;/*__wpads[i] && */i<__wpad_devs.num_registered;i++) { - BD_ADDR(&(bdaddr),__wpad_devs.registered[i].bdaddr[5],__wpad_devs.registered[i].bdaddr[4],__wpad_devs.registered[i].bdaddr[3],__wpad_devs.registered[i].bdaddr[2],__wpad_devs.registered[i].bdaddr[1],__wpad_devs.registered[i].bdaddr[0]); - wiiuse_register(&__wpads_listen[i],&(bdaddr),__wpad_assign_slot); +static void __wpad_confsave_thread_stop(void) +{ + if (__wpad_confsave_sem != LWP_SEM_NULL) { + if (__wpad_confsave_thread != LWP_THREAD_NULL) { + __wpad_confsave_thread_running = false; + LWP_SemPost(__wpad_confsave_sem); + LWP_JoinThread(__wpad_confsave_thread, NULL); + __wpad_confsave_thread = LWP_THREAD_NULL; } - BD_ADDR(&(bdaddr),__wpad_devs.balance_board.bdaddr[5],__wpad_devs.balance_board.bdaddr[4],__wpad_devs.balance_board.bdaddr[3],__wpad_devs.balance_board.bdaddr[2],__wpad_devs.balance_board.bdaddr[1],__wpad_devs.balance_board.bdaddr[0]); - if(ibdaddr); + registeredEntry = GetRegisteredSlot(&wml->bdaddr); + + if(BTE_GetPairMode() == PAIR_MODE_NORMAL) { + // Permanent pair, need to save bdaddr as known controller + if(registeredEntry >= __wpad_devs.num_registered) { + // If currently guest, we want to allow for upgrade to permanent pair + if(guestEntry < CONF_PAD_MAX_ACTIVE) { + // Wipe guest entry and shift later ones up + for(i = guestEntry; i < (__wpad_guests.num_guests - 1); i++) { + memcpy(&__wpad_guests.guests[i], &__wpad_guests.guests[i+1], sizeof(conf_pad_guest_device)); + } + memset(&__wpad_guests.guests[--__wpad_guests.num_guests], 0, sizeof(conf_pad_guest_device)); + } + + WIIUSE_DEBUG("Registering Wiimote '%s' with system...", wml->name); + memmove(&__wpad_devs.registered[1], &__wpad_devs.registered[0], sizeof(conf_pad_device)*(CONF_PAD_MAX_REGISTERED-1)); + BYTES_FROM_BD_ADDR(__wpad_devs.registered[0].bdaddr, &wml->bdaddr); + memcpy(__wpad_devs.registered[0].name, wml->name, sizeof(__wpad_devs.registered[0].name)); + if (__wpad_devs.num_registered < CONF_PAD_MAX_REGISTERED) + __wpad_devs.num_registered++; + LWP_SemPost(__wpad_confsave_sem); + } + } else if(registeredEntry >= CONF_PAD_MAX_REGISTERED) { + // Not permanent pair, need to save bdaddr and link key as guest controller + if(guestEntry >= CONF_PAD_MAX_ACTIVE) { + WIIUSE_DEBUG("Saving Wiimote '%s' as guest...", wml->name); + memmove(&__wpad_guests.guests[1], &__wpad_guests.guests[0], sizeof(conf_pad_guest_device)*(CONF_PAD_MAX_ACTIVE-1)); + BYTES_FROM_BD_ADDR(__wpad_guests.guests[0].bdaddr, &wml->bdaddr); + memcpy(__wpad_guests.guests[0].name, wml->name, sizeof(__wpad_guests.guests[0].name)); + if (__wpad_guests.num_guests < CONF_PAD_MAX_ACTIVE) + __wpad_guests.num_guests++; + + for(i=0; ibdaddr,&__wpad_guest_keys[i].bdaddr)) { + u8 *src = __wpad_guest_keys[i].key; + u8 *dst = __wpad_guests.guests[0].link_key; + // Keys are stored in config backwards, like bdaddrs + for (j=0;jwm; @@ -628,30 +761,428 @@ static void __wpad_eventCB(struct wiimote_t *wm,s32 event) memset(&wpaddata[chan],0,sizeof(WPADData)); memset(wpdcb->queue_int,0,(sizeof(WPADData)*EVENTQUEUE_LENGTH)); __wpads_active &= ~(0x01<name, 13)) { + // Found Wii accessory, is it controller or something else? + if (!strncmp("Nintendo RVL-CNT-", (char *)info->name, 17)) { + // Check active list + for(i=0; ibdaddr,&bdaddr)) { + WIIUSE_DEBUG("Wiimote already active in slot %d", i); + slot = i; + break; + } + } + + // Not active, try to make active + if(slot >= CONF_PAD_MAX_ACTIVE) { + for(i=0; ibdaddr,&bdaddr)) { + WIIUSE_DEBUG("Balance Board already registered"); + slot = WPAD_BALANCE_BOARD; + } + + // Not active, try to make active + if(slot != WPAD_BALANCE_BOARD) { + if(!(__wpads_used & (1<bdaddr,info->name,__wpad_register_new); + __wpads_used |= (0x01<= WPAD_MAX_DEVICES) { + for(i=0; i= WPAD_BALANCE_BOARD) { + slot = WPAD_MAX_DEVICES; + } + } else { + if(!(__wpads_used & (1<count;i++) { + struct inquiry_info_ex *info = &inq_res->info[i]; + + if(!bd_addr_cmp(&info->bdaddr,BD_ADDR_ANY)) { + // Read name of first valid device + padinfo = (struct pad_name_info *)malloc(sizeof(struct pad_name_info)); + if (padinfo == NULL) + return ERR_MEM; + bd_addr_set(&padinfo->bdaddr, &info->bdaddr); + BTE_ReadRemoteName(padinfo, __wpad_read_remote_name_finished); + break; + } + } + } + + return ERR_OK; +} + +s32 WPAD_StartPairing(void) +{ + u32 level; + + _CPU_ISR_Disable(level); + WIIUSE_INFO("WPAD Begin Pairing"); + BTE_Inquiry(BD_MAX_INQUIRY_DEVS, TRUE, __wpad_inquiry_finished); + _CPU_ISR_Restore(level); + + return ERR_OK; +} + +s32 WPAD_WipeSavedControllers(void) +{ + u32 level; + int i; + + _CPU_ISR_Disable(level); + WIIUSE_DEBUG("WPAD Wipe Registered Pads"); + + for(i=0;i CONF_PAD_MAX_REGISTERED) { + WPAD_Shutdown(); + _CPU_ISR_Restore(level); + return WPAD_ERR_BADCONF; + } + + if(CONF_GetPadGuestDevices(&__wpad_guests) < 0) { WPAD_Shutdown(); _CPU_ISR_Restore(level); - return WPAD_ERR_NONEREGISTERED; + return WPAD_ERR_BADCONF; } - if(__wpad_devs.num_registered > CONF_PAD_MAX_REGISTERED) { + if(__wpad_guests.num_guests > CONF_PAD_MAX_ACTIVE) { WPAD_Shutdown(); _CPU_ISR_Restore(level); return WPAD_ERR_BADCONF; } - __wpads = wiiuse_init(WPAD_MAX_WIIMOTES,__wpad_eventCB); + // Clear guest devices after loading so guests are unregistered in case of unexpected shutdown + if(CONF_SetPadGuestDevices(NULL) < 0) { + WPAD_Shutdown(); + _CPU_ISR_Restore(level); + return WPAD_ERR_BADCONF; + } + + __wpads = wiiuse_init(WPAD_MAX_DEVICES,__wpad_eventCB); if(__wpads==NULL) { WPAD_Shutdown(); _CPU_ISR_Restore(level); @@ -712,8 +1259,14 @@ s32 WPAD_Init(void) __wiiuse_sensorbar_enable(1); + __wpads_inited = WPAD_STATE_ENABLING; + BTE_Init(); BTE_SetDisconnectCallback(__wpad_disconnectCB); + BTE_SetHostSyncButtonCallback(__wpad_hostsyncbuttonCB); + BTE_SetConnectionRequestCallback(__wpad_connreqCB); + BTE_SetLinkKeyRequestCallback(__wpad_linkkeyreqCB); + BTE_SetLinkKeyNotificationCallback(__wpad_linkkeynotCB); BTE_InitCore(__initcore_finished); if (SYS_CreateAlarm(&__wpad_timer) < 0) @@ -728,7 +1281,18 @@ s32 WPAD_Init(void) tb.tv_sec = 1; tb.tv_nsec = 0; SYS_SetPeriodicAlarm(__wpad_timer,&tb,&tb,__wpad_timeouthandler,NULL); - __wpads_inited = WPAD_STATE_ENABLING; + + if (LWP_SemInit(&__wpad_confsave_sem,0,1)<0) { + WPAD_Shutdown(); + _CPU_ISR_Restore(level); + return WPAD_ERR_UNKNOWN; + } + + if(LWP_CreateThread(&__wpad_confsave_thread,__wpad_confsave_thread_func,NULL,NULL,0,80)<0) { + WPAD_Shutdown(); + _CPU_ISR_Restore(level); + return WPAD_ERR_UNKNOWN; + } } _CPU_ISR_Restore(level); return WPAD_ERR_NONE; @@ -742,7 +1306,7 @@ s32 WPAD_ReadEvent(s32 chan, WPADData *data) struct _wpad_cb *wpdcb = NULL; WPADData *lstate = NULL,*wpadd = NULL; - if(chan=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + if(chan=WPAD_MAX_DEVICES) return WPAD_ERR_BAD_CHANNEL; _CPU_ISR_Disable(level); if(__wpads_inited==WPAD_STATE_DISABLED) { @@ -795,7 +1359,7 @@ s32 WPAD_DroppedEvents(s32 chan) int dropped = 0; if(chan == WPAD_CHAN_ALL) { - for(i=WPAD_CHAN_0; i=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + if(chan=WPAD_MAX_DEVICES) return WPAD_ERR_BAD_CHANNEL; _CPU_ISR_Disable(level); if(__wpads_inited==WPAD_STATE_DISABLED) { @@ -825,7 +1389,7 @@ s32 WPAD_Flush(s32 chan) int i; int count = 0; if(chan == WPAD_CHAN_ALL) { - for(i=WPAD_CHAN_0; i= WPAD_ERR_NONE) count += ret; return count; @@ -908,13 +1472,13 @@ s32 WPAD_SetDataFormat(s32 chan, s32 fmt) int i; if(chan == WPAD_CHAN_ALL) { - for(i=WPAD_CHAN_0; i=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + if(chan=WPAD_MAX_DEVICES) return WPAD_ERR_BAD_CHANNEL; _CPU_ISR_Disable(level); if(__wpads_inited==WPAD_STATE_DISABLED) { @@ -946,13 +1510,13 @@ s32 WPAD_SetMotionPlus(s32 chan, u8 enable) int i; if(chan == WPAD_CHAN_ALL) { - for(i=WPAD_CHAN_0; i=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + if(chan=WPAD_MAX_DEVICES) return WPAD_ERR_BAD_CHANNEL; _CPU_ISR_Disable(level); if(__wpads_inited==WPAD_STATE_DISABLED) { @@ -974,13 +1538,13 @@ s32 WPAD_SetVRes(s32 chan,u32 xres,u32 yres) int i; if(chan == WPAD_CHAN_ALL) { - for(i=WPAD_CHAN_0; i=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + if(chan=WPAD_MAX_DEVICES) return WPAD_ERR_BAD_CHANNEL; _CPU_ISR_Disable(level); if(__wpads_inited==WPAD_STATE_DISABLED) { @@ -1013,7 +1577,7 @@ s32 WPAD_Probe(s32 chan,u32 *type) u32 level,dev; wiimote *wm = NULL; - if(chan=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + if(chan=WPAD_MAX_DEVICES) return WPAD_ERR_BAD_CHANNEL; _CPU_ISR_Disable(level); if(__wpads_inited==WPAD_STATE_DISABLED) { @@ -1051,7 +1615,7 @@ s32 WPAD_SetEventBufs(s32 chan, WPADData *bufs, u32 cnt) u32 level; struct _wpad_cb *wpdcb = NULL; - if(chan=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + if(chan=WPAD_MAX_DEVICES) return WPAD_ERR_BAD_CHANNEL; _CPU_ISR_Disable(level); wpdcb = &__wpdcb[chan]; @@ -1064,6 +1628,7 @@ s32 WPAD_SetEventBufs(s32 chan, WPADData *bufs, u32 cnt) return WPAD_ERR_NONE; } +[[deprecated]] void WPAD_SetPowerButtonCallback(WPADShutdownCallback cb) { u32 level; @@ -1076,6 +1641,7 @@ void WPAD_SetPowerButtonCallback(WPADShutdownCallback cb) _CPU_ISR_Restore(level); } +[[deprecated]] void WPAD_SetBatteryDeadCallback(WPADShutdownCallback cb) { u32 level; @@ -1085,58 +1651,94 @@ void WPAD_SetBatteryDeadCallback(WPADShutdownCallback cb) _CPU_ISR_Restore(level); } +void WPAD_SetDisconnectCallback(WPADDisconnectCallback cb) +{ + u32 level; + + _CPU_ISR_Disable(level); + __wpad_disconncb = cb; + _CPU_ISR_Restore(level); +} + +void WPAD_SetHostSyncButtonCallback(WPADHostSyncBtnCallback cb) +{ + u32 level; + + _CPU_ISR_Disable(level); + if(cb) + __wpad_hostsynccb = cb; + else + __wpad_hostsynccb = __wpad_def_hostsynccb; + _CPU_ISR_Restore(level); +} + +void WPAD_SetStatusCallback(WPADStatusCallback cb) +{ + u32 level; + + _CPU_ISR_Disable(level); + __wpad_statuscb = cb; + _CPU_ISR_Restore(level); +} + s32 WPAD_Disconnect(s32 chan) { + s32 err = WPAD_ERR_NONE; u32 level, cnt = 0; struct _wpad_cb *wpdcb = NULL; - if(chan=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + if(chan=WPAD_MAX_DEVICES) return WPAD_ERR_BAD_CHANNEL; _CPU_ISR_Disable(level); - if(__wpads_inited==WPAD_STATE_DISABLED) { - _CPU_ISR_Restore(level); - return WPAD_ERR_NOT_READY; - } - - wpdcb = &__wpdcb[chan]; - __wpad_disconnect(wpdcb); + if(__wpads_inited==WPAD_STATE_ENABLED) { + wpdcb = &__wpdcb[chan]; + __wpad_disconnect(wpdcb); - _CPU_ISR_Restore(level); + _CPU_ISR_Restore(level); - while(__wpads_active&(0x01< 3000) break; + while(__wpads_used&(0x01< 3000) break; + } + } else { + _CPU_ISR_Restore(level); + err = WPAD_ERR_NOT_READY; } - return WPAD_ERR_NONE; + return err; } -void WPAD_Shutdown(void) +s32 WPAD_Shutdown(void) { + s32 err = WPAD_ERR_NONE; s32 i; u32 level; - u32 cnt = 0; struct _wpad_cb *wpdcb = NULL; - + + WIIUSE_DEBUG("WPAD_Shutdown"); + _CPU_ISR_Disable(level); + BTE_Close(); + + __wpad_confsave_thread_stop(); + CONF_SetPadGuestDevices(&__wpad_guests); + CONF_SaveChanges(); __wpads_inited = WPAD_STATE_DISABLED; SYS_RemoveAlarm(__wpad_timer); - for(i=0;isound_alarm); - __wpad_disconnect(wpdcb); + bte_free(__wpads_listen[i].sock); + __wpads_listen[i].sock = NULL; } __wiiuse_sensorbar_enable(0); _CPU_ISR_Restore(level); - while(__wpads_active) { - usleep(50); - if(++cnt > 3000) break; - } - BTE_Shutdown(); + + return err; } void WPAD_SetIdleTimeout(u32 seconds) @@ -1160,13 +1762,13 @@ s32 WPAD_Rumble(s32 chan, int status) u32 level; if(chan == WPAD_CHAN_ALL) { - for(i=WPAD_CHAN_0; i=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + if(chan=WPAD_MAX_DEVICES) return WPAD_ERR_BAD_CHANNEL; _CPU_ISR_Disable(level); if(__wpads_inited==WPAD_STATE_DISABLED) { @@ -1188,13 +1790,13 @@ s32 WPAD_SetIdleThresholds(s32 chan, s32 btns, s32 ir, s32 accel, s32 js, s32 wb u32 level; if(chan == WPAD_CHAN_ALL) { - for(i=WPAD_CHAN_0; i=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + if(chan=WPAD_MAX_DEVICES) return WPAD_ERR_BAD_CHANNEL; _CPU_ISR_Disable(level); if(__wpads_inited==WPAD_STATE_DISABLED) { @@ -1221,13 +1823,13 @@ s32 WPAD_ControlSpeaker(s32 chan,s32 enable) u32 level; if(chan == WPAD_CHAN_ALL) { - for(i=WPAD_CHAN_0; i=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + if(chan=WPAD_MAX_DEVICES) return WPAD_ERR_BAD_CHANNEL; _CPU_ISR_Disable(level); if(__wpads_inited==WPAD_STATE_DISABLED) { @@ -1250,7 +1852,7 @@ s32 WPAD_IsSpeakerEnabled(s32 chan) u32 level; wiimote *wm = NULL; - if(chan=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + if(chan=WPAD_MAX_DEVICES) return WPAD_ERR_BAD_CHANNEL; _CPU_ISR_Disable(level); if(__wpads_inited==WPAD_STATE_DISABLED) { @@ -1275,7 +1877,7 @@ s32 WPAD_SendStreamData(s32 chan,void *buf,u32 len) struct timespec tb; wiimote *wm = NULL; - if(chan=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL; + if(chan=WPAD_MAX_DEVICES) return WPAD_ERR_BAD_CHANNEL; _CPU_ISR_Disable(level); if(__wpads_inited==WPAD_STATE_DISABLED) { @@ -1321,60 +1923,86 @@ void WPAD_EncodeData(WPADEncStatus *info,u32 flag,const s16 *pcmSamples,s32 numS WPADData *WPAD_Data(int chan) { - if(chan<0 || chan>=WPAD_MAX_WIIMOTES) return NULL; + if(chan<0 || chan>=WPAD_MAX_DEVICES) return NULL; return &wpaddata[chan]; } u8 WPAD_BatteryLevel(int chan) { - if(chan<0 || chan>=WPAD_MAX_WIIMOTES) return 0; + if(chan<0 || chan>=WPAD_MAX_DEVICES) return 0; return wpaddata[chan].battery_level; } u32 WPAD_ButtonsUp(int chan) { - if(chan<0 || chan>=WPAD_MAX_WIIMOTES) return 0; + if(chan<0 || chan>=WPAD_MAX_DEVICES) return 0; return wpaddata[chan].btns_u; } u32 WPAD_ButtonsDown(int chan) { - if(chan<0 || chan>=WPAD_MAX_WIIMOTES) return 0; + if(chan<0 || chan>=WPAD_MAX_DEVICES) return 0; return wpaddata[chan].btns_d; } u32 WPAD_ButtonsHeld(int chan) { - if(chan<0 || chan>=WPAD_MAX_WIIMOTES) return 0; + if(chan<0 || chan>=WPAD_MAX_DEVICES) return 0; return wpaddata[chan].btns_h; } void WPAD_IR(int chan, struct ir_t *ir) { - if(chan<0 || chan>=WPAD_MAX_WIIMOTES || ir==NULL ) return; + if(chan<0 || chan>=WPAD_MAX_DEVICES || ir==NULL ) return; *ir = wpaddata[chan].ir; } void WPAD_Orientation(int chan, struct orient_t *orient) { - if(chan<0 || chan>=WPAD_MAX_WIIMOTES || orient==NULL ) return; + if(chan<0 || chan>=WPAD_MAX_DEVICES || orient==NULL ) return; *orient = wpaddata[chan].orient; } void WPAD_GForce(int chan, struct gforce_t *gforce) { - if(chan<0 || chan>=WPAD_MAX_WIIMOTES || gforce==NULL ) return; + if(chan<0 || chan>=WPAD_MAX_DEVICES || gforce==NULL ) return; *gforce = wpaddata[chan].gforce; } void WPAD_Accel(int chan, struct vec3w_t *accel) { - if(chan<0 || chan>=WPAD_MAX_WIIMOTES || accel==NULL ) return; + if(chan<0 || chan>=WPAD_MAX_DEVICES || accel==NULL ) return; *accel = wpaddata[chan].accel; } void WPAD_Expansion(int chan, struct expansion_t *exp) { - if(chan<0 || chan>=WPAD_MAX_WIIMOTES || exp==NULL ) return; + if(chan<0 || chan>=WPAD_MAX_DEVICES || exp==NULL ) return; *exp = wpaddata[chan].exp; } + +void __wpad_status_finished(struct wiimote_t *wm,ubyte *data,uword len) +{ + u32 level; + + _CPU_ISR_Disable(level); + if (wm && __wpad_statuscb) __wpad_statuscb(wm->unid); + _CPU_ISR_Restore(level); +} + +void WPAD_PadStatus(int chan) +{ + u32 level; + + _CPU_ISR_Disable(level); + if(chan<0 || chan>=WPAD_MAX_DEVICES) return; + if(__wpads[chan] && WIIMOTE_IS_SET(__wpads[chan],WIIMOTE_STATE_CONNECTED)) wiiuse_status(__wpads[chan], __wpad_status_finished); + + _CPU_ISR_Restore(level); +} + +bool WPAD_IsBatteryCritical(int chan) +{ + if(chan<0 || chan>=WPAD_MAX_DEVICES) return false; + return WIIMOTE_IS_SET(__wpads[chan],WIIMOTE_STATE_BATTERY_CRITICAL); +}