WIP i2c-tiny-usb stuff
This commit is contained in:
parent
4de8c00613
commit
c6fdc53fdd
|
@ -46,8 +46,6 @@ if(FAMILY STREQUAL "rp2040")
|
||||||
pico_enable_stdio_usb(${PROJECT} 0)
|
pico_enable_stdio_usb(${PROJECT} 0)
|
||||||
|
|
||||||
target_sources(${PROJECT} PUBLIC
|
target_sources(${PROJECT} PUBLIC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/main.c
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/usb_descriptors.c
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/libco/libco.S
|
${CMAKE_CURRENT_SOURCE_DIR}/libco/libco.S
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/DAP.c
|
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/DAP.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/JTAG_DP.c
|
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/JTAG_DP.c
|
||||||
|
@ -56,11 +54,14 @@ if(FAMILY STREQUAL "rp2040")
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/SW_DP.c
|
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/SW_DP.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/cdc_uart.c
|
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/cdc_uart.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/spi_serprog.c
|
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/spi_serprog.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/cdc_serprog.c
|
${CMAKE_CURRENT_SOURCE_DIR}/src/cdc_serprog.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/rtconf.c
|
${CMAKE_CURRENT_SOURCE_DIR}/src/i2ctinyusb.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/rtconf.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
|
||||||
)
|
)
|
||||||
target_include_directories(${PROJECT} PUBLIC
|
target_include_directories(${PROJECT} PUBLIC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/
|
${CMAKE_CURRENT_SOURCE_DIR}/src/
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/libco/
|
${CMAKE_CURRENT_SOURCE_DIR}/libco/
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Include/
|
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Include/
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/Core/Include/
|
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/Core/Include/
|
||||||
|
|
13
README.md
13
README.md
|
@ -157,6 +157,7 @@ libco is licensed under the [ISC license](https://opensource.org/licenses/ISC)
|
||||||
separate mode that temporarily disables all other IO protocols
|
separate mode that temporarily disables all other IO protocols
|
||||||
- [x] UART with CTS/RTS flow control
|
- [x] UART with CTS/RTS flow control
|
||||||
- [x] Needs configurable stuff as well, as some UART interfaces won't use this.
|
- [x] Needs configurable stuff as well, as some UART interfaces won't use this.
|
||||||
|
- [ ] Second UART port for when stdio UART is disabled?
|
||||||
- [x] Debug interface to send printf stuff directly to USB, instead of having
|
- [x] Debug interface to send printf stuff directly to USB, instead of having
|
||||||
- to use the UART interface as a loopback thing.
|
- to use the UART interface as a loopback thing.
|
||||||
- [ ] I2C support by emulating the I2C Tiny USB
|
- [ ] I2C support by emulating the I2C Tiny USB
|
||||||
|
@ -175,16 +176,16 @@ libco is licensed under the [ISC license](https://opensource.org/licenses/ISC)
|
||||||
- https://github.com/derekmulcahy/xvcpi
|
- https://github.com/derekmulcahy/xvcpi
|
||||||
- OpenOCD as XVC client??
|
- OpenOCD as XVC client??
|
||||||
- [ ] Maybe use the ADCs for something?
|
- [ ] Maybe use the ADCs for something?
|
||||||
|
- [ ] SD/MMC/SDIO (will be a pain)
|
||||||
|
- [ ] SUMP logic analyzer?????
|
||||||
|
- see also [this](https://github.com/perexg/picoprobe-sump)
|
||||||
- [ ] AVR programming (USBavr emulation?)
|
- [ ] AVR programming (USBavr emulation?)
|
||||||
- AVR ISP is hardly used anymore
|
- AVR ISP is hardly used anymore
|
||||||
- TPI/UPDI requires 5V levels, Pico doesn't do that :/
|
- TPI/UPDI requires 5V levels, Pico doesn't do that :/
|
||||||
- debugWIRE????
|
- debugWIRE????
|
||||||
- Renesas E7-{0,1,2} programming thing????
|
- Renesas E7-{0,1,2} programming thing????
|
||||||
- Renesas tell us how this works pls
|
- Renesas tell us how this works pls
|
||||||
- Maybe steal other features from the Bus Pirate or Glasgow or so
|
- Maybe steal other features from the Bus Pirate, [HydraBus](https://github.com/hydrabus/hydrafw) or Glasgow or so
|
||||||
- 1-wire? Never seen this one in the wild
|
- 1-wire and 3-wire? Never seen this one in the wild
|
||||||
- MIDI? Feels mostly gimmicky...
|
- CAN? LIN? If I'd first be able to find a CAN device to test it with, sure
|
||||||
- PS/2? Hmmmm idk
|
|
||||||
- HD44780 LCD? See MIDI
|
|
||||||
- CAN? If I'd first be able to find a CAN device to test it with, sure
|
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,12 @@
|
||||||
#define DBOARD_HAS_UART
|
#define DBOARD_HAS_UART
|
||||||
#define DBOARD_HAS_CMSISDAP
|
#define DBOARD_HAS_CMSISDAP
|
||||||
#define DBOARD_HAS_SERPROG
|
#define DBOARD_HAS_SERPROG
|
||||||
/*#define DBOARD_HAS_TINYI2C*/
|
#define DBOARD_HAS_I2C
|
||||||
|
|
||||||
#define HID_N_CMSISDAP 0
|
#define HID_N_CMSISDAP 0
|
||||||
#define CDC_N_UART 0
|
#define CDC_N_UART 0
|
||||||
#define CDC_N_SERPROG 1
|
#define CDC_N_SERPROG 1
|
||||||
|
#define VND_N_I2CTINYUSB 0
|
||||||
|
|
||||||
#ifdef USE_USBCDC_FOR_STDIO
|
#ifdef USE_USBCDC_FOR_STDIO
|
||||||
#define CDC_N_STDIO 2
|
#define CDC_N_STDIO 2
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
obj-m := i2c-tiny-usb.o
|
||||||
|
KDIR := /lib/modules/$(shell uname -r)/build
|
||||||
|
PWD := $(shell pwd)
|
||||||
|
|
||||||
|
default:
|
||||||
|
$(MAKE) -C $(KDIR) M=$(PWD) modules
|
||||||
|
|
|
@ -0,0 +1,156 @@
|
||||||
|
all multibyte words are little-endian
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
USB interface is a vendor interface, with an in and an out endpoint
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
module:
|
||||||
|
cmd value index len
|
||||||
|
kernel:
|
||||||
|
request reqtype(fix) value index dmalen
|
||||||
|
i2c_msg:
|
||||||
|
cmd? type? flags index len
|
||||||
|
CMD_SET_DELAY:
|
||||||
|
delayv 0 0
|
||||||
|
CMD_GET_STATUS: data=[status retval]
|
||||||
|
0 0 1
|
||||||
|
|
||||||
|
i2c_msg:
|
||||||
|
type: byte
|
||||||
|
cmd: byte
|
||||||
|
flags: ushort
|
||||||
|
addr: ushort
|
||||||
|
len: ushort
|
||||||
|
data: byte[len]
|
||||||
|
|
||||||
|
commands:
|
||||||
|
CMD_ECHO = 0
|
||||||
|
CMD_GET_FUNC = 1
|
||||||
|
CMD_SET_DELAY = 2
|
||||||
|
CMD_GET_STATUS = 3
|
||||||
|
|
||||||
|
CMD_I2C_IO = 4
|
||||||
|
CMD_I2C_IO_W_BEGIN = 5 = CMD_I2C_IO | CMD_I2C_IO_BEGIN
|
||||||
|
CMD_I2C_IO_W_END = 6 = CMD_I2C_IO | CMD_I2C_IO_END
|
||||||
|
CMD_I2C_IO_W_BEGINEND = 7 = CMD_I2C_IO | CMD_I2C_IO_BEGIN | CMD_I2C_IO_END
|
||||||
|
|
||||||
|
CMD_I2C_IO_BEGIN = 1<<0 // the beginning of the I2C transaction: do a start cond
|
||||||
|
CMD_I2C_IO_END = 1<<1 // the end of the I2C transaction: do an end cond
|
||||||
|
// if none of the above two: repeated start condition anyway?
|
||||||
|
|
||||||
|
statuses:
|
||||||
|
STATUS_IDLE = 0
|
||||||
|
STATUS_ADDRESS_ACK = 1
|
||||||
|
STATUS_DDRESS_NAK = 2
|
||||||
|
|
||||||
|
flags: (literally just from the kernel)
|
||||||
|
I2C_M_RD 0x0001 /* guaranteed to be 0x0001! */
|
||||||
|
I2C_M_TEN 0x0010 /* use only if I2C_FUNC_10BIT_ADDR */
|
||||||
|
I2C_M_DMA_SAFE 0x0200 /* use only in kernel space */
|
||||||
|
I2C_M_RECV_LEN 0x0400 /* use only if I2C_FUNC_SMBUS_READ_BLOCK_DATA */
|
||||||
|
I2C_M_NO_RD_ACK 0x0800 /* use only if I2C_FUNC_PROTOCOL_MANGLING */
|
||||||
|
I2C_M_IGNORE_NAK 0x1000 /* use only if I2C_FUNC_PROTOCOL_MANGLING */
|
||||||
|
I2C_M_REV_DIR_ADDR 0x2000 /* use only if I2C_FUNC_PROTOCOL_MANGLING */
|
||||||
|
I2C_M_NOSTART 0x4000 /* use only if I2C_FUNC_NOSTART */
|
||||||
|
I2C_M_STOP 0x8000 /* use only if I2C_FUNC_PROTOCOL_MANGLING */
|
||||||
|
|
||||||
|
funcs:
|
||||||
|
* I2C_FUNC_I2C 0x00000001
|
||||||
|
I2C_FUNC_10BIT_ADDR 0x00000002 /* required for I2C_M_TEN */
|
||||||
|
I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* required for I2C_M_IGNORE_NAK etc. */
|
||||||
|
I2C_FUNC_SMBUS_PEC 0x00000008
|
||||||
|
I2C_FUNC_NOSTART 0x00000010 /* required for I2C_M_NOSTART */
|
||||||
|
I2C_FUNC_SLAVE 0x00000020
|
||||||
|
I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 or later */
|
||||||
|
* I2C_FUNC_SMBUS_QUICK 0x00010000
|
||||||
|
* I2C_FUNC_SMBUS_READ_BYTE 0x00020000
|
||||||
|
* I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000
|
||||||
|
* I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000
|
||||||
|
* I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000
|
||||||
|
* I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000
|
||||||
|
* I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000
|
||||||
|
* I2C_FUNC_SMBUS_PROC_CALL 0x00800000
|
||||||
|
I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000 /* required for I2C_M_RECV_LEN */
|
||||||
|
* I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
|
||||||
|
* I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */
|
||||||
|
* I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */
|
||||||
|
I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 0x10000000 /* I2C-like block xfer */
|
||||||
|
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 0x20000000 /* w/ 2-byte reg. addr. */
|
||||||
|
* I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC 0x40000000 /* SMBus 2.0 or later */
|
||||||
|
* I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC 0x80000000 /* SMBus 2.0 or later */
|
||||||
|
|
||||||
|
* I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE)
|
||||||
|
* I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)
|
||||||
|
* I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA)
|
||||||
|
I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)
|
||||||
|
* I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)
|
||||||
|
|
||||||
|
* I2C_FUNC_SMBUS_EMUL (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | \
|
||||||
|
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | \
|
||||||
|
I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \
|
||||||
|
I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_PEC)
|
||||||
|
|
||||||
|
/* if I2C_M_RECV_LEN is also supported */
|
||||||
|
I2C_FUNC_SMBUS_EMUL_ALL (I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_READ_BLOCK_DATA | \
|
||||||
|
I2C_FUNC_SMBUS_BLOCK_PROC_CALL)
|
||||||
|
|
||||||
|
USB vendor setup:
|
||||||
|
state machine: 3 8-bit registers: status, cmd, len
|
||||||
|
status is STATUS_ADDRESS_IDLE at reset
|
||||||
|
cmd, len are reset to 0
|
||||||
|
|
||||||
|
ECHO command:
|
||||||
|
send back flags bytes
|
||||||
|
|
||||||
|
GET_FUNC command:
|
||||||
|
send back supported functions: 4-byte little-endian of the above flags
|
||||||
|
|
||||||
|
SET_DELAY command:
|
||||||
|
sets clock period, in flags, unit is half a microsecond
|
||||||
|
|
||||||
|
GET_STATUS command:
|
||||||
|
return the status register (1 byte)
|
||||||
|
|
||||||
|
|
||||||
|
I2C_IO command: I2C xfers:
|
||||||
|
actual CMD_I2C_IO stuff:
|
||||||
|
do start cond
|
||||||
|
send (device addr << 1) | (I2C_M_RD?1:0) (aka set device address and read/write mode)
|
||||||
|
if ack bit received from previous step
|
||||||
|
status = STATUS_ADDRESS_ACK
|
||||||
|
save cmd and len in state regs
|
||||||
|
if CMD_I2C_IO_END set in cmd AND len is 0:
|
||||||
|
do end cond
|
||||||
|
else
|
||||||
|
status = STATUS_ADDRESS_NAK
|
||||||
|
do end cond
|
||||||
|
|
||||||
|
USB vendor read:
|
||||||
|
if status == STATUS_ADDRESS_ACK:
|
||||||
|
if number of bytes in this block larger than bytes expected:
|
||||||
|
clamp this length, only use the number of expected bytes in the block
|
||||||
|
|
||||||
|
read bytes, decrease len reg by number of bytes read
|
||||||
|
(if last byte read, set NAK in I2C xfer, else ACK)
|
||||||
|
if CMD_I2C_IO_END set in cmd reg AND len reg is 0:
|
||||||
|
do end cond
|
||||||
|
return bytes read over USB
|
||||||
|
else:
|
||||||
|
do nothing, return zeros
|
||||||
|
|
||||||
|
USB vendor write:
|
||||||
|
if status == STATUS_ADDRESS_ACK:
|
||||||
|
if number of bytes in this block larger than bytes expected:
|
||||||
|
clamp this length, only use the number of expected bytes in the block
|
||||||
|
|
||||||
|
write bytes, decrease len reg by number of bytes written
|
||||||
|
(if no ack bit returned, maybe set an error state??)
|
||||||
|
if CMD_I2C_IO_END set in cmd reg AND len reg is 0:
|
||||||
|
do end cond
|
||||||
|
|
||||||
|
echo back bytes written
|
||||||
|
else:
|
||||||
|
do nothing, return zeros
|
||||||
|
|
|
@ -0,0 +1,388 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* driver for the i2c-tiny-usb adapter - 1.0
|
||||||
|
* http://www.harbaum.org/till/i2c_tiny_usb
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006-2007 Till Harbaum (Till@Harbaum.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
/* include interfaces to usb layer */
|
||||||
|
#include <linux/usb.h>
|
||||||
|
|
||||||
|
/* include interface to i2c layer */
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
|
||||||
|
/* commands via USB, must match command ids in the firmware */
|
||||||
|
#define CMD_ECHO 0
|
||||||
|
#define CMD_GET_FUNC 1
|
||||||
|
#define CMD_SET_DELAY 2
|
||||||
|
#define CMD_GET_STATUS 3
|
||||||
|
|
||||||
|
#define CMD_I2C_IO 4
|
||||||
|
#define CMD_I2C_IO_BEGIN (1<<0)
|
||||||
|
#define CMD_I2C_IO_END (1<<1)
|
||||||
|
|
||||||
|
/* i2c bit delay, default is 10us -> 100kHz max
|
||||||
|
(in practice, due to additional delays in the i2c bitbanging
|
||||||
|
code this results in a i2c clock of about 50kHz) */
|
||||||
|
static unsigned short delay = 10;
|
||||||
|
module_param(delay, ushort, 0);
|
||||||
|
MODULE_PARM_DESC(delay, "bit delay in microseconds "
|
||||||
|
"(default is 10us for 100kHz max)");
|
||||||
|
|
||||||
|
static int usb_read(struct i2c_adapter *adapter, int cmd,
|
||||||
|
int value, int index, void *data, int len);
|
||||||
|
|
||||||
|
static int usb_write(struct i2c_adapter *adapter, int cmd,
|
||||||
|
int value, int index, void *data, int len);
|
||||||
|
|
||||||
|
/* ----- begin of i2c layer ---------------------------------------------- */
|
||||||
|
|
||||||
|
#define STATUS_IDLE 0
|
||||||
|
#define STATUS_ADDRESS_ACK 1
|
||||||
|
#define STATUS_ADDRESS_NAK 2
|
||||||
|
|
||||||
|
static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
|
||||||
|
{
|
||||||
|
unsigned char *pstatus;
|
||||||
|
struct i2c_msg *pmsg;
|
||||||
|
int i, ret, r;
|
||||||
|
|
||||||
|
dev_dbg(&adapter->dev, "master xfer %d messages:\n", num);
|
||||||
|
|
||||||
|
pstatus = kmalloc(sizeof(*pstatus), GFP_KERNEL);
|
||||||
|
if (!pstatus)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
for (i = 0 ; i < num ; i++) {
|
||||||
|
int cmd = CMD_I2C_IO;
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
cmd |= CMD_I2C_IO_BEGIN;
|
||||||
|
|
||||||
|
if (i == num-1)
|
||||||
|
cmd |= CMD_I2C_IO_END;
|
||||||
|
|
||||||
|
pmsg = &msgs[i];
|
||||||
|
|
||||||
|
dev_dbg(&adapter->dev,
|
||||||
|
" %d: %s (flags %d) %d bytes to 0x%02x\n",
|
||||||
|
i, pmsg->flags & I2C_M_RD ? "read" : "write",
|
||||||
|
pmsg->flags, pmsg->len, pmsg->addr);
|
||||||
|
|
||||||
|
/* and directly send the message */
|
||||||
|
if (pmsg->flags & I2C_M_RD) {
|
||||||
|
/* read data */
|
||||||
|
if ((r = usb_read(adapter, cmd,
|
||||||
|
pmsg->flags, pmsg->addr,
|
||||||
|
pmsg->buf, pmsg->len)) != pmsg->len) {
|
||||||
|
dev_err(&adapter->dev,
|
||||||
|
"failure reading data: %i\n", r);
|
||||||
|
ret = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* write data */
|
||||||
|
if ((r = usb_write(adapter, cmd,
|
||||||
|
pmsg->flags, pmsg->addr,
|
||||||
|
pmsg->buf, pmsg->len)) != pmsg->len) {
|
||||||
|
dev_err(&adapter->dev,
|
||||||
|
"failure writing data: %i\n", r);
|
||||||
|
ret = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read status */
|
||||||
|
if ((r = usb_read(adapter, CMD_GET_STATUS, 0, 0, pstatus, 1)) != 1) {
|
||||||
|
dev_err(&adapter->dev, "failure reading status: %i\n", r);
|
||||||
|
ret = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_dbg(&adapter->dev, " status = %d\n", *pstatus);
|
||||||
|
if (*pstatus == STATUS_ADDRESS_NAK) {
|
||||||
|
ret = -ENXIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = i;
|
||||||
|
out:
|
||||||
|
kfree(pstatus);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 usb_func(struct i2c_adapter *adapter)
|
||||||
|
{
|
||||||
|
__le32 *pfunc;
|
||||||
|
u32 ret;
|
||||||
|
int i=-1;
|
||||||
|
|
||||||
|
pfunc = kmalloc(sizeof(*pfunc), GFP_KERNEL);
|
||||||
|
|
||||||
|
/* get functionality from adapter */
|
||||||
|
if (!pfunc || (i=usb_read(adapter, CMD_GET_FUNC, 0, 0, pfunc,
|
||||||
|
sizeof(*pfunc))) != sizeof(*pfunc)) {
|
||||||
|
dev_err(&adapter->dev, "failure reading functionality: %i\n");
|
||||||
|
ret = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = le32_to_cpup(pfunc);
|
||||||
|
dev_warn(&adapter->dev, "itu func=%08x\n", ret);
|
||||||
|
out:
|
||||||
|
kfree(pfunc);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is the actual algorithm we define */
|
||||||
|
static const struct i2c_algorithm usb_algorithm = {
|
||||||
|
.master_xfer = usb_xfer,
|
||||||
|
.functionality = usb_func,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ----- end of i2c layer ------------------------------------------------ */
|
||||||
|
|
||||||
|
/* ----- begin of usb layer ---------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initially the usb i2c interface uses a vid/pid pair donated by
|
||||||
|
* Future Technology Devices International Ltd., later a pair was
|
||||||
|
* bought from EZPrototypes
|
||||||
|
*/
|
||||||
|
static const struct usb_device_id i2c_tiny_usb_table[] = {
|
||||||
|
{ USB_DEVICE(0x0403, 0xc631) }, /* FTDI */
|
||||||
|
{ USB_DEVICE(0x1c40, 0x0534) }, /* EZPrototypes */
|
||||||
|
{ USB_DEVICE_INTERFACE_CLASS(0xcafe, 0x4017, 0/*255*/) }, /* TinyUSB DapperMime: we want the Vendor interface */
|
||||||
|
{ } /* Terminating entry */
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_DEVICE_TABLE(usb, i2c_tiny_usb_table);
|
||||||
|
|
||||||
|
/* Structure to hold all of our device specific stuff */
|
||||||
|
struct i2c_tiny_usb {
|
||||||
|
struct usb_device *usb_dev; /* the usb device for this device */
|
||||||
|
struct usb_interface *interface; /* the interface for this device */
|
||||||
|
struct i2c_adapter adapter; /* i2c related things */
|
||||||
|
bool is_tusb_dmime;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int usb_read(struct i2c_adapter *adapter, int cmd,
|
||||||
|
int value, int index, void *data, int len)
|
||||||
|
{
|
||||||
|
struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
|
||||||
|
uint8_t *dmadata;
|
||||||
|
int ret, actual_len = 0;
|
||||||
|
|
||||||
|
if (dev->is_tusb_dmime) {
|
||||||
|
// actual_len = len;
|
||||||
|
// if (actual_len < 7) actual_len = 7; /* cmd(1), value(2), index(2), len(2) */
|
||||||
|
//
|
||||||
|
// dmadata = (uint8_t*)kzalloc(actual_len, GFP_KERNEL);
|
||||||
|
// if (!dmadata)
|
||||||
|
// return -ENOMEM;
|
||||||
|
//
|
||||||
|
// dmadata[0] = cmd;
|
||||||
|
// dmadata[1] = value & 0xff;
|
||||||
|
// dmadata[2] = (value >> 8) & 0xff;
|
||||||
|
// dmadata[3] = index & 0xff;
|
||||||
|
// dmadata[4] = (index >> 8) & 0xff;
|
||||||
|
// dmadata[5] = len & 0xff;
|
||||||
|
// dmadata[6] = (len >> 8) & 0xff;
|
||||||
|
//
|
||||||
|
// /* send command */
|
||||||
|
// ret = usb_bulk_msg(dev->usb_dev, usb_sndbulkpipe(dev->usb_dev, 9),
|
||||||
|
// dmadata, 7, &actual_len, 2000);
|
||||||
|
//
|
||||||
|
// dev_warn(&dev->usb_dev->dev, "read bulk msg retval=%i\n", ret);
|
||||||
|
//
|
||||||
|
// /* command received correctly */
|
||||||
|
// if (ret == 7) {
|
||||||
|
// actual_len = 0;
|
||||||
|
// /* receive reply */
|
||||||
|
// ret = usb_bulk_msg(dev->usb_dev, usb_rcvbulkpipe(dev->usb_dev, 9),
|
||||||
|
// dmadata, len, &actual_len, 2000);
|
||||||
|
//
|
||||||
|
// memcpy(data, dmadata, len);
|
||||||
|
// }
|
||||||
|
dmadata = kmalloc(len, GFP_KERNEL);
|
||||||
|
|
||||||
|
if (!dmadata)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* do control transfer */
|
||||||
|
ret = usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
|
||||||
|
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_IN,
|
||||||
|
value, index, dmadata, len, 2000);
|
||||||
|
|
||||||
|
memcpy(data, dmadata, len);
|
||||||
|
} else {
|
||||||
|
dmadata = kmalloc(len, GFP_KERNEL);
|
||||||
|
|
||||||
|
if (!dmadata)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* do control transfer */
|
||||||
|
ret = usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
|
||||||
|
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_IN,
|
||||||
|
value, index, dmadata, len, 2000);
|
||||||
|
|
||||||
|
memcpy(data, dmadata, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(dmadata);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int usb_write(struct i2c_adapter *adapter, int cmd,
|
||||||
|
int value, int index, void *data, int len)
|
||||||
|
{
|
||||||
|
struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
|
||||||
|
uint8_t *dmadata;
|
||||||
|
int ret, actual_len = 0;
|
||||||
|
|
||||||
|
if (dev->is_tusb_dmime) {
|
||||||
|
// dmadata = (uint8_t*)kzalloc(len + 7, GFP_KERNEL); /* cmd(1), value(2), index(2), len(2) */
|
||||||
|
// if (!dmadata)
|
||||||
|
// return -ENOMEM;
|
||||||
|
//
|
||||||
|
// dmadata[0] = cmd;
|
||||||
|
// dmadata[1] = value & 0xff;
|
||||||
|
// dmadata[2] = (value >> 8) & 0xff;
|
||||||
|
// dmadata[3] = index & 0xff;
|
||||||
|
// dmadata[4] = (index >> 8) & 0xff;
|
||||||
|
// dmadata[5] = len & 0xff;
|
||||||
|
// dmadata[6] = (len >> 8) & 0xff;
|
||||||
|
//
|
||||||
|
// if (data && len)
|
||||||
|
// memcpy(&dmadata[7], data, len);
|
||||||
|
//
|
||||||
|
// /* send command data */
|
||||||
|
// ret = usb_bulk_msg(dev->usb_dev, usb_sndbulkpipe(dev->usb_dev, 9),
|
||||||
|
// dmadata, len+7, &actual_len, 2000);
|
||||||
|
dmadata = (uint8_t*)kmemdup(data, len, GFP_KERNEL);
|
||||||
|
if (!dmadata)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* do control transfer */
|
||||||
|
ret = usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
|
||||||
|
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
|
||||||
|
value, index, dmadata, len, 2000);
|
||||||
|
} else {
|
||||||
|
dmadata = (uint8_t*)kmemdup(data, len, GFP_KERNEL);
|
||||||
|
if (!dmadata)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* do control transfer */
|
||||||
|
ret = usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
|
||||||
|
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
|
||||||
|
value, index, dmadata, len, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(dmadata);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev)
|
||||||
|
{
|
||||||
|
usb_put_dev(dev->usb_dev);
|
||||||
|
kfree(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int i2c_tiny_usb_probe(struct usb_interface *interface,
|
||||||
|
const struct usb_device_id *id)
|
||||||
|
{
|
||||||
|
struct i2c_tiny_usb *dev;
|
||||||
|
int retval = -ENOMEM;
|
||||||
|
u16 version;
|
||||||
|
|
||||||
|
dev_dbg(&interface->dev, "probing usb device\n");
|
||||||
|
|
||||||
|
/* allocate memory for our device state and initialize it */
|
||||||
|
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||||
|
if (dev == NULL) {
|
||||||
|
dev_err(&interface->dev, "Out of memory\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
|
||||||
|
dev->interface = interface;
|
||||||
|
|
||||||
|
/* TinyUSB DapperMime needs different treatment because it has MANY endpoints */
|
||||||
|
dev->is_tusb_dmime = le16_to_cpu(dev->usb_dev->descriptor.idVendor ) == 0xcafe
|
||||||
|
&& le16_to_cpu(dev->usb_dev->descriptor.idProduct) == 0x4017;
|
||||||
|
|
||||||
|
/* save our data pointer in this interface device */
|
||||||
|
usb_set_intfdata(interface, dev);
|
||||||
|
|
||||||
|
version = le16_to_cpu(dev->usb_dev->descriptor.bcdDevice);
|
||||||
|
dev_info(&interface->dev,
|
||||||
|
"version %x.%02x found at bus %03d address %03d\n",
|
||||||
|
version >> 8, version & 0xff,
|
||||||
|
dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
|
||||||
|
|
||||||
|
/* setup i2c adapter description */
|
||||||
|
dev->adapter.owner = THIS_MODULE;
|
||||||
|
dev->adapter.class = I2C_CLASS_HWMON;
|
||||||
|
dev->adapter.algo = &usb_algorithm;
|
||||||
|
dev->adapter.algo_data = dev;
|
||||||
|
snprintf(dev->adapter.name, sizeof(dev->adapter.name),
|
||||||
|
"i2c-tiny-usb at bus %03d device %03d",
|
||||||
|
dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
|
||||||
|
|
||||||
|
if (usb_write(&dev->adapter, CMD_SET_DELAY, delay, 0, NULL, 0) != 0) {
|
||||||
|
dev_err(/*&dev->adapter.dev*/ &dev->usb_dev->dev, /* adapter.dev is null at this point */
|
||||||
|
"failure setting delay to %dus\n", delay);
|
||||||
|
retval = -EIO;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->adapter.dev.parent = &dev->interface->dev;
|
||||||
|
|
||||||
|
/* and finally attach to i2c layer */
|
||||||
|
i2c_add_adapter(&dev->adapter);
|
||||||
|
|
||||||
|
/* inform user about successful attachment to i2c layer */
|
||||||
|
dev_info(&dev->adapter.dev, "connected i2c-tiny-usb device\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (dev)
|
||||||
|
i2c_tiny_usb_free(dev);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void i2c_tiny_usb_disconnect(struct usb_interface *interface)
|
||||||
|
{
|
||||||
|
struct i2c_tiny_usb *dev = usb_get_intfdata(interface);
|
||||||
|
|
||||||
|
i2c_del_adapter(&dev->adapter);
|
||||||
|
usb_set_intfdata(interface, NULL);
|
||||||
|
i2c_tiny_usb_free(dev);
|
||||||
|
|
||||||
|
dev_dbg(&interface->dev, "disconnected\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct usb_driver i2c_tiny_usb_driver = {
|
||||||
|
.name = "i2c-tiny-usb",
|
||||||
|
.probe = i2c_tiny_usb_probe,
|
||||||
|
.disconnect = i2c_tiny_usb_disconnect,
|
||||||
|
.id_table = i2c_tiny_usb_table,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_usb_driver(i2c_tiny_usb_driver);
|
||||||
|
|
||||||
|
/* ----- end of usb layer ------------------------------------------------ */
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Till Harbaum <Till@Harbaum.org>");
|
||||||
|
MODULE_DESCRIPTION("i2c-tiny-usb driver v1.0");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,135 @@
|
||||||
|
|
||||||
|
#include "protocfg.h"
|
||||||
|
|
||||||
|
#ifdef DBOARD_HAS_I2C
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "tusb.h"
|
||||||
|
#include "device/usbd_pvt.h"
|
||||||
|
|
||||||
|
#include "protos.h"
|
||||||
|
#include "thread.h"
|
||||||
|
|
||||||
|
static uint8_t itf_num;
|
||||||
|
|
||||||
|
static void iub_init(void) {
|
||||||
|
//printf("i2c init\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iub_reset(uint8_t rhport) {
|
||||||
|
//printf("i2c reset %02x\n", rhport);
|
||||||
|
|
||||||
|
itf_num = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t iub_open(uint8_t rhport, tusb_desc_interface_t const* itf_desc,
|
||||||
|
uint16_t max_len) {
|
||||||
|
TU_VERIFY(itf_desc->bInterfaceClass == 0
|
||||||
|
&& itf_desc->bInterfaceSubClass == 0
|
||||||
|
&& itf_desc->bInterfaceProtocol == 0, 0);
|
||||||
|
|
||||||
|
const uint16_t drv_len = sizeof(tusb_desc_interface_t);
|
||||||
|
TU_VERIFY(max_len >= drv_len, 0);
|
||||||
|
|
||||||
|
itf_num = itf_desc->bInterfaceNumber;
|
||||||
|
|
||||||
|
return drv_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern char msgbuf[256];
|
||||||
|
extern volatile bool msgflag;
|
||||||
|
char msgbuf[256] = {0};
|
||||||
|
volatile bool msgflag = false;
|
||||||
|
|
||||||
|
//, b, c, d, e ,f
|
||||||
|
#define printf(fmt, a, b, c, d, e) do { \
|
||||||
|
/*while (msgflag) ;*/\
|
||||||
|
snprintf(msgbuf, sizeof msgbuf, fmt, a, b, c, d, e);\
|
||||||
|
msgbuf[sizeof msgbuf - 1] = 0; \
|
||||||
|
msgflag = true;\
|
||||||
|
} while (0);\
|
||||||
|
|
||||||
|
static bool iub_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const* req) {
|
||||||
|
if (stage != CONTROL_STAGE_SETUP) return true;
|
||||||
|
|
||||||
|
/*printf("ctl req rhport=%02x, stage=%02x, wIndex=%04x, bReq=%02x, wValue=%04x\n",
|
||||||
|
rhport, stage,
|
||||||
|
req->wIndex, req->bRequest, req->wValue);*/
|
||||||
|
|
||||||
|
if (req->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR) {
|
||||||
|
switch (req->bRequest) {
|
||||||
|
case 1: // get func
|
||||||
|
{
|
||||||
|
const uint32_t flags = 0xceff0001;
|
||||||
|
uint8_t rv[4];
|
||||||
|
rv[0]=flags&0xff;
|
||||||
|
rv[1]=(flags>>8)&0xff;
|
||||||
|
rv[2]=(flags>>16)&0xff;
|
||||||
|
rv[3]=(flags>>24)&0xff;
|
||||||
|
return tud_control_xfer(rhport, req, rv, sizeof rv);
|
||||||
|
}
|
||||||
|
case 2: // set delay
|
||||||
|
return tud_control_status(rhport, req);
|
||||||
|
case 3: // get status
|
||||||
|
{
|
||||||
|
uint8_t rv = 0; // idle
|
||||||
|
return tud_control_xfer(rhport, req, &rv, 1);
|
||||||
|
}
|
||||||
|
case 4: case 5: case 6: case 7: // I2C_IO
|
||||||
|
{
|
||||||
|
if (req->wValue & 1) { // read: we need to return shit
|
||||||
|
printf("read!%c%c%c%c%c\n", ' ', ' ', ' ', ' ', ' ');
|
||||||
|
// so, we'll return some garbage
|
||||||
|
uint8_t buf[req->wLength];
|
||||||
|
return tud_control_xfer(rhport, req, buf, req->wLength);
|
||||||
|
} else {
|
||||||
|
//printf("write!%c%c%c%c%c\n", ' ', ' ', ' ', ' ', ' ');
|
||||||
|
// ????
|
||||||
|
return tud_control_status(rhport, req);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // unk
|
||||||
|
}
|
||||||
|
|
||||||
|
// never actually called
|
||||||
|
static bool iub_xfer(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
|
||||||
|
printf("xfer cb! rh=%02x ep=%02x res=%02x len=%08x%c\n",
|
||||||
|
rhport, ep_addr, result, xferred_bytes, ' ');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// interfacing stuff for TinyUSB API, actually defines the driver
|
||||||
|
|
||||||
|
static usbd_class_driver_t const i2ctinyusb_driver = {
|
||||||
|
#if CFG_TUSB_DEBUG >= 2
|
||||||
|
.name = "i2c-tiny-usb",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
.init = iub_init,
|
||||||
|
.reset = iub_reset,
|
||||||
|
.open = iub_open,
|
||||||
|
.control_xfer_cb = iub_ctl_req,
|
||||||
|
.xfer_cb = iub_xfer,
|
||||||
|
.sof = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) {
|
||||||
|
*driver_count = 1;
|
||||||
|
return &i2ctinyusb_driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need to implement this one, because tinyusb uses hardcoded stuff for
|
||||||
|
// endpoint 0, which is what the i2c-tiny-usb kernel module uses
|
||||||
|
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, tusb_control_request_t const* req) {
|
||||||
|
return iub_ctl_req(rhport, ep_addr, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* DBOARD_HAS_I2C */
|
||||||
|
|
|
@ -52,6 +52,9 @@ static cothread_t mainthread
|
||||||
#ifdef DBOARD_HAS_SERPROG
|
#ifdef DBOARD_HAS_SERPROG
|
||||||
, serprogthread
|
, serprogthread
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef DBOARD_HAS_I2C
|
||||||
|
//, ituthread
|
||||||
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
void thread_yield(void) {
|
void thread_yield(void) {
|
||||||
|
@ -80,18 +83,41 @@ static void serprog_thread_fn(void) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef DBOARD_HAS_I2C
|
||||||
|
/*static void itu_thread_fn(void) {
|
||||||
|
itu_init();
|
||||||
|
thread_yield();
|
||||||
|
while (1) {
|
||||||
|
itu_task();
|
||||||
|
thread_yield();
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DBOARD_HAS_UART
|
#ifdef DBOARD_HAS_UART
|
||||||
static uint8_t uartstack[4096];
|
static uint8_t uartstack[4096];
|
||||||
#endif
|
#endif
|
||||||
#ifdef DBOARD_HAS_UART
|
#ifdef DBOARD_HAS_SERPROG
|
||||||
static uint8_t serprogstack[4096];
|
static uint8_t serprogstack[4096];
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef DBOARD_HAS_I2C
|
||||||
|
static uint8_t itustack[4096];
|
||||||
|
#endif
|
||||||
|
|
||||||
extern uint32_t co_active_buffer[64];
|
extern uint32_t co_active_buffer[64];
|
||||||
uint32_t co_active_buffer[64];
|
uint32_t co_active_buffer[64];
|
||||||
extern cothread_t co_active_handle;
|
extern cothread_t co_active_handle;
|
||||||
cothread_t co_active_handle;
|
cothread_t co_active_handle;
|
||||||
|
|
||||||
|
extern char msgbuf[256];
|
||||||
|
extern volatile bool msgflag;
|
||||||
|
static void domsg(void) {
|
||||||
|
if (msgflag) {
|
||||||
|
printf("%s", msgbuf);
|
||||||
|
//msgflag = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
mainthread = co_active();
|
mainthread = co_active();
|
||||||
|
@ -104,15 +130,17 @@ int main(void)
|
||||||
board_init();
|
board_init();
|
||||||
|
|
||||||
#ifdef DBOARD_HAS_UART
|
#ifdef DBOARD_HAS_UART
|
||||||
//cdc_uart_init();
|
|
||||||
uartthread = co_derive(uartstack, sizeof uartstack, uart_thread_fn);
|
uartthread = co_derive(uartstack, sizeof uartstack, uart_thread_fn);
|
||||||
co_switch(uartthread); // will call cdc_uart_init() on correct thread
|
co_switch(uartthread); // will call cdc_uart_init() on correct thread
|
||||||
#endif
|
#endif
|
||||||
#ifdef DBOARD_HAS_SERPROG
|
#ifdef DBOARD_HAS_SERPROG
|
||||||
//cdc_serprog_init();
|
|
||||||
serprogthread = co_derive(serprogstack, sizeof serprogstack, serprog_thread_fn);
|
serprogthread = co_derive(serprogstack, sizeof serprogstack, serprog_thread_fn);
|
||||||
co_switch(serprogthread); // will call cdc_serprog_init() on correct thread
|
co_switch(serprogthread); // will call cdc_serprog_init() on correct thread
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef DBOARD_HAS_I2C
|
||||||
|
//ituthread = co_derive(itustack, sizeof itustack, itu_thread_fn);
|
||||||
|
//co_switch(ituthread);
|
||||||
|
#endif
|
||||||
#ifdef DBOARD_HAS_CMSISDAP
|
#ifdef DBOARD_HAS_CMSISDAP
|
||||||
DAP_Setup();
|
DAP_Setup();
|
||||||
#endif
|
#endif
|
||||||
|
@ -127,19 +155,27 @@ int main(void)
|
||||||
{
|
{
|
||||||
//printf("hi\n");
|
//printf("hi\n");
|
||||||
|
|
||||||
|
domsg();
|
||||||
tud_task(); // tinyusb device task
|
tud_task(); // tinyusb device task
|
||||||
#ifdef DBOARD_HAS_UART
|
#ifdef DBOARD_HAS_UART
|
||||||
//cdc_uart_task();
|
//cdc_uart_task();
|
||||||
co_switch(uartthread);
|
co_switch(uartthread);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
domsg();
|
||||||
tud_task(); // tinyusb device task
|
tud_task(); // tinyusb device task
|
||||||
#ifdef DBOARD_HAS_SERPROG
|
#ifdef DBOARD_HAS_SERPROG
|
||||||
//cdc_serprog_task();
|
//cdc_serprog_task();
|
||||||
co_switch(serprogthread);
|
co_switch(serprogthread);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//printf("hi\n");
|
//domsg();
|
||||||
|
//tud_task();
|
||||||
|
#ifdef DBOARD_HAS_I2C
|
||||||
|
//co_switch(ituthread);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//printf("hi2\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
|
@ -19,10 +19,15 @@ void cdc_serprog_task(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_USBCDC_FOR_STDIO
|
#ifdef USE_USBCDC_FOR_STDIO
|
||||||
//#ifndef PICO_BOARD
|
//#ifdef PICO_BOARD
|
||||||
bool stdio_usb_init(void);
|
bool stdio_usb_init(void);
|
||||||
//#endif
|
//#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef DBOARD_HAS_I2C
|
||||||
|
void itu_init(void);
|
||||||
|
void itu_task(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -115,6 +115,8 @@
|
||||||
// CDC FIFO size of TX and RX
|
// CDC FIFO size of TX and RX
|
||||||
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||||
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||||
|
#define CFG_TUD_VENDOR_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||||
|
#define CFG_TUD_VENDOR_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
#include "protocfg.h"
|
#include "protocfg.h"
|
||||||
|
|
||||||
|
// TODO: actually do this properly
|
||||||
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
|
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
|
||||||
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
|
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
|
||||||
*
|
*
|
||||||
|
@ -103,31 +104,28 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance)
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
#ifdef DBOARD_HAS_CMSISDAP
|
|
||||||
ITF_NUM_HID_CMSISDAP,
|
ITF_NUM_HID_CMSISDAP,
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DBOARD_HAS_UART
|
|
||||||
ITF_NUM_CDC_UART_COM,
|
ITF_NUM_CDC_UART_COM,
|
||||||
ITF_NUM_CDC_UART_DATA,
|
ITF_NUM_CDC_UART_DATA,
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DBOARD_HAS_SERPROG
|
|
||||||
ITF_NUM_CDC_SERPROG_COM,
|
ITF_NUM_CDC_SERPROG_COM,
|
||||||
ITF_NUM_CDC_SERPROG_DATA,
|
ITF_NUM_CDC_SERPROG_DATA,
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_USBCDC_FOR_STDIO
|
|
||||||
ITF_NUM_CDC_STDIO_COM,
|
ITF_NUM_CDC_STDIO_COM,
|
||||||
ITF_NUM_CDC_STDIO_DATA,
|
ITF_NUM_CDC_STDIO_DATA,
|
||||||
#endif
|
ITF_NUM_VND_I2CTINYUSB,
|
||||||
|
|
||||||
ITF_NUM_TOTAL
|
ITF_NUM_TOTAL
|
||||||
};
|
};
|
||||||
|
|
||||||
/*#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_HID_INOUT_DESC_LEN)*/
|
#define TUD_I2CTINYUSB_LEN (9)
|
||||||
|
#define TUD_I2CTINYUSB_DESCRIPTOR(_itfnum, _stridx) \
|
||||||
|
9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, 0, 0, 0, _stridx \
|
||||||
|
|
||||||
static const int CONFIG_TOTAL_LEN = TUD_CONFIG_DESC_LEN
|
|
||||||
|
/*enum {*/ static const int CONFIG_TOTAL_LEN = TUD_CONFIG_DESC_LEN
|
||||||
|
#ifdef DBOARD_HAS_I2C
|
||||||
|
+ TUD_I2CTINYUSB_LEN
|
||||||
|
//+ TUD_VENDOR_DESC_LEN
|
||||||
|
#endif
|
||||||
#ifdef DBOARD_HAS_UART
|
#ifdef DBOARD_HAS_UART
|
||||||
+ TUD_CDC_DESC_LEN
|
+ TUD_CDC_DESC_LEN
|
||||||
#endif
|
#endif
|
||||||
|
@ -140,7 +138,7 @@ static const int CONFIG_TOTAL_LEN = TUD_CONFIG_DESC_LEN
|
||||||
#ifdef USE_USBCDC_FOR_STDIO
|
#ifdef USE_USBCDC_FOR_STDIO
|
||||||
+ TUD_CDC_DESC_LEN
|
+ TUD_CDC_DESC_LEN
|
||||||
#endif
|
#endif
|
||||||
;
|
/*}*/;
|
||||||
|
|
||||||
#define EPNUM_CDC_UART_OUT 0x02 // 2
|
#define EPNUM_CDC_UART_OUT 0x02 // 2
|
||||||
#define EPNUM_CDC_UART_IN 0x82 // 83
|
#define EPNUM_CDC_UART_IN 0x82 // 83
|
||||||
|
@ -152,23 +150,32 @@ static const int CONFIG_TOTAL_LEN = TUD_CONFIG_DESC_LEN
|
||||||
#define EPNUM_CDC_STDIO_OUT 0x07
|
#define EPNUM_CDC_STDIO_OUT 0x07
|
||||||
#define EPNUM_CDC_STDIO_IN 0x87
|
#define EPNUM_CDC_STDIO_IN 0x87
|
||||||
#define EPNUM_CDC_STDIO_NOTIF 0x88
|
#define EPNUM_CDC_STDIO_NOTIF 0x88
|
||||||
|
#define EPNUM_VND_I2C_OUT 0x09
|
||||||
|
#define EPNUM_VND_I2C_IN 0x89
|
||||||
|
|
||||||
// NOTE: if you modify this table, don't forget to keep tusb_config.h up to date as well!
|
// NOTE: if you modify this table, don't forget to keep tusb_config.h up to date as well!
|
||||||
|
// TODO: maybe add some strings to all these interfaces
|
||||||
uint8_t const desc_configuration[] =
|
uint8_t const desc_configuration[] =
|
||||||
{
|
{
|
||||||
// Config number, interface count, string index, total length, attribute, power in mA
|
// Config number, interface count, string index, total length, attribute, power in mA
|
||||||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||||
|
|
||||||
#ifdef DBOARD_HAS_UART
|
|
||||||
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
|
|
||||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_UART_COM, 0, EPNUM_CDC_UART_NOTIF, 64, EPNUM_CDC_UART_OUT, EPNUM_CDC_UART_IN, 64),
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DBOARD_HAS_CMSISDAP
|
#ifdef DBOARD_HAS_CMSISDAP
|
||||||
// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
|
// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
|
||||||
TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID_CMSISDAP, 0, 0/*HID_PROTOCOL_NONE*/, sizeof(desc_hid_report), EPNUM_HID_CMSISDAP, 0x80 | (EPNUM_HID_CMSISDAP+0), CFG_TUD_HID_EP_BUFSIZE, 1),
|
TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID_CMSISDAP, 0, 0/*HID_PROTOCOL_NONE*/, sizeof(desc_hid_report), EPNUM_HID_CMSISDAP, 0x80 | (EPNUM_HID_CMSISDAP+0), CFG_TUD_HID_EP_BUFSIZE, 1),
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef DBOARD_HAS_I2C
|
||||||
|
// ???
|
||||||
|
TUD_I2CTINYUSB_DESCRIPTOR(ITF_NUM_VND_I2CTINYUSB, 0),
|
||||||
|
//TUD_VENDOR_DESCRIPTOR(ITF_NUM_VND_I2CTINYUSB, 0, EPNUM_VND_I2C_OUT, EPNUM_VND_I2C_IN, 64),
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DBOARD_HAS_UART
|
||||||
|
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
|
||||||
|
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_UART_COM, 0, EPNUM_CDC_UART_NOTIF, 64, EPNUM_CDC_UART_OUT, EPNUM_CDC_UART_IN, 64),
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DBOARD_HAS_SERPROG
|
#ifdef DBOARD_HAS_SERPROG
|
||||||
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
|
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
|
||||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_SERPROG_COM, 0, EPNUM_CDC_SERPROG_NOTIF, 64, EPNUM_CDC_SERPROG_OUT, EPNUM_CDC_SERPROG_IN, 64),
|
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_SERPROG_COM, 0, EPNUM_CDC_SERPROG_NOTIF, 64, EPNUM_CDC_SERPROG_OUT, EPNUM_CDC_SERPROG_IN, 64),
|
Loading…
Reference in New Issue