User | Revision | Line number | New contents of line |
RichardUK |
0:63d45df56584
|
1
|
/*
|
RichardUK |
0:63d45df56584
|
2
|
A host controller driver from the mBed device.
|
RichardUK |
0:63d45df56584
|
3
|
Copyright (C) 2012 Richard e Collins - richard.collins@linux.com
|
RichardUK |
0:63d45df56584
|
4
|
|
RichardUK |
0:63d45df56584
|
5
|
This program is free software: you can redistribute it and/or modify
|
RichardUK |
0:63d45df56584
|
6
|
it under the terms of the GNU General Public License as published by
|
RichardUK |
0:63d45df56584
|
7
|
the Free Software Foundation, either version 3 of the License, or
|
RichardUK |
0:63d45df56584
|
8
|
(at your option) any later version.
|
RichardUK |
0:63d45df56584
|
9
|
|
RichardUK |
0:63d45df56584
|
10
|
This program is distributed in the hope that it will be useful,
|
RichardUK |
0:63d45df56584
|
11
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
RichardUK |
0:63d45df56584
|
12
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
RichardUK |
0:63d45df56584
|
13
|
GNU General Public License for more details.
|
RichardUK |
0:63d45df56584
|
14
|
|
RichardUK |
0:63d45df56584
|
15
|
You should have received a copy of the GNU General Public License
|
RichardUK |
0:63d45df56584
|
16
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
RichardUK |
0:63d45df56584
|
17
|
*/
|
RichardUK |
0:63d45df56584
|
18
|
|
RichardUK |
0:63d45df56584
|
19
|
#include <mbed.h>
|
RichardUK |
0:63d45df56584
|
20
|
#include "UsbHost.h"
|
RichardUK |
0:63d45df56584
|
21
|
#include "UsbHostController.h"
|
RichardUK |
0:63d45df56584
|
22
|
#include "HardwareDefines.h"
|
RichardUK |
0:63d45df56584
|
23
|
#include "Debug.h"
|
RichardUK |
0:63d45df56584
|
24
|
#include "UsbStructures.h"
|
RichardUK |
0:63d45df56584
|
25
|
#include "UsbEnums.h"
|
RichardUK |
0:63d45df56584
|
26
|
|
RichardUK |
1:4461071ed964
|
27
|
#if 0
|
RichardUK |
1:4461071ed964
|
28
|
#define DEBUGV DEBUG
|
RichardUK |
1:4461071ed964
|
29
|
#else
|
RichardUK |
1:4461071ed964
|
30
|
#define DEBUGV(...) do {} while(0)
|
RichardUK |
0:63d45df56584
|
31
|
#endif
|
RichardUK |
0:63d45df56584
|
32
|
|
RichardUK |
1:4461071ed964
|
33
|
|
RichardUK |
1:4461071ed964
|
34
|
|
RichardUK |
0:63d45df56584
|
35
|
namespace USB
|
RichardUK |
0:63d45df56584
|
36
|
{
|
RichardUK |
0:63d45df56584
|
37
|
|
RichardUK |
0:63d45df56584
|
38
|
uint32_t controlTransferDataLength = 0;
|
RichardUK |
0:63d45df56584
|
39
|
|
RichardUK |
0:63d45df56584
|
40
|
Host::Host()
|
RichardUK |
0:63d45df56584
|
41
|
{
|
RichardUK |
0:63d45df56584
|
42
|
for( int n = 0 ; n < MAX_DEVICES ; n++ )
|
RichardUK |
0:63d45df56584
|
43
|
{
|
RichardUK |
0:63d45df56584
|
44
|
devices[n] = NULL;
|
RichardUK |
0:63d45df56584
|
45
|
}
|
RichardUK |
0:63d45df56584
|
46
|
|
RichardUK |
0:63d45df56584
|
47
|
driver = HostController::get();
|
RichardUK |
0:63d45df56584
|
48
|
driver->Init(this,deviceZero);
|
RichardUK |
0:63d45df56584
|
49
|
}
|
RichardUK |
0:63d45df56584
|
50
|
|
RichardUK |
0:63d45df56584
|
51
|
Host::~Host()
|
RichardUK |
0:63d45df56584
|
52
|
{
|
RichardUK |
0:63d45df56584
|
53
|
}
|
RichardUK |
0:63d45df56584
|
54
|
|
RichardUK |
0:63d45df56584
|
55
|
Device* Host::AllocateDevice(int endpointZeroMaxPacketSize,int hubPortStatus)
|
RichardUK |
0:63d45df56584
|
56
|
{
|
RichardUK |
0:63d45df56584
|
57
|
for( int n = 0 ; n < MAX_DEVICES ; n++ )
|
RichardUK |
0:63d45df56584
|
58
|
{
|
RichardUK |
0:63d45df56584
|
59
|
if( devices[n] == NULL )
|
RichardUK |
0:63d45df56584
|
60
|
{
|
RichardUK |
0:63d45df56584
|
61
|
devices[n] = (Device *)driver->AllocateMemoryPoolItem();
|
RichardUK |
1:4461071ed964
|
62
|
memset(devices[n],0,sizeof(Device));
|
RichardUK |
0:63d45df56584
|
63
|
devices[n]->id = (uint8_t)(n+1);//The device is +1 as device 0 is the host controller.
|
RichardUK |
0:63d45df56584
|
64
|
devices[n]->endpointZeroMaxPacketSize = endpointZeroMaxPacketSize;
|
RichardUK |
0:63d45df56584
|
65
|
devices[n]->lowspeed = (hubPortStatus&ROOTHUB_LOW_SPEED_DEVICE_ATTACHED) ? 1 : 0;
|
RichardUK |
1:4461071ed964
|
66
|
devices[n]->blockOnEP = -1;
|
RichardUK |
0:63d45df56584
|
67
|
return devices[n];
|
RichardUK |
0:63d45df56584
|
68
|
}
|
RichardUK |
0:63d45df56584
|
69
|
}
|
RichardUK |
0:63d45df56584
|
70
|
return NULL;
|
RichardUK |
0:63d45df56584
|
71
|
}
|
RichardUK |
0:63d45df56584
|
72
|
|
RichardUK |
0:63d45df56584
|
73
|
void Host::SendControlTransferData(Device* device,int dataToggle)
|
RichardUK |
0:63d45df56584
|
74
|
{
|
RichardUK |
1:4461071ed964
|
75
|
driver->QueueControlTransfer(
|
RichardUK |
0:63d45df56584
|
76
|
device->id,
|
RichardUK |
0:63d45df56584
|
77
|
device->controlTransferDirToHost == 1 ? TDD_IN : TDD_OUT,
|
RichardUK |
0:63d45df56584
|
78
|
0,
|
RichardUK |
0:63d45df56584
|
79
|
device->endpointZeroMaxPacketSize,
|
RichardUK |
0:63d45df56584
|
80
|
device->lowspeed,
|
RichardUK |
0:63d45df56584
|
81
|
dataToggle,
|
RichardUK |
0:63d45df56584
|
82
|
device->controlTransferData,
|
RichardUK |
0:63d45df56584
|
83
|
device->controlTransferDataLength);
|
RichardUK |
0:63d45df56584
|
84
|
|
RichardUK |
0:63d45df56584
|
85
|
device->controlTransferState = CTS_DATA;
|
RichardUK |
0:63d45df56584
|
86
|
}
|
RichardUK |
0:63d45df56584
|
87
|
|
RichardUK |
0:63d45df56584
|
88
|
void Host::SendControlTransferAcknowledge(Device* device,int dataToggle)
|
RichardUK |
0:63d45df56584
|
89
|
{
|
RichardUK |
0:63d45df56584
|
90
|
//Send empty packet to ACK.
|
RichardUK |
1:4461071ed964
|
91
|
driver->QueueControlTransfer(
|
RichardUK |
0:63d45df56584
|
92
|
device->id,
|
RichardUK |
0:63d45df56584
|
93
|
device->controlTransferDirToHost == 0 ? TDD_IN : TDD_OUT,
|
RichardUK |
0:63d45df56584
|
94
|
0,
|
RichardUK |
0:63d45df56584
|
95
|
device->endpointZeroMaxPacketSize,
|
RichardUK |
0:63d45df56584
|
96
|
device->lowspeed,
|
RichardUK |
0:63d45df56584
|
97
|
dataToggle,
|
RichardUK |
0:63d45df56584
|
98
|
NULL,0);
|
RichardUK |
0:63d45df56584
|
99
|
|
RichardUK |
0:63d45df56584
|
100
|
device->controlTransferState = CTS_ACK;
|
RichardUK |
0:63d45df56584
|
101
|
}
|
RichardUK |
0:63d45df56584
|
102
|
|
RichardUK |
0:63d45df56584
|
103
|
Device* Host::getDevice(int deviceID)
|
RichardUK |
0:63d45df56584
|
104
|
{
|
RichardUK |
0:63d45df56584
|
105
|
if( deviceID == 0 )
|
RichardUK |
0:63d45df56584
|
106
|
{
|
RichardUK |
0:63d45df56584
|
107
|
return deviceZero;
|
RichardUK |
0:63d45df56584
|
108
|
}
|
RichardUK |
0:63d45df56584
|
109
|
|
RichardUK |
0:63d45df56584
|
110
|
deviceID--;
|
RichardUK |
0:63d45df56584
|
111
|
if( deviceID > -1 && deviceID < MAX_DEVICES )
|
RichardUK |
0:63d45df56584
|
112
|
{
|
RichardUK |
0:63d45df56584
|
113
|
return devices[deviceID];
|
RichardUK |
0:63d45df56584
|
114
|
}
|
RichardUK |
0:63d45df56584
|
115
|
return NULL;
|
RichardUK |
0:63d45df56584
|
116
|
}
|
RichardUK |
0:63d45df56584
|
117
|
|
RichardUK |
0:63d45df56584
|
118
|
void Host::Update()
|
RichardUK |
0:63d45df56584
|
119
|
{
|
RichardUK |
0:63d45df56584
|
120
|
driver->Update();
|
RichardUK |
1:4461071ed964
|
121
|
//Now the host has been updated service any outstanding transfers.
|
RichardUK |
1:4461071ed964
|
122
|
for(int n = 0 ; n < MAX_DEVICES ; n++ )
|
RichardUK |
1:4461071ed964
|
123
|
{
|
RichardUK |
1:4461071ed964
|
124
|
if( devices[n] != NULL && devices[n]->pendingCallbacks != NULL )
|
RichardUK |
1:4461071ed964
|
125
|
{
|
RichardUK |
1:4461071ed964
|
126
|
TransferDescriptor *transfer = devices[n]->pendingCallbacks;
|
RichardUK |
1:4461071ed964
|
127
|
devices[n]->pendingCallbacks = NULL;
|
RichardUK |
1:4461071ed964
|
128
|
|
RichardUK |
1:4461071ed964
|
129
|
while( transfer )
|
RichardUK |
1:4461071ed964
|
130
|
{
|
RichardUK |
1:4461071ed964
|
131
|
TransferDescriptor *next = transfer->nextTD;
|
RichardUK |
1:4461071ed964
|
132
|
// DEBUG("onReceive (0x%08x) (0x%08x)",transfer,next);
|
RichardUK |
1:4461071ed964
|
133
|
|
RichardUK |
1:4461071ed964
|
134
|
|
RichardUK |
1:4461071ed964
|
135
|
int deviceEP = transfer->ep | (transfer->direction == TDD_IN ? 0x80 : 0);
|
RichardUK |
1:4461071ed964
|
136
|
int reciveLength = transfer->CurrentBufferPointer - transfer->data;
|
RichardUK |
1:4461071ed964
|
137
|
transfer->transferCallback->onReceive(devices[n]->id,deviceEP,0,transfer->data,reciveLength);
|
RichardUK |
1:4461071ed964
|
138
|
|
RichardUK |
1:4461071ed964
|
139
|
driver->FreeMemoryPoolItem(transfer);
|
RichardUK |
1:4461071ed964
|
140
|
transfer = next;
|
RichardUK |
1:4461071ed964
|
141
|
}
|
RichardUK |
1:4461071ed964
|
142
|
}
|
RichardUK |
1:4461071ed964
|
143
|
}
|
RichardUK |
0:63d45df56584
|
144
|
}
|
RichardUK |
0:63d45df56584
|
145
|
|
RichardUK |
0:63d45df56584
|
146
|
int Host::getDeviceDescriptor(int deviceID,DeviceDescription &description)
|
RichardUK |
0:63d45df56584
|
147
|
{
|
RichardUK |
0:63d45df56584
|
148
|
return ControlTransfer(deviceID,LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_DESCRIPTOR,(LIBUSB_DT_DEVICE << 8), 0, (uint8_t*)&description, sizeof(description),DEFAULT_TIMEOUT);
|
RichardUK |
0:63d45df56584
|
149
|
}
|
RichardUK |
0:63d45df56584
|
150
|
|
RichardUK |
0:63d45df56584
|
151
|
const uint8_t* Host::getConfigurationDescriptor(int deviceID,int index)
|
RichardUK |
0:63d45df56584
|
152
|
{
|
RichardUK |
0:63d45df56584
|
153
|
uint8_t* buf = driver->getScratchRam();
|
RichardUK |
0:63d45df56584
|
154
|
ControlTransfer(deviceID,LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_DESCRIPTOR,(LIBUSB_DT_CONFIG << 8)|index, 0,buf,255,DEFAULT_TIMEOUT);
|
RichardUK |
0:63d45df56584
|
155
|
return (const uint8_t*)buf;
|
RichardUK |
0:63d45df56584
|
156
|
}
|
RichardUK |
0:63d45df56584
|
157
|
|
RichardUK |
0:63d45df56584
|
158
|
const char* Host::getStringDescriptor(int deviceID,int index)
|
RichardUK |
0:63d45df56584
|
159
|
{
|
RichardUK |
0:63d45df56584
|
160
|
Device* dev = getDevice(deviceID);
|
RichardUK |
0:63d45df56584
|
161
|
if( dev == NULL )
|
RichardUK |
0:63d45df56584
|
162
|
{
|
RichardUK |
0:63d45df56584
|
163
|
return "error";
|
RichardUK |
0:63d45df56584
|
164
|
}
|
RichardUK |
0:63d45df56584
|
165
|
|
RichardUK |
0:63d45df56584
|
166
|
uint8_t* buf = driver->getScratchRam();
|
RichardUK |
0:63d45df56584
|
167
|
ControlTransfer(deviceID,LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_DESCRIPTOR,(LIBUSB_DT_STRING << 8)|index, dev->languageID,buf,255,DEFAULT_TIMEOUT);
|
RichardUK |
0:63d45df56584
|
168
|
|
RichardUK |
0:63d45df56584
|
169
|
uint8_t* string = buf;
|
RichardUK |
0:63d45df56584
|
170
|
int len = buf[0];
|
RichardUK |
0:63d45df56584
|
171
|
for( int n = 2 ; n < len ; n += 2 )
|
RichardUK |
0:63d45df56584
|
172
|
{
|
RichardUK |
0:63d45df56584
|
173
|
*string++ = buf[n];
|
RichardUK |
0:63d45df56584
|
174
|
}
|
RichardUK |
0:63d45df56584
|
175
|
*string = 0;
|
RichardUK |
0:63d45df56584
|
176
|
return (char*)buf;
|
RichardUK |
0:63d45df56584
|
177
|
}
|
RichardUK |
0:63d45df56584
|
178
|
|
RichardUK |
0:63d45df56584
|
179
|
int Host::setConfiguration(int deviceID,int configuration)
|
RichardUK |
0:63d45df56584
|
180
|
{
|
RichardUK |
0:63d45df56584
|
181
|
return ControlTransfer(deviceID,LIBUSB_ENDPOINT_OUT, LIBUSB_REQUEST_SET_CONFIGURATION,configuration, 0,NULL,0,DEFAULT_TIMEOUT);
|
RichardUK |
0:63d45df56584
|
182
|
}
|
RichardUK |
0:63d45df56584
|
183
|
|
RichardUK |
0:63d45df56584
|
184
|
/*
|
RichardUK |
0:63d45df56584
|
185
|
* Control transfer uses three stages, the setup stage where the request is sent.
|
RichardUK |
0:63d45df56584
|
186
|
* The optional Data Stage consists of one or multiple IN or OUT transfers.
|
RichardUK |
0:63d45df56584
|
187
|
* The setup request indicates the amount of data to be transmitted in this stage.
|
RichardUK |
0:63d45df56584
|
188
|
* If it exceeds the maximum packet size, data will be sent in multiple transfers each being the maximum packet length except for the last packet.
|
RichardUK |
0:63d45df56584
|
189
|
* Status Stage reports the status of the overall request and this once again varies due to direction of transfer. Status reporting is always performed by the function.
|
RichardUK |
0:63d45df56584
|
190
|
*/
|
RichardUK |
0:63d45df56584
|
191
|
int Host::ControlTransfer(int deviceID,uint8_t requestType, uint8_t request, uint16_t value, uint16_t index,const uint8_t *data, uint16_t length, uint32_t timeout)
|
RichardUK |
0:63d45df56584
|
192
|
{
|
RichardUK |
1:4461071ed964
|
193
|
DEBUGV("ControlTransfer");
|
RichardUK |
0:63d45df56584
|
194
|
|
RichardUK |
0:63d45df56584
|
195
|
Device* device = getDevice(deviceID);
|
RichardUK |
0:63d45df56584
|
196
|
|
RichardUK |
0:63d45df56584
|
197
|
//Remeber the packet we are sending so that when we get the responce from the setup packet we can then ask for or send the data.
|
RichardUK |
0:63d45df56584
|
198
|
device->controlTransferData = data;
|
RichardUK |
0:63d45df56584
|
199
|
device->controlTransferDataLength = length;
|
RichardUK |
0:63d45df56584
|
200
|
device->controlTransferDirToHost = (requestType & LIBUSB_ENDPOINT_IN) ? 1 : 0;
|
RichardUK |
0:63d45df56584
|
201
|
device->controlTransferState = CTS_SETUP;
|
RichardUK |
0:63d45df56584
|
202
|
|
RichardUK |
0:63d45df56584
|
203
|
//First do the setup packet.
|
RichardUK |
0:63d45df56584
|
204
|
SetupPacket* sp = (SetupPacket*)driver->AllocateMemoryPoolItem();
|
RichardUK |
0:63d45df56584
|
205
|
|
RichardUK |
0:63d45df56584
|
206
|
sp->requestType = requestType;
|
RichardUK |
0:63d45df56584
|
207
|
sp->request = request;
|
RichardUK |
0:63d45df56584
|
208
|
sp->value = value;
|
RichardUK |
0:63d45df56584
|
209
|
sp->index = index;
|
RichardUK |
0:63d45df56584
|
210
|
sp->length = length;
|
RichardUK |
0:63d45df56584
|
211
|
|
RichardUK |
1:4461071ed964
|
212
|
DEBUGV("Setup %d %d %d %d %d",sp->requestType,sp->request,sp->value,sp->index,sp->length);
|
RichardUK |
0:63d45df56584
|
213
|
|
RichardUK |
1:4461071ed964
|
214
|
driver->QueueControlTransfer(deviceID,TDD_SETUP,0,device->endpointZeroMaxPacketSize,device->lowspeed,TOGGLE_DATA0,(const uint8_t*)sp,sizeof(SetupPacket));
|
RichardUK |
0:63d45df56584
|
215
|
|
RichardUK |
0:63d45df56584
|
216
|
while(device->controlTransferState != CTS_IDLE)
|
RichardUK |
0:63d45df56584
|
217
|
{
|
RichardUK |
1:4461071ed964
|
218
|
wait_ms(50);
|
RichardUK |
0:63d45df56584
|
219
|
};
|
RichardUK |
0:63d45df56584
|
220
|
|
RichardUK |
0:63d45df56584
|
221
|
//Free this up.
|
RichardUK |
0:63d45df56584
|
222
|
driver->FreeMemoryPoolItem(sp);
|
RichardUK |
1:4461071ed964
|
223
|
DEBUGV("Done, recived %d",controlTransferDataLength);
|
RichardUK |
0:63d45df56584
|
224
|
|
RichardUK |
0:63d45df56584
|
225
|
return 0;
|
RichardUK |
0:63d45df56584
|
226
|
}
|
RichardUK |
0:63d45df56584
|
227
|
|
RichardUK |
1:4461071ed964
|
228
|
int Host::BulkTransfer(int deviceID,uint8_t endpoint,const uint8_t* data,int length,TransferCallback* callback)
|
RichardUK |
0:63d45df56584
|
229
|
{
|
RichardUK |
1:4461071ed964
|
230
|
DEBUGV("BulkTransfer Device(%d) EP(%d) Len(%d) CB(0x%08x)",deviceID,endpoint,length,callback);
|
RichardUK |
0:63d45df56584
|
231
|
|
RichardUK |
0:63d45df56584
|
232
|
Device* device = getDevice(deviceID);
|
RichardUK |
1:4461071ed964
|
233
|
device->blockOnEP = endpoint;
|
RichardUK |
1:4461071ed964
|
234
|
|
RichardUK |
1:4461071ed964
|
235
|
driver->QueueBulkTransfer(deviceID,(endpoint&LIBUSB_ENDPOINT_IN) ? TDD_IN : TDD_OUT,endpoint&0x7f,device->endpointZeroMaxPacketSize,device->lowspeed,callback,data,length);
|
RichardUK |
0:63d45df56584
|
236
|
|
RichardUK |
1:4461071ed964
|
237
|
if( callback == NULL )
|
RichardUK |
0:63d45df56584
|
238
|
{
|
RichardUK |
1:4461071ed964
|
239
|
while( device->blockOnEP == endpoint )
|
RichardUK |
1:4461071ed964
|
240
|
{
|
RichardUK |
1:4461071ed964
|
241
|
driver->Update();
|
RichardUK |
1:4461071ed964
|
242
|
wait_ms(100);
|
RichardUK |
1:4461071ed964
|
243
|
}
|
RichardUK |
1:4461071ed964
|
244
|
}
|
RichardUK |
0:63d45df56584
|
245
|
|
RichardUK |
0:63d45df56584
|
246
|
return 0;
|
RichardUK |
0:63d45df56584
|
247
|
}
|
RichardUK |
0:63d45df56584
|
248
|
|
RichardUK |
0:63d45df56584
|
249
|
|
RichardUK |
0:63d45df56584
|
250
|
void Host::AddDevice(int hub,int port,int hubPortStatus)
|
RichardUK |
0:63d45df56584
|
251
|
{
|
RichardUK |
0:63d45df56584
|
252
|
DEBUG("AddDevice(%d,%d,%08x)",hub,port,hubPortStatus);
|
RichardUK |
0:63d45df56584
|
253
|
DeviceDescription description;
|
RichardUK |
0:63d45df56584
|
254
|
description.length = sizeof(DeviceDescription);
|
RichardUK |
0:63d45df56584
|
255
|
|
RichardUK |
0:63d45df56584
|
256
|
//Setup device zero.
|
RichardUK |
0:63d45df56584
|
257
|
deviceZero->endpointZeroMaxPacketSize = 8;
|
RichardUK |
0:63d45df56584
|
258
|
deviceZero->lowspeed = (hubPortStatus&ROOTHUB_LOW_SPEED_DEVICE_ATTACHED) ? 1 : 0;
|
RichardUK |
0:63d45df56584
|
259
|
|
RichardUK |
0:63d45df56584
|
260
|
//For the enumeration we'll use device zero, once done will set the device address and get the rest of the details.
|
RichardUK |
0:63d45df56584
|
261
|
//Now we add the first endpoint, endpoint zero by default.
|
RichardUK |
0:63d45df56584
|
262
|
//Once added we'll read the device's config and add endpoints for them.
|
RichardUK |
0:63d45df56584
|
263
|
//I add my endpoints to the host controller and leave them there.
|
RichardUK |
0:63d45df56584
|
264
|
//I set the direction code so that the direction is read from the transfer descriptor.
|
RichardUK |
0:63d45df56584
|
265
|
//This means that I need less endpoint objects.
|
RichardUK |
0:63d45df56584
|
266
|
//I leave them attached with not transfers to do. That is ok and as per the spec.
|
RichardUK |
0:63d45df56584
|
267
|
//Old devices may only have a max packet size of 8 bytes.
|
RichardUK |
0:63d45df56584
|
268
|
|
RichardUK |
0:63d45df56584
|
269
|
//Using device 0 for the setup and enum phase of the newley connected device.
|
RichardUK |
0:63d45df56584
|
270
|
//We do this just to get some info on the device and then send a 'set address' command.
|
RichardUK |
0:63d45df56584
|
271
|
//At that point we'll start using it's real ID.
|
RichardUK |
1:4461071ed964
|
272
|
DEBUGV("Getting endpoint zero maxPacketSize");
|
RichardUK |
0:63d45df56584
|
273
|
ControlTransfer(0,LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_DESCRIPTOR,(LIBUSB_DT_DEVICE << 8), 0, (uint8_t*)&description,8,DEFAULT_TIMEOUT);
|
RichardUK |
0:63d45df56584
|
274
|
|
RichardUK |
0:63d45df56584
|
275
|
|
RichardUK |
0:63d45df56584
|
276
|
//Now allocate the device and it's ID.
|
RichardUK |
1:4461071ed964
|
277
|
DEBUGV("Allocating device");
|
RichardUK |
0:63d45df56584
|
278
|
Device* device = AllocateDevice(description.maxPacketSize,hubPortStatus);
|
RichardUK |
0:63d45df56584
|
279
|
|
RichardUK |
0:63d45df56584
|
280
|
//Now correct the endpoint's max packet size. Needs this for when we setup the endpoint descriptor for a transfer.
|
RichardUK |
1:4461071ed964
|
281
|
DEBUGV("endpointZeroMaxPacketSize(%d)",device->endpointZeroMaxPacketSize);
|
RichardUK |
0:63d45df56584
|
282
|
|
RichardUK |
0:63d45df56584
|
283
|
//Set the devices new address.
|
RichardUK |
1:4461071ed964
|
284
|
DEBUGV("Setting device address to %d",device->id);
|
RichardUK |
0:63d45df56584
|
285
|
ControlTransfer(0,LIBUSB_ENDPOINT_OUT | LIBUSB_RECIPIENT_DEVICE, LIBUSB_REQUEST_SET_ADDRESS, device->id,0,NULL,0,DEFAULT_TIMEOUT);
|
RichardUK |
0:63d45df56584
|
286
|
|
RichardUK |
0:63d45df56584
|
287
|
//New ID is now set, so we can free the object used when it was called device zero.
|
RichardUK |
0:63d45df56584
|
288
|
driver->DetachDevice(0);
|
RichardUK |
0:63d45df56584
|
289
|
|
RichardUK |
0:63d45df56584
|
290
|
//Now fetch the full device description.
|
RichardUK |
1:4461071ed964
|
291
|
DEBUGV("Getting device description");
|
RichardUK |
0:63d45df56584
|
292
|
getDeviceDescriptor(device->id,description);
|
RichardUK |
0:63d45df56584
|
293
|
|
RichardUK |
1:4461071ed964
|
294
|
DEBUGV("idVendor(0x%04x) idProduct(0x%04x)",description.idVendor,description.idProduct);
|
RichardUK |
0:63d45df56584
|
295
|
|
RichardUK |
0:63d45df56584
|
296
|
//Get the language ID.
|
RichardUK |
0:63d45df56584
|
297
|
uint16_t* lang = (uint16_t*)driver->AllocateMemoryPoolItem();
|
RichardUK |
0:63d45df56584
|
298
|
ControlTransfer(device->id,LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_DESCRIPTOR,LIBUSB_DT_STRING<<8,0,(uint8_t*)lang,16,DEFAULT_TIMEOUT);
|
RichardUK |
0:63d45df56584
|
299
|
device->languageID = lang[1];
|
RichardUK |
0:63d45df56584
|
300
|
driver->FreeMemoryPoolItem(lang);
|
RichardUK |
0:63d45df56584
|
301
|
|
RichardUK |
0:63d45df56584
|
302
|
//Set the first config by default, will get most things up and running.
|
RichardUK |
0:63d45df56584
|
303
|
const USB::ConfigurationDescription* config = (const USB::ConfigurationDescription*)getConfigurationDescriptor(device->id,0);
|
RichardUK |
0:63d45df56584
|
304
|
wait_ms(100);
|
RichardUK |
0:63d45df56584
|
305
|
setConfiguration(device->id,config->configID);
|
RichardUK |
0:63d45df56584
|
306
|
wait_ms(100);
|
RichardUK |
0:63d45df56584
|
307
|
|
RichardUK |
0:63d45df56584
|
308
|
//Tell the app's inherted code about this new device.
|
RichardUK |
0:63d45df56584
|
309
|
onConnected(device->id,description);
|
RichardUK |
0:63d45df56584
|
310
|
}
|
RichardUK |
0:63d45df56584
|
311
|
|
RichardUK |
0:63d45df56584
|
312
|
void Host::TransferDone(TransferDescriptor *transfer)
|
RichardUK |
0:63d45df56584
|
313
|
{
|
RichardUK |
1:4461071ed964
|
314
|
//This is the endpoint with the dir encoded into it, the way it is done to the applicaition coder.
|
RichardUK |
1:4461071ed964
|
315
|
//Needed when we are blocking for a non interput transfer to finish.
|
RichardUK |
1:4461071ed964
|
316
|
int epDir = transfer->ep | (transfer->direction==TDD_IN?0x80:0);
|
RichardUK |
1:4461071ed964
|
317
|
DEBUGV("TransferDone, device(%d) ep(%d) errorCount(%d) status(%d) direction(%d) dataToggle(%d)",transfer->deviceID,epDir,transfer->errorCount,transfer->conditionCode,transfer->direction,transfer->dataToggle);
|
RichardUK |
0:63d45df56584
|
318
|
|
RichardUK |
0:63d45df56584
|
319
|
//Get the device this TD that has just been done for.
|
RichardUK |
0:63d45df56584
|
320
|
Device* device = getDevice(transfer->deviceID);
|
RichardUK |
0:63d45df56584
|
321
|
|
RichardUK |
1:4461071ed964
|
322
|
if( transfer->transferType == TT_CONTROL )
|
RichardUK |
0:63d45df56584
|
323
|
{
|
RichardUK |
1:4461071ed964
|
324
|
//See if this was a setup packet, if so do we have data to ask for, if not then just ack the transaction.
|
RichardUK |
1:4461071ed964
|
325
|
//TODO: Error checking!
|
RichardUK |
1:4461071ed964
|
326
|
switch( device->controlTransferState )
|
RichardUK |
0:63d45df56584
|
327
|
{
|
RichardUK |
1:4461071ed964
|
328
|
case CTS_SETUP:
|
RichardUK |
1:4461071ed964
|
329
|
if( device->controlTransferData != NULL )
|
RichardUK |
1:4461071ed964
|
330
|
{
|
RichardUK |
1:4461071ed964
|
331
|
SendControlTransferData(device,transfer->dataToggle);
|
RichardUK |
1:4461071ed964
|
332
|
}
|
RichardUK |
1:4461071ed964
|
333
|
else
|
RichardUK |
1:4461071ed964
|
334
|
{
|
RichardUK |
1:4461071ed964
|
335
|
SendControlTransferAcknowledge(device,transfer->dataToggle);
|
RichardUK |
1:4461071ed964
|
336
|
}
|
RichardUK |
1:4461071ed964
|
337
|
break;
|
RichardUK |
1:4461071ed964
|
338
|
|
RichardUK |
1:4461071ed964
|
339
|
case CTS_DATA:
|
RichardUK |
1:4461071ed964
|
340
|
controlTransferDataLength = (transfer->bufferEnd - device->controlTransferData) + 1;
|
RichardUK |
0:63d45df56584
|
341
|
SendControlTransferAcknowledge(device,transfer->dataToggle);
|
RichardUK |
1:4461071ed964
|
342
|
break;
|
RichardUK |
1:4461071ed964
|
343
|
|
RichardUK |
1:4461071ed964
|
344
|
case CTS_ACK:
|
RichardUK |
1:4461071ed964
|
345
|
device->controlTransferState = CTS_IDLE;
|
RichardUK |
1:4461071ed964
|
346
|
break;
|
RichardUK |
0:63d45df56584
|
347
|
}
|
RichardUK |
1:4461071ed964
|
348
|
}
|
RichardUK |
1:4461071ed964
|
349
|
|
RichardUK |
1:4461071ed964
|
350
|
if( transfer->transferCallback != NULL )
|
RichardUK |
1:4461071ed964
|
351
|
{
|
RichardUK |
1:4461071ed964
|
352
|
transfer->nextTD = device->pendingCallbacks;
|
RichardUK |
1:4461071ed964
|
353
|
device->pendingCallbacks = transfer;
|
RichardUK |
1:4461071ed964
|
354
|
}
|
RichardUK |
1:4461071ed964
|
355
|
|
RichardUK |
1:4461071ed964
|
356
|
if( device->blockOnEP == epDir )
|
RichardUK |
1:4461071ed964
|
357
|
{
|
RichardUK |
1:4461071ed964
|
358
|
device->blockOnEP = -1;
|
RichardUK |
1:4461071ed964
|
359
|
}
|
RichardUK |
0:63d45df56584
|
360
|
|
RichardUK |
0:63d45df56584
|
361
|
}
|
RichardUK |
0:63d45df56584
|
362
|
|
RichardUK |
0:63d45df56584
|
363
|
};//namespace USB
|