📄 usb2uart.c
字号:
/*
* written by albertr, (c) 2004
*
* Not a production quality code!
* Use with causion, it can kill your CSR module.
*
* For examples on using CSR USB driver, please see
* "BlueCore USB Kernel Device Driver Interface (bcore-an-013Pa).pdf"
* which is a part of CSR USB driver download at:
* http://www.csrsupport.com/document.php?did=454&path=72
*
*/
#include <windows.h>
#include <winioctl.h>
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
//#define PKT_DUMP
#define CSRBC01_IOCTL_INDEX 0x0000
#define IOCTL_CSRBC01_SEND_HCI_COMMAND CTL_CODE(FILE_DEVICE_UNKNOWN, \
CSRBC01_IOCTL_INDEX, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_CSRBC01_GET_HCI_EVENT CTL_CODE(FILE_DEVICE_UNKNOWN, \
CSRBC01_IOCTL_INDEX+1, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_CSRBC01_GET_VERSION CTL_CODE(FILE_DEVICE_UNKNOWN, \
CSRBC01_IOCTL_INDEX+2, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_CSRBC01_GET_DRIVER_NAME CTL_CODE(FILE_DEVICE_UNKNOWN, \
CSRBC01_IOCTL_INDEX+3, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_CSRBC01_GET_CONFIG_DESCRIPTOR CTL_CODE(FILE_DEVICE_UNKNOWN, \
CSRBC01_IOCTL_INDEX+4, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_CSRBC01_GET_DEVICE_DESCRIPTOR CTL_CODE(FILE_DEVICE_UNKNOWN, \
CSRBC01_IOCTL_INDEX+5,\
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_CSRBC01_RESET_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, \
CSRBC01_IOCTL_INDEX+6,\
METHOD_BUFFERED,\
FILE_ANY_ACCESS)
#define IOCTL_CSRBC01_RESET_PIPE CTL_CODE(FILE_DEVICE_UNKNOWN, \
CSRBC01_IOCTL_INDEX+7,\
METHOD_BUFFERED,\
FILE_ANY_ACCESS)
#define IOCTL_CSRBC01_BLOCK_HCI_EVENT CTL_CODE(FILE_DEVICE_UNKNOWN, \
CSRBC01_IOCTL_INDEX+12, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_CSRBC01_BLOCK_HCI_DATA CTL_CODE(FILE_DEVICE_UNKNOWN, \
CSRBC01_IOCTL_INDEX+13, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_CSRBC01_SEND_CONTROL_TRANSFER CTL_CODE(FILE_DEVICE_UNKNOWN, \
CSRBC01_IOCTL_INDEX+14,\
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_CSRBC01_SELECT_ALTERNATE_INTERFACE CTL_CODE(FILE_DEVICE_UNKNOWN, \
CSRBC01_IOCTL_INDEX+15, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_CSRBC01_START_SCO_DATA CTL_CODE(FILE_DEVICE_UNKNOWN, \
CSRBC01_IOCTL_INDEX+16, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_CSRBC01_SEND_SCO_DATA CTL_CODE(FILE_DEVICE_UNKNOWN, \
CSRBC01_IOCTL_INDEX+17, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_CSRBC01_RECV_SCO_DATA CTL_CODE(FILE_DEVICE_UNKNOWN, \
CSRBC01_IOCTL_INDEX+18, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define BCCMD_GETREQ 0x0000
#define BCCMD_GETRESP 0x0001
#define BCCMD_SETREQ 0x0002
/* these bits can be or'ed */
#define PSSTORE_DEFAULT 0x0000 /* on write: psi,psram; on read: psram,psi,psf,psrom */
#define PSSTORE_PSI 0x0001
#define PSSTORE_PSF 0x0002
#define PSSTORE_PSROM 0x0004
#define PSSTORE_PSRAM 0x0008
#define PSKEY_BDADDR 0x0001
#define PSKEY_HOSTIO_UART_PS_BLOCK 0x0191
#define PSKEY_HOST_INTERFACE 0x01F9
#define PSKEY_DEEP_SLEEP_STATE 0x0229
#define PSKEY_DEEP_SLEEP_WAKE_CTS 0x023C
#define PSKEY_UART_SLEEP_TIMEOUT 0x0222
#define PSKEY_HOSTIO_UART_RESET_TIMEOUT 0x01A4
#define PSKEY_HOSTIO_BREAK_POLL_PERIOD 0x01AD
#define PSKEY_WD_PERIOD 0x01F8
#define PSKEY_WD_TIMEOUT 0x01F7
#define PSKEY_MKT_TASK_ACTIVE 0x01FA
#define PSKEY_DEBUG_TASK_PERIOD 0x0218
#ifndef uint16
#define uint16 USHORT
#endif
/* 18 bytes -long device descriptor */
typedef struct {
UCHAR type;
UCHAR length;
USHORT bcdUSB;
UCHAR bDeviceClass;
UCHAR bDeviceSubClass;
UCHAR bDeviceProtocol;
UCHAR bMaxPacketSize0;
USHORT idVendor;
USHORT idProduct;
USHORT bcdDevice;
UCHAR iManufacturer;
UCHAR iProduct;
UCHAR iSerialNumber;
UCHAR bNumConfigurations;
} dev_desc;
static uint16 bccmd_seq = 0x0000; /* BCCMD sequence number */
static HANDLE handle = INVALID_HANDLE_VALUE;
void close_connection_on_error(char *fn)
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0,
NULL
);
printf("ERROR: %s, error#%d:%s", fn, GetLastError(), lpMsgBuf);
LocalFree( lpMsgBuf );
if (handle != INVALID_HANDLE_VALUE)
CloseHandle(handle);
exit(1);
}
/* should return the number of bytes written, but it never does? */
int send_hci_command(void *buffer, unsigned long length)
{
int status = 0;
unsigned long written = 0;
status = DeviceIoControl(handle,
IOCTL_CSRBC01_SEND_HCI_COMMAND,
buffer,
length,
0,
0,
&written,
NULL);
if (!status)
close_connection_on_error ("send_hci_command");
return written;
}
int get_hci_event(void *buffer)
{
int status;
unsigned long written;
status = DeviceIoControl(handle,
IOCTL_CSRBC01_GET_HCI_EVENT,
0,
0,
buffer,
16, /* length is always 16 */
&written,
NULL);
if (!status)
close_connection_on_error ("send_hci_command");
return written;
}
/* read length of pfkey from the persistent store, the key should exist */
static uint16 pfkey_len(uint16 pfkey)
{
uint16 bccmd_req, bccmd_varid, bccmd_len, pskey_len, psstore;
unsigned char buf[258];
int len = 0, chunk = 0;
bccmd_req = BCCMD_GETREQ;
psstore = PSSTORE_DEFAULT;
bccmd_seq++;
bccmd_varid = 0x3006; /* varid: PS value size */
bccmd_len = 9; /* minimum possible length, one uint16 is wasted */
pskey_len = 0x0000;
memset(&buf, 0, sizeof(buf));
/* need to construct a hand-crafted HCI cmd pkt */
buf[0] = 0x00; buf[1] = 0xFC; /* OGF = 0x3F & OCF = 0x00 */
buf[2] = bccmd_len * 2 + 1; /* pkt len - 3 */
buf[3] = 0xC2; /* payload descriptor: last frag =1;
first frag = 1; channel = 2 */
buf[4] = bccmd_req & 0xFF; buf[5] = bccmd_req >> 8;
buf[6] = bccmd_len & 0xFF; buf[7] = bccmd_len >> 8;
buf[8] = bccmd_seq & 0xFF; buf[9] = bccmd_seq >> 8;
buf[10] = bccmd_varid & 0xFF; buf[11] = bccmd_varid >> 8;
buf[12] = 0x00; buf[13] = 0x00; /* status */
buf[14] = pfkey & 0xFF; buf[15] = pfkey >> 8;
buf[16] = pskey_len & 0xFF; buf[17] = pskey_len >> 8;
buf[18] = psstore & 0xFF; buf[19] = psstore >> 8;
/* FIXME: IOCTL_CSRBC01_SEND_HCI_COMMAND doesn't return the number of bytes written? */
send_hci_command (&buf, buf[2] + 3);
#ifdef PKT_DUMP
printf("HCI cmd[%d]: ", buf[2] + 3);
for (chunk=0; chunk != buf[2] + 3; chunk++)
printf("%02x ", buf[chunk]);
printf("\n");
#endif
/* not really efficient, but who cares? */
while (!(chunk = get_hci_event (&buf)))
Sleep(10);
if (chunk == 1) /* too short to read packet length */
{
while (!(chunk = get_hci_event (&buf[1])))
Sleep(10);
chunk++;
}
for (len = chunk; len != buf[1] + 2; len = len + chunk)
{
while (!(chunk = get_hci_event (&buf[len])))
Sleep(10);
}
#ifdef PKT_DUMP
printf("Event [%d]: ", len);
for (chunk=0; chunk!=len; chunk++)
printf("%02x ", buf[chunk]);
printf("\n");
#endif
if (buf[0] != 0xFF) /* manuf-specific HCI event */
close_connection_on_error ("invalid packet received");
if (buf[1] != 9 * 2 + 1)
close_connection_on_error ("hci event has invalid length");
if (buf[2] != 0xC2) /* payload descriptor */
close_connection_on_error ("invalid payload descriptor");
if ((buf[3] + (buf[4] << 8)) != BCCMD_GETRESP)
close_connection_on_error ("!= GETRESP");
if ((buf[5] + (buf[6] << 8)) != 9)
close_connection_on_error ("invalid length");
if ((buf[7] + (buf[8] << 8)) != bccmd_seq)
close_connection_on_error ("invalid sequence number");
if ((buf[9] + (buf[10] << 8)) != bccmd_varid)
close_connection_on_error ("invalid varid");
switch (buf[11] + (buf[12] << 8))
{
case 0x0000:
/* OK status, continue */
break;
case 0x0001:
close_connection_on_error ("status NO_SUCH_VARID");
break;
case 0x0002:
close_connection_on_error ("status TOO_BIG");
break;
case 0x0003:
close_connection_on_error ("status NO_VALUE");
break;
case 0x0004:
close_connection_on_error ("status BAD_REQ");
break;
case 0x0005:
close_connection_on_error ("status NO_ACCESS");
break;
case 0x0006:
close_connection_on_error ("status READ_ONLY");
break;
case 0x0007:
close_connection_on_error ("status WRITE_ONLY");
break;
case 0x0008:
close_connection_on_error ("status ERROR");
break;
case 0x0009:
close_connection_on_error ("status PERMISSION_DENIED");
break;
default:
close_connection_on_error ("invalid status");
break;
}
if ((buf[13] + (buf[14] << 8)) != pfkey)
close_connection_on_error ("incorrect pfkey");
pskey_len = buf[15] + (buf[16] << 8);
#ifdef PKT_DUMP
printf("PSKey length: %d\n", pskey_len);
#endif
return pskey_len;
}
/* Read/write pfkey.
*
* Parameters:
*
* - write: if 0 then read performed, write otherwise.
* - pfkey: pfkey
* - data: buffer to store the data to read/write
* - data_len: size of the data in buffer to write (in bytes)
*
* Returns the number of bytes read, or 0 on write.
*/
static int pfkey(int write, uint16 pfkey, unsigned char *data, int data_len)
{
uint16 bccmd_req, bccmd_varid, bccmd_len, pskey_len, psstore;
unsigned char buf[258];
int len = 0, chunk = 0;
if (write)
{
if (data_len % 2)
pskey_len = (data_len + 1) / 2;
else
pskey_len = data_len / 2;
bccmd_req = BCCMD_SETREQ;
psstore = PSSTORE_PSRAM; /* write to RAM */
// psstore = PSSTORE_DEFAULT;
bccmd_len = pskey_len + 8;
}
else
{
pskey_len = pfkey_len(pfkey);
if (!pskey_len)
close_connection_on_error ("pfkey has zero length");
bccmd_req = BCCMD_GETREQ;
psstore = PSSTORE_DEFAULT;
bccmd_len = pskey_len + 8;
if (bccmd_len < 9)
bccmd_len = 9; /* min allowed length == 9 */
}
bccmd_seq++;
bccmd_varid = 0x7003; /* varid: Read/Write PS key */
memset(&buf, 0, sizeof(buf));
/* need to construct a hand-crafted HCI cmd pkt */
buf[0] = 0x00; buf[1] = 0xFC; /* OGF = 0x3F & OCF = 0x00 */
buf[2] = bccmd_len * 2 + 1; /* pkt len - 3 */
buf[3] = 0xC2; /* payload descriptor: last frag =1;
first frag = 1; channel = 2 */
buf[4] = bccmd_req & 0xFF; buf[5] = bccmd_req >> 8;
buf[6] = bccmd_len & 0xFF; buf[7] = bccmd_len >> 8;
buf[8] = bccmd_seq & 0xFF; buf[9] = bccmd_seq >> 8;
buf[10] = bccmd_varid & 0xFF; buf[11] = bccmd_varid >> 8;
buf[12] = 0x00; buf[13] = 0x00; /* status */
buf[14] = pfkey & 0xFF; buf[15] = pfkey >> 8;
buf[16] = pskey_len & 0xFF; buf[17] = pskey_len >> 8;
buf[18] = psstore & 0xFF; buf[19] = psstore >> 8;
if (write)
memcpy(&buf[20], data, data_len);
/* FIXME: IOCTL_CSRBC01_SEND_HCI_COMMAND doesn't return the number of bytes written? */
send_hci_command (&buf, buf[2] + 3);
#ifdef PKT_DUMP
printf("HCI cmd[%d]: ", buf[2] + 3);
for (chunk=0; chunk != buf[2] + 3; chunk++)
printf("%02x ", buf[chunk]);
printf("\n");
#endif
/* not really efficient, but who cares? */
while (!(chunk = get_hci_event (&buf)))
Sleep(10);
if (chunk == 1) /* too short to read packet length */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -