Added new HOST_STATE_WaitForDeviceRemoval host state machine state for non-blocking...
[pub/USBasp.git] / LUFA / Drivers / USB / LowLevel / Host.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2009.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
7 */
8
9 /*
10 Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, and distribute this software
13 and its documentation for any purpose and without fee is hereby
14 granted, provided that the above copyright notice appear in all
15 copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaim all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29 */
30
31 #include "../HighLevel/USBMode.h"
32
33 #if defined(USB_CAN_BE_HOST)
34
35 #define INCLUDE_FROM_HOST_C
36 #include "Host.h"
37
38 void USB_Host_ProcessNextHostState(void)
39 {
40 uint8_t ErrorCode = HOST_ENUMERROR_NoError;
41 uint8_t SubErrorCode = HOST_ENUMERROR_NoError;
42
43 static uint16_t WaitMSRemaining;
44 static uint8_t PostWaitState;
45
46 switch (USB_HostState)
47 {
48 case HOST_STATE_WaitForDevice:
49 if (WaitMSRemaining)
50 {
51 if ((SubErrorCode = USB_Host_WaitMS(1)) != HOST_WAITERROR_Successful)
52 {
53 USB_HostState = PostWaitState;
54 ErrorCode = HOST_ENUMERROR_WaitStage;
55 break;
56 }
57
58 if (!(--WaitMSRemaining))
59 USB_HostState = PostWaitState;
60 }
61
62 break;
63 case HOST_STATE_Attached:
64 WaitMSRemaining = HOST_DEVICE_SETTLE_DELAY_MS;
65
66 USB_HostState = HOST_STATE_Attached_WaitForDeviceSettle;
67 break;
68 case HOST_STATE_Attached_WaitForDeviceSettle:
69 #if HOST_DEVICE_SETTLE_DELAY_MS > 0
70 _delay_ms(1);
71
72 if (!(WaitMSRemaining--))
73 {
74 USB_Host_VBUS_Manual_Off();
75
76 USB_OTGPAD_On();
77 USB_Host_VBUS_Auto_Enable();
78 USB_Host_VBUS_Auto_On();
79
80 USB_HostState = HOST_STATE_Attached_WaitForConnect;
81 }
82 #else
83 USB_HostState = HOST_STATE_Attached_WaitForConnect;
84 #endif
85
86 break;
87 case HOST_STATE_Attached_WaitForConnect:
88 if (USB_INT_HasOccurred(USB_INT_DCONNI))
89 {
90 USB_INT_Clear(USB_INT_DCONNI);
91 USB_INT_Clear(USB_INT_DDISCI);
92
93 USB_INT_Clear(USB_INT_VBERRI);
94 USB_INT_Enable(USB_INT_VBERRI);
95
96 USB_IsConnected = true;
97 EVENT_USB_Connect();
98
99 USB_Host_ResumeBus();
100 Pipe_ClearPipes();
101
102 HOST_TASK_NONBLOCK_WAIT(100, HOST_STATE_Attached_DoReset);
103 }
104
105 break;
106 case HOST_STATE_Attached_DoReset:
107 USB_Host_ResetDevice();
108
109 HOST_TASK_NONBLOCK_WAIT(200, HOST_STATE_Powered);
110 break;
111 case HOST_STATE_Powered:
112 Pipe_ConfigurePipe(PIPE_CONTROLPIPE, EP_TYPE_CONTROL,
113 PIPE_TOKEN_SETUP, ENDPOINT_CONTROLEP,
114 PIPE_CONTROLPIPE_DEFAULT_SIZE, PIPE_BANK_SINGLE);
115
116 if (!(Pipe_IsConfigured()))
117 {
118 ErrorCode = HOST_ENUMERROR_PipeConfigError;
119 SubErrorCode = 0;
120 break;
121 }
122
123 USB_HostState = HOST_STATE_Default;
124 break;
125 case HOST_STATE_Default:
126 USB_ControlRequest = (USB_Request_Header_t)
127 {
128 .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE),
129 .bRequest = REQ_GetDescriptor,
130 .wValue = (DTYPE_Device << 8),
131 .wIndex = 0,
132 .wLength = 8,
133 };
134
135 uint8_t DataBuffer[8];
136
137 if ((SubErrorCode = USB_Host_SendControlRequest(DataBuffer)) != HOST_SENDCONTROL_Successful)
138 {
139 ErrorCode = HOST_ENUMERROR_ControlError;
140 break;
141 }
142
143 #if defined(USE_NONSTANDARD_DESCRIPTOR_NAMES)
144 USB_ControlPipeSize = DataBuffer[offsetof(USB_Descriptor_Device_t, Endpoint0Size)];
145 #else
146 USB_ControlPipeSize = DataBuffer[offsetof(USB_Descriptor_Device_t, bMaxPacketSize0)];
147 #endif
148
149 USB_Host_ResetDevice();
150
151 HOST_TASK_NONBLOCK_WAIT(200, HOST_STATE_Default_PostReset);
152 break;
153 case HOST_STATE_Default_PostReset:
154 Pipe_DisablePipe();
155 Pipe_DeallocateMemory();
156 Pipe_ResetPipe(PIPE_CONTROLPIPE);
157
158 Pipe_ConfigurePipe(PIPE_CONTROLPIPE, EP_TYPE_CONTROL,
159 PIPE_TOKEN_SETUP, ENDPOINT_CONTROLEP,
160 USB_ControlPipeSize, PIPE_BANK_SINGLE);
161
162 if (!(Pipe_IsConfigured()))
163 {
164 ErrorCode = HOST_ENUMERROR_PipeConfigError;
165 SubErrorCode = 0;
166 break;
167 }
168
169 USB_ControlRequest = (USB_Request_Header_t)
170 {
171 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_DEVICE),
172 .bRequest = REQ_SetAddress,
173 .wValue = USB_HOST_DEVICEADDRESS,
174 .wIndex = 0,
175 .wLength = 0,
176 };
177
178 if ((SubErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful)
179 {
180 ErrorCode = HOST_ENUMERROR_ControlError;
181 break;
182 }
183
184 HOST_TASK_NONBLOCK_WAIT(100, HOST_STATE_Default_PostAddressSet);
185 break;
186 case HOST_STATE_Default_PostAddressSet:
187 USB_Host_SetDeviceAddress(USB_HOST_DEVICEADDRESS);
188
189 EVENT_USB_DeviceEnumerationComplete();
190 USB_HostState = HOST_STATE_Addressed;
191
192 break;
193 }
194
195 if ((ErrorCode != HOST_ENUMERROR_NoError) && (USB_HostState != HOST_STATE_Unattached))
196 {
197 EVENT_USB_DeviceEnumerationFailed(ErrorCode, SubErrorCode);
198
199 USB_Host_VBUS_Auto_Off();
200
201 EVENT_USB_DeviceUnattached();
202
203 if (USB_IsConnected)
204 EVENT_USB_Disconnect();
205
206 USB_ResetInterface();
207 }
208 }
209
210 uint8_t USB_Host_WaitMS(uint8_t MS)
211 {
212 bool BusSuspended = USB_Host_IsBusSuspended();
213 uint8_t ErrorCode = HOST_WAITERROR_Successful;
214
215 USB_Host_ResumeBus();
216
217 while (MS)
218 {
219 if (USB_INT_HasOccurred(USB_INT_HSOFI))
220 {
221 USB_INT_Clear(USB_INT_HSOFI);
222 MS--;
223 }
224
225 if ((USB_IsConnected == false) || (USB_CurrentMode == USB_MODE_DEVICE))
226 {
227 ErrorCode = HOST_WAITERROR_DeviceDisconnect;
228
229 break;
230 }
231
232 if (Pipe_IsError() == true)
233 {
234 Pipe_ClearError();
235 ErrorCode = HOST_WAITERROR_PipeError;
236
237 break;
238 }
239
240 if (Pipe_IsStalled() == true)
241 {
242 Pipe_ClearStall();
243 ErrorCode = HOST_WAITERROR_SetupStalled;
244
245 break;
246 }
247 }
248
249 if (BusSuspended)
250 USB_Host_SuspendBus();
251
252 return ErrorCode;
253 }
254
255 static void USB_Host_ResetDevice(void)
256 {
257 bool BusSuspended = USB_Host_IsBusSuspended();
258
259 USB_INT_Disable(USB_INT_DDISCI);
260
261 USB_Host_ResetBus();
262 while (!(USB_Host_IsBusResetComplete()));
263
264 USB_Host_ResumeBus();
265
266 USB_INT_Clear(USB_INT_HSOFI);
267
268 for (uint8_t MSRem = 10; MSRem != 0; MSRem--)
269 {
270 /* Workaround for powerless-pull-up devices. After a USB bus reset,
271 all disconnection interrupts are suppressed while a USB frame is
272 looked for - if it is found within 10ms, the device is still
273 present. */
274
275 if (USB_INT_HasOccurred(USB_INT_HSOFI))
276 {
277 USB_INT_Clear(USB_INT_HSOFI);
278 USB_INT_Clear(USB_INT_DDISCI);
279 break;
280 }
281
282 _delay_ms(1);
283 }
284
285 if (BusSuspended)
286 USB_Host_SuspendBus();
287
288 USB_INT_Enable(USB_INT_DDISCI);
289 }
290
291 uint8_t USB_Host_SetDeviceConfiguration(uint8_t ConfigNumber)
292 {
293 USB_ControlRequest = (USB_Request_Header_t)
294 {
295 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_DEVICE),
296 .bRequest = REQ_SetConfiguration,
297 .wValue = ConfigNumber,
298 .wIndex = 0,
299 .wLength = 0,
300 };
301
302 Pipe_SelectPipe(PIPE_CONTROLPIPE);
303
304 return USB_Host_SendControlRequest(NULL);
305 }
306
307 uint8_t USB_Host_GetDeviceDescriptor(void* DeviceDescriptorPtr)
308 {
309 USB_ControlRequest = (USB_Request_Header_t)
310 {
311 bmRequestType: (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE),
312 bRequest: REQ_GetDescriptor,
313 wValue: (DTYPE_Device << 8),
314 wIndex: 0,
315 wLength: sizeof(USB_Descriptor_Device_t),
316 };
317
318 Pipe_SelectPipe(PIPE_CONTROLPIPE);
319
320 return USB_Host_SendControlRequest(DeviceDescriptorPtr);
321 }
322
323 uint8_t USB_Host_ClearPipeStall(uint8_t EndpointNum)
324 {
325 if (Pipe_GetPipeToken() == PIPE_TOKEN_IN)
326 EndpointNum |= (1 << 7);
327
328 USB_ControlRequest = (USB_Request_Header_t)
329 {
330 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_ENDPOINT),
331 .bRequest = REQ_ClearFeature,
332 .wValue = FEATURE_ENDPOINT_HALT,
333 .wIndex = EndpointNum,
334 .wLength = 0,
335 };
336
337 Pipe_SelectPipe(PIPE_CONTROLPIPE);
338
339 return USB_Host_SendControlRequest(NULL);
340 }
341
342 #endif