Reformatting and add const qualifiers.
[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(uint8_t 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
88 case CCID_GET_CLOCK_FREQUENCIES:
89 {
90 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
91 {
92
93 Endpoint_ClearSETUP();
94 Endpoint_Write_8(0); // Not supported
95 Endpoint_ClearOUT();
96 }
97 break;
98 }
99
100 case CCID_GET_DATA_RATES:
101 {
102 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
103 {
104
105 Endpoint_ClearSETUP();
106 Endpoint_Write_8(0); // Not supported
107 Endpoint_ClearOUT();
108 }
109 break;
110 }
111 }
112 }
113
114 bool CCID_Device_ConfigureEndpoints(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo)
115 {
116 CCIDInterfaceInfo->Config.DataINEndpoint.Type = EP_TYPE_BULK;
117 CCIDInterfaceInfo->Config.DataOUTEndpoint.Type = EP_TYPE_BULK;
118
119 if (!(Endpoint_ConfigureEndpointTable(&CCIDInterfaceInfo->Config.DataINEndpoint, 1)))
120 return false;
121
122 if (!(Endpoint_ConfigureEndpointTable(&CCIDInterfaceInfo->Config.DataOUTEndpoint, 1)))
123 return false;
124
125 return true;
126 }
127
128 void CCID_Device_USBTask(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo)
129 {
130 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataOUTEndpoint.Address);
131
132 uint8_t BlockBuffer[0x20];
133 CCIDInterfaceInfo->State.Aborted = false;
134 CCIDInterfaceInfo->State.AbortedSeq = -1;
135
136 if (Endpoint_IsOUTReceived())
137 {
138 USB_CCID_BulkMessage_Header_t CCIDHeader;
139 CCIDHeader.MessageType = Endpoint_Read_8();
140 CCIDHeader.Length = Endpoint_Read_32_LE();
141 CCIDHeader.Slot = Endpoint_Read_8();
142 CCIDHeader.Seq = Endpoint_Read_8();
143
144 uint8_t Status;
145 uint8_t Error = CCID_ERROR_NO_ERROR;
146
147 switch (CCIDHeader.MessageType)
148 {
149 case CCID_PC_to_RDR_IccPowerOn:
150 {
151 uint8_t AtrLength;
152 USB_CCID_RDR_to_PC_DataBlock_t* ResponseATR = (USB_CCID_RDR_to_PC_DataBlock_t*)&BlockBuffer;
153
154 ResponseATR->CCIDHeader.MessageType = CCID_RDR_to_PC_DataBlock;
155 ResponseATR->CCIDHeader.Slot = CCIDHeader.Slot;
156 ResponseATR->CCIDHeader.Seq = CCIDHeader.Seq;
157 ResponseATR->ChainParam = 0;
158
159 Status = CALLBACK_CCID_IccPowerOn(CCIDInterfaceInfo, ResponseATR->CCIDHeader.Slot, (uint8_t*)ResponseATR->Data, &AtrLength, &Error);
160
161 if (CCID_CheckStatusNoError(Status) && !CCIDInterfaceInfo->State.Aborted)
162 {
163 ResponseATR->CCIDHeader.Length = AtrLength;
164 }
165 else if (CCIDInterfaceInfo->State.Aborted)
166 {
167 Status = CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_PRESENTANDACTIVE;
168 Error = CCID_ERROR_CMD_ABORTED;
169 AtrLength = 0;
170 }
171 else
172 {
173 AtrLength = 0;
174 }
175
176 ResponseATR->Status = Status;
177 ResponseATR->Error = Error;
178
179 Endpoint_ClearOUT();
180
181 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
182 Endpoint_Write_Stream_LE(ResponseATR, sizeof(USB_CCID_RDR_to_PC_DataBlock_t) + AtrLength, NULL);
183 Endpoint_ClearIN();
184 break;
185 }
186
187 case CCID_PC_to_RDR_IccPowerOff:
188 {
189 USB_CCID_RDR_to_PC_SlotStatus_t* ResponsePowerOff = (USB_CCID_RDR_to_PC_SlotStatus_t*)&BlockBuffer;
190 ResponsePowerOff->CCIDHeader.MessageType = CCID_RDR_to_PC_SlotStatus;
191 ResponsePowerOff->CCIDHeader.Length = 0;
192 ResponsePowerOff->CCIDHeader.Slot = CCIDHeader.Slot;
193 ResponsePowerOff->CCIDHeader.Seq = CCIDHeader.Seq;
194
195 ResponsePowerOff->ClockStatus = 0;
196
197 Status = CALLBACK_CCID_IccPowerOff(CCIDInterfaceInfo, CCIDHeader.Slot, &Error);
198
199 ResponsePowerOff->Status = Status;
200 ResponsePowerOff->Error = Error;
201
202 Endpoint_ClearOUT();
203
204 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
205 Endpoint_Write_Stream_LE(ResponsePowerOff, sizeof(USB_CCID_RDR_to_PC_SlotStatus_t), NULL);
206 Endpoint_ClearIN();
207 break;
208 }
209
210 case CCID_PC_to_RDR_GetSlotStatus:
211 {
212 USB_CCID_RDR_to_PC_SlotStatus_t* ResponseSlotStatus = (USB_CCID_RDR_to_PC_SlotStatus_t*)&BlockBuffer;
213 ResponseSlotStatus->CCIDHeader.MessageType = CCID_RDR_to_PC_SlotStatus;
214 ResponseSlotStatus->CCIDHeader.Length = 0;
215 ResponseSlotStatus->CCIDHeader.Slot = CCIDHeader.Slot;
216 ResponseSlotStatus->CCIDHeader.Seq = CCIDHeader.Seq;
217
218 ResponseSlotStatus->ClockStatus = 0;
219
220 Status = CALLBACK_CCID_GetSlotStatus(CCIDInterfaceInfo, CCIDHeader.Slot, &Error);
221
222 ResponseSlotStatus->Status = Status;
223 ResponseSlotStatus->Error = Error;
224
225 Endpoint_ClearOUT();
226
227 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
228 Endpoint_Write_Stream_LE(ResponseSlotStatus, sizeof(USB_CCID_RDR_to_PC_SlotStatus_t), NULL);
229 Endpoint_ClearIN();
230 break;
231 }
232
233 case CCID_PC_to_RDR_Abort:
234 {
235 USB_CCID_RDR_to_PC_SlotStatus_t* ResponseAbort = (USB_CCID_RDR_to_PC_SlotStatus_t*)&BlockBuffer;
236 ResponseAbort->CCIDHeader.MessageType = CCID_RDR_to_PC_SlotStatus;
237 ResponseAbort->CCIDHeader.Length = 0;
238 ResponseAbort->CCIDHeader.Slot = CCIDHeader.Slot;
239 ResponseAbort->CCIDHeader.Seq = CCIDHeader.Seq;
240
241 ResponseAbort->ClockStatus = 0;
242
243 Status = CALLBACK_CCID_Abort(CCIDInterfaceInfo, CCIDHeader.Slot, CCIDHeader.Seq, &Error);
244
245 ResponseAbort->Status = Status;
246 ResponseAbort->Error = Error;
247
248 Endpoint_ClearOUT();
249
250 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
251 Endpoint_Write_Stream_LE(ResponseAbort, sizeof(USB_CCID_RDR_to_PC_SlotStatus_t), NULL);
252 Endpoint_ClearIN();
253 break;
254 }
255
256 default:
257 {
258 memset(BlockBuffer, 0x00, sizeof(BlockBuffer));
259
260 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
261 Endpoint_Write_Stream_LE(BlockBuffer, sizeof(BlockBuffer), NULL);
262 Endpoint_ClearIN();
263 }
264 }
265 }
266 }
267
268 #endif