⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usb2uart.c

📁 To change pskey, convert USB bluetooth to UART
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * 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 + -