CDC.c 13.5 KB
Newer Older
1
2
/*
             LUFA Library
Dean Camera's avatar
Dean Camera committed
3
     Copyright (C) Dean Camera, 2010.
4
5
6
7
8
9
              
  dean [at] fourwalledcubicle [dot] com
      www.fourwalledcubicle.com
*/

/*
Dean Camera's avatar
Dean Camera committed
10
  Copyright 2010  Dean Camera (dean [at] fourwalledcubicle [dot] com)
11

12
13
14
15
16
17
18
  Permission to use, copy, modify, distribute, and sell this 
  software and its documentation for any purpose is hereby granted
  without fee, provided that the above copyright notice appear in 
  all copies and that both that the copyright notice and this
  permission notice and warranty disclaimer appear in supporting 
  documentation, and that the name of the author not be used in 
  advertising or publicity pertaining to distribution of the 
19
20
21
22
23
24
25
26
27
28
29
30
  software without specific, written prior permission.

  The author disclaim all warranties with regard to this
  software, including all implied warranties of merchantability
  and fitness.  In no event shall the author be liable for any
  special, indirect or consequential damages or any damages
  whatsoever resulting from loss of use, data or profits, whether
  in an action of contract, negligence or other tortious action,
  arising out of or in connection with the use or performance of
  this software.
*/

31
#define  __INCLUDE_FROM_USB_DRIVER
32
33
34
#include "../../HighLevel/USBMode.h"
#if defined(USB_CAN_BE_HOST)

35
36
#define  __INCLUDE_FROM_CDC_CLASS_HOST_C
#define  __INCLUDE_FROM_CDC_DRIVER
37
38
#include "CDC.h"

39
uint8_t CDC_Host_ConfigurePipes(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, uint16_t ConfigDescriptorSize,
40
                                void* ConfigDescriptorData)
41
{
42
	uint8_t FoundEndpoints = 0;
43

44
45
	memset(&CDCInterfaceInfo->State, 0x00, sizeof(CDCInterfaceInfo->State));

46
	if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
47
	  return CDC_ENUMERROR_InvalidConfigDescriptor;
48
49
50
51
	
	if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
	                              DComp_CDC_Host_NextCDCControlInterface) != DESCRIPTOR_SEARCH_COMP_Found)
	{
52
		return CDC_ENUMERROR_NoCDCInterfaceFound;
53
	}
54
	
55
	CDCInterfaceInfo->State.ControlInterfaceNumber = DESCRIPTOR_CAST(ConfigDescriptorData, USB_Descriptor_Interface_t).InterfaceNumber;
56

57
	while (FoundEndpoints != (CDC_FOUND_NOTIFICATION_IN | CDC_FOUND_DATAPIPE_IN | CDC_FOUND_DATAPIPE_OUT))
58
59
	{
		if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
60
		                              DComp_CDC_Host_NextCDCInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
61
		{
62
			if (FoundEndpoints & CDC_FOUND_NOTIFICATION_IN)
63
64
65
66
			{
				if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData, 
				                              DComp_CDC_Host_NextCDCDataInterface) != DESCRIPTOR_SEARCH_COMP_Found)
				{
67
					return CDC_ENUMERROR_NoCDCInterfaceFound;
68
69
70
71
72
73
				}
			}
			else
			{
				FoundEndpoints = 0;

74
				Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber);
75
				Pipe_DisablePipe();
76
				Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
77
				Pipe_DisablePipe();
78
				Pipe_SelectPipe(CDCInterfaceInfo->Config.NotificationPipeNumber);
79
80
81
82
83
				Pipe_DisablePipe();
			
				if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
				                              DComp_CDC_Host_NextCDCControlInterface) != DESCRIPTOR_SEARCH_COMP_Found)
				{
84
					return CDC_ENUMERROR_NoCDCInterfaceFound;
85
86
87
88
				}
			}

			if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
89
			                              DComp_CDC_Host_NextCDCInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
90
			{
91
				return CDC_ENUMERROR_EndpointsNotFound;
92
93
94
95
96
97
98
99
			}
		}
		
		USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);

		if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT)
		{
			if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
100
			{
101
				Pipe_ConfigurePipe(CDCInterfaceInfo->Config.NotificationPipeNumber, EP_TYPE_INTERRUPT, PIPE_TOKEN_IN,
102
103
								   EndpointData->EndpointAddress, EndpointData->EndpointSize,
								   CDCInterfaceInfo->Config.NotificationPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
104
				CDCInterfaceInfo->State.NotificationPipeSize = EndpointData->EndpointSize;
105
106
107

				Pipe_SetInterruptPeriod(EndpointData->PollingIntervalMS);
				
108
				FoundEndpoints |= CDC_FOUND_NOTIFICATION_IN;
109
110
111
112
113
114
			}
		}
		else
		{
			if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
			{
115
				Pipe_ConfigurePipe(CDCInterfaceInfo->Config.DataINPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_IN,
116
117
				                   EndpointData->EndpointAddress, EndpointData->EndpointSize, 
				                   CDCInterfaceInfo->Config.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
118

119
				CDCInterfaceInfo->State.DataINPipeSize = EndpointData->EndpointSize;
120

121
				FoundEndpoints |= CDC_FOUND_DATAPIPE_IN;
122
123
124
			}
			else
			{
125
126
127
128
				Pipe_ConfigurePipe(CDCInterfaceInfo->Config.DataOUTPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_OUT,
								   EndpointData->EndpointAddress, EndpointData->EndpointSize, 
								   CDCInterfaceInfo->Config.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
			
129
				CDCInterfaceInfo->State.DataOUTPipeSize = EndpointData->EndpointSize;
130
				
131
				FoundEndpoints |= CDC_FOUND_DATAPIPE_OUT;
132
133
134
135
			}
		}
	}

136
137
	CDCInterfaceInfo->State.ControlLineStates.HostToDevice = (CDC_CONTROL_LINE_OUT_RTS | CDC_CONTROL_LINE_OUT_DTR);
	CDCInterfaceInfo->State.ControlLineStates.DeviceToHost = (CDC_CONTROL_LINE_IN_DCD  | CDC_CONTROL_LINE_IN_DSR);
138
	CDCInterfaceInfo->State.IsActive = true;
139
	return CDC_ENUMERROR_NoError;
140
141
}

142
static uint8_t DComp_CDC_Host_NextCDCControlInterface(void* const CurrentDescriptor)
143
144
145
{
	if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
	{
146
147
148
149
150
151
		USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,
		                                                                USB_Descriptor_Interface_t);
	
		if ((CurrentInterface->Class    == CDC_CONTROL_CLASS)    &&
		    (CurrentInterface->SubClass == CDC_CONTROL_SUBCLASS) &&
			(CurrentInterface->Protocol == CDC_CONTROL_PROTOCOL))
152
153
154
155
156
157
158
159
		{
			return DESCRIPTOR_SEARCH_Found;
		}
	}
	
	return DESCRIPTOR_SEARCH_NotFound;
}

160
static uint8_t DComp_CDC_Host_NextCDCDataInterface(void* const CurrentDescriptor)
161
162
163
{
	if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
	{
164
165
166
167
168
169
		USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,
		                                                                USB_Descriptor_Interface_t);
	
		if ((CurrentInterface->Class    == CDC_DATA_CLASS)    &&
		    (CurrentInterface->SubClass == CDC_DATA_SUBCLASS) &&
			(CurrentInterface->Protocol == CDC_DATA_PROTOCOL))
170
171
172
173
174
175
176
177
		{
			return DESCRIPTOR_SEARCH_Found;
		}
	}
	
	return DESCRIPTOR_SEARCH_NotFound;
}

178
static uint8_t DComp_CDC_Host_NextCDCInterfaceEndpoint(void* const CurrentDescriptor)
179
180
181
{
	if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint)
	{
182
		USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor,
183
		                                                              USB_Descriptor_Endpoint_t);
184
185
	
		uint8_t EndpointType = (CurrentEndpoint->Attributes & EP_TYPE_MASK);
186
	
187
188
		if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) &&
		    !(Pipe_IsEndpointBound(CurrentEndpoint->EndpointAddress)))
189
190
191
		{
			return DESCRIPTOR_SEARCH_Found;
		}
192
193
194
195
196
197
198
199
200
	}
	else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
	{
		return DESCRIPTOR_SEARCH_Fail;
	}

	return DESCRIPTOR_SEARCH_NotFound;
}

201
void CDC_Host_USBTask(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
202
{
203
	if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
204
205
	  return;
	
206
207
	Pipe_SelectPipe(CDCInterfaceInfo->Config.NotificationPipeNumber);
	Pipe_SetPipeToken(PIPE_TOKEN_IN);
208
209
210
211
212
	Pipe_Unfreeze();

	if (Pipe_IsINReceived())
	{
		USB_Request_Header_t Notification;
213
		Pipe_Read_Stream_LE(&Notification, sizeof(USB_Request_Header_t), NO_STREAM_CALLBACK);
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
		
		if ((Notification.bRequest      == NOTIF_SerialState) &&
		    (Notification.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)))
		{
			Pipe_Read_Stream_LE(&CDCInterfaceInfo->State.ControlLineStates.DeviceToHost,
			                    sizeof(CDCInterfaceInfo->State.ControlLineStates.DeviceToHost),
			                    NO_STREAM_CALLBACK);
			
		}

		Pipe_ClearIN();

		EVENT_CDC_Host_ControLineStateChanged(CDCInterfaceInfo);
	}
	
	Pipe_Freeze();
230
231
}

232
uint8_t CDC_Host_SetLineEncoding(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
233
234
235
236
{
	USB_ControlRequest = (USB_Request_Header_t)
	{
		.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
237
		.bRequest      = REQ_SetLineEncoding,
238
239
240
241
242
243
244
245
246
247
		.wValue        = 0,
		.wIndex        = CDCInterfaceInfo->State.ControlInterfaceNumber,
		.wLength       = sizeof(CDCInterfaceInfo->State.LineEncoding),
	};

	Pipe_SelectPipe(PIPE_CONTROLPIPE);
	
	return USB_Host_SendControlRequest(&CDCInterfaceInfo->State.LineEncoding);
}

248
uint8_t CDC_Host_SendControlLineStateChange(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
{
	USB_ControlRequest = (USB_Request_Header_t)
	{
		.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
		.bRequest      = REQ_SetControlLineState,
		.wValue        = CDCInterfaceInfo->State.ControlLineStates.HostToDevice,
		.wIndex        = CDCInterfaceInfo->State.ControlInterfaceNumber,
		.wLength       = 0,
	};

	Pipe_SelectPipe(PIPE_CONTROLPIPE);
	
	return USB_Host_SendControlRequest(NULL);
}

264
uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, char* Data, const uint16_t Length)
265
{
266
	if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
267
	  return PIPE_READYWAIT_DeviceDisconnected;
268

269
270
	uint8_t ErrorCode;

271
	Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);	
272

273
	Pipe_Unfreeze();
274
	ErrorCode = Pipe_Write_Stream_LE(Data, Length, NO_STREAM_CALLBACK);
275
	Pipe_Freeze();
276
277
	
	return ErrorCode;
278
279
}

280
uint8_t CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo, const uint8_t Data)
281
{
282
	if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
283
	  return PIPE_READYWAIT_DeviceDisconnected;
284
	  
285
	uint8_t ErrorCode;
286

287
	Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);	
288
289
290
291
292
	Pipe_Unfreeze();
	
	if (!(Pipe_IsReadWriteAllowed()))
	{
		Pipe_ClearOUT();
293
294
295

		if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
		  return ErrorCode;
296
297
298
299
	}

	Pipe_Write_Byte(Data);	
	Pipe_Freeze();
300
	
301
	return PIPE_READYWAIT_NoError;
302
303
}

304
uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
305
306
307
{
	uint16_t BytesInPipe = 0;

308
	if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
309
	  return 0;
310
	
311
312
	Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber);
	Pipe_SetPipeToken(PIPE_TOKEN_IN);
313
314
	Pipe_Unfreeze();

315
316
317
	if (Pipe_IsINReceived())
	{
		if (!(Pipe_BytesInPipe()))
318
319
320
321
322
323
324
325
326
327
		{
			Pipe_ClearIN();
			Pipe_Freeze();
			return 0;
		}
		else
		{
			Pipe_Freeze();
			return Pipe_BytesInPipe();
		}
328
329
330
331
332
333
334
	}
	else
	{
		Pipe_Freeze();
		
		return 0;
	}
335
336
}

337
uint8_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
338
339
340
{
	uint8_t ReceivedByte = 0;

341
	if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
342
	  return 0;
343
	  
344
345
	Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber);
	Pipe_SetPipeToken(PIPE_TOKEN_IN);
346
347
348
349
350
351
352
353
354
355
356
357
	Pipe_Unfreeze();

	ReceivedByte = Pipe_Read_Byte();
	
	if (!(Pipe_BytesInPipe()))
	  Pipe_ClearIN();
	
	Pipe_Freeze();
	
	return ReceivedByte;
}

358
359
360
361
362
363
364
uint8_t CDC_Host_Flush(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
{
	if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
	  return PIPE_READYWAIT_DeviceDisconnected;
	  
	uint8_t ErrorCode;

365
	Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);	
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
	Pipe_Unfreeze();
	
	if (!(Pipe_BytesInPipe()))
	  return PIPE_READYWAIT_NoError;

	bool BankFull = !(Pipe_IsReadWriteAllowed());

	Pipe_ClearOUT();

	if (BankFull)
	{
		if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
		  return ErrorCode;

		Pipe_ClearOUT();
	}

	Pipe_Freeze();
	
	return PIPE_READYWAIT_NoError;
}

388
389
390
391
392
393
void CDC_Host_CreateStream(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo, FILE* Stream)
{
	*Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar, _FDEV_SETUP_RW);
	fdev_set_udata(Stream, CDCInterfaceInfo);
}

394
395
396
397
398
399
void CDC_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t* CDCInterfaceInfo, FILE* Stream)
{
	*Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar_Blocking, _FDEV_SETUP_RW);
	fdev_set_udata(Stream, CDCInterfaceInfo);
}

400
401
static int CDC_Host_putchar(char c, FILE* Stream)
{
402
	return CDC_Host_SendByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream), c) ? _FDEV_ERR : 0;
403
404
405
406
407
}

static int CDC_Host_getchar(FILE* Stream)
{
	if (!(CDC_Host_BytesReceived((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream))))
408
	  return _FDEV_EOF;
409
410
411
412

	return CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
}

413
414
415
416
static int CDC_Host_getchar_Blocking(FILE* Stream)
{
	while (!(CDC_Host_BytesReceived((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream))))
	{
417
418
419
		if (USB_HostState == HOST_STATE_Unattached)
		  return _FDEV_EOF;

420
421
422
423
424
425
426
		CDC_Host_USBTask((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
		USB_USBTask();
	}

	return CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
}

427
void CDC_Host_Event_Stub(void)
428
429
430
431
432
{

}

#endif