Add CCID class driver and associated demos.
[pub/USBasp.git] / LUFA / Drivers / USB / Class / Device / CCIDClassDevice.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2018.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7 */
8
9 /*
10 Copyright 2018 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11 Copyright 2018 Filipe Rodrigues (filipepazrodrigues [at] gmail [dot] com)
12
13 Permission to use, copy, modify, distribute, and sell this
14 software and its documentation for any purpose is hereby granted
15 without fee, provided that the above copyright notice appear in
16 all copies and that both that the copyright notice and this
17 permission notice and warranty disclaimer appear in supporting
18 documentation, and that the name of the author not be used in
19 advertising or publicity pertaining to distribution of the
20 software without specific, written prior permission.
21
22 The author disclaims all warranties with regard to this
23 software, including all implied warranties of merchantability
24 and fitness. In no event shall the author be liable for any
25 special, indirect or consequential damages or any damages
26 whatsoever resulting from loss of use, data or profits, whether
27 in an action of contract, negligence or other tortious action,
28 arising out of or in connection with the use or performance of
29 this software.
30 */
31
32 #define __INCLUDE_FROM_USB_DRIVER
33 #include "../../Core/USBMode.h"
34
35 #if defined(USB_CAN_BE_DEVICE)
36
37 #define __INCLUDE_FROM_CCID_DRIVER
38 #define __INCLUDE_FROM_CCID_DEVICE_C
39 #include "CCIDClassDevice.h"
40
41
42 bool CCID_CheckStatusNoError(int status)
43 {
44 return (status & 0xC0) == 0x0;
45 }
46
47 void CCID_Device_ProcessControlRequest(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo)
48 {
49 if (!(Endpoint_IsSETUPReceived()))
50 return;
51
52 if (USB_ControlRequest.wIndex != CCIDInterfaceInfo->Config.InterfaceNumber)
53 return;
54
55 switch (USB_ControlRequest.bRequest)
56 {
57 case CCID_ABORT:
58 {
59 // Initiates the abort process.
60 // The host should send 2 messages in the following order:
61 // - CCID_ABORT control request
62 // - CCID_PC_t_PCo_RDR_Abort command
63 //
64 // If the device is still processing a message, it should fail it until receiving a CCIRPC_to_RDR_Abort
65 // command.
66 //
67 // When the device receives the CCIRPC_to_RDR_Abort message, it replies with RDR_to_PC_SlotStatus
68 // and the abort process ends.
69
70 // The wValue field contains the slot number (bSlot) in the low byte and the sequence number (bSeq) in
71 // the high byte
72 uint8_t Slot = USB_ControlRequest.wValue & 0xFF;
73 uint8_t Seq = USB_ControlRequest.wValue >> 8;
74
75 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE) && Slot == 0)
76 {
77 Endpoint_ClearSETUP();
78
79 CCIDInterfaceInfo->State.Aborted = true;
80 CCIDInterfaceInfo->State.AbortedSeq = Seq;
81
82 Endpoint_ClearOUT();
83 }
84
85 break;
86 }
87 case CCID_GET_CLOCK_FREQUENCIES:
88 {
89 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
90 {
91
92 Endpoint_ClearSETUP();
93 Endpoint_Write_8(0); // Not supported
94 Endpoint_ClearOUT();
95 }
96 break;
97 }
98 case CCID_GET_DATA_RATES:
99 {
100 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
101 {
102
103 Endpoint_ClearSETUP();
104 Endpoint_Write_8(0); // Not supported
105 Endpoint_ClearOUT();
106 }
107 break;
108 }
109 }
110 }
111
112 bool CCID_Device_ConfigureEndpoints(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo)
113 {
114 CCIDInterfaceInfo->Config.DataINEndpoint.Type = EP_TYPE_BULK;
115 CCIDInterfaceInfo->Config.DataOUTEndpoint.Type = EP_TYPE_BULK;
116
117 if (!(Endpoint_ConfigureEndpointTable(&CCIDInterfaceInfo->Config.DataINEndpoint, 1)))
118 return false;
119
120 if (!(Endpoint_ConfigureEndpointTable(&CCIDInterfaceInfo->Config.DataOUTEndpoint, 1)))
121 return false;
122
123 return true;
124 }
125
126 void CCID_Device_USBTask(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo)
127 {
128 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataOUTEndpoint.Address);
129
130 uint8_t BlockBuffer[0x20];
131 CCIDInterfaceInfo->State.Aborted = false;
132 CCIDInterfaceInfo->State.AbortedSeq = -1;
133
134 if (Endpoint_IsOUTReceived())
135 {
136 USB_CCID_BulkMessage_Header_t CCIDHeader;
137 CCIDHeader.MessageType = Endpoint_Read_8();
138 CCIDHeader.Length = Endpoint_Read_32_LE();
139 CCIDHeader.Slot = Endpoint_Read_8();
140 CCIDHeader.Seq = Endpoint_Read_8();
141
142 uint8_t Status;
143 uint8_t Error = CCID_ERROR_NO_ERROR;
144
145 switch (CCIDHeader.MessageType)
146 {
147 case CCID_PC_to_RDR_IccPowerOn:
148 {
149 uint8_t AtrLength;
150 USB_CCID_RDR_to_PC_DataBlock_t* ResponseATR = (USB_CCID_RDR_to_PC_DataBlock_t*)&BlockBuffer;
151
152 ResponseATR->CCIDHeader.MessageType = CCID_RDR_to_PC_DataBlock;
153 ResponseATR->CCIDHeader.Slot = CCIDHeader.Slot;
154 ResponseATR->CCIDHeader.Seq = CCIDHeader.Seq;
155 ResponseATR->ChainParam = 0;
156
157 Status = CALLBACK_CCID_IccPowerOn(ResponseATR->CCIDHeader.Slot, (uint8_t*)ResponseATR->Data, &AtrLength, &Error);
158
159 if (CCID_CheckStatusNoError(Status) && !CCIDInterfaceInfo->State.Aborted)
160 {
161 ResponseATR->CCIDHeader.Length = AtrLength;
162 }
163 else if (CCIDInterfaceInfo->State.Aborted)
164 {
165 Status = CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_PRESENTANDACTIVE;
166 Error = CCID_ERROR_CMD_ABORTED;
167 AtrLength = 0;
168 }
169 else
170 {
171 AtrLength = 0;
172 }
173
174 ResponseATR->Status = Status;
175 ResponseATR->Error = Error;
176
177 Endpoint_ClearOUT();
178
179 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
180 Endpoint_Write_Stream_LE(ResponseATR, sizeof(USB_CCID_RDR_to_PC_DataBlock_t) + AtrLength, NULL);
181 Endpoint_ClearIN();
182 break;
183 }
184
185 case CCID_PC_to_RDR_IccPowerOff:
186 {
187 USB_CCID_RDR_to_PC_SlotStatus_t* ResponsePowerOff = (USB_CCID_RDR_to_PC_SlotStatus_t*)&BlockBuffer;
188 ResponsePowerOff->CCIDHeader.MessageType = CCID_RDR_to_PC_SlotStatus;
189 ResponsePowerOff->CCIDHeader.Length = 0;
190 ResponsePowerOff->CCIDHeader.Slot = CCIDHeader.Slot;
191 ResponsePowerOff->CCIDHeader.Seq = CCIDHeader.Seq;
192
193 ResponsePowerOff->ClockStatus = 0;
194
195 Status = CALLBACK_CCID_IccPowerOff(CCIDHeader.Slot, &Error);
196
197 ResponsePowerOff->Status = Status;
198 ResponsePowerOff->Error = Error;
199
200 Endpoint_ClearOUT();
201
202 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
203 Endpoint_Write_Stream_LE(ResponsePowerOff, sizeof(USB_CCID_RDR_to_PC_SlotStatus_t), NULL);
204 Endpoint_ClearIN();
205 break;
206 }
207
208 case CCID_PC_to_RDR_GetSlotStatus:
209 {
210 USB_CCID_RDR_to_PC_SlotStatus_t* ResponseSlotStatus = (USB_CCID_RDR_to_PC_SlotStatus_t*)&BlockBuffer;
211 ResponseSlotStatus->CCIDHeader.MessageType = CCID_RDR_to_PC_SlotStatus;
212 ResponseSlotStatus->CCIDHeader.Length = 0;
213 ResponseSlotStatus->CCIDHeader.Slot = CCIDHeader.Slot;
214 ResponseSlotStatus->CCIDHeader.Seq = CCIDHeader.Seq;
215
216 ResponseSlotStatus->ClockStatus = 0;
217
218 Status = CALLBACK_CCID_GetSlotStatus(CCIDHeader.Slot, &Error);
219
220 ResponseSlotStatus->Status = Status;
221 ResponseSlotStatus->Error = Error;
222
223 Endpoint_ClearOUT();
224
225 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
226 Endpoint_Write_Stream_LE(ResponseSlotStatus, sizeof(USB_CCID_RDR_to_PC_SlotStatus_t), NULL);
227 Endpoint_ClearIN();
228 break;
229 }
230
231 case CCID_PC_to_RDR_XfrBlock:
232 {
233 uint8_t Bwi = Endpoint_Read_8();
234 uint16_t LevelParameter = Endpoint_Read_16_LE();
235 uint8_t ReceivedBuffer[0x4];
236
237 (void)Bwi;
238 (void)LevelParameter;
239
240 Endpoint_Read_Stream_LE(ReceivedBuffer, sizeof(ReceivedBuffer), NULL);
241
242 uint8_t SendBuffer[0x2] = {0x90, 0x00};
243 uint8_t SendLength = sizeof(SendBuffer);
244
245 USB_CCID_RDR_to_PC_DataBlock_t* ResponseBlock = (USB_CCID_RDR_to_PC_DataBlock_t*)&BlockBuffer;
246 ResponseBlock->CCIDHeader.MessageType = CCID_RDR_to_PC_DataBlock;
247 ResponseBlock->CCIDHeader.Slot = CCIDHeader.Slot;
248 ResponseBlock->CCIDHeader.Seq = CCIDHeader.Seq;
249
250 ResponseBlock->ChainParam = 0;
251
252 //TODO: Callback
253 Status = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_PRESENTANDACTIVE;
254
255 if (CCID_CheckStatusNoError(Status) && !CCIDInterfaceInfo->State.Aborted)
256 {
257 ResponseBlock->CCIDHeader.Length = SendLength;
258 memcpy(&ResponseBlock->Data, SendBuffer, SendLength);
259 }
260 else if(CCIDInterfaceInfo->State.Aborted)
261 {
262 Status = CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_PRESENTANDACTIVE;
263 Error = CCID_ERROR_CMD_ABORTED;
264 SendLength = 0;
265 }
266 else
267 {
268 SendLength = 0;
269 }
270
271 ResponseBlock->Status = Status;
272 ResponseBlock->Error = Error;
273
274 Endpoint_ClearOUT();
275
276 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
277 Endpoint_Write_Stream_LE(ResponseBlock, sizeof(USB_CCID_RDR_to_PC_DataBlock_t) + SendLength, NULL);
278 Endpoint_ClearIN();
279 break;
280 }
281
282 case CCID_PC_to_RDR_Abort:
283 {
284 USB_CCID_RDR_to_PC_SlotStatus_t* ResponseAbort = (USB_CCID_RDR_to_PC_SlotStatus_t*)&BlockBuffer;
285 ResponseAbort->CCIDHeader.MessageType = CCID_RDR_to_PC_SlotStatus;
286 ResponseAbort->CCIDHeader.Length = 0;
287 ResponseAbort->CCIDHeader.Slot = CCIDHeader.Slot;
288 ResponseAbort->CCIDHeader.Seq = CCIDHeader.Seq;
289
290 ResponseAbort->ClockStatus = 0;
291
292 Status = CALLBACK_CCID_Abort(CCIDHeader.Slot, CCIDHeader.Seq, &Error);
293
294 ResponseAbort->Status = Status;
295 ResponseAbort->Error = Error;
296
297 Endpoint_ClearOUT();
298
299 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
300 Endpoint_Write_Stream_LE(ResponseAbort, sizeof(USB_CCID_RDR_to_PC_SlotStatus_t), NULL);
301 Endpoint_ClearIN();
302 break;
303 }
304 default:
305 {
306 memset(BlockBuffer, 0x00, sizeof(BlockBuffer));
307
308 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
309 Endpoint_Write_Stream_LE(BlockBuffer, sizeof(BlockBuffer), NULL);
310 Endpoint_ClearIN();
311 }
312 }
313 }
314 }
315
316 #endif