Skip to content

Commit cd110d8

Browse files
committed
Model A(+) support is working
FIXED: Handling for USB no-split interrupt transactions was incomplete "class" DWHCIFrameSchedulerNoSplit added Model check removed from DWHCIDeviceInitialize() FIXED: URB status was not properly set on failure USB reset recovery time increased to 20ms (an USB stick wasn't detected)
1 parent 65fcf12 commit cd110d8

File tree

6 files changed

+195
-32
lines changed

6 files changed

+195
-32
lines changed

uspi/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ OBJS = \
3939
lib/devicenameservice.o \
4040
lib/dwhcidevice.o \
4141
lib/dwhciframeschednper.o \
42+
lib/dwhciframeschednsplit.o \
4243
lib/dwhciframeschedper.o \
4344
lib/dwhciregister.o \
4445
lib/dwhcirootport.o \

uspi/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ USPi
66
Overview
77
--------
88

9-
USPi is a bare metal USB driver for the Raspberry Pi written in C. It was ported from the Circle USB library. Using C allows it to be used from bare metal C code for the Raspberry Pi. Like the Circle USB library it supports control (synchronous), bulk and interrupt (synchronous and asynchronous) transfers. Function drivers are available for USB keyboards, mass storage devices (e.g. USB flash devices) and the on-board Ethernet controller. USPi is only running on the Raspberry Pi model B and B+ at the moment.
9+
USPi is a bare metal USB driver for the Raspberry Pi written in C. It was ported from the Circle USB library. Using C allows it to be used from bare metal C code for the Raspberry Pi. Like the Circle USB library it supports control (synchronous), bulk and interrupt (synchronous and asynchronous) transfers. Function drivers are available for USB keyboards, mass storage devices (e.g. USB flash devices) and the on-board Ethernet controller. USPi should run on all existing Raspberry Pi models.
1010

1111
USPi was "mechanically" ported from the Circle USB library which is written in C++. That's why the source code may look a little bit strange. But it was faster to do so.
1212

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//
2+
// dwhciframeschednsplit.h
3+
//
4+
// USPi - An USB driver for Raspberry Pi written in C
5+
// Copyright (C) 2014 R. Stange <[email protected]>
6+
//
7+
// This program is free software: you can redistribute it and/or modify
8+
// it under the terms of the GNU General Public License as published by
9+
// the Free Software Foundation, either version 3 of the License, or
10+
// (at your option) any later version.
11+
//
12+
// This program is distributed in the hope that it will be useful,
13+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
// GNU General Public License for more details.
16+
//
17+
// You should have received a copy of the GNU General Public License
18+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
//
20+
#ifndef _uspi_dwhciframeschednsplit_h
21+
#define _uspi_dwhciframeschednsplit_h
22+
23+
#include <uspi/dwhciframescheduler.h>
24+
#include <uspi/types.h>
25+
26+
typedef struct TDWHCIFrameSchedulerNoSplit
27+
{
28+
TDWHCIFrameScheduler m_DWHCIFrameScheduler;
29+
30+
boolean m_bIsPeriodic;
31+
unsigned m_nNextFrame;
32+
}
33+
TDWHCIFrameSchedulerNoSplit;
34+
35+
void DWHCIFrameSchedulerNoSplit (TDWHCIFrameSchedulerNoSplit *pThis, boolean bIsPeriodic);
36+
void _DWHCIFrameSchedulerNoSplit (TDWHCIFrameScheduler *pBase);
37+
38+
void DWHCIFrameSchedulerNoSplitStartSplit (TDWHCIFrameScheduler *pBase);
39+
boolean DWHCIFrameSchedulerNoSplitCompleteSplit (TDWHCIFrameScheduler *pBase);
40+
void DWHCIFrameSchedulerNoSplitTransactionComplete (TDWHCIFrameScheduler *pBase, u32 nStatus);
41+
42+
void DWHCIFrameSchedulerNoSplitWaitForFrame (TDWHCIFrameScheduler *pBase);
43+
44+
boolean DWHCIFrameSchedulerNoSplitIsOddFrame (TDWHCIFrameScheduler *pBase);
45+
46+
#endif

uspi/lib/dwhcidevice.c

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -113,22 +113,6 @@ boolean DWHCIDeviceInitialize (TDWHCIDevice *pThis)
113113
{
114114
assert (pThis != 0);
115115

116-
// Check model to prevent non-high-speed devices from over-clocking
117-
int nRevision = GetBoardRevision ();
118-
if (nRevision < 0)
119-
{
120-
LogWrite (FromDWHCI, LOG_ERROR, "Cannot get board revision");
121-
return FALSE;
122-
}
123-
124-
nRevision &= 0xFFFF;
125-
if ( (7 <= nRevision && nRevision <= 9)
126-
|| nRevision >= 0x11)
127-
{
128-
LogWrite (FromDWHCI, LOG_ERROR, "Model is not supported");
129-
return FALSE;
130-
}
131-
132116
DataMemBarrier ();
133117

134118
TDWHCIRegister VendorId;
@@ -552,7 +536,8 @@ boolean DWHCIDeviceEnableRootPort (TDWHCIDevice *pThis)
552536
DWHCIRegisterAnd (&HostPort, ~DWHCI_HOST_PORT_RESET);
553537
DWHCIRegisterWrite (&HostPort);
554538

555-
MsDelay (10); // see USB 2.0 spec (tRSTRCY)
539+
// normally 10ms, seems to be too short for some devices
540+
MsDelay (20); // see USB 2.0 spec (tRSTRCY)
556541

557542
_DWHCIRegister (&HostPort);
558543

@@ -996,7 +981,7 @@ void DWHCIDeviceChannelInterruptHandler (TDWHCIDevice *pThis, unsigned nChannel)
996981

997982
assert ( !DWHCITransferStageDataIsPeriodic (pStageData)
998983
|| DWHCI_HOST_CHAN_XFER_SIZ_PID (DWHCIRegisterGet (&TransferSize))
999-
!= DWHCI_HOST_CHAN_XFER_SIZ_PID_MDATA);
984+
!= DWHCI_HOST_CHAN_XFER_SIZ_PID_MDATA);
1000985

1001986
DWHCITransferStageDataTransactionComplete (pStageData, DWHCIRegisterRead (&ChanInterrupt),
1002987
DWHCI_HOST_CHAN_XFER_SIZ_PACKETS (DWHCIRegisterGet (&TransferSize)),
@@ -1016,12 +1001,23 @@ void DWHCIDeviceChannelInterruptHandler (TDWHCIDevice *pThis, unsigned nChannel)
10161001
switch (DWHCITransferStageDataGetState (pStageData))
10171002
{
10181003
case StageStateNoSplitTransfer:
1019-
DWHCIDeviceDisableChannelInterrupt (pThis, nChannel);
1020-
10211004
nStatus = DWHCITransferStageDataGetTransactionStatus (pStageData);
10221005
if (nStatus & DWHCI_HOST_CHAN_INT_ERROR_MASK)
10231006
{
10241007
LogWrite (FromDWHCI, LOG_ERROR, "Transaction failed (status 0x%X)", nStatus);
1008+
1009+
USBRequestSetStatus (pURB, 0);
1010+
}
1011+
else if ( (nStatus & (DWHCI_HOST_CHAN_INT_NAK | DWHCI_HOST_CHAN_INT_NYET))
1012+
&& DWHCITransferStageDataIsPeriodic (pStageData))
1013+
{
1014+
DWHCITransferStageDataSetState (pStageData, StageStatePeriodicDelay);
1015+
1016+
unsigned nInterval = USBEndpointGetInterval (USBRequestGetEndpoint (pURB));
1017+
1018+
StartKernelTimer (MSEC2HZ (nInterval), DWHCIDeviceTimerHandler, pStageData, pThis);
1019+
1020+
break;
10251021
}
10261022
else
10271023
{
@@ -1033,6 +1029,8 @@ void DWHCIDeviceChannelInterruptHandler (TDWHCIDevice *pThis, unsigned nChannel)
10331029
USBRequestSetStatus (pURB, 1);
10341030
}
10351031

1032+
DWHCIDeviceDisableChannelInterrupt (pThis, nChannel);
1033+
10361034
_DWHCITransferStageData (pStageData);
10371035
free (pStageData);
10381036
pThis->m_pStageData[nChannel] = 0;
@@ -1050,6 +1048,8 @@ void DWHCIDeviceChannelInterruptHandler (TDWHCIDevice *pThis, unsigned nChannel)
10501048
{
10511049
LogWrite (FromDWHCI, LOG_ERROR, "Transaction failed (status 0x%X)", nStatus);
10521050

1051+
USBRequestSetStatus (pURB, 0);
1052+
10531053
DWHCIDeviceDisableChannelInterrupt (pThis, nChannel);
10541054

10551055
_DWHCITransferStageData (pStageData);
@@ -1081,6 +1081,8 @@ void DWHCIDeviceChannelInterruptHandler (TDWHCIDevice *pThis, unsigned nChannel)
10811081
{
10821082
LogWrite (FromDWHCI, LOG_ERROR, "Transaction failed (status 0x%X)", nStatus);
10831083

1084+
USBRequestSetStatus (pURB, 0);
1085+
10841086
DWHCIDeviceDisableChannelInterrupt (pThis, nChannel);
10851087

10861088
_DWHCITransferStageData (pStageData);
@@ -1106,6 +1108,8 @@ void DWHCIDeviceChannelInterruptHandler (TDWHCIDevice *pThis, unsigned nChannel)
11061108
{
11071109
if (!DWHCITransferStageDataBeginSplitCycle (pStageData))
11081110
{
1111+
USBRequestSetStatus (pURB, 0);
1112+
11091113
DWHCIDeviceDisableChannelInterrupt (pThis, nChannel);
11101114

11111115
_DWHCITransferStageData (pStageData);
@@ -1234,13 +1238,21 @@ void DWHCIDeviceTimerHandler (unsigned hTimer, void *pParam, void *pContext)
12341238

12351239
assert (pStageData != 0);
12361240
assert (DWHCITransferStageDataGetState (pStageData) == StageStatePeriodicDelay);
1237-
DWHCITransferStageDataSetState (pStageData, StageStateStartSplit);
1238-
1239-
DWHCITransferStageDataSetSplitComplete (pStageData, FALSE);
1240-
TDWHCIFrameScheduler *pFrameScheduler =
1241-
DWHCITransferStageDataGetFrameScheduler (pStageData);
1242-
assert (pFrameScheduler != 0);
1243-
pFrameScheduler->StartSplit (pFrameScheduler);
1241+
1242+
if (DWHCITransferStageDataIsSplit (pStageData))
1243+
{
1244+
DWHCITransferStageDataSetState (pStageData, StageStateStartSplit);
1245+
1246+
DWHCITransferStageDataSetSplitComplete (pStageData, FALSE);
1247+
TDWHCIFrameScheduler *pFrameScheduler =
1248+
DWHCITransferStageDataGetFrameScheduler (pStageData);
1249+
assert (pFrameScheduler != 0);
1250+
pFrameScheduler->StartSplit (pFrameScheduler);
1251+
}
1252+
else
1253+
{
1254+
DWHCITransferStageDataSetState (pStageData, StageStateNoSplitTransfer);
1255+
}
12441256

12451257
DWHCIDeviceStartTransaction (pThis, pStageData);
12461258

@@ -1302,9 +1314,9 @@ boolean DWHCIDeviceWaitForBit (TDWHCIDevice *pThis, TDWHCIRegister *pRegister, u
13021314

13031315
if (--nMsTimeout == 0)
13041316
{
1305-
LogWrite (FromDWHCI, LOG_WARNING, "Timeout");
1317+
//LogWrite (FromDWHCI, LOG_WARNING, "Timeout");
13061318
#ifndef NDEBUG
1307-
DWHCIRegisterDump (pRegister);
1319+
//DWHCIRegisterDump (pRegister);
13081320
#endif
13091321
return FALSE;
13101322
}

uspi/lib/dwhciframeschednsplit.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
//
2+
// dwhciframeschednsplit.c
3+
//
4+
// USPi - An USB driver for Raspberry Pi written in C
5+
// Copyright (C) 2014 R. Stange <[email protected]>
6+
//
7+
// This program is free software: you can redistribute it and/or modify
8+
// it under the terms of the GNU General Public License as published by
9+
// the Free Software Foundation, either version 3 of the License, or
10+
// (at your option) any later version.
11+
//
12+
// This program is distributed in the hope that it will be useful,
13+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
// GNU General Public License for more details.
16+
//
17+
// You should have received a copy of the GNU General Public License
18+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
//
20+
#include <uspi/dwhciframeschednsplit.h>
21+
#include <uspi/dwhciregister.h>
22+
#include <uspi/assert.h>
23+
24+
#define FRAME_UNSET (DWHCI_MAX_FRAME_NUMBER+1)
25+
26+
void DWHCIFrameSchedulerNoSplit (TDWHCIFrameSchedulerNoSplit *pThis, boolean bIsPeriodic)
27+
{
28+
assert (pThis != 0);
29+
30+
TDWHCIFrameScheduler *pBase = (TDWHCIFrameScheduler *) pThis;
31+
32+
pBase->_DWHCIFrameScheduler = _DWHCIFrameSchedulerNoSplit;
33+
pBase->StartSplit = DWHCIFrameSchedulerNoSplitStartSplit;
34+
pBase->CompleteSplit = DWHCIFrameSchedulerNoSplitCompleteSplit;
35+
pBase->TransactionComplete = DWHCIFrameSchedulerNoSplitTransactionComplete;
36+
pBase->WaitForFrame = DWHCIFrameSchedulerNoSplitWaitForFrame;
37+
pBase->IsOddFrame = DWHCIFrameSchedulerNoSplitIsOddFrame;
38+
39+
pThis->m_bIsPeriodic = bIsPeriodic;
40+
pThis->m_nNextFrame = FRAME_UNSET;
41+
42+
}
43+
44+
void _DWHCIFrameSchedulerNoSplit (TDWHCIFrameScheduler *pBase)
45+
{
46+
}
47+
48+
void DWHCIFrameSchedulerNoSplitStartSplit (TDWHCIFrameScheduler *pBase)
49+
{
50+
assert (0);
51+
}
52+
53+
boolean DWHCIFrameSchedulerNoSplitCompleteSplit (TDWHCIFrameScheduler *pBase)
54+
{
55+
assert (0);
56+
return FALSE;
57+
}
58+
59+
void DWHCIFrameSchedulerNoSplitTransactionComplete (TDWHCIFrameScheduler *pBase, u32 nStatus)
60+
{
61+
assert (0);
62+
}
63+
64+
void DWHCIFrameSchedulerNoSplitWaitForFrame (TDWHCIFrameScheduler *pBase)
65+
{
66+
TDWHCIFrameSchedulerNoSplit *pThis = (TDWHCIFrameSchedulerNoSplit *) pBase;
67+
assert (pThis != 0);
68+
69+
TDWHCIRegister FrameNumber;
70+
DWHCIRegister (&FrameNumber, DWHCI_HOST_FRM_NUM);
71+
72+
pThis->m_nNextFrame = (DWHCI_HOST_FRM_NUM_NUMBER (DWHCIRegisterRead (&FrameNumber))+1) & DWHCI_MAX_FRAME_NUMBER;
73+
74+
if (!pThis->m_bIsPeriodic)
75+
{
76+
while ((DWHCI_HOST_FRM_NUM_NUMBER (DWHCIRegisterRead (&FrameNumber)) & DWHCI_MAX_FRAME_NUMBER) != pThis->m_nNextFrame)
77+
{
78+
// do nothing
79+
}
80+
}
81+
82+
_DWHCIRegister (&FrameNumber);
83+
}
84+
85+
boolean DWHCIFrameSchedulerNoSplitIsOddFrame (TDWHCIFrameScheduler *pBase)
86+
{
87+
TDWHCIFrameSchedulerNoSplit *pThis = (TDWHCIFrameSchedulerNoSplit *) pBase;
88+
assert (pThis != 0);
89+
90+
return pThis->m_nNextFrame & 1 ? TRUE : FALSE;
91+
}

uspi/lib/dwhcixferstagedata.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <uspi/dwhcixferstagedata.h>
2121
#include <uspi/dwhciframeschedper.h>
2222
#include <uspi/dwhciframeschednper.h>
23+
#include <uspi/dwhciframeschednsplit.h>
2324
#include <uspi/dwhci.h>
2425
#include <uspios.h>
2526
#include <uspi/assert.h>
@@ -121,6 +122,16 @@ void DWHCITransferStageData (TDWHCITransferStageData *pThis, unsigned nChannel,
121122

122123
assert (pThis->m_pFrameScheduler != 0);
123124
}
125+
else
126+
{
127+
if ( USBDeviceGetHubAddress (pThis->m_pDevice) == 0
128+
&& pThis->m_Speed != USBSpeedHigh)
129+
{
130+
pThis->m_pFrameScheduler = (TDWHCIFrameScheduler *) malloc (sizeof (TDWHCIFrameSchedulerNoSplit));
131+
DWHCIFrameSchedulerNoSplit ((TDWHCIFrameSchedulerNoSplit *) pThis->m_pFrameScheduler, DWHCITransferStageDataIsPeriodic (pThis));
132+
assert (pThis->m_pFrameScheduler != 0);
133+
}
134+
}
124135
}
125136

126137
void _DWHCITransferStageData (TDWHCITransferStageData *pThis)
@@ -406,7 +417,8 @@ u8 DWHCITransferStageDataGetHubPortAddress (TDWHCITransferStageData *pThis)
406417
u8 DWHCITransferStageDataGetSplitPosition (TDWHCITransferStageData *pThis)
407418
{
408419
assert (pThis != 0);
409-
return DWHCI_HOST_CHAN_SPLIT_CTRL_ALL; // TODO: may not work in any case
420+
assert (pThis->m_nTransferSize <= 188); // TODO
421+
return DWHCI_HOST_CHAN_SPLIT_CTRL_ALL;
410422
}
411423

412424
u32 DWHCITransferStageDataGetStatusMask (TDWHCITransferStageData *pThis)
@@ -415,7 +427,8 @@ u32 DWHCITransferStageDataGetStatusMask (TDWHCITransferStageData *pThis)
415427
u32 nMask = DWHCI_HOST_CHAN_INT_XFER_COMPLETE
416428
| DWHCI_HOST_CHAN_INT_ERROR_MASK;
417429

418-
if (pThis->m_bSplitTransaction)
430+
if ( pThis->m_bSplitTransaction
431+
|| DWHCITransferStageDataIsPeriodic (pThis))
419432
{
420433
nMask |= DWHCI_HOST_CHAN_INT_ACK
421434
| DWHCI_HOST_CHAN_INT_NAK

0 commit comments

Comments
 (0)