1 /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
3 This software may be distributed and modified under the terms of the GNU
4 General Public License version 2 (GPL2) as published by the Free Software
5 Foundation and appearing in the file GPL2.TXT included in the packaging of
6 this file. Please note that GPL2 Section 2[b] requires that all works based
7 on this software must also be made publicly available under the terms of
14 Web : http://www.circuitsathome.com
15 e-mail : support@circuitsathome.com
19 const uint8_t ACM::epDataInIndex
= 1;
20 const uint8_t ACM::epDataOutIndex
= 2;
21 const uint8_t ACM::epInterruptInIndex
= 3;
23 ACM::ACM(USB
*p
, CDCAsyncOper
*pasync
) :
33 _enhanced_status
= enhanced_features(); // Set up features
34 for(uint8_t i
= 0; i
< ACM_MAX_ENDPOINTS
; i
++) {
36 epInfo
[i
].maxPktSize
= (i
) ? 0 : 8;
37 epInfo
[i
].epAttribs
= 0;
38 epInfo
[i
].bmNakPower
= (i
== epDataInIndex
) ? USB_NAK_NOWAIT
: USB_NAK_MAX_POWER
;
42 pUsb
->RegisterDeviceClass(this);
45 uint8_t ACM::Init(uint8_t parent
, uint8_t port
, bool lowspeed
) {
47 const uint8_t constBufSize
= sizeof (USB_DEVICE_DESCRIPTOR
);
49 uint8_t buf
[constBufSize
];
50 USB_DEVICE_DESCRIPTOR
* udd
= reinterpret_cast<USB_DEVICE_DESCRIPTOR
*>(buf
);
54 EpInfo
*oldep_ptr
= NULL
;
55 uint8_t num_of_conf
; // number of configurations
57 AddressPool
&addrPool
= pUsb
->GetAddressPool();
59 USBTRACE("ACM Init\r\n");
62 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE
;
64 // Get pointer to pseudo device with address 0 assigned
65 p
= addrPool
.GetUsbDevicePtr(0);
68 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
;
71 USBTRACE("epinfo\r\n");
72 return USB_ERROR_EPINFO_IS_NULL
;
75 // Save old pointer to EP_RECORD of address 0
76 oldep_ptr
= p
->epinfo
;
78 // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
81 p
->lowspeed
= lowspeed
;
83 // Get device descriptor
84 rcode
= pUsb
->getDevDescr(0, 0, constBufSize
, (uint8_t*)buf
);
87 p
->epinfo
= oldep_ptr
;
92 // Allocate new address according to device class
93 bAddress
= addrPool
.AllocAddress(parent
, false, port
);
96 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL
;
98 // Extract Max Packet Size from the device descriptor
99 epInfo
[0].maxPktSize
= udd
->bMaxPacketSize0
;
101 // Assign new address to the device
102 rcode
= pUsb
->setAddr(0, 0, bAddress
);
106 addrPool
.FreeAddress(bAddress
);
108 USBTRACE2("setAddr:", rcode
);
112 USBTRACE2("Addr:", bAddress
);
116 p
= addrPool
.GetUsbDevicePtr(bAddress
);
119 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
;
121 p
->lowspeed
= lowspeed
;
123 num_of_conf
= udd
->bNumConfigurations
;
125 // Assign epInfo to epinfo pointer
126 rcode
= pUsb
->setEpInfoEntry(bAddress
, 1, epInfo
);
129 goto FailSetDevTblEntry
;
131 USBTRACE2("NC:", num_of_conf
);
133 for(uint8_t i
= 0; i
< num_of_conf
; i
++) {
134 ConfigDescParser
< USB_CLASS_COM_AND_CDC_CTRL
,
136 CDC_PROTOCOL_ITU_T_V_250
,
137 CP_MASK_COMPARE_CLASS
|
138 CP_MASK_COMPARE_SUBCLASS
|
139 CP_MASK_COMPARE_PROTOCOL
> CdcControlParser(this);
141 ConfigDescParser
<USB_CLASS_CDC_DATA
, 0, 0,
142 CP_MASK_COMPARE_CLASS
> CdcDataParser(this);
144 rcode
= pUsb
->getConfDescr(bAddress
, 0, i
, &CdcControlParser
);
147 goto FailGetConfDescr
;
149 rcode
= pUsb
->getConfDescr(bAddress
, 0, i
, &CdcDataParser
);
152 goto FailGetConfDescr
;
159 return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED
;
161 // Assign epInfo to epinfo pointer
162 rcode
= pUsb
->setEpInfoEntry(bAddress
, bNumEP
, epInfo
);
164 USBTRACE2("Conf:", bConfNum
);
166 // Set Configuration Value
167 rcode
= pUsb
->setConf(bAddress
, 0, bConfNum
);
170 goto FailSetConfDescr
;
172 // Set up features status
173 _enhanced_status
= enhanced_features();
178 wide(false); // Always false, because this is only available in custom mode.
179 rcode
= pAsync
->OnInit(this);
184 USBTRACE("ACM configured\r\n");
188 //bPollEnable = true;
190 //USBTRACE("Poll enabled\r\n");
194 #ifdef DEBUG_USB_HOST
195 NotifyFailGetDevDescr();
200 #ifdef DEBUG_USB_HOST
201 NotifyFailSetDevTblEntry();
206 #ifdef DEBUG_USB_HOST
207 NotifyFailGetConfDescr();
212 #ifdef DEBUG_USB_HOST
213 NotifyFailSetConfDescr();
218 #ifdef DEBUG_USB_HOST
222 #ifdef DEBUG_USB_HOST
230 void ACM::EndpointXtract(uint8_t conf
, uint8_t iface
, uint8_t alt
, uint8_t proto
, const USB_ENDPOINT_DESCRIPTOR
*pep
) {
231 //ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
232 //ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
233 //ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
239 if((pep
->bmAttributes
& 0x03) == 3 && (pep
->bEndpointAddress
& 0x80) == 0x80)
240 index
= epInterruptInIndex
;
242 if((pep
->bmAttributes
& 0x02) == 2)
243 index
= ((pep
->bEndpointAddress
& 0x80) == 0x80) ? epDataInIndex
: epDataOutIndex
;
247 // Fill in the endpoint info structure
248 epInfo
[index
].epAddr
= (pep
->bEndpointAddress
& 0x0F);
249 epInfo
[index
].maxPktSize
= (uint8_t)pep
->wMaxPacketSize
;
250 epInfo
[index
].epAttribs
= 0;
254 PrintEndpointDescriptor(pep
);
257 uint8_t ACM::Release() {
259 pUsb
->GetAddressPool().FreeAddress(bAddress
);
271 uint8_t ACM::Poll() {
280 uint8_t ACM::RcvData(uint16_t *bytes_rcvd
, uint8_t *dataptr
) {
281 return pUsb
->inTransfer(bAddress
, epInfo
[epDataInIndex
].epAddr
, bytes_rcvd
, dataptr
);
284 uint8_t ACM::SndData(uint16_t nbytes
, uint8_t *dataptr
) {
285 return pUsb
->outTransfer(bAddress
, epInfo
[epDataOutIndex
].epAddr
, nbytes
, dataptr
);
288 uint8_t ACM::SetCommFeature(uint16_t fid
, uint8_t nbytes
, uint8_t *dataptr
) {
289 return ( pUsb
->ctrlReq(bAddress
, 0, bmREQ_CDCOUT
, CDC_SET_COMM_FEATURE
, (fid
& 0xff), (fid
>> 8), bControlIface
, nbytes
, nbytes
, dataptr
, NULL
));
292 uint8_t ACM::GetCommFeature(uint16_t fid
, uint8_t nbytes
, uint8_t *dataptr
) {
293 return ( pUsb
->ctrlReq(bAddress
, 0, bmREQ_CDCIN
, CDC_GET_COMM_FEATURE
, (fid
& 0xff), (fid
>> 8), bControlIface
, nbytes
, nbytes
, dataptr
, NULL
));
296 uint8_t ACM::ClearCommFeature(uint16_t fid
) {
297 return ( pUsb
->ctrlReq(bAddress
, 0, bmREQ_CDCOUT
, CDC_CLEAR_COMM_FEATURE
, (fid
& 0xff), (fid
>> 8), bControlIface
, 0, 0, NULL
, NULL
));
300 uint8_t ACM::SetLineCoding(const LINE_CODING
*dataptr
) {
301 return ( pUsb
->ctrlReq(bAddress
, 0, bmREQ_CDCOUT
, CDC_SET_LINE_CODING
, 0x00, 0x00, bControlIface
, sizeof (LINE_CODING
), sizeof (LINE_CODING
), (uint8_t*)dataptr
, NULL
));
304 uint8_t ACM::GetLineCoding(LINE_CODING
*dataptr
) {
305 return ( pUsb
->ctrlReq(bAddress
, 0, bmREQ_CDCIN
, CDC_GET_LINE_CODING
, 0x00, 0x00, bControlIface
, sizeof (LINE_CODING
), sizeof (LINE_CODING
), (uint8_t*)dataptr
, NULL
));
308 uint8_t ACM::SetControlLineState(uint8_t state
) {
309 return ( pUsb
->ctrlReq(bAddress
, 0, bmREQ_CDCOUT
, CDC_SET_CONTROL_LINE_STATE
, state
, 0, bControlIface
, 0, 0, NULL
, NULL
));
312 uint8_t ACM::SendBreak(uint16_t duration
) {
313 return ( pUsb
->ctrlReq(bAddress
, 0, bmREQ_CDCOUT
, CDC_SEND_BREAK
, (duration
& 0xff), (duration
>> 8), bControlIface
, 0, 0, NULL
, NULL
));
316 void ACM::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR
* ep_ptr
) {
317 Notify(PSTR("Endpoint descriptor:"), 0x80);
318 Notify(PSTR("\r\nLength:\t\t"), 0x80);
319 D_PrintHex
<uint8_t > (ep_ptr
->bLength
, 0x80);
320 Notify(PSTR("\r\nType:\t\t"), 0x80);
321 D_PrintHex
<uint8_t > (ep_ptr
->bDescriptorType
, 0x80);
322 Notify(PSTR("\r\nAddress:\t"), 0x80);
323 D_PrintHex
<uint8_t > (ep_ptr
->bEndpointAddress
, 0x80);
324 Notify(PSTR("\r\nAttributes:\t"), 0x80);
325 D_PrintHex
<uint8_t > (ep_ptr
->bmAttributes
, 0x80);
326 Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
327 D_PrintHex
<uint16_t > (ep_ptr
->wMaxPacketSize
, 0x80);
328 Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
329 D_PrintHex
<uint8_t > (ep_ptr
->bInterval
, 0x80);
330 Notify(PSTR("\r\n"), 0x80);