1 /* ----------------------------------------------------------------------------
\r
2 * ATMEL Microcontroller Software Support
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2008, Atmel Corporation
\r
6 * All rights reserved.
\r
8 * Redistribution and use in source and binary forms, with or without
\r
9 * modification, are permitted provided that the following conditions are met:
\r
11 * - Redistributions of source code must retain the above copyright notice,
\r
12 * this list of conditions and the disclaimer below.
\r
14 * Atmel's name may not be used to endorse or promote products derived from
\r
15 * this software without specific prior written permission.
\r
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
\r
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
\r
20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
\r
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
\r
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
\r
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
\r
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
\r
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
27 * ----------------------------------------------------------------------------
\r
31 * Implementation of the CDCDSerialPort class methods.
\r
34 /** \addtogroup usbd_cdc
\r
38 /*------------------------------------------------------------------------------
\r
40 *------------------------------------------------------------------------------*/
\r
42 #include <CDCDSerialPort.h>
\r
43 #include <CDCDescriptors.h>
\r
44 #include <USBLib_Trace.h>
\r
46 /*------------------------------------------------------------------------------
\r
48 *------------------------------------------------------------------------------*/
\r
50 /** Parse data extention for descriptor parsing */
\r
51 typedef struct _CDCDParseData {
\r
52 /** Pointer to CDCDSerialPort instance */
\r
53 CDCDSerialPort * pCdcd;
\r
54 /** Pointer to found interface descriptor */
\r
55 USBInterfaceDescriptor * pIfDesc;
\r
59 /*------------------------------------------------------------------------------
\r
60 * Internal variables
\r
61 *------------------------------------------------------------------------------*/
\r
63 /** Line coding values */
\r
64 static CDCLineCoding lineCoding;
\r
66 /*------------------------------------------------------------------------------
\r
67 * Internal functions
\r
68 *------------------------------------------------------------------------------*/
\r
71 * Parse descriptors: Interface, Bulk IN/OUT, Interrupt IN.
\r
72 * \param desc Pointer to descriptor list.
\r
73 * \param arg Argument, pointer to AUDDParseData instance.
\r
75 static uint32_t _Interfaces_Parse(USBGenericDescriptor *pDesc,
\r
76 CDCDParseData * pArg)
\r
78 CDCDSerialPort *pCdcd = pArg->pCdcd;
\r
80 /* Not a valid descriptor */
\r
81 if (pDesc->bLength == 0)
\r
82 return USBRC_PARAM_ERR;
\r
84 /* Find interface descriptor */
\r
85 if (pDesc->bDescriptorType == USBGenericDescriptor_INTERFACE) {
\r
86 USBInterfaceDescriptor *pIf = (USBInterfaceDescriptor*)pDesc;
\r
88 /* Obtain interface from descriptor */
\r
89 if (pCdcd->bInterfaceNdx == 0xFF) {
\r
90 /* First interface is communication */
\r
91 if (pIf->bInterfaceClass ==
\r
92 CDCCommunicationInterfaceDescriptor_CLASS) {
\r
93 pCdcd->bInterfaceNdx = pIf->bInterfaceNumber;
\r
94 pCdcd->bNumInterface = 2;
\r
96 /* Only data interface */
\r
97 else if(pIf->bInterfaceClass == CDCDataInterfaceDescriptor_CLASS) {
\r
98 pCdcd->bInterfaceNdx = pIf->bInterfaceNumber;
\r
99 pCdcd->bNumInterface = 1;
\r
101 pArg->pIfDesc = pIf;
\r
103 else if (pCdcd->bInterfaceNdx <= pIf->bInterfaceNumber
\r
104 && pCdcd->bInterfaceNdx + pCdcd->bNumInterface
\r
105 > pIf->bInterfaceNumber) {
\r
106 pArg->pIfDesc = pIf;
\r
110 /* Parse valid interfaces */
\r
111 if (pArg->pIfDesc == 0)
\r
114 /* Find endpoint descriptors */
\r
115 if (pDesc->bDescriptorType == USBGenericDescriptor_ENDPOINT) {
\r
116 USBEndpointDescriptor *pEp = (USBEndpointDescriptor*)pDesc;
\r
117 switch(pEp->bmAttributes & 0x3) {
\r
118 case USBEndpointDescriptor_INTERRUPT:
\r
119 if (pEp->bEndpointAddress & 0x80)
\r
120 pCdcd->bIntInPIPE = pEp->bEndpointAddress & 0x7F;
\r
122 case USBEndpointDescriptor_BULK:
\r
123 if (pEp->bEndpointAddress & 0x80)
\r
124 pCdcd->bBulkInPIPE = pEp->bEndpointAddress & 0x7F;
\r
126 pCdcd->bBulkOutPIPE = pEp->bEndpointAddress;
\r
130 if ( pCdcd->bInterfaceNdx != 0xFF
\r
131 && pCdcd->bBulkInPIPE != 0
\r
132 && pCdcd->bBulkOutPIPE != 0)
\r
133 return USBRC_FINISHED;
\r
139 * Callback function which should be invoked after the data of a
\r
140 * SetLineCoding request has been retrieved. Sends a zero-length packet
\r
141 * to the host for acknowledging the request.
\r
142 * \param pCdcd Pointer to CDCDSerialPort instance.
\r
144 static void _SetLineCodingCallback(CDCDSerialPort * pCdcd)
\r
147 if (pCdcd->fEventHandler) {
\r
148 uint32_t rc = pCdcd->fEventHandler(
\r
149 CDCDSerialPortEvent_SETLINECODING,
\r
150 (uint32_t)(&lineCoding),
\r
152 if (rc == USBD_STATUS_SUCCESS) {
\r
153 pCdcd->lineCoding.dwDTERate = lineCoding.dwDTERate;
\r
154 pCdcd->lineCoding.bCharFormat = lineCoding.bCharFormat;
\r
155 pCdcd->lineCoding.bParityType = lineCoding.bParityType;
\r
156 pCdcd->lineCoding.bDataBits = lineCoding.bDataBits;
\r
161 if (exec) USBD_Write(0, 0, 0, 0, 0);
\r
162 else USBD_Stall(0);
\r
166 * Receives new line coding information from the USB host.
\r
167 * \param pCdcd Pointer to CDCDSerialPort instance.
\r
169 static void _SetLineCoding(CDCDSerialPort * pCdcd)
\r
171 TRACE_INFO_WP("sLineCoding ");
\r
174 (void *) & (lineCoding),
\r
175 sizeof(CDCLineCoding),
\r
176 (TransferCallback)_SetLineCodingCallback,
\r
181 * Sends the current line coding information to the host through Control
\r
183 * \param pCdcd Pointer to CDCDSerialPort instance.
\r
185 static void _GetLineCoding(CDCDSerialPort * pCdcd)
\r
187 TRACE_INFO_WP("gLineCoding ");
\r
190 (void *) &(pCdcd->lineCoding),
\r
191 sizeof(CDCLineCoding),
\r
197 * Changes the state of the serial driver according to the information
\r
198 * sent by the host via a SetControlLineState request, and acknowledges
\r
199 * the request with a zero-length packet.
\r
200 * \param pCdcd Pointer to CDCDSerialPort instance.
\r
201 * \param request Pointer to a USBGenericRequest instance.
\r
203 static void _SetControlLineState(
\r
204 CDCDSerialPort * pCdcd,
\r
205 const USBGenericRequest *request)
\r
207 #if (TRACE_LEVEL >= TRACE_LEVEL_INFO)
\r
210 DTR = ((request->wValue & CDCControlLineState_DTR) > 0);
\r
211 RTS = ((request->wValue & CDCControlLineState_RTS) > 0);
\r
212 TRACE_INFO_WP("sControlLineState(%d, %d) ", DTR, RTS);
\r
215 pCdcd->bControlLineState = (uint8_t)request->wValue;
\r
216 USBD_Write(0, 0, 0, 0, 0);
\r
218 if (pCdcd->fEventHandler)
\r
219 pCdcd->fEventHandler(CDCDSerialPortEvent_SETCONTROLLINESTATE,
\r
221 (uint32_t)pCdcd->bControlLineState,
\r
225 /*------------------------------------------------------------------------------
\r
226 * Exported functions
\r
227 *------------------------------------------------------------------------------*/
\r
230 * Initializes the USB Device CDC serial port function.
\r
231 * \param pCdcd Pointer to CDCDSerialPort instance.
\r
232 * \param pUsbd Pointer to USBDDriver instance.
\r
233 * \param fEventHandler Pointer to event handler function.
\r
234 * \param firstInterface First interface index for the function
\r
235 * (0xFF to parse from descriptors).
\r
236 * \param numInterface Number of interfaces for the function.
\r
238 void CDCDSerialPort_Initialize(CDCDSerialPort * pCdcd,
\r
239 USBDDriver * pUsbd,
\r
240 CDCDSerialPortEventHandler fEventHandler,
\r
242 uint8_t firstInterface,uint8_t numInterface)
\r
244 TRACE_INFO("CDCDSerialPort_Initialize\n\r");
\r
246 /* Initialize event handler */
\r
247 pCdcd->fEventHandler = fEventHandler;
\r
248 pCdcd->pArg = pArg;
\r
250 /* Initialize USB Device Driver interface */
\r
251 pCdcd->pUsbd = pUsbd;
\r
252 pCdcd->bInterfaceNdx = firstInterface;
\r
253 pCdcd->bNumInterface = numInterface;
\r
254 pCdcd->bIntInPIPE = 0;
\r
255 pCdcd->bBulkInPIPE = 0;
\r
256 pCdcd->bBulkOutPIPE = 0;
\r
258 /* Initialize Abstract Control Model attributes */
\r
259 pCdcd->bControlLineState = 0;
\r
260 pCdcd->wSerialState = 0;
\r
261 CDCLineCoding_Initialize(&(pCdcd->lineCoding),
\r
263 CDCLineCoding_ONESTOPBIT,
\r
264 CDCLineCoding_NOPARITY,
\r
269 * Parse CDC Serial Port information for CDCDSerialPort instance.
\r
270 * Accepted interfaces:
\r
271 * - Communication Interface + Data Interface
\r
272 * - Data Interface ONLY
\r
273 * \param pCdcd Pointer to CDCDSerialPort instance.
\r
274 * \param pDescriptors Pointer to descriptor list.
\r
275 * \param dwLength Descriptor list size in bytes.
\r
277 USBGenericDescriptor *CDCDSerialPort_ParseInterfaces(
\r
278 CDCDSerialPort *pCdcd,
\r
279 USBGenericDescriptor *pDescriptors,
\r
282 CDCDParseData parseData;
\r
284 parseData.pCdcd = pCdcd;
\r
285 parseData.pIfDesc = 0;
\r
287 return USBGenericDescriptor_Parse(
\r
288 pDescriptors, dwLength,
\r
289 (USBDescriptorParseFunction)_Interfaces_Parse,
\r
295 * Handles CDC-specific SETUP requests. Should be called from a
\r
296 * re-implementation of USBDCallbacks_RequestReceived() method.
\r
297 * \param pCdcd Pointer to CDCDSerialPort instance.
\r
298 * \param request Pointer to a USBGenericRequest instance.
\r
299 * \return USBRC_SUCCESS if request handled, otherwise error.
\r
301 uint32_t CDCDSerialPort_RequestHandler(
\r
302 CDCDSerialPort *pCdcd,
\r
303 const USBGenericRequest *request)
\r
305 if (USBGenericRequest_GetType(request) != USBGenericRequest_CLASS)
\r
306 return USBRC_PARAM_ERR;
\r
308 TRACE_INFO_WP("Cdcs ");
\r
310 /* Validate interface */
\r
311 if (request->wIndex >= pCdcd->bInterfaceNdx &&
\r
312 request->wIndex < pCdcd->bInterfaceNdx + pCdcd->bNumInterface) {
\r
315 return USBRC_PARAM_ERR;
\r
318 /* Handle the request */
\r
319 switch (USBGenericRequest_GetRequest(request)) {
\r
321 case CDCGenericRequest_SETLINECODING:
\r
323 _SetLineCoding(pCdcd);
\r
326 case CDCGenericRequest_GETLINECODING:
\r
328 _GetLineCoding(pCdcd);
\r
331 case CDCGenericRequest_SETCONTROLLINESTATE:
\r
333 _SetControlLineState(pCdcd, request);
\r
338 return USBRC_PARAM_ERR;
\r
341 return USBRC_SUCCESS;
\r
345 * Receives data from the host through the virtual COM port created by
\r
346 * the CDC device serial driver. This function behaves like USBD_Read.
\r
347 * \param pCdcd Pointer to CDCDSerialPort instance.
\r
348 * \param pData Pointer to the data buffer to put received data.
\r
349 * \param dwSize Size of the data buffer in bytes.
\r
350 * \param fCallback Optional callback function to invoke when the transfer
\r
352 * \param pArg Optional argument to the callback function.
\r
353 * \return USBD_STATUS_SUCCESS if the read operation has been started normally;
\r
354 * otherwise, the corresponding error code.
\r
356 uint32_t CDCDSerialPort_Read(const CDCDSerialPort * pCdcd,
\r
357 void * pData,uint32_t dwSize,
\r
358 TransferCallback fCallback,void * pArg)
\r
360 if (pCdcd->bBulkOutPIPE == 0)
\r
361 return USBRC_PARAM_ERR;
\r
363 return USBD_Read(pCdcd->bBulkOutPIPE,
\r
369 * Sends a data buffer through the virtual COM port created by the CDC
\r
370 * device serial driver. This function behaves exactly like USBD_Write.
\r
371 * \param pCdcd Pointer to CDCDSerialPort instance.
\r
372 * \param pData Pointer to the data buffer to send.
\r
373 * \param dwSize Size of the data buffer in bytes.
\r
374 * \param fCallback Optional callback function to invoke when the transfer
\r
376 * \param pArg Optional argument to the callback function.
\r
377 * \return USBD_STATUS_SUCCESS if the read operation has been started normally;
\r
378 * otherwise, the corresponding error code.
\r
380 uint32_t CDCDSerialPort_Write(const CDCDSerialPort * pCdcd,
\r
381 void * pData, uint32_t dwSize,
\r
382 TransferCallback fCallback, void * pArg)
\r
384 if (pCdcd->bBulkInPIPE == 0)
\r
385 return USBRC_PARAM_ERR;
\r
387 return USBD_Write(pCdcd->bBulkInPIPE,
\r
393 * Returns the current control line state of the RS-232 line.
\r
394 * \param pCdcd Pointer to CDCDSerialPort instance.
\r
396 uint8_t CDCDSerialPort_GetControlLineState(const CDCDSerialPort * pCdcd)
\r
398 return pCdcd->bControlLineState;
\r
402 * Copy current line coding settings to pointered space.
\r
403 * \param pCdcd Pointer to CDCDSerialPort instance.
\r
404 * \param pLineCoding Pointer to CDCLineCoding instance.
\r
406 void CDCDSerialPort_GetLineCoding(const CDCDSerialPort * pCdcd,
\r
407 CDCLineCoding* pLineCoding)
\r
410 pLineCoding->dwDTERate = pCdcd->lineCoding.dwDTERate;
\r
411 pLineCoding->bCharFormat = pCdcd->lineCoding.bCharFormat;
\r
412 pLineCoding->bParityType = pCdcd->lineCoding.bParityType;
\r
413 pLineCoding->bDataBits = pCdcd->lineCoding.bDataBits;
\r
418 * Returns the current status of the RS-232 line.
\r
419 * \param pCdcd Pointer to CDCDSerialPort instance.
\r
421 uint16_t CDCDSerialPort_GetSerialState(const CDCDSerialPort * pCdcd)
\r
423 return pCdcd->wSerialState;
\r
427 * Sets the current serial state of the device to the given value.
\r
428 * \param pCdcd Pointer to CDCDSerialPort instance.
\r
429 * \param wSerialState New device state.
\r
431 void CDCDSerialPort_SetSerialState(CDCDSerialPort * pCdcd,
\r
432 uint16_t wSerialState)
\r
434 if (pCdcd->bIntInPIPE == 0)
\r
437 /* If new state is different from previous one, send a notification to the
\r
439 if (pCdcd->wSerialState != wSerialState) {
\r
441 pCdcd->wSerialState = wSerialState;
\r
442 USBD_Write(pCdcd->bIntInPIPE,
\r
443 &(pCdcd->wSerialState),
\r
448 /* Reset one-time flags */
\r
449 pCdcd->wSerialState &= ~(CDCSerialState_OVERRUN
\r
450 | CDCSerialState_PARITY
\r
451 | CDCSerialState_FRAMING
\r
452 | CDCSerialState_RINGSIGNAL
\r
453 | CDCSerialState_BREAK);
\r