📄 hci_vendor.c
字号:
typedef struct csr_packstat_rep{ u16 n_pkts; u16 n_good; u16 n_corr; u16 rssi; u16 rssi_valid;} __attribute__ ((packed)) csr_packstat_rep;typedef struct csr_biterr_rep{ u16 index; u16 val_last; u16 val_tot;} __attribute__ ((packed)) csr_biterr_rep;static u16 csr_count = 0;static s32 csr_send_general_hq(csr_bccmd *cmd);#define PSRETBUF_SIZE 10 /* should be enough for what we want to do */static u16 ps_retbuf[PSRETBUF_SIZE];#ifdef CONFIG_BLUETOOTH_SUPPORT_BCSPvoidhci_receive_bcsp(u8 *data, u32 count){ csr_bccmd *cmd; csr_bccmd_ps *ps; D_REC(__FUNCTION__ "\n"); hci_ctrl.hc_buf.cmd_num = 1; release_cmd_timer(); cmd = (struct csr_bccmd *)data; ps = (struct csr_bccmd_ps *)cmd->payload; if (cmd->status == CSR_STATUS_OK) { if (cmd->type == CSR_MSGTYPE_GETRESP) { switch (cmd->var_id) { case CSR_CMD_CONFIG_UART: break; case CSR_CMD_BUILD_ID: /* Store this for later retrieval */ sprintf(bt_hw_firmware_info, "\n Firmware version: %d", cmd->payload[0]); break; case CSR_CMD_CHIP_VER: break; case CSR_CMD_CHIP_REV: break; case CSR_CMD_PS: D_CMD(__FUNCTION__": ps key[0x%x]\n", ps->ps_key); PRINTPKT("", (u8*)ps->ps_val, ps->ps_len*sizeof(u16)); /* Now copy this data to return buf */ memcpy(ps_retbuf, ps->ps_val, ps->ps_len*sizeof(u16)); break; default: break; } } else { DSYS(__FUNCTION__": Not a GETRESP msg\n"); print_data(__FUNCTION__, data, count); } } else { D_ERR(__FUNCTION__": BCSP status error 0x%x\n", cmd->status); print_data(__FUNCTION__, data, count); } wake_up_interruptible(&hci_wq); }voidhci_receive_hq(u8 *data, u32 count){ csr_bccmd *cmd; csr_bccmd_ps *ps; D_REC(__FUNCTION__"\n"); /* FIXME -- is there only one cmd buffer available ? */ hci_ctrl.hc_buf.cmd_num = 1; release_cmd_timer(); cmd = (struct csr_bccmd *)data; ps = (struct csr_bccmd_ps *)cmd->payload; if (cmd->status == CSR_STATUS_OK) { if (cmd->type == CSR_MSGTYPE_GETRESP) { switch (cmd->var_id) { case CSR_VARID_RSSI_REPORT: { csr_rssi_rep *rep; rep = (csr_rssi_rep *)cmd->payload; DSYS("RSSI report, rssi : %d\n", rep->rssi); break; } case CSR_VARID_PACKET_STAT_REPORT: { csr_packstat_rep *rep; rep = (struct csr_packstat_rep*)cmd->payload; DSYS("Packet status report : n_pkts %d, n_good %d, n_corr %d, rssi %d, rssi_valid %d\n", rep->n_pkts, rep->n_good, rep->n_corr, rep->rssi, rep->rssi_valid); break; } case CSR_VARID_BITERR_REPORT: { csr_biterr_rep *rep; rep = (struct csr_biterr_rep*)cmd->payload; DSYS("Biterror report : index %d, val_last %d, val_tot %d\n", rep->index, rep->val_last, rep->val_tot); break; } default: D_ERR("Unknown varid [0x%x]!\n", cmd->var_id); break; } } else if (cmd->type == CSR_MSGTYPE_SETREQ) { DSYS(__FUNCTION__": Received a SETREQ, sending back GETRESP\n"); print_data(__FUNCTION__, data, count); cmd->type = CSR_MSGTYPE_GETRESP; csr_send_general_hq(cmd); } else if (cmd->type == CSR_MSGTYPE_GETREQ) { DSYS(__FUNCTION__": Received a GETREQ\n"); print_data(__FUNCTION__, data, count); } else { DSYS(__FUNCTION__": Unknown message type\n"); print_data(__FUNCTION__, data, count); } } else { D_ERR(__FUNCTION__": HQ status error 0x%x\n", cmd->status); print_data(__FUNCTION__, data, count); } wake_up_interruptible(&hci_wq); }static struct dfu_response{ struct dfu_response *next; u32 length; u8 data[0];} *dfu_responses = NULL;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)static struct wait_queue *dfu_wq = NULL;#elsestatic wait_queue_head_t dfu_wq;#endif /* LINUX_VERSION_CODE */voidhci_dfu_module_init(void){#ifdef __KERNEL__#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) init_waitqueue_head(&dfu_wq);#endif /* LINUX_VERSION_CODE */#endif /* __KERNEL__ */}voidhci_shutdown_dfu(void){ struct dfu_response *response; while (dfu_responses) { cli(); response = dfu_responses; dfu_responses = response->next; sti(); kfree(response); } wake_up_interruptible(&dfu_wq);}voidhci_receive_dfu(u8 *data, u32 count){ struct dfu_response *response; if ((response = kmalloc(sizeof(*response) + count, GFP_ATOMIC))) { response->length = count; memcpy(response->data, data, count); cli(); response->next = dfu_responses; dfu_responses = response; sti(); wake_up_interruptible(&dfu_wq); }}s32hci_read_dfu(u8* data, u32 count){ struct dfu_response *response; u32 length; if (!dfu_responses) interruptible_sleep_on(&dfu_wq); cli(); response = dfu_responses; dfu_responses = response->next; sti(); if (!response) return -EINTR; length = response->length; if (count < length) { cli(); response->next = dfu_responses; dfu_responses = response; sti(); printk(__FUNCTION__ ": DFU response was too big!\n"); return -E2BIG; } copy_to_user(data, response->data, length); kfree(response); return (s32)length;}s32csr_send_general_hq(csr_bccmd *cmd){ csr_msg *msg; /* HCI Manufacturer specific header */ c_pkt.type = CMD_PKT; c_pkt.opcode = hci_put_opcode(0x00, MANUFACTURER_SPEC); c_pkt.len = 1 + cmd->len * 2; msg = (csr_msg *)c_pkt.data; /* General msg header */ CSR_SET_LAST(msg, 1); /* first and last segment */ CSR_SET_FIRST(msg, 1); CSR_SET_CH_ID(msg, CSR_CH_ID_HQ); memcpy(msg->msg, cmd, cmd->len * 2); print_data(__FUNCTION__, (u8*)&c_pkt, c_pkt.len + CMD_HDR_LEN + HCI_HDR_LEN); return bt_write_lower_driver((u8*) &c_pkt, c_pkt.len + CMD_HDR_LEN + HCI_HDR_LEN);}/* When using BCSP this function is used to wait for the COMMAND_STATUS which contains cmd_num */void csr_waitcmdnum(void){ D_CMD(__FUNCTION__"\n"); hci_ctrl.hc_buf.cmd_num = 0; /* wait for command status */ while (hci_ctrl.hc_buf.cmd_num == 0) { current->state = TASK_INTERRUPTIBLE;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) schedule_timeout(HZ/100);#else current->timeout = HZ/100; schedule(); current->timeout = 0;#endif }}#endif /* CONFIG_BLUETOOTH_SUPPORT_BCSP */s32 csr_pskey(u16 ps_key, u16 rw_mode, u16 *retb, u16 n_pars){ s32 tmp; csr_msg *msg; csr_bccmd *cmd; csr_bccmd_ps *ps; D_CMD(__FUNCTION__" : ps_key 0x%x [%d]\n", ps_key, rw_mode); PRINTPKT("pars : ", (u8*)retb, n_pars*sizeof(u16)); /* HCI Manufacturer specific header */ c_pkt.type = CMD_PKT; c_pkt.opcode = hci_put_opcode(0x00, MANUFACTURER_SPEC); c_pkt.len = 1 + 5*sizeof(u16) + 3*sizeof(u16) + n_pars*sizeof(u16); msg = (csr_msg *)c_pkt.data; cmd = (csr_bccmd *)msg->msg; ps = (csr_bccmd_ps *)cmd->payload; /* General msg header */ CSR_SET_LAST(msg, 1); /* first and last segment */ CSR_SET_FIRST(msg, 1); CSR_SET_CH_ID(msg, CSR_CH_ID_BCCMD); /* BCCMD type */ cmd->type = rw_mode; cmd->len = 5 + 3 + n_pars; cmd->seq = csr_count++; cmd->var_id = CSR_CMD_PS; cmd->status = CSR_STATUS_OK; /* always OK in SETREQ */ /* Actual PS key request */ ps->ps_key = ps_key; ps->ps_len = n_pars; /* x 16 bits */ ps->unused = 0x0000; if (rw_mode == CSR_MSGTYPE_GETREQ) memset(ps->ps_val, 0, n_pars*sizeof(u16)); /* zero params in GETREQ */ else memcpy(ps->ps_val, retb, n_pars*sizeof(16)); /* copy params in SETREQ */ /* Clear return buf */ memset(ps_retbuf, 0, PSRETBUF_SIZE*2); tmp = send_cmd_block((u8*) &c_pkt, c_pkt.len + CMD_HDR_LEN + HCI_HDR_LEN, DEFAULT_TIMEOUT); if (rw_mode == CSR_MSGTYPE_GETREQ) memcpy(retb, ps_retbuf, n_pars*sizeof(u16)); /* Signal status back in SETREQ ? */ return tmp;}s32 hci_set_bd_addr(u8 bd[6]){ csr_msg *msg; csr_bccmd *cmd; csr_bccmd_ps *ps; D_CMD(__FUNCTION__"\n"); /* HCI Manufacturer specific header */ c_pkt.type = CMD_PKT; c_pkt.opcode = hci_put_opcode(0x00, MANUFACTURER_SPEC); c_pkt.len = 1 + 5*sizeof(u16) + 3*sizeof(u16) + 4*sizeof(u16); msg = (csr_msg *)c_pkt.data; cmd = (csr_bccmd *)msg->msg; ps = (csr_bccmd_ps *)cmd->payload; /* General msg header */ CSR_SET_LAST(msg, 1); /* first and last segment */ CSR_SET_FIRST(msg, 1); CSR_SET_CH_ID(msg, CSR_CH_ID_BCCMD); /* BCCMD type */ cmd->type = CSR_MSGTYPE_SETREQ; cmd->len = 5 + 3 + 4; cmd->seq = csr_count++; cmd->var_id = CSR_CMD_PS; cmd->status = CSR_STATUS_OK; /* always OK in SETREQ */ /* Actual PS key request */ ps->ps_key = CSR_PS_BDADDR; ps->ps_len = 4; /* x 16 bits */ ps->unused = 0x0000; ps->ps_val[0] = ((u16)bd[3]) & 0x00ff; ps->ps_val[1] = ((((u16)bd[4]) << 8) | ((u16)bd[5])); ps->ps_val[2] = (u16)bd[2]; ps->ps_val[3] = (((u16)bd[0] << 8) | ((u16)bd[1])); return send_cmd_block((u8*) &c_pkt, c_pkt.len + CMD_HDR_LEN + HCI_HDR_LEN, DEFAULT_TIMEOUT);}s32hci_read_firmware_rev_info(void){ s32 tmp; csr_msg *msg; csr_bccmd *cmd; D_CMD(__FUNCTION__ VENDOR " BuildID/ChipVer/ChipRev\n"); /* HCI Manufacturer specific header */ c_pkt.type = CMD_PKT; c_pkt.opcode = hci_put_opcode(0x00, MANUFACTURER_SPEC); c_pkt.len = 1 + 5*sizeof(u16) + 6*sizeof(u16); msg = (csr_msg *)c_pkt.data; cmd = (csr_bccmd *)msg->msg; /* General msg header */ CSR_SET_LAST(msg, 1); /* first and last segment */ CSR_SET_FIRST(msg, 1); CSR_SET_CH_ID(msg, CSR_CH_ID_BCCMD); /* BCCMD type */ cmd->type = CSR_MSGTYPE_GETREQ; cmd->len = 5 + 6; cmd->seq = csr_count++; cmd->var_id = CSR_CMD_BUILD_ID; cmd->status = CSR_STATUS_OK; /* always OK in GETREQ */ memset(cmd->payload, 0, 6*sizeof(u16)); tmp = send_cmd_block((u8*) &c_pkt, c_pkt.len + CMD_HDR_LEN + HCI_HDR_LEN, DEFAULT_TIMEOUT); if (tmp < 0) return tmp; cmd->seq = csr_count++; cmd->var_id = CSR_CMD_CHIP_VER; memset(cmd->payload, 0, 6*sizeof(u16)); tmp = send_cmd_block((u8*) &c_pkt, c_pkt.len + CMD_HDR_LEN + HCI_HDR_LEN, DEFAULT_TIMEOUT); if (tmp < 0) return tmp; cmd->seq = csr_count++; cmd->var_id = CSR_CMD_CHIP_REV; memset(cmd->payload, 0, 6*sizeof(u16)); tmp = send_cmd_block((u8*) &c_pkt, c_pkt.len + CMD_HDR_LEN + HCI_HDR_LEN, DEFAULT_TIMEOUT); return tmp;}s32hci_set_baudrate(u32 baudrate){ s32 tmp; csr_msg *msg; csr_bccmd *cmd; csr_bccmd_ps *ps; u16 baud_divider; D_CMD(__FUNCTION__ VENDOR " (%u baud)\n", baudrate); switch (baudrate) { case 9600: baud_divider = CSR_UART_RATE_9K6; break; case 19200: baud_divider = CSR_UART_RATE_19K2; break; case 38400: baud_divider = CSR_UART_RATE_38K4; break; case 57600: baud_divider = CSR_UART_RATE_57K6; break; case 115200: baud_divider = CSR_UART_RATE_115K2; break; case 230400: baud_divider = CSR_UART_RATE_230K4;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -