mirror of
https://github.com/gdsports/USBHost_t36
synced 2025-02-16 06:50:14 -05:00
Do only 1 control transfer at a time to hubs, clear other change status
This commit is contained in:
parent
81f30ecd5f
commit
ba0e6f495b
19
USBHost.h
19
USBHost.h
@ -307,6 +307,7 @@ class USBHub : public USBDriver {
|
|||||||
public:
|
public:
|
||||||
USBHub();
|
USBHub();
|
||||||
enum { MAXPORTS = 7 };
|
enum { MAXPORTS = 7 };
|
||||||
|
typedef uint8_t portbitmask_t;
|
||||||
enum {
|
enum {
|
||||||
PORT_OFF = 0,
|
PORT_OFF = 0,
|
||||||
PORT_DISCONNECT = 1,
|
PORT_DISCONNECT = 1,
|
||||||
@ -324,10 +325,17 @@ protected:
|
|||||||
virtual void control(const Transfer_t *transfer);
|
virtual void control(const Transfer_t *transfer);
|
||||||
virtual void timer_event(USBDriverTimer *whichTimer);
|
virtual void timer_event(USBDriverTimer *whichTimer);
|
||||||
virtual void disconnect();
|
virtual void disconnect();
|
||||||
|
bool can_send_control_now();
|
||||||
|
|
||||||
void send_poweron(uint32_t port);
|
void send_poweron(uint32_t port);
|
||||||
void send_getstatus(uint32_t port);
|
void send_getstatus(uint32_t port);
|
||||||
void send_clearstatus(uint32_t port);
|
void send_clearstatus_connect(uint32_t port);
|
||||||
|
void send_clearstatus_enable(uint32_t port);
|
||||||
|
void send_clearstatus_suspend(uint32_t port);
|
||||||
|
void send_clearstatus_overcurrent(uint32_t port);
|
||||||
|
void send_clearstatus_reset(uint32_t port);
|
||||||
void send_setreset(uint32_t port);
|
void send_setreset(uint32_t port);
|
||||||
|
|
||||||
static void callback(const Transfer_t *transfer);
|
static void callback(const Transfer_t *transfer);
|
||||||
void status_change(const Transfer_t *transfer);
|
void status_change(const Transfer_t *transfer);
|
||||||
void new_port_status(uint32_t port, uint32_t status);
|
void new_port_status(uint32_t port, uint32_t status);
|
||||||
@ -346,6 +354,15 @@ protected:
|
|||||||
uint8_t numports;
|
uint8_t numports;
|
||||||
uint8_t characteristics;
|
uint8_t characteristics;
|
||||||
uint8_t powertime;
|
uint8_t powertime;
|
||||||
|
uint8_t sending_control_transfer;
|
||||||
|
portbitmask_t send_pending_poweron;
|
||||||
|
portbitmask_t send_pending_getstatus;
|
||||||
|
portbitmask_t send_pending_clearstatus_connect;
|
||||||
|
portbitmask_t send_pending_clearstatus_enable;
|
||||||
|
portbitmask_t send_pending_clearstatus_suspend;
|
||||||
|
portbitmask_t send_pending_clearstatus_overcurrent;
|
||||||
|
portbitmask_t send_pending_clearstatus_reset;
|
||||||
|
portbitmask_t send_pending_setreset;
|
||||||
Pipe_t *changepipe;
|
Pipe_t *changepipe;
|
||||||
uint32_t changebits;
|
uint32_t changebits;
|
||||||
uint8_t portstate[MAXPORTS];
|
uint8_t portstate[MAXPORTS];
|
||||||
|
136
hub.cpp
136
hub.cpp
@ -84,6 +84,7 @@ bool USBHub::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t
|
|||||||
numports = 0; // unknown until hub descriptor is read
|
numports = 0; // unknown until hub descriptor is read
|
||||||
changepipe = NULL;
|
changepipe = NULL;
|
||||||
changebits = 0;
|
changebits = 0;
|
||||||
|
sending_control_transfer = 0;
|
||||||
memset(portstate, 0, sizeof(portstate));
|
memset(portstate, 0, sizeof(portstate));
|
||||||
|
|
||||||
mk_setup(setup[0], 0xA0, 6, 0x2900, 0, sizeof(hub_desc));
|
mk_setup(setup[0], 0xA0, 6, 0x2900, 0, sizeof(hub_desc));
|
||||||
@ -93,36 +94,115 @@ bool USBHub::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool USBHub::can_send_control_now()
|
||||||
|
{
|
||||||
|
if (sending_control_transfer) return false;
|
||||||
|
sending_control_transfer = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void USBHub::send_poweron(uint32_t port)
|
void USBHub::send_poweron(uint32_t port)
|
||||||
{
|
{
|
||||||
if (port == 0 || port > numports) return;
|
if (port == 0 || port > numports) return;
|
||||||
mk_setup(setup[port], 0x23, 3, 8, port, 0);
|
if (can_send_control_now()) {
|
||||||
queue_Control_Transfer(device, &setup[port], NULL, this);
|
mk_setup(setup[port], 0x23, 3, 8, port, 0);
|
||||||
|
queue_Control_Transfer(device, &setup[port], NULL, this);
|
||||||
|
send_pending_poweron &= ~(1 << port);
|
||||||
|
} else {
|
||||||
|
send_pending_poweron |= (1 << port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBHub::send_getstatus(uint32_t port)
|
void USBHub::send_getstatus(uint32_t port)
|
||||||
{
|
{
|
||||||
if (port > numports) return;
|
if (port > numports) return;
|
||||||
|
if (can_send_control_now()) {
|
||||||
println("getstatus, port = ", port);
|
println("getstatus, port = ", port);
|
||||||
mk_setup(setup[port], ((port > 0) ? 0xA3 : 0xA0), 0, 0, port, 4);
|
mk_setup(setup[port], ((port > 0) ? 0xA3 : 0xA0), 0, 0, port, 4);
|
||||||
queue_Control_Transfer(device, &setup[port], &statusbits[port], this);
|
queue_Control_Transfer(device, &setup[port], &statusbits[port], this);
|
||||||
|
send_pending_getstatus &= ~(1 << port);
|
||||||
|
} else {
|
||||||
|
send_pending_getstatus |= (1 << port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBHub::send_clearstatus(uint32_t port)
|
void USBHub::send_clearstatus_connect(uint32_t port)
|
||||||
{
|
{
|
||||||
if (port > numports) return;
|
if (port == 0 || port > numports) return;
|
||||||
mk_setup(setup[port], ((port > 0) ? 0x23 : 0x20), 1, 0x10, port, 0);
|
if (can_send_control_now()) {
|
||||||
queue_Control_Transfer(device, &setup[port], NULL, this);
|
mk_setup(setup[port], 0x23, 1, 16, port, 0); // 16=C_PORT_CONNECTION
|
||||||
|
queue_Control_Transfer(device, &setup[port], NULL, this);
|
||||||
|
send_pending_clearstatus_connect &= ~(1 << port);
|
||||||
|
} else {
|
||||||
|
send_pending_clearstatus_connect |= (1 << port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBHub::send_clearstatus_enable(uint32_t port)
|
||||||
|
{
|
||||||
|
if (port == 0 || port > numports) return;
|
||||||
|
if (can_send_control_now()) {
|
||||||
|
mk_setup(setup[port], 0x23, 1, 17, port, 0); // 17=C_PORT_ENABLE
|
||||||
|
queue_Control_Transfer(device, &setup[port], NULL, this);
|
||||||
|
send_pending_clearstatus_enable &= ~(1 << port);
|
||||||
|
} else {
|
||||||
|
send_pending_clearstatus_enable |= (1 << port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBHub::send_clearstatus_suspend(uint32_t port)
|
||||||
|
{
|
||||||
|
if (port == 0 || port > numports) return;
|
||||||
|
if (can_send_control_now()) {
|
||||||
|
mk_setup(setup[port], 0x23, 1, 18, port, 0); // 18=C_PORT_SUSPEND
|
||||||
|
queue_Control_Transfer(device, &setup[port], NULL, this);
|
||||||
|
send_pending_clearstatus_suspend &= ~(1 << port);
|
||||||
|
} else {
|
||||||
|
send_pending_clearstatus_suspend |= (1 << port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBHub::send_clearstatus_overcurrent(uint32_t port)
|
||||||
|
{
|
||||||
|
if (port == 0 || port > numports) return;
|
||||||
|
if (can_send_control_now()) {
|
||||||
|
mk_setup(setup[port], 0x23, 1, 19, port, 0); // 19=C_PORT_OVER_CURRENT
|
||||||
|
queue_Control_Transfer(device, &setup[port], NULL, this);
|
||||||
|
send_pending_clearstatus_overcurrent &= ~(1 << port);
|
||||||
|
} else {
|
||||||
|
send_pending_clearstatus_overcurrent |= (1 << port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBHub::send_clearstatus_reset(uint32_t port)
|
||||||
|
{
|
||||||
|
if (port == 0 || port > numports) return;
|
||||||
|
if (can_send_control_now()) {
|
||||||
|
mk_setup(setup[port], 0x23, 1, 20, port, 0); // 20=C_PORT_RESET
|
||||||
|
queue_Control_Transfer(device, &setup[port], NULL, this);
|
||||||
|
send_pending_clearstatus_reset &= ~(1 << port);
|
||||||
|
} else {
|
||||||
|
send_pending_clearstatus_reset |= (1 << port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBHub::send_setreset(uint32_t port)
|
void USBHub::send_setreset(uint32_t port)
|
||||||
{
|
{
|
||||||
if (port == 0 || port > numports) return;
|
if (port == 0 || port > numports) return;
|
||||||
println("send_setreset");
|
println("send_setreset");
|
||||||
mk_setup(setup[port], 0x23, 3, 4, port, 0); // set feature PORT_RESET
|
if (can_send_control_now()) {
|
||||||
queue_Control_Transfer(device, &setup[port], NULL, this);
|
mk_setup(setup[port], 0x23, 3, 4, port, 0); // set feature PORT_RESET
|
||||||
|
queue_Control_Transfer(device, &setup[port], NULL, this);
|
||||||
|
send_pending_setreset &= ~(1 << port);
|
||||||
|
} else {
|
||||||
|
send_pending_setreset |= (1 << port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t lowestbit(uint32_t bitmask)
|
||||||
|
{
|
||||||
|
return 31 - __builtin_clz(bitmask);
|
||||||
|
}
|
||||||
|
|
||||||
void USBHub::control(const Transfer_t *transfer)
|
void USBHub::control(const Transfer_t *transfer)
|
||||||
{
|
{
|
||||||
@ -157,7 +237,6 @@ void USBHub::control(const Transfer_t *transfer)
|
|||||||
|
|
||||||
case 0x000000A0: // get hub status
|
case 0x000000A0: // get hub status
|
||||||
println("New Hub Status");
|
println("New Hub Status");
|
||||||
send_clearstatus(0);
|
|
||||||
break;
|
break;
|
||||||
case 0x000000A3: // get port status
|
case 0x000000A3: // get port status
|
||||||
println("New Port Status");
|
println("New Port Status");
|
||||||
@ -168,7 +247,7 @@ void USBHub::control(const Transfer_t *transfer)
|
|||||||
}
|
}
|
||||||
//if (changebits & (1 << port)) {
|
//if (changebits & (1 << port)) {
|
||||||
//changebits &= ~(1 << port);
|
//changebits &= ~(1 << port);
|
||||||
send_clearstatus(port);
|
//send_clearstatus(port);
|
||||||
//}
|
//}
|
||||||
break;
|
break;
|
||||||
case 0x00100120: // clear hub status
|
case 0x00100120: // clear hub status
|
||||||
@ -180,6 +259,29 @@ void USBHub::control(const Transfer_t *transfer)
|
|||||||
default:
|
default:
|
||||||
println("unhandled setup, message = ", mesg, HEX);
|
println("unhandled setup, message = ", mesg, HEX);
|
||||||
}
|
}
|
||||||
|
// After we've completed processing for this control
|
||||||
|
// transfer, check if any more need to be sent. These
|
||||||
|
// allow only a single control transfer to occur at once
|
||||||
|
// which isn't fast, but requires only 3 Transfer_t and
|
||||||
|
// allows reusing the setup and other buffers
|
||||||
|
sending_control_transfer = 0;
|
||||||
|
if (send_pending_poweron) {
|
||||||
|
send_poweron(lowestbit(send_pending_poweron));
|
||||||
|
} else if (send_pending_clearstatus_connect) {
|
||||||
|
send_clearstatus_connect(lowestbit(send_pending_clearstatus_connect));
|
||||||
|
} else if (send_pending_clearstatus_enable) {
|
||||||
|
send_clearstatus_enable(lowestbit(send_pending_clearstatus_enable));
|
||||||
|
} else if (send_pending_clearstatus_suspend) {
|
||||||
|
send_clearstatus_suspend(lowestbit(send_pending_clearstatus_suspend));
|
||||||
|
} else if (send_pending_clearstatus_overcurrent) {
|
||||||
|
send_clearstatus_overcurrent(lowestbit(send_pending_clearstatus_overcurrent));
|
||||||
|
} else if (send_pending_clearstatus_reset) {
|
||||||
|
send_clearstatus_reset(lowestbit(send_pending_clearstatus_reset));
|
||||||
|
} else if (send_pending_getstatus) {
|
||||||
|
send_getstatus(lowestbit(send_pending_getstatus));
|
||||||
|
} else if (send_pending_setreset) {
|
||||||
|
send_setreset(lowestbit(send_pending_setreset));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBHub::callback(const Transfer_t *transfer)
|
void USBHub::callback(const Transfer_t *transfer)
|
||||||
@ -211,7 +313,7 @@ void USBHub::new_port_status(uint32_t port, uint32_t status)
|
|||||||
// status bits, USB 2.0: 11.24.2.7.1 page 427
|
// status bits, USB 2.0: 11.24.2.7.1 page 427
|
||||||
if (status & 0x0001) println(" Device is present: ");
|
if (status & 0x0001) println(" Device is present: ");
|
||||||
if (status & 0x0002) {
|
if (status & 0x0002) {
|
||||||
println(" Enabled, speed = ");
|
print(" Enabled, speed = ");
|
||||||
if (status & 0x0200) {
|
if (status & 0x0200) {
|
||||||
print("1.5");
|
print("1.5");
|
||||||
} else {
|
} else {
|
||||||
@ -237,6 +339,7 @@ void USBHub::new_port_status(uint32_t port, uint32_t status)
|
|||||||
if (status & 0x0001) { // connected
|
if (status & 0x0001) { // connected
|
||||||
state = PORT_DEBOUNCE1;
|
state = PORT_DEBOUNCE1;
|
||||||
start_debounce_timer(port);
|
start_debounce_timer(port);
|
||||||
|
send_clearstatus_connect(port);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PORT_DEBOUNCE1:
|
case PORT_DEBOUNCE1:
|
||||||
@ -258,6 +361,13 @@ void USBHub::new_port_status(uint32_t port, uint32_t status)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PORT_RESET:
|
case PORT_RESET:
|
||||||
|
if (status & 0x0002) {
|
||||||
|
// port is now enabled
|
||||||
|
//while (1) ;
|
||||||
|
//send_clearstatus_enable(port);
|
||||||
|
//send_clearstatus_connect(port);
|
||||||
|
send_clearstatus_reset(port);
|
||||||
|
}
|
||||||
case PORT_RECOVERY:
|
case PORT_RECOVERY:
|
||||||
case PORT_ACTIVE:
|
case PORT_ACTIVE:
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user