From 044ad7c3987460ede48ff27afd6bdb0ca05a0432 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 4 Jul 2011 20:52:54 +0200 Subject: import at91lib from at91lib_20100901_softpack_1_9_v_1_0_svn_v15011 it's sad to see that atmel doesn't publish their svn repo or has a centralized location or even puts proper version/release info into the library itself --- usb/USBFrameworkArchitecture.png | Bin 0 -> 5288 bytes usb/common/audio/AUDControlInterfaceDescriptor.h | 72 + usb/common/audio/AUDDataEndpointDescriptor.h | 104 + usb/common/audio/AUDDeviceDescriptor.h | 72 + usb/common/audio/AUDEndpointDescriptor.h | 86 + usb/common/audio/AUDFeatureUnitDescriptor.h | 116 + usb/common/audio/AUDFeatureUnitRequest.c | 60 + usb/common/audio/AUDFeatureUnitRequest.h | 81 + usb/common/audio/AUDFormatTypeOneDescriptor.h | 101 + usb/common/audio/AUDGenericDescriptor.h | 121 + usb/common/audio/AUDGenericRequest.c | 57 + usb/common/audio/AUDGenericRequest.h | 94 + usb/common/audio/AUDHeaderDescriptor.h | 100 + usb/common/audio/AUDInputTerminalDescriptor.h | 139 ++ usb/common/audio/AUDOutputTerminalDescriptor.h | 112 + usb/common/audio/AUDStreamingInterfaceDescriptor.h | 129 ++ usb/common/audio/audio.dir | 40 + .../cdc/CDCAbstractControlManagementDescriptor.h | 104 + usb/common/cdc/CDCCallManagementDescriptor.h | 97 + .../cdc/CDCCommunicationInterfaceDescriptor.h | 65 + usb/common/cdc/CDCDataInterfaceDescriptor.h | 65 + usb/common/cdc/CDCDeviceDescriptor.h | 64 + usb/common/cdc/CDCGenericDescriptor.h | 91 + usb/common/cdc/CDCGenericRequest.h | 63 + usb/common/cdc/CDCHeaderDescriptor.h | 77 + usb/common/cdc/CDCLineCoding.c | 78 + usb/common/cdc/CDCLineCoding.h | 136 ++ usb/common/cdc/CDCSetControlLineStateRequest.c | 84 + usb/common/cdc/CDCSetControlLineStateRequest.h | 59 + usb/common/cdc/CDCUnionDescriptor.h | 79 + usb/common/cdc/cdc.dir | 39 + usb/common/common.dir | 55 + usb/common/core/USBConfigurationDescriptor.c | 162 ++ usb/common/core/USBConfigurationDescriptor.h | 150 ++ usb/common/core/USBConfigurationOTG.c | 51 + usb/common/core/USBConfigurationOTG.h | 118 + usb/common/core/USBDeviceDescriptor.h | 125 + usb/common/core/USBDeviceQualifierDescriptor.h | 89 + usb/common/core/USBEndpointDescriptor.c | 109 + usb/common/core/USBEndpointDescriptor.h | 224 ++ usb/common/core/USBFeatureRequest.c | 70 + usb/common/core/USBFeatureRequest.h | 146 ++ usb/common/core/USBGenericDescriptor.c | 80 + usb/common/core/USBGenericDescriptor.h | 133 ++ usb/common/core/USBGenericRequest.c | 138 ++ usb/common/core/USBGenericRequest.h | 244 ++ usb/common/core/USBGetDescriptorRequest.c | 72 + usb/common/core/USBGetDescriptorRequest.h | 67 + .../core/USBInterfaceAssociationDescriptor.h | 86 + usb/common/core/USBInterfaceDescriptor.h | 87 + usb/common/core/USBInterfaceRequest.c | 69 + usb/common/core/USBInterfaceRequest.h | 68 + usb/common/core/USBIrqHandler.c | 62 + usb/common/core/USBIrqHandler.h | 52 + usb/common/core/USBSetAddressRequest.c | 56 + usb/common/core/USBSetAddressRequest.h | 60 + usb/common/core/USBSetConfigurationRequest.c | 58 + usb/common/core/USBSetConfigurationRequest.h | 61 + usb/common/core/USBStringDescriptor.h | 74 + usb/common/core/core.dir | 53 + usb/common/hid/HIDButton.h | 55 + usb/common/hid/HIDDescriptor.h | 93 + usb/common/hid/HIDDeviceDescriptor.h | 68 + usb/common/hid/HIDGenericDescriptor.h | 63 + usb/common/hid/HIDGenericDesktop.h | 98 + usb/common/hid/HIDGenericRequest.h | 75 + usb/common/hid/HIDIdleRequest.c | 56 + usb/common/hid/HIDIdleRequest.h | 68 + usb/common/hid/HIDInterfaceDescriptor.h | 77 + usb/common/hid/HIDKeypad.c | 56 + usb/common/hid/HIDKeypad.h | 276 +++ usb/common/hid/HIDLeds.h | 79 + usb/common/hid/HIDReport.h | 231 ++ usb/common/hid/HIDReportRequest.c | 68 + usb/common/hid/HIDReportRequest.h | 86 + usb/common/hid/hid.dir | 39 + usb/common/massstorage/MSDeviceDescriptor.h | 73 + usb/common/massstorage/MSInterfaceDescriptor.h | 75 + usb/common/massstorage/massstorage.dir | 39 + usb/device/USBDCallbackInvocationFlowchart.png | Bin 0 -> 11380 bytes usb/device/USBDeviceStateDiagram.png | Bin 0 -> 8827 bytes usb/device/audio-looprec/AUDDLoopRecChannel.c | 129 ++ usb/device/audio-looprec/AUDDLoopRecChannel.h | 92 + usb/device/audio-looprec/AUDDLoopRecDriver.c | 493 ++++ usb/device/audio-looprec/AUDDLoopRecDriver.h | 163 ++ .../audio-looprec/AUDDLoopRecDriverDescriptors.c | 1461 ++++++++++++ .../audio-looprec/AUDDLoopRecDriverDescriptors.h | 148 ++ usb/device/audio-looprec/audio-looprec.dir | 51 + usb/device/audio-speaker/AUDDSpeakerChannel.c | 129 ++ usb/device/audio-speaker/AUDDSpeakerChannel.h | 92 + usb/device/audio-speaker/AUDDSpeakerDriver.c | 378 ++++ usb/device/audio-speaker/AUDDSpeakerDriver.h | 201 ++ .../audio-speaker/AUDDSpeakerDriverDescriptors.c | 620 +++++ .../audio-speaker/AUDDSpeakerDriverDescriptors.h | 146 ++ usb/device/audio-speaker/USBAudioSpeaker.png | Bin 0 -> 3711 bytes .../audio-speaker/USBAudioSpeakerDescriptors.png | Bin 0 -> 8026 bytes .../audio-speaker/USBAudioSpeakerRecorder.png | Bin 0 -> 5053 bytes .../USBAudioSpeakerRecorderDescriptors.png | Bin 0 -> 10906 bytes usb/device/audio-speaker/audio-speaker.dir | 617 +++++ usb/device/ccid/cciddriver.c | 1503 ++++++++++++ usb/device/ccid/cciddriver.h | 378 ++++ usb/device/ccid/cciddriverdescriptors.h | 152 ++ usb/device/cdc-serial/CDCDSerialDriver.c | 300 +++ usb/device/cdc-serial/CDCDSerialDriver.h | 117 + .../cdc-serial/CDCDSerialDriverDescriptors.c | 661 ++++++ .../cdc-serial/CDCDSerialDriverDescriptors.h | 77 + usb/device/cdc-serial/CDCarchitecture.png | Bin 0 -> 28223 bytes usb/device/cdc-serial/USB-SerialConverter.png | Bin 0 -> 10177 bytes usb/device/cdc-serial/cdc-serial.dir | 646 ++++++ usb/device/cdc-serial/drv/6119.inf | 45 + usb/device/cdc-serial/drv/drv.dir | 41 + usb/device/composite/AUDDFunctionDriver.c | 282 +++ usb/device/composite/AUDDFunctionDriver.h | 105 + .../composite/AUDDFunctionDriverDescriptors.h | 69 + usb/device/composite/CDCDFunctionDriver.c | 337 +++ usb/device/composite/CDCDFunctionDriver.h | 128 ++ .../composite/CDCDFunctionDriverDescriptors.h | 65 + usb/device/composite/CDCHIDDDriver.c | 227 ++ usb/device/composite/CDCHIDDDriver.h | 78 + usb/device/composite/CDCHIDDDriverDescriptors.c | 592 +++++ usb/device/composite/CDCHIDDDriverDescriptors.h | 70 + usb/device/composite/CDCMSDDDriver.c | 213 ++ usb/device/composite/CDCMSDDDriver.h | 77 + usb/device/composite/CDCMSDDDriverDescriptors.c | 568 +++++ usb/device/composite/CDCMSDDDriverDescriptors.h | 71 + usb/device/composite/COMPOSITEDDriver.c | 292 +++ usb/device/composite/COMPOSITEDDriver.h | 93 + usb/device/composite/COMPOSITEDDriverDescriptors.c | 954 ++++++++ usb/device/composite/COMPOSITEDDriverDescriptors.h | 61 + usb/device/composite/DUALCDCDDriver.c | 189 ++ usb/device/composite/DUALCDCDDriver.h | 77 + usb/device/composite/DUALCDCDDriverDescriptors.c | 702 ++++++ usb/device/composite/DUALCDCDDriverDescriptors.h | 72 + usb/device/composite/HIDDFunctionDriver.c | 477 ++++ usb/device/composite/HIDDFunctionDriver.h | 64 + .../composite/HIDDFunctionDriverDescriptors.c | 118 + .../composite/HIDDFunctionDriverDescriptors.h | 86 + usb/device/composite/HIDMSDDDriver.c | 227 ++ usb/device/composite/HIDMSDDDriver.h | 79 + usb/device/composite/HIDMSDDDriverDescriptors.c | 449 ++++ usb/device/composite/HIDMSDDDriverDescriptors.h | 66 + usb/device/composite/MSDDFunctionDriver.c | 327 +++ usb/device/composite/MSDDFunctionDriver.h | 72 + .../composite/MSDDFunctionDriverDescriptors.h | 69 + usb/device/composite/drv/CompositeCDCSerial.inf | 57 + usb/device/composite/drv/drv.dir | 45 + usb/device/core/USBD.h | 276 +++ usb/device/core/USBDCallbacks.h | 65 + usb/device/core/USBDCallbacks_Initialized.c | 67 + usb/device/core/USBDCallbacks_RequestReceived.c | 49 + usb/device/core/USBDCallbacks_Reset.c | 47 + usb/device/core/USBDCallbacks_Resumed.c | 54 + usb/device/core/USBDCallbacks_Suspended.c | 51 + usb/device/core/USBDDriver.c | 753 +++++++ usb/device/core/USBDDriver.h | 101 + usb/device/core/USBDDriverCallbacks.h | 61 + usb/device/core/USBDDriverCb_CfgChanged.c | 49 + usb/device/core/USBDDriverCb_IfSettingChanged.c | 52 + usb/device/core/USBDDriverDescriptors.h | 86 + usb/device/core/USBD_OTGHS.c | 1697 ++++++++++++++ usb/device/core/USBD_UDP.c | 1692 ++++++++++++++ usb/device/core/USBD_UDPHS.c | 2384 ++++++++++++++++++++ usb/device/core/core.dir | 41 + usb/device/device.dir | 655 ++++++ usb/device/hid-keyboard/HIDClassArch.png | Bin 0 -> 3495 bytes usb/device/hid-keyboard/HIDDKeyboardCallbacks.h | 57 + .../HIDDKeyboardCallbacks_LedsChanged.c | 59 + usb/device/hid-keyboard/HIDDKeyboardDriver.c | 477 ++++ usb/device/hid-keyboard/HIDDKeyboardDriver.h | 75 + .../hid-keyboard/HIDDKeyboardDriverDescriptors.c | 420 ++++ .../hid-keyboard/HIDDKeyboardDriverDescriptors.h | 114 + usb/device/hid-keyboard/HIDDKeyboardInputReport.c | 164 ++ usb/device/hid-keyboard/HIDDKeyboardInputReport.h | 149 ++ usb/device/hid-keyboard/HIDDKeyboardOutputReport.c | 94 + usb/device/hid-keyboard/HIDDKeyboardOutputReport.h | 96 + usb/device/hid-keyboard/hid-keyboard.dir | 787 +++++++ usb/device/hid-mouse/HIDDMouseDriver.c | 392 ++++ usb/device/hid-mouse/HIDDMouseDriver.h | 107 + usb/device/hid-mouse/HIDDMouseDriverDescriptors.c | 385 ++++ usb/device/hid-mouse/HIDDMouseDriverDescriptors.h | 86 + usb/device/hid-mouse/HIDDMouseInputReport.c | 72 + usb/device/hid-mouse/HIDDMouseInputReport.h | 93 + usb/device/hid-mouse/hid-mouse.dir | 544 +++++ usb/device/hid-transfer/HIDDTransferDriver.c | 479 ++++ usb/device/hid-transfer/HIDDTransferDriver.h | 87 + usb/device/hid-transfer/HIDDTransferDriverDesc.c | 417 ++++ usb/device/hid-transfer/HIDDTransferDriverDesc.h | 87 + usb/device/hid-transfer/hid-transfer.dir | 473 ++++ usb/device/massstorage/MSD.h | 233 ++ usb/device/massstorage/MSDAppArch.png | Bin 0 -> 7248 bytes usb/device/massstorage/MSDDStateMachine.c | 607 +++++ usb/device/massstorage/MSDDStateMachine.h | 264 +++ usb/device/massstorage/MSDDriver.c | 343 +++ usb/device/massstorage/MSDDriver.h | 75 + usb/device/massstorage/MSDDriverArch.png | Bin 0 -> 4889 bytes usb/device/massstorage/MSDDriverClasses.png | Bin 0 -> 12031 bytes usb/device/massstorage/MSDDriverDescriptors.c | 475 ++++ usb/device/massstorage/MSDDriverDescriptors.h | 83 + usb/device/massstorage/MSDDriverStates.png | Bin 0 -> 7920 bytes usb/device/massstorage/MSDIOFifo.c | 68 + usb/device/massstorage/MSDIOFifo.h | 133 ++ usb/device/massstorage/MSDLun.c | 366 +++ usb/device/massstorage/MSDLun.h | 152 ++ usb/device/massstorage/MSDMediaArch.png | Bin 0 -> 3622 bytes usb/device/massstorage/SBC.h | 653 ++++++ usb/device/massstorage/SBCMethods.c | 1611 +++++++++++++ usb/device/massstorage/SBCMethods.h | 111 + usb/device/massstorage/massstorage.dir | 1005 +++++++++ usb/host/core/USBH.h | 73 + usb/host/core/USB_UHP.c | 223 ++ usb/host/ohci/ohci.c | 124 + usb/host/ohci/ohci.h | 139 ++ usb/otg/compiler.h | 65 + usb/otg/usb_drv.c | 246 ++ usb/otg/usb_drv.h | 859 +++++++ usb/otg/usb_host_enum.c | 670 ++++++ usb/otg/usb_host_enum.h | 329 +++ usb/otg/usb_host_enum_with_srp_hnp.c | 754 +++++++ usb/otg/usb_host_task.c | 1260 +++++++++++ usb/otg/usb_host_task.h | 230 ++ usb/otg/usb_host_task_with_srp_hnp.c | 1493 ++++++++++++ usb/otg/usb_task.c | 999 ++++++++ usb/otg/usb_task.h | 232 ++ usb/otg/usb_task_host_only.c | 287 +++ usb/otg/usb_task_with_SRP_HNP.c | 852 +++++++ usb/usb.dir | 532 +++++ 226 files changed, 52617 insertions(+) create mode 100644 usb/USBFrameworkArchitecture.png create mode 100644 usb/common/audio/AUDControlInterfaceDescriptor.h create mode 100644 usb/common/audio/AUDDataEndpointDescriptor.h create mode 100644 usb/common/audio/AUDDeviceDescriptor.h create mode 100644 usb/common/audio/AUDEndpointDescriptor.h create mode 100644 usb/common/audio/AUDFeatureUnitDescriptor.h create mode 100644 usb/common/audio/AUDFeatureUnitRequest.c create mode 100644 usb/common/audio/AUDFeatureUnitRequest.h create mode 100644 usb/common/audio/AUDFormatTypeOneDescriptor.h create mode 100644 usb/common/audio/AUDGenericDescriptor.h create mode 100644 usb/common/audio/AUDGenericRequest.c create mode 100644 usb/common/audio/AUDGenericRequest.h create mode 100644 usb/common/audio/AUDHeaderDescriptor.h create mode 100644 usb/common/audio/AUDInputTerminalDescriptor.h create mode 100644 usb/common/audio/AUDOutputTerminalDescriptor.h create mode 100644 usb/common/audio/AUDStreamingInterfaceDescriptor.h create mode 100644 usb/common/audio/audio.dir create mode 100644 usb/common/cdc/CDCAbstractControlManagementDescriptor.h create mode 100644 usb/common/cdc/CDCCallManagementDescriptor.h create mode 100644 usb/common/cdc/CDCCommunicationInterfaceDescriptor.h create mode 100644 usb/common/cdc/CDCDataInterfaceDescriptor.h create mode 100644 usb/common/cdc/CDCDeviceDescriptor.h create mode 100644 usb/common/cdc/CDCGenericDescriptor.h create mode 100644 usb/common/cdc/CDCGenericRequest.h create mode 100644 usb/common/cdc/CDCHeaderDescriptor.h create mode 100644 usb/common/cdc/CDCLineCoding.c create mode 100644 usb/common/cdc/CDCLineCoding.h create mode 100644 usb/common/cdc/CDCSetControlLineStateRequest.c create mode 100644 usb/common/cdc/CDCSetControlLineStateRequest.h create mode 100644 usb/common/cdc/CDCUnionDescriptor.h create mode 100644 usb/common/cdc/cdc.dir create mode 100644 usb/common/common.dir create mode 100644 usb/common/core/USBConfigurationDescriptor.c create mode 100644 usb/common/core/USBConfigurationDescriptor.h create mode 100644 usb/common/core/USBConfigurationOTG.c create mode 100644 usb/common/core/USBConfigurationOTG.h create mode 100644 usb/common/core/USBDeviceDescriptor.h create mode 100644 usb/common/core/USBDeviceQualifierDescriptor.h create mode 100644 usb/common/core/USBEndpointDescriptor.c create mode 100644 usb/common/core/USBEndpointDescriptor.h create mode 100644 usb/common/core/USBFeatureRequest.c create mode 100644 usb/common/core/USBFeatureRequest.h create mode 100644 usb/common/core/USBGenericDescriptor.c create mode 100644 usb/common/core/USBGenericDescriptor.h create mode 100644 usb/common/core/USBGenericRequest.c create mode 100644 usb/common/core/USBGenericRequest.h create mode 100644 usb/common/core/USBGetDescriptorRequest.c create mode 100644 usb/common/core/USBGetDescriptorRequest.h create mode 100644 usb/common/core/USBInterfaceAssociationDescriptor.h create mode 100644 usb/common/core/USBInterfaceDescriptor.h create mode 100644 usb/common/core/USBInterfaceRequest.c create mode 100644 usb/common/core/USBInterfaceRequest.h create mode 100644 usb/common/core/USBIrqHandler.c create mode 100644 usb/common/core/USBIrqHandler.h create mode 100644 usb/common/core/USBSetAddressRequest.c create mode 100644 usb/common/core/USBSetAddressRequest.h create mode 100644 usb/common/core/USBSetConfigurationRequest.c create mode 100644 usb/common/core/USBSetConfigurationRequest.h create mode 100644 usb/common/core/USBStringDescriptor.h create mode 100644 usb/common/core/core.dir create mode 100644 usb/common/hid/HIDButton.h create mode 100644 usb/common/hid/HIDDescriptor.h create mode 100644 usb/common/hid/HIDDeviceDescriptor.h create mode 100644 usb/common/hid/HIDGenericDescriptor.h create mode 100644 usb/common/hid/HIDGenericDesktop.h create mode 100644 usb/common/hid/HIDGenericRequest.h create mode 100644 usb/common/hid/HIDIdleRequest.c create mode 100644 usb/common/hid/HIDIdleRequest.h create mode 100644 usb/common/hid/HIDInterfaceDescriptor.h create mode 100644 usb/common/hid/HIDKeypad.c create mode 100644 usb/common/hid/HIDKeypad.h create mode 100644 usb/common/hid/HIDLeds.h create mode 100644 usb/common/hid/HIDReport.h create mode 100644 usb/common/hid/HIDReportRequest.c create mode 100644 usb/common/hid/HIDReportRequest.h create mode 100644 usb/common/hid/hid.dir create mode 100644 usb/common/massstorage/MSDeviceDescriptor.h create mode 100644 usb/common/massstorage/MSInterfaceDescriptor.h create mode 100644 usb/common/massstorage/massstorage.dir create mode 100644 usb/device/USBDCallbackInvocationFlowchart.png create mode 100644 usb/device/USBDeviceStateDiagram.png create mode 100644 usb/device/audio-looprec/AUDDLoopRecChannel.c create mode 100644 usb/device/audio-looprec/AUDDLoopRecChannel.h create mode 100644 usb/device/audio-looprec/AUDDLoopRecDriver.c create mode 100644 usb/device/audio-looprec/AUDDLoopRecDriver.h create mode 100644 usb/device/audio-looprec/AUDDLoopRecDriverDescriptors.c create mode 100644 usb/device/audio-looprec/AUDDLoopRecDriverDescriptors.h create mode 100644 usb/device/audio-looprec/audio-looprec.dir create mode 100644 usb/device/audio-speaker/AUDDSpeakerChannel.c create mode 100644 usb/device/audio-speaker/AUDDSpeakerChannel.h create mode 100644 usb/device/audio-speaker/AUDDSpeakerDriver.c create mode 100644 usb/device/audio-speaker/AUDDSpeakerDriver.h create mode 100644 usb/device/audio-speaker/AUDDSpeakerDriverDescriptors.c create mode 100644 usb/device/audio-speaker/AUDDSpeakerDriverDescriptors.h create mode 100644 usb/device/audio-speaker/USBAudioSpeaker.png create mode 100644 usb/device/audio-speaker/USBAudioSpeakerDescriptors.png create mode 100644 usb/device/audio-speaker/USBAudioSpeakerRecorder.png create mode 100644 usb/device/audio-speaker/USBAudioSpeakerRecorderDescriptors.png create mode 100644 usb/device/audio-speaker/audio-speaker.dir create mode 100644 usb/device/ccid/cciddriver.c create mode 100644 usb/device/ccid/cciddriver.h create mode 100644 usb/device/ccid/cciddriverdescriptors.h create mode 100644 usb/device/cdc-serial/CDCDSerialDriver.c create mode 100644 usb/device/cdc-serial/CDCDSerialDriver.h create mode 100644 usb/device/cdc-serial/CDCDSerialDriverDescriptors.c create mode 100644 usb/device/cdc-serial/CDCDSerialDriverDescriptors.h create mode 100644 usb/device/cdc-serial/CDCarchitecture.png create mode 100644 usb/device/cdc-serial/USB-SerialConverter.png create mode 100644 usb/device/cdc-serial/cdc-serial.dir create mode 100644 usb/device/cdc-serial/drv/6119.inf create mode 100644 usb/device/cdc-serial/drv/drv.dir create mode 100644 usb/device/composite/AUDDFunctionDriver.c create mode 100644 usb/device/composite/AUDDFunctionDriver.h create mode 100644 usb/device/composite/AUDDFunctionDriverDescriptors.h create mode 100644 usb/device/composite/CDCDFunctionDriver.c create mode 100644 usb/device/composite/CDCDFunctionDriver.h create mode 100644 usb/device/composite/CDCDFunctionDriverDescriptors.h create mode 100644 usb/device/composite/CDCHIDDDriver.c create mode 100644 usb/device/composite/CDCHIDDDriver.h create mode 100644 usb/device/composite/CDCHIDDDriverDescriptors.c create mode 100644 usb/device/composite/CDCHIDDDriverDescriptors.h create mode 100644 usb/device/composite/CDCMSDDDriver.c create mode 100644 usb/device/composite/CDCMSDDDriver.h create mode 100644 usb/device/composite/CDCMSDDDriverDescriptors.c create mode 100644 usb/device/composite/CDCMSDDDriverDescriptors.h create mode 100644 usb/device/composite/COMPOSITEDDriver.c create mode 100644 usb/device/composite/COMPOSITEDDriver.h create mode 100644 usb/device/composite/COMPOSITEDDriverDescriptors.c create mode 100644 usb/device/composite/COMPOSITEDDriverDescriptors.h create mode 100644 usb/device/composite/DUALCDCDDriver.c create mode 100644 usb/device/composite/DUALCDCDDriver.h create mode 100644 usb/device/composite/DUALCDCDDriverDescriptors.c create mode 100644 usb/device/composite/DUALCDCDDriverDescriptors.h create mode 100644 usb/device/composite/HIDDFunctionDriver.c create mode 100644 usb/device/composite/HIDDFunctionDriver.h create mode 100644 usb/device/composite/HIDDFunctionDriverDescriptors.c create mode 100644 usb/device/composite/HIDDFunctionDriverDescriptors.h create mode 100644 usb/device/composite/HIDMSDDDriver.c create mode 100644 usb/device/composite/HIDMSDDDriver.h create mode 100644 usb/device/composite/HIDMSDDDriverDescriptors.c create mode 100644 usb/device/composite/HIDMSDDDriverDescriptors.h create mode 100644 usb/device/composite/MSDDFunctionDriver.c create mode 100644 usb/device/composite/MSDDFunctionDriver.h create mode 100644 usb/device/composite/MSDDFunctionDriverDescriptors.h create mode 100644 usb/device/composite/drv/CompositeCDCSerial.inf create mode 100644 usb/device/composite/drv/drv.dir create mode 100644 usb/device/core/USBD.h create mode 100644 usb/device/core/USBDCallbacks.h create mode 100644 usb/device/core/USBDCallbacks_Initialized.c create mode 100644 usb/device/core/USBDCallbacks_RequestReceived.c create mode 100644 usb/device/core/USBDCallbacks_Reset.c create mode 100644 usb/device/core/USBDCallbacks_Resumed.c create mode 100644 usb/device/core/USBDCallbacks_Suspended.c create mode 100644 usb/device/core/USBDDriver.c create mode 100644 usb/device/core/USBDDriver.h create mode 100644 usb/device/core/USBDDriverCallbacks.h create mode 100644 usb/device/core/USBDDriverCb_CfgChanged.c create mode 100644 usb/device/core/USBDDriverCb_IfSettingChanged.c create mode 100644 usb/device/core/USBDDriverDescriptors.h create mode 100644 usb/device/core/USBD_OTGHS.c create mode 100644 usb/device/core/USBD_UDP.c create mode 100644 usb/device/core/USBD_UDPHS.c create mode 100644 usb/device/core/core.dir create mode 100644 usb/device/device.dir create mode 100644 usb/device/hid-keyboard/HIDClassArch.png create mode 100644 usb/device/hid-keyboard/HIDDKeyboardCallbacks.h create mode 100644 usb/device/hid-keyboard/HIDDKeyboardCallbacks_LedsChanged.c create mode 100644 usb/device/hid-keyboard/HIDDKeyboardDriver.c create mode 100644 usb/device/hid-keyboard/HIDDKeyboardDriver.h create mode 100644 usb/device/hid-keyboard/HIDDKeyboardDriverDescriptors.c create mode 100644 usb/device/hid-keyboard/HIDDKeyboardDriverDescriptors.h create mode 100644 usb/device/hid-keyboard/HIDDKeyboardInputReport.c create mode 100644 usb/device/hid-keyboard/HIDDKeyboardInputReport.h create mode 100644 usb/device/hid-keyboard/HIDDKeyboardOutputReport.c create mode 100644 usb/device/hid-keyboard/HIDDKeyboardOutputReport.h create mode 100644 usb/device/hid-keyboard/hid-keyboard.dir create mode 100644 usb/device/hid-mouse/HIDDMouseDriver.c create mode 100644 usb/device/hid-mouse/HIDDMouseDriver.h create mode 100644 usb/device/hid-mouse/HIDDMouseDriverDescriptors.c create mode 100644 usb/device/hid-mouse/HIDDMouseDriverDescriptors.h create mode 100644 usb/device/hid-mouse/HIDDMouseInputReport.c create mode 100644 usb/device/hid-mouse/HIDDMouseInputReport.h create mode 100644 usb/device/hid-mouse/hid-mouse.dir create mode 100644 usb/device/hid-transfer/HIDDTransferDriver.c create mode 100644 usb/device/hid-transfer/HIDDTransferDriver.h create mode 100644 usb/device/hid-transfer/HIDDTransferDriverDesc.c create mode 100644 usb/device/hid-transfer/HIDDTransferDriverDesc.h create mode 100644 usb/device/hid-transfer/hid-transfer.dir create mode 100644 usb/device/massstorage/MSD.h create mode 100644 usb/device/massstorage/MSDAppArch.png create mode 100644 usb/device/massstorage/MSDDStateMachine.c create mode 100644 usb/device/massstorage/MSDDStateMachine.h create mode 100644 usb/device/massstorage/MSDDriver.c create mode 100644 usb/device/massstorage/MSDDriver.h create mode 100644 usb/device/massstorage/MSDDriverArch.png create mode 100644 usb/device/massstorage/MSDDriverClasses.png create mode 100644 usb/device/massstorage/MSDDriverDescriptors.c create mode 100644 usb/device/massstorage/MSDDriverDescriptors.h create mode 100644 usb/device/massstorage/MSDDriverStates.png create mode 100644 usb/device/massstorage/MSDIOFifo.c create mode 100644 usb/device/massstorage/MSDIOFifo.h create mode 100644 usb/device/massstorage/MSDLun.c create mode 100644 usb/device/massstorage/MSDLun.h create mode 100644 usb/device/massstorage/MSDMediaArch.png create mode 100644 usb/device/massstorage/SBC.h create mode 100644 usb/device/massstorage/SBCMethods.c create mode 100644 usb/device/massstorage/SBCMethods.h create mode 100644 usb/device/massstorage/massstorage.dir create mode 100644 usb/host/core/USBH.h create mode 100644 usb/host/core/USB_UHP.c create mode 100644 usb/host/ohci/ohci.c create mode 100644 usb/host/ohci/ohci.h create mode 100644 usb/otg/compiler.h create mode 100644 usb/otg/usb_drv.c create mode 100644 usb/otg/usb_drv.h create mode 100644 usb/otg/usb_host_enum.c create mode 100644 usb/otg/usb_host_enum.h create mode 100644 usb/otg/usb_host_enum_with_srp_hnp.c create mode 100644 usb/otg/usb_host_task.c create mode 100644 usb/otg/usb_host_task.h create mode 100644 usb/otg/usb_host_task_with_srp_hnp.c create mode 100644 usb/otg/usb_task.c create mode 100644 usb/otg/usb_task.h create mode 100644 usb/otg/usb_task_host_only.c create mode 100644 usb/otg/usb_task_with_SRP_HNP.c create mode 100644 usb/usb.dir (limited to 'usb') diff --git a/usb/USBFrameworkArchitecture.png b/usb/USBFrameworkArchitecture.png new file mode 100644 index 0000000..83e77eb Binary files /dev/null and b/usb/USBFrameworkArchitecture.png differ diff --git a/usb/common/audio/AUDControlInterfaceDescriptor.h b/usb/common/audio/AUDControlInterfaceDescriptor.h new file mode 100644 index 0000000..ada2f1e --- /dev/null +++ b/usb/common/audio/AUDControlInterfaceDescriptor.h @@ -0,0 +1,72 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !!!Purpose +/// +/// Definitions for using USB %audio control interfaces. +/// +/// !!!Usage +/// +/// -# When declaring a standard USB interface descriptor for an %audio control +/// interface, use the "USB Audio control interface codes" constants. +//------------------------------------------------------------------------------ + +#ifndef AUDCONTROLINTERFACEDESCRIPTOR_H +#define AUDCONTROLINTERFACEDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Audio control interface codes" +/// +/// This page lists the class, subclass and protocol codes that a USB Audio +/// Control interface descriptor should display. +/// +/// !Codes +/// - AUDControlInterfaceDescriptor_CLASS +/// - AUDControlInterfaceDescriptor_SUBCLASS +/// - AUDControlInterfaceDescriptor_PROTOCOL + +/// Class code for an audio control interface. +#define AUDControlInterfaceDescriptor_CLASS 0x01 + +/// Subclass code for an audio control interface. +#define AUDControlInterfaceDescriptor_SUBCLASS 0x01 + +/// Protocol code for an audio control interface. +#define AUDControlInterfaceDescriptor_PROTOCOL 0x00 +//------------------------------------------------------------------------------ + +#endif //#ifndef AUDCONTROLINTERFACEDESCRIPTOR_H + diff --git a/usb/common/audio/AUDDataEndpointDescriptor.h b/usb/common/audio/AUDDataEndpointDescriptor.h new file mode 100644 index 0000000..5963546 --- /dev/null +++ b/usb/common/audio/AUDDataEndpointDescriptor.h @@ -0,0 +1,104 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !!!Purpose +/// +/// Definition of the USB audio-specific data endpoint descriptor. +/// +/// !!!Usage +/// +/// -# Declare an AUDDataEndpointDescriptor instance as part of the +/// configuration descriptors of a USB %audio %device. +//------------------------------------------------------------------------------ + +#ifndef AUDDATAENDPOINTDESCRIPTOR_H +#define AUDDATAENDPOINTDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +/// Descriptor subtype for an Audio data endpoint. +#define AUDDataEndpointDescriptor_SUBTYPE 0x01 + +//------------------------------------------------------------------------------ +/// \page "USB Audio Lock delay units" +/// +/// This page lists the valid lock delay unit types. +/// +/// !Units +/// - AUDDataEndpointDescriptor_MILLISECONDS +/// - AUDDataEndpointDescriptor_PCMSAMPLES + +/// Lock delay is expressed in milliseconds. +#define AUDDataEndpointDescriptor_MILLISECONDS 1 + +/// Lock delay is expressed in decoded PCM samples. +#define AUDDataEndpointDescriptor_PCMSAMPLES 2 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// Gives additional information about an USB endpoint used to transmit audio +/// data to or from the host. +//------------------------------------------------------------------------------ +typedef struct { + + /// Size of descriptor in bytes. + unsigned char bLength; + /// Descriptor type (AUDGenericDescriptor_ENDPOINT). + unsigned char bDescriptorType; + /// Descriptor subtype (AUDDataEndpointDescriptor_SUBTYPE). + unsigned char bDescriptorSubType; + /// Indicates available controls and requirement on packet sizes. + unsigned char bmAttributes; + /// Indicates the units of the wLockDelay fields. + /// \sa "USB Audio Lock delay units" + unsigned char bLockDelayUnits; + /// Time it takes for the endpoint to lock its internal clock circuitry. + unsigned short wLockDelay; + +} __attribute__ ((packed)) AUDDataEndpointDescriptor; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +#endif //#ifndef AUDDATAENDPOINTDESCRIPTOR_H diff --git a/usb/common/audio/AUDDeviceDescriptor.h b/usb/common/audio/AUDDeviceDescriptor.h new file mode 100644 index 0000000..f33523a --- /dev/null +++ b/usb/common/audio/AUDDeviceDescriptor.h @@ -0,0 +1,72 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !!!Purpose +/// +/// Fields values for an USB Audio %device descriptor. +/// +/// !!!Usage +/// +/// -# When declaring the %device descriptor of a USB %audio %device, use +/// "USB Audio device descriptor values" defined here. +//------------------------------------------------------------------------------ + +#ifndef AUDDEVICEDESCRIPTOR_H +#define AUDDEVICEDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Audio device descriptor values" +/// +/// This page lists the class, subclass & protocol codes that a USB audio +/// device should display in its device descriptor. +/// +/// !Codes +/// - AUDDeviceDescriptor_CLASS +/// - AUDDeviceDescriptor_SUBCLASS +/// - AUDDeviceDescriptor_PROTOCOL + +/// Class code for a USB audio device. +#define AUDDeviceDescriptor_CLASS 0x00 + +/// Subclass code for a USB audio device. +#define AUDDeviceDescriptor_SUBCLASS 0x00 + +/// Protocol code for a USB audio device. +#define AUDDeviceDescriptor_PROTOCOL 0x00 +//------------------------------------------------------------------------------ + +#endif //#ifndef AUDDEVICEDESCRIPTOR_H + diff --git a/usb/common/audio/AUDEndpointDescriptor.h b/usb/common/audio/AUDEndpointDescriptor.h new file mode 100644 index 0000000..9dce6ab --- /dev/null +++ b/usb/common/audio/AUDEndpointDescriptor.h @@ -0,0 +1,86 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !!!Purpose +/// +/// Re-definition of the standard USB endpoint descriptor with two additional +/// fields. This is required by the USB audio 1.00 specification. +/// +/// !!!Usage +/// +/// -# Declare an AUDEndpointDescriptor instance as part of the configuration +/// descriptors of an USB %audio %device. +//------------------------------------------------------------------------------ + +#ifndef AUDENDPOINTDESCRIPTOR_H +#define AUDENDPOINTDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// Modified endpoint descriptor with two additional fields, with are +/// USB audio specific. +//------------------------------------------------------------------------------ +typedef struct { + + /// Size of the descriptor in bytes. + unsigned char bLength; + /// Descriptor type (USBGenericDescriptor_ENDPOINT). + unsigned char bDescriptorType; + /// Address and direction of the endpoint. + unsigned char bEndpointAddress; + /// Endpoint type and additional characteristics (for isochronous endpoints). + unsigned char bmAttributes; + /// Maximum packet size (in bytes) of the endpoint. + unsigned short wMaxPacketSize; + /// Polling rate of the endpoint. + unsigned char bInterval; + /// Refresh rate for a feedback endpoint. + unsigned char bRefresh; + /// Address of the associated feedback endpoint if any. + unsigned char bSyncAddress; + +} __attribute__ ((packed)) AUDEndpointDescriptor; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +#endif //#ifndef AUDENDPOINTDESCRIPTOR_H + diff --git a/usb/common/audio/AUDFeatureUnitDescriptor.h b/usb/common/audio/AUDFeatureUnitDescriptor.h new file mode 100644 index 0000000..a1ba45f --- /dev/null +++ b/usb/common/audio/AUDFeatureUnitDescriptor.h @@ -0,0 +1,116 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !!!Purpose +/// +/// Class for manipulating USB %audio feature unit descriptor. +/// +/// !!!Usage +/// +/// -# Declare an AUDFeatureUnitDescriptor instance as part of the +/// configuration descriptors returned by a USB %audio %device. +//------------------------------------------------------------------------------ + +#ifndef AUDFEATUREUNITDESCRIPTOR_H +#define AUDFEATUREUNITDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Audio Channel controls" +/// +/// This page lists the available controls for each channel of the audio +/// interface. Each channel can have any control combination; simply perform +/// a bitwise OR ('|') to combine several values. +/// +/// !Controls +/// -# AUDFeatureUnitDescriptor_MUTE +/// -# AUDFeatureUnitDescriptor_VOLUME +/// -# AUDFeatureUnitDescriptor_BASS +/// -# AUDFeatureUnitDescriptor_MID +/// -# AUDFeatureUnitDescriptor_TREBLE + +/// Channel mute control. +#define AUDFeatureUnitDescriptor_MUTE (1 << 0) + +/// Channel volume control. +#define AUDFeatureUnitDescriptor_VOLUME (1 << 1) + +/// Channel bass control. +#define AUDFeatureUnitDescriptor_BASS (1 << 2) + +/// Channel middle control. +#define AUDFeatureUnitDescriptor_MID (1 << 3) + +/// Channel treble control. +#define AUDFeatureUnitDescriptor_TREBLE (1 << 4) +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// Describes available controls for each channel of the unit or terminal +/// it is connected to. This type must be augmented with the relevant number +/// of bmaControls fields and the iFeature field. +//------------------------------------------------------------------------------ +typedef struct { + + /// Size of descriptor in bytes. + unsigned char bLength; + /// Descriptor type (AUDGenericDescriptor_INTERFACE). + unsigned char bDescriptorType; + /// Descriptor subtype (AUDGenericDescriptor_FEATURE). + unsigned char bDescriptorSubType; + /// Identifier of this feature unit. + unsigned char bUnitID; + /// Identifier of the unit or terminal this feature unit is connected to. + unsigned char bSourceID; + /// Size in bytes of a channel controls field. + unsigned char bControlSize; + +} __attribute__ ((packed)) AUDFeatureUnitDescriptor; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +#endif //#ifndef AUDFEATUREUNITDESCRIPTOR_H + diff --git a/usb/common/audio/AUDFeatureUnitRequest.c b/usb/common/audio/AUDFeatureUnitRequest.c new file mode 100644 index 0000000..bc6c642 --- /dev/null +++ b/usb/common/audio/AUDFeatureUnitRequest.c @@ -0,0 +1,60 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "AUDFeatureUnitRequest.h" + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Returns the control selector value indicating the target of a Feature Unit +/// request. +/// \param request Pointer to a USBGenericRequest instance. +/// \sa "USB Audio Control selector values" +//------------------------------------------------------------------------------ +unsigned char AUDFeatureUnitRequest_GetControl(const USBGenericRequest *request) +{ + return ((USBGenericRequest_GetValue(request) >> 8) & 0xFF); +} + +//------------------------------------------------------------------------------ +/// Returns the channel number of a Feature unit which should be altered by the +/// given request. +/// \param request Pointer to a USBGenericRequest instance. +//------------------------------------------------------------------------------ +unsigned char AUDFeatureUnitRequest_GetChannel(const USBGenericRequest *request) +{ + return (USBGenericRequest_GetValue(request) & 0xFF); +} + diff --git a/usb/common/audio/AUDFeatureUnitRequest.h b/usb/common/audio/AUDFeatureUnitRequest.h new file mode 100644 index 0000000..289f598 --- /dev/null +++ b/usb/common/audio/AUDFeatureUnitRequest.h @@ -0,0 +1,81 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !!!Purpose +/// +/// Definitions of constants and methods for using USB %audio requests +/// targetted at a Feature unit. +/// +/// !!!Usage +/// +/// - For a USB %device: +/// -# Use AUDFeatureUnitRequest_GetControl to determine which control +/// shall be tweaked following a host request. +// -# Use AUDFeatureUnitRequest_GetChannel to identify the channel which +// will have its control altered. +//------------------------------------------------------------------------------ + +#ifndef AUDFEATUREUNITREQUEST_H +#define AUDFEATUREUNITREQUEST_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include + +//------------------------------------------------------------------------------ +// Constants +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Audio Control selector values" +/// +/// This page lists the available control selectors for a Feature Unit request. +/// +/// !Controls +/// - AUDFeatureUnitRequest_MUTE + +/// Mute control selector. +#define AUDFeatureUnitRequest_MUTE 0x01 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ +extern unsigned char AUDFeatureUnitRequest_GetControl( + const USBGenericRequest *request); +extern unsigned char AUDFeatureUnitRequest_GetChannel( + const USBGenericRequest *request); + +#endif //#ifndef AUDFEATUREUNITREQUEST_H + diff --git a/usb/common/audio/AUDFormatTypeOneDescriptor.h b/usb/common/audio/AUDFormatTypeOneDescriptor.h new file mode 100644 index 0000000..0aa6b63 --- /dev/null +++ b/usb/common/audio/AUDFormatTypeOneDescriptor.h @@ -0,0 +1,101 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !!!Purpose +/// +/// Definitions for using USB %audio format type I descriptors. +/// +/// !!!Usage +/// +/// -# Declare an instance of AUDFormatTypeOneDescriptor as part of the +/// configuration descriptors of an audio device. +//------------------------------------------------------------------------------ + +#ifndef AUDFORMATTYPEONEDESCRIPTOR_H +#define AUDFORMATTYPEONEDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +/// Format type for a format type I descriptor. +#define AUDFormatTypeOneDescriptor_FORMATTYPEONE 0x01 + +/// AUDFormatTypeOneDescriptor_PCM - PCM format. +#define AUDFormatTypeOneDescriptor_PCM 0x0001 + +/// Indicates the sampling frequency can have any value in the provided range. +#define AUDFormatTypeOneDescriptor_CONTINUOUS 0 + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// Describes an audio data stream that is constructed on a sample-by-sample +/// basis. This type must be augmented with either the continuous sampling +/// frequency range (if bSamFreqType = ) +/// or with an array containing the possible discrete frequencies. +//------------------------------------------------------------------------------ +typedef struct { + + /// Size of descriptor in bytes. + unsigned char bLength; + /// Descriptor type (AUDGenericDescriptor_INTERFACE). + unsigned char bDescriptorType; + /// Descriptor subtype (AUDStreamingInterfaceDescriptor_FORMATTYPE). + unsigned char bDescriptorSubType; + /// Format type (AUDFormatTypeOneDescriptor_FORMATTYPEONE). + unsigned char bFormatType; + /// Number of physical channels in the audio stream. + unsigned char bNrChannels; + /// Number of bytes occupied by one audio subframe. + unsigned char bSubFrameSize; + /// Number of bits effectively used in an audio subframe. + unsigned char bBitResolution; + /// Number of supported discrete sampling frequencies, or + /// AUDFormatTypeOneDescriptor_CONTINUOUS. + unsigned char bSamFreqType; + +} __attribute__ ((packed)) AUDFormatTypeOneDescriptor; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +#endif //#ifndef AUDFORMATTYPEONEDESCRIPTOR_H + diff --git a/usb/common/audio/AUDGenericDescriptor.h b/usb/common/audio/AUDGenericDescriptor.h new file mode 100644 index 0000000..8758a92 --- /dev/null +++ b/usb/common/audio/AUDGenericDescriptor.h @@ -0,0 +1,121 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !!!Purpose +/// +/// Constants for manipulating USB audio-specific descriptors. +/// +/// !!!Usage +/// +/// - For a USB %device: +/// -# When declaring an Audio-specific descriptor, use the descriptor types +/// and subtypes defined in this unit (see "USB Audio descriptor types" +/// and "USB Audio descriptor subtypes"). +//------------------------------------------------------------------------------ + +#ifndef AUDGENERICDESCRIPTOR_H +#define AUDGENERICDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Audio descriptor types" +/// +/// This page lists the available types for USB audio-specific descriptors. +/// +/// !Types +/// - AUDGenericDescriptor_DEVICE +/// - AUDGenericDescriptor_CONFIGURATION +/// - AUDGenericDescriptor_STRING +/// - AUDGenericDescriptor_INTERFACE +/// - AUDGenericDescriptor_ENDPOINT + +/// Descriptor gives detail about the whole device. +#define AUDGenericDescriptor_DEVICE 0x21 + +/// Descriptor gives detail about a configuration. +#define AUDGenericDescriptor_CONFIGURATION 0x22 + +/// Descriptor gives detail about a string. +#define AUDGenericDescriptor_STRING 0x23 + +/// Descriptor gives detail about an interface. +#define AUDGenericDescriptor_INTERFACE 0x24 + +/// Descriptor gives detail about an endpoint. +#define AUDGenericDescriptor_ENDPOINT 0x25 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Audio descriptor subtypes" +/// +/// This page lists the possible subtypes for USB audio-specific descriptors. +/// +/// !Subtypes +/// - AUDGenericDescriptor_HEADER +/// - AUDGenericDescriptor_INPUTTERMINAL +/// - AUDGenericDescriptor_OUTPUTTERMINAL +/// - AUDGenericDescriptor_MIXERUNIT +/// - AUDGenericDescriptor_SELECTORUNIT +/// - AUDGenericDescriptor_FEATUREUNIT +/// - AUDGenericDescriptor_PROCESSINGUNIT +/// - AUDGenericDescriptor_EXTENSIONUNIT + +/// Header descriptor subtype. +#define AUDGenericDescriptor_HEADER 0x01 + +/// Input terminal descriptor subtype. +#define AUDGenericDescriptor_INPUTTERMINAL 0x02 + +/// Output terminal descriptor subtype. +#define AUDGenericDescriptor_OUTPUTTERMINAL 0x03 + +/// Mixer unit descriptor subtype. +#define AUDGenericDescriptor_MIXERUNIT 0x04 + +/// Selector unit descriptor subtype. +#define AUDGenericDescriptor_SELECTORUNIT 0x05 + +/// Feature unit descriptor subtype. +#define AUDGenericDescriptor_FEATUREUNIT 0x06 + +/// Processing unit descriptor subtype. +#define AUDGenericDescriptor_PROCESSINGUNIT 0x07 + +///Extension unit descriptor subtype. +#define AUDGenericDescriptor_EXTENSIONUNIT 0x08 +//------------------------------------------------------------------------------ + +#endif //#ifndef AUDGENERICDESCRIPTOR_H + diff --git a/usb/common/audio/AUDGenericRequest.c b/usb/common/audio/AUDGenericRequest.c new file mode 100644 index 0000000..c9c6e87 --- /dev/null +++ b/usb/common/audio/AUDGenericRequest.c @@ -0,0 +1,57 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "AUDGenericRequest.h" + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Returns the ID of the unit or terminal targetted by an USB audio request. +/// \param request Pointer to a USBGenericRequest instance. +//------------------------------------------------------------------------------ +unsigned char AUDGenericRequest_GetEntity(const USBGenericRequest *request) +{ + return ((USBGenericRequest_GetIndex(request) >> 8) & 0xFF); +} + +//------------------------------------------------------------------------------ +/// Returns the ID of the interface targetted by an USB audio request. +/// \param request Pointer to a USBGenericRequest instance. +//------------------------------------------------------------------------------ +unsigned char AUDGenericRequest_GetInterface(const USBGenericRequest *request) +{ + return (USBGenericRequest_GetIndex(request) & 0xFF); +} + diff --git a/usb/common/audio/AUDGenericRequest.h b/usb/common/audio/AUDGenericRequest.h new file mode 100644 index 0000000..b0b8527 --- /dev/null +++ b/usb/common/audio/AUDGenericRequest.h @@ -0,0 +1,94 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !!!Purpose +/// +/// Constants for using USB %audio SETUP requests. +/// +/// !!!Usage +/// +/// - For a USB %device: +/// -# After receiving an Audio request from the host, use +/// AUDGenericRequest_GetEntity to determine the target Unit or Terminal. +/// -# After receiving an Audio request from the host, use +/// AUDGenericRequest_GetInterface to know which interface is referenced. +//------------------------------------------------------------------------------ + +#ifndef AUDGENERICREQUEST_H +#define AUDGENERICREQUEST_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Audio request codes" +/// +/// This page lists the codes of the existing Audio requests. +/// +/// !Requests +/// - AUDGenericRequest_SETCUR +/// - AUDGenericRequest_GETCUR + +/// SET_CUR request code. +#define AUDGenericRequest_SETCUR 0x01 + +/// GET_CUR request code. +#define AUDGenericRequest_GETCUR 0x81 + +/// GET_MIN request code. +#define AUDGenericRequest_GETMIN 0x82 + +/// GET_MAX request code. +#define AUDGenericRequest_GETMAX 0x83 + +/// GET_RES request code. +#define AUDGenericRequest_GETRES 0x84 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char AUDGenericRequest_GetEntity( + const USBGenericRequest *request); +extern unsigned char AUDGenericRequest_GetInterface( + const USBGenericRequest *request); + +#endif //#ifndef AUDGENERICREQUEST_H + diff --git a/usb/common/audio/AUDHeaderDescriptor.h b/usb/common/audio/AUDHeaderDescriptor.h new file mode 100644 index 0000000..ca30a0b --- /dev/null +++ b/usb/common/audio/AUDHeaderDescriptor.h @@ -0,0 +1,100 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !!!Purpose +/// +/// Class for manipulating USB %audio header descriptors. +/// +/// !!!Usage +/// +/// - For a USB %device: +/// -# Declare a AUDHeaderDescriptor as part of the configuration +/// descriptors of the %device. +//------------------------------------------------------------------------------ + +#ifndef AUDHEADERDESCRIPTOR_H +#define AUDHEADERDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Audio class releases" +/// This page lists the existing versions of the Audio class specification. +/// +/// +/// !Versions +/// - AUDHeaderDescriptor_AUD1_00 + +/// Indentifies the USB audio specification release 1.00. +#define AUDHeaderDescriptor_AUD1_00 0x0100 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// Groups the various audio interfaces to display one single function to +/// the USB host. Subclass this structure to add a particular number of +/// slave interface descriptors. +//------------------------------------------------------------------------------ +typedef struct { + + /// Size of descriptor in bytes. + unsigned char bLength; + /// Descriptor type (AUDGenericDescriptor_INTERFACE). + unsigned char bDescriptorType; + /// Descriptor subtype (AUDGenericDescriptor_HEADER). + unsigned char bDescriptorSubType; + /// Audio class release number in BCD format + /// \sa "USB Audio class releases" + unsigned short bcdADC; + /// Length of all descriptors used to qualify the Audio Control interface. + unsigned short wTotalLength; + /// Number of Streaming interfaces contained in this collection. + unsigned char bInCollection; + +} __attribute__ ((packed)) AUDHeaderDescriptor; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +#endif //#ifndef AUDHEADERDESCRIPTOR_H + diff --git a/usb/common/audio/AUDInputTerminalDescriptor.h b/usb/common/audio/AUDInputTerminalDescriptor.h new file mode 100644 index 0000000..e0895fb --- /dev/null +++ b/usb/common/audio/AUDInputTerminalDescriptor.h @@ -0,0 +1,139 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !!!Purpose +/// +/// Class for manipulating input terminal descriptors. +/// +/// !!!Usage +/// +/// - For a USB %device: +/// -# Declare an AUDInputTerminalDescriptor instance as part of the +/// configuration of the %device. +//------------------------------------------------------------------------------ + +#ifndef AUDINPUTTERMINALDESCRIPTOR_H +#define AUDINPUTTERMINALDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Audio Input terminal types" +/// +/// This page lists the available types for an Input terminal. +/// +/// !Types +/// +/// - AUDInputTerminalDescriptor_USBSTREAMING +/// - AUDInputTerminalDescriptor_MICROPHONE +/// - AUDInputTerminalDescriptor_SPEAKERPHONE +/// - AUDInputTerminalDescriptor_LINEIN + +/// A terminal receiving its data from a USB isochronous endpoint. +#define AUDInputTerminalDescriptor_USBSTREAMING 0x0101 +/// A terminal sampling data from a microphone. +#define AUDInputTerminalDescriptor_MICROPHONE 0x0201 +/// A terminal sampling data from a Handset In. +#define AUDInputTerminalDescriptor_HANDSETIN 0x0401 +/// A terminal sampling data from a speakerphone +#define AUDInputTerminalDescriptor_SPEAKERPHONE 0x0403 +/// A terminal sampling data from a Phone Line In. +#define AUDInputTerminalDescriptor_LINEIN 0x0501 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Audio Channel spatial locations" +/// +/// This page lists the possible spatial locations for audio channels. +/// +/// !Locations +/// +/// - AUDInputTerminalDescriptor_LEFTFRONT +/// - AUDInputTerminalDescriptor_RIGHTFRONT +/// - AUDInputTerminalDescriptor_CENTERFRONT + +/// Front left channel. +#define AUDInputTerminalDescriptor_LEFTFRONT (1 << 0) + +/// Front right channel. +#define AUDInputTerminalDescriptor_RIGHTFRONT (1 << 1) + +/// Front center channel. +#define AUDInputTerminalDescriptor_CENTERFRONT (1 << 2) +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// Describes an input of a USB audio device. +//------------------------------------------------------------------------------ +typedef struct { + + /// Size of descriptor in bytes. + unsigned char bLength; + /// Descriptor type (AUDGenericDescriptor_INTERFACE). + unsigned char bDescriptorType; + /// Descriptor subtype (AUDGenericDescriptor_INPUTTERMINAL). + unsigned char bDescriptorSubType; + /// ID of the terminal in the audio function. + unsigned char bTerminalID; + /// Terminal type. + /// \sa "USB Audio Input terminal types" + unsigned short wTerminalType; + /// ID of the output terminal to which this input terminal is associated. + unsigned char bAssocTerminal; + /// Number of logical output channels in this terminal. + unsigned char bNrChannels; + /// Spatial configuration of the logical channels. + unsigned short wChannelConfig; + /// Index of a string descriptor for the first logical channel. + unsigned char iChannelNames; + /// Index of a string descriptor for this terminal. + unsigned char iTerminal; + +} __attribute__ ((packed)) AUDInputTerminalDescriptor; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +#endif //#ifndef AUDINPUTTERMINALDESCRIPTOR_H + diff --git a/usb/common/audio/AUDOutputTerminalDescriptor.h b/usb/common/audio/AUDOutputTerminalDescriptor.h new file mode 100644 index 0000000..6ba3156 --- /dev/null +++ b/usb/common/audio/AUDOutputTerminalDescriptor.h @@ -0,0 +1,112 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !!!Purpose +/// +/// Definition of a class for using USB %audio output terminal descriptors. +/// +/// !!!Usage +/// +/// - For a USB %device: +/// -# Declare a AUDOutputTerminalDescriptor instance as part of the +/// configuration descriptors of a USB %audio %device. +//------------------------------------------------------------------------------ + +#ifndef AUDOUTPUTTERMINALDESCRIPTOR_H +#define AUDOUTPUTTERMINALDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Audio Output terminal types" +/// +/// This page lists the available types for an output terminal. +/// +/// !Types +/// - AUDOutputTerminalDescriptor_USBTREAMING +/// - AUDOutputTerminalDescriptor_SPEAKER +/// - AUDOutputTerminalDescriptor_HANDSETOUT +/// - AUDOutputTerminalDescriptor_LINEOUT + +/// A terminal sending data through USB isochronous endpoint. +#define AUDOutputTerminalDescriptor_USBTREAMING 0x0101 +/// A terminal sending data to a USB host through an Isochronous endpoint. +#define AUDOutputTerminalDescriptor_SPEAKER 0x0301 +/// A terminal sending data to Handset Out. +#define AUDOutputTerminalDescriptor_HANDSETOUT 0x0401 +/// A terminal sending data to Phone Line Out. +#define AUDOutputTerminalDescriptor_LINEOUT 0x0501 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// \typedef AUDOutputTerminalDescriptor +/// Describes an output of the USB audio function. +//------------------------------------------------------------------------------ +typedef struct { + + /// Size of descriptor in bytes. + unsigned char bLength; + /// Descriptor type (AUDGenericDescriptor_INTERFACE). + unsigned char bDescriptorType; + /// Descriptor subtype (AUDGenericDescriptor_OUTPUTTERMINAL). + unsigned char bDescriptorSubType; + /// Identifier for this terminal. + unsigned char bTerminalID; + /// Terminal type. + /// \sa "USB Audio Output terminal types" + unsigned short wTerminalType; + /// Identifier of the associated input terminal. + unsigned char bAssocTerminal; + /// Identifier of the unit or terminal to which this terminal is connected. + unsigned char bSourceID; + /// Index of a string descriptor for this terminal. + unsigned char iTerminal; + +} __attribute__ ((packed)) AUDOutputTerminalDescriptor; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +#endif //#ifndef AUDOUTPUTTERMINALDESCRIPTOR_H + diff --git a/usb/common/audio/AUDStreamingInterfaceDescriptor.h b/usb/common/audio/AUDStreamingInterfaceDescriptor.h new file mode 100644 index 0000000..80c9cfd --- /dev/null +++ b/usb/common/audio/AUDStreamingInterfaceDescriptor.h @@ -0,0 +1,129 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !!!Purpose +/// +/// Definition of a class for manipulating USB %audio streaming interface +/// descriptors. +/// +/// !!!Usage +/// +/// - For a USB %device: +/// -# Declare an AUDStreamingInterfaceDescriptor instance as part of the +/// configuration descriptors returned by a USB %audio %device. +//------------------------------------------------------------------------------ + +#ifndef AUDSTREAMINGINTERFACEDESCRIPTOR_H +#define AUDSTREAMINGINTERFACEDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Audio streaming interface codes" +/// +/// This page lists the class, subclass and protocol codes that an Audio +/// Streaming interface should display in its descriptor. +/// +/// !Codes +/// - AUDStreamingInterfaceDescriptor_CLASS +/// - AUDStreamingInterfaceDescriptor_SUBCLASS +/// - AUDStreamingInterfaceDescriptor_PROTOCOL + +/// Class code for an USB audio streaming interface. +#define AUDStreamingInterfaceDescriptor_CLASS 0x01 + +/// Subclass code for an audio streaming interface. +#define AUDStreamingInterfaceDescriptor_SUBCLASS 0x02 + +/// Protocol code for an audio streaming interface. +#define AUDStreamingInterfaceDescriptor_PROTOCOL 0x00 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Audio streaming descriptor subtypes" +/// +/// This page lists the possible subtypes for audio-specific descriptor appended +/// to an Audio Streaming interface. +/// +/// !Subtypes +/// - AUDStreamingInterfaceDescriptor_GENERAL +/// - AUDStreamingInterfaceDescriptor_FORMATTYPE +/// - AUDStreamingInterfaceDescriptor_FORMATSPECIFIC + +/// General descriptor subtype. +#define AUDStreamingInterfaceDescriptor_GENERAL 0x01 + +/// Format type descriptor subtype. +#define AUDStreamingInterfaceDescriptor_FORMATTYPE 0x02 + +/// Format specific descriptor subtype. +#define AUDStreamingInterfaceDescriptor_FORMATSPECIFIC 0x03 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// Provides additional information about an audio streaming interface to +/// the USB host. +//------------------------------------------------------------------------------ +typedef struct { + + /// Size of descriptor in bytes. + unsigned char bLength; + /// Descriptor type (AUDGenericDescriptor_INTERFACE). + unsigned char bDescriptorType; + /// Descriptor subtype (AUDStreamingInterfaceDescriptor_GENERAL). + unsigned char bDescriptorSubType; + /// Terminal ID to which the interface is connected. + unsigned char bTerminalLink; + /// Delay introduced by the data path, in number of frames. + unsigned char bDelay; + /// Audio data format used by this interface. + unsigned short wFormatTag; + +} __attribute__ ((packed)) AUDStreamingInterfaceDescriptor; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +#endif //#ifndef AUDSTREAMINGINTERFACEDESCRIPTOR_H + diff --git a/usb/common/audio/audio.dir b/usb/common/audio/audio.dir new file mode 100644 index 0000000..2bc574f --- /dev/null +++ b/usb/common/audio/audio.dir @@ -0,0 +1,40 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// !!!Purpose +/// +/// This directory contains definitions, structures and funcions related to the +/// USB Audio Class specification. They can be divided into two groups: +/// - Audio-specific descriptors, prefixed with AUD and suffixed with +/// Descriptor. +/// - Audio-specific requests, prefixed with AUD and suffixed with Request. +//------------------------------------------------------------------------------ + diff --git a/usb/common/cdc/CDCAbstractControlManagementDescriptor.h b/usb/common/cdc/CDCAbstractControlManagementDescriptor.h new file mode 100644 index 0000000..943204c --- /dev/null +++ b/usb/common/cdc/CDCAbstractControlManagementDescriptor.h @@ -0,0 +1,104 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of a class for manipulating CDC abstract control management + descriptors. + + !!!Usage + + Should be included in a list of USB configuration descriptors. +*/ + +#ifndef CDCABSTRACTCONTROLMANAGEMENTDESCRIPTOR_H +#define CDCABSTRACTCONTROLMANAGEMENTDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "CDC ACM Capabilities" +/// This page lists the capabilities of the CDC ACM. +/// +/// !Capabilities +/// - CDCAbstractControlManagementDescriptor_COMMFEATURE +/// - CDCAbstractControlManagementDescriptor_LINE +/// - CDCAbstractControlManagementDescriptor_SENDBREAK +/// - CDCAbstractControlManagementDescriptor_NETWORKCONNECTION + +/// Device supports the request combination of SetCommFeature, ClearCommFeature +/// and GetCommFeature. +#define CDCAbstractControlManagementDescriptor_COMMFEATURE (1 << 0) +/// Device supports the request combination of SetLineCoding, GetLineCoding and +/// SetControlLineState. +#define CDCAbstractControlManagementDescriptor_LINE (1 << 1) +/// Device supports the SendBreak request. +#define CDCAbstractControlManagementDescriptor_SENDBREAK (1 << 2) +/// Device supports the NetworkConnection notification. +#define CDCAbstractControlManagementDescriptor_NETWORKCONNECTION (1 << 3) +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// Describes the command supported by the communication interface class +/// with the Abstract Control Model subclass code. +//------------------------------------------------------------------------------ +typedef struct { + + /// Size of this descriptor in bytes. + unsigned char bFunctionLength; + /// Descriptor type (CDCDescriptors_INTERFACE). + unsigned char bDescriptorType; + /// Descriptor subtype (CDCDescriptors_ABSTRACTCONTROLMANAGEMENT). + unsigned char bDescriptorSubtype; + /// Configuration capabilities. + /// \sa "CDC ACM Capabilities". + unsigned char bmCapabilities; + +} __attribute__ ((packed)) CDCAbstractControlManagementDescriptor; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +#endif //#ifndef CDCABSTRACTCONTROLMANAGEMENTDESCRIPTOR_H + diff --git a/usb/common/cdc/CDCCallManagementDescriptor.h b/usb/common/cdc/CDCCallManagementDescriptor.h new file mode 100644 index 0000000..191ff61 --- /dev/null +++ b/usb/common/cdc/CDCCallManagementDescriptor.h @@ -0,0 +1,97 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of a class for managing CDC call management descriptors. + + !!!Usage + + Should be included in a list of configuration descriptors for a USB + device. +*/ + +#ifndef CDCCALLMANAGEMENTDESCRIPTOR_H +#define CDCCALLMANAGEMENTDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "CDC CallManagement Capabilities" +/// This page lists CDC CallManagement Capabilities. +/// +/// !Capabilities +/// - CDCCallManagementDescriptor_SELFCALLMANAGEMENT +/// - CDCCallManagementDescriptor_DATACALLMANAGEMENT + +/// Device handles call management itself. +#define CDCCallManagementDescriptor_SELFCALLMANAGEMENT (1 << 0) +/// Device can exchange call management information over a Data class interface. +#define CDCCallManagementDescriptor_DATACALLMANAGEMENT (1 << 1) +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// Describes the processing of calls for the communication class interface. +//------------------------------------------------------------------------------ +typedef struct { + + /// Size of this descriptor in bytes. + unsigned char bFunctionLength; + /// Descriptor type (CDCDescriptors_INTERFACE). + unsigned char bDescriptorType; + /// Descriptor sub-type (CDCDescriptors_CALLMANAGEMENT). + unsigned char bDescriptorSubtype; + /// Configuration capabilities ("CDC CallManagement Capabilities"). + unsigned char bmCapabilities; + /// Interface number of the data class interface used for call management + /// (optional). + unsigned char bDataInterface; + +} __attribute__ ((packed)) CDCCallManagementDescriptor; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +#endif //#ifndef CDCCALLMANAGEMENTDESCRIPTOR_H + diff --git a/usb/common/cdc/CDCCommunicationInterfaceDescriptor.h b/usb/common/cdc/CDCCommunicationInterfaceDescriptor.h new file mode 100644 index 0000000..aa13915 --- /dev/null +++ b/usb/common/cdc/CDCCommunicationInterfaceDescriptor.h @@ -0,0 +1,65 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of several constants used when declaring a CDC communication + class interface descriptor. +*/ + +#ifndef CDCCOMMUNICATIONINTERFACEDESCRIPTOR_H +#define CDCCOMMUNICATIONINTERFACEDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "CDC Communication Interface Values" +/// This page lists the values for CDC Communication Interface Descriptor. +/// +/// !Values +/// - CDCCommunicationInterfaceDescriptor_CLASS +/// - CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL +/// - CDCCommunicationInterfaceDescriptor_NOPROTOCOL + +/// Interface class code for a CDC communication class interface. +#define CDCCommunicationInterfaceDescriptor_CLASS 0x02 +/// Interface subclass code for an Abstract Control Model interface descriptor. +#define CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL 0x02 +/// Interface protocol code when a CDC communication interface does not +/// implemenent any particular protocol. +#define CDCCommunicationInterfaceDescriptor_NOPROTOCOL 0x00 +//------------------------------------------------------------------------------ + +#endif //#ifndef CDCCOMMUNICATIONINTERFACEDESCRIPTOR_H + diff --git a/usb/common/cdc/CDCDataInterfaceDescriptor.h b/usb/common/cdc/CDCDataInterfaceDescriptor.h new file mode 100644 index 0000000..640f8dc --- /dev/null +++ b/usb/common/cdc/CDCDataInterfaceDescriptor.h @@ -0,0 +1,65 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definitions of constants used when declaring a CDC data class interface + descriptor. +*/ + +#ifndef CDCDATAINTERFACEDESCRIPTOR_H +#define CDCDATAINTERFACEDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "CDC Data Interface Values" +/// This page lists the values for CDC Data Interface Descriptor. +/// +/// !Values +/// - CDCDataInterfaceDescriptor_CLASS +/// - CDCDataInterfaceDescriptor_SUBCLASS +/// - CDCDataInterfaceDescriptor_NOPROTOCOL + +/// Interface class code for a data class interface. +#define CDCDataInterfaceDescriptor_CLASS 0x0A +/// Interface subclass code for a data class interface. +#define CDCDataInterfaceDescriptor_SUBCLASS 0x00 +/// Protocol code for a data class interface which does not implement any +/// particular protocol. +#define CDCDataInterfaceDescriptor_NOPROTOCOL 0x00 +//------------------------------------------------------------------------------ + +#endif //#ifndef CDCDATAINTERFACEDESCRIPTOR_H + diff --git a/usb/common/cdc/CDCDeviceDescriptor.h b/usb/common/cdc/CDCDeviceDescriptor.h new file mode 100644 index 0000000..b1bc177 --- /dev/null +++ b/usb/common/cdc/CDCDeviceDescriptor.h @@ -0,0 +1,64 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of several constants used when declaring USB CDC device + descriptors. +*/ + +#ifndef CDCDEVICEDESCRIPTOR_H +#define CDCDEVICEDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "CDC Device Descriptor Values" +/// This page lists the values for CDC Device Descriptor. +/// +/// !Values +/// - CDCDeviceDescriptor_CLASS +/// - CDCDeviceDescriptor_SUBCLASS +/// - CDCDeviceDescriptor_PROTOCOL + +/// Device class code when using the CDC class. +#define CDCDeviceDescriptor_CLASS 0x02 +/// Device subclass code when using the CDC class. +#define CDCDeviceDescriptor_SUBCLASS 0x00 +/// Device protocol code when using the CDC class. +#define CDCDeviceDescriptor_PROTOCOL 0x00 +//------------------------------------------------------------------------------ + +#endif //#ifndef CDCDEVICEDESCRIPTOR_H + diff --git a/usb/common/cdc/CDCGenericDescriptor.h b/usb/common/cdc/CDCGenericDescriptor.h new file mode 100644 index 0000000..3d93656 --- /dev/null +++ b/usb/common/cdc/CDCGenericDescriptor.h @@ -0,0 +1,91 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of several constants for declaring CDC descriptors. +*/ + +#ifndef CDCGENERICDESCRIPTOR_H +#define CDCGENERICDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "CDC Specification Release Numbers" +/// This page list the CDC Spec. Release Numbers. +/// +/// !Numbers +/// - CDCGenericDescriptor_CDC1_10 + +/// Identify CDC specification version 1.10. +#define CDCGenericDescriptor_CDC1_10 0x0110 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "CDC Descriptro Types" +/// This page lists CDC descriptor types. +/// +/// !Types +/// - CDCGenericDescriptor_INTERFACE +/// - CDCGenericDescriptor_ENDPOINT + +///Indicates that a CDC descriptor applies to an interface. +#define CDCGenericDescriptor_INTERFACE 0x24 +/// Indicates that a CDC descriptor applies to an endpoint. +#define CDCGenericDescriptor_ENDPOINT 0x25 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "CDC Descriptor Subtypes" +/// This page lists CDC descriptor sub types +/// +/// !Types +/// - CDCGenericDescriptor_HEADER +/// - CDCGenericDescriptor_CALLMANAGEMENT +/// - CDCGenericDescriptor_ABSTRACTCONTROLMANAGEMENT +/// - CDCGenericDescriptor_UNION + +/// Header functional descriptor subtype. +#define CDCGenericDescriptor_HEADER 0x00 +/// Call management functional descriptor subtype. +#define CDCGenericDescriptor_CALLMANAGEMENT 0x01 +/// Abstract control management descriptor subtype. +#define CDCGenericDescriptor_ABSTRACTCONTROLMANAGEMENT 0x02 +/// Union descriptor subtype. +#define CDCGenericDescriptor_UNION 0x06 +//------------------------------------------------------------------------------ + +#endif //#ifndef CDCGENERICDESCRIPTOR_H + diff --git a/usb/common/cdc/CDCGenericRequest.h b/usb/common/cdc/CDCGenericRequest.h new file mode 100644 index 0000000..d6abd0b --- /dev/null +++ b/usb/common/cdc/CDCGenericRequest.h @@ -0,0 +1,63 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Various definitions used for characterizing USB CDC requests. +*/ + +#ifndef CDCGENERICREQUEST_H +#define CDCGENERICREQUEST_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "CDC Request Codes" +/// This page lists USB CDC Request Codes. +/// +/// !Codes +/// - CDCGenericRequest_SETLINECODING +/// - CDCGenericRequest_GETLINECODING +/// - CDCGenericRequest_SETCONTROLLINESTATE + +/// SetLineCoding request code. +#define CDCGenericRequest_SETLINECODING 0x20 +/// GetLineCoding request code. +#define CDCGenericRequest_GETLINECODING 0x21 +/// SetControlLineState request code. +#define CDCGenericRequest_SETCONTROLLINESTATE 0x22 +//------------------------------------------------------------------------------ + +#endif //#ifndef CDCGENERICREQUEST_H + diff --git a/usb/common/cdc/CDCHeaderDescriptor.h b/usb/common/cdc/CDCHeaderDescriptor.h new file mode 100644 index 0000000..b04926f --- /dev/null +++ b/usb/common/cdc/CDCHeaderDescriptor.h @@ -0,0 +1,77 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of the CDCHeaderDescriptor class. + + !!!Usage + + Should be included in a USB configuration descriptor. +*/ + +#ifndef CDCHEADERDESCRIPTOR_H +#define CDCHEADERDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// Marks the beginning of the concatenated set of functional descriptors +/// for the interface. +//------------------------------------------------------------------------------ +typedef struct { + + /// Size of this descriptor in bytes. + unsigned char bFunctionLength; + /// Descriptor type (CDCDescriptors_INTERFACE). + unsigned char bDescriptorType; + /// Descriptor sub-type (CDCDescriptors_HEADER). + unsigned char bDescriptorSubtype; + /// USB CDC specification release number. + unsigned short bcdCDC; + +} __attribute__ ((packed)) CDCHeaderDescriptor; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +#endif //#ifndef CDCHEADERDESCRIPTOR_H + + diff --git a/usb/common/cdc/CDCLineCoding.c b/usb/common/cdc/CDCLineCoding.c new file mode 100644 index 0000000..4223fec --- /dev/null +++ b/usb/common/cdc/CDCLineCoding.c @@ -0,0 +1,78 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: CDCLineCoding + + About: Purpose + Implementation of the CDCLineCoding class. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "CDCLineCoding.h" +#include + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes the bitrate, number of stop bits, parity checking and +/// number of data bits of a CDCLineCoding object. +/// \param lineCoding Pointer to a CDCLineCoding instance. +/// \param bitrate Bitrate of the virtual COM connection. +/// \param stopbits Number of stop bits ("CDC LineCoding StopBits"). +/// \param parity Parity check type ("CDC LineCoding ParityChecking"). +/// \param databits Number of data bits. +//------------------------------------------------------------------------------ +void CDCLineCoding_Initialize(CDCLineCoding *lineCoding, + unsigned int bitrate, + unsigned char stopbits, + unsigned char parity, + unsigned char databits) +{ + ASSERT(stopbits <= CDCLineCoding_TWOSTOPBITS, + "CDCLineCoding_Initialize: Invalid stopbits value (%d)\n\r", + stopbits); + ASSERT(parity <= CDCLineCoding_SPACEPARITY, + "CDCLineCoding_Initialize: Invalid parity value (%d)\n\r", + parity); + ASSERT(((databits >= 5) && (databits <= 8)) || (databits == 16), + "CDCLineCoding_Initialize: Invalid databits value (%d)\n\r", + databits); + + lineCoding->dwDTERate = bitrate; + lineCoding->bCharFormat = stopbits; + lineCoding->bParityType = parity; + lineCoding->bDataBits = databits; +} + diff --git a/usb/common/cdc/CDCLineCoding.h b/usb/common/cdc/CDCLineCoding.h new file mode 100644 index 0000000..dfe3c10 --- /dev/null +++ b/usb/common/cdc/CDCLineCoding.h @@ -0,0 +1,136 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Line coding structure used for by the CDC GetLineCoding and SetLineCoding + requests. + + !!!Usage + + -# Initialize a CDCLineCoding instance using CDCLineCoding_Initialize. + -# Send a CDCLineCoding object to the host in response to a GetLineCoding + request. + -# Receive a CDCLineCoding object from the host after a SetLineCoding + request. +*/ + +#ifndef CDCLINECODING_H +#define CDCLINECODING_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "CDC LineCoding StopBits" +/// This page lists Stop Bits for CDC Line Coding. +/// +/// !Stop bits +/// - CDCLineCoding_ONESTOPBIT +/// - CDCLineCoding_ONE5STOPBIT +/// - CDCLineCoding_TWOSTOPBITS + +/// The transmission protocol uses one stop bit. +#define CDCLineCoding_ONESTOPBIT 0 +/// The transmission protocol uses 1.5 stop bit. +#define CDCLineCoding_ONE5STOPBIT 1 +/// The transmissin protocol uses two stop bits. +#define CDCLineCoding_TWOSTOPBITS 2 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "CDC LineCoding ParityCheckings" +/// This page lists Parity checkings for CDC Line Coding. +/// +/// !Parity checking +/// - CDCLineCoding_NOPARITY +/// - CDCLineCoding_ODDPARITY +/// - CDCLineCoding_EVENPARITY +/// - CDCLineCoding_MARKPARITY +/// - CDCLineCoding_SPACEPARITY + +/// No parity checking. +#define CDCLineCoding_NOPARITY 0 +/// Odd parity checking. +#define CDCLineCoding_ODDPARITY 1 +/// Even parity checking. +#define CDCLineCoding_EVENPARITY 2 +/// Mark parity checking. +#define CDCLineCoding_MARKPARITY 3 +/// Space parity checking. +#define CDCLineCoding_SPACEPARITY 4 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// Format of the data returned when a GetLineCoding request is received. +//------------------------------------------------------------------------------ +typedef struct { + + /// Data terminal rate in bits per second. + unsigned int dwDTERate; + /// Number of stop bits. + /// \sa "CDC LineCoding StopBits". + char bCharFormat; + /// Type of parity checking used. + /// \sa "CDC LineCoding ParityCheckings". + char bParityType; + /// Number of data bits (5, 6, 7, 8 or 16). + char bDataBits; + +} __attribute__ ((packed)) CDCLineCoding; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern void CDCLineCoding_Initialize(CDCLineCoding *lineCoding, + unsigned int bitrate, + unsigned char stopbits, + unsigned char parity, + unsigned char databits); + +#endif //#ifndef CDCLINECODING_H + diff --git a/usb/common/cdc/CDCSetControlLineStateRequest.c b/usb/common/cdc/CDCSetControlLineStateRequest.c new file mode 100644 index 0000000..43079ca --- /dev/null +++ b/usb/common/cdc/CDCSetControlLineStateRequest.c @@ -0,0 +1,84 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + CDCSetControlLineStateRequest.c + + !!!Purpose + + Implementation of the CDCSetControlLineStateRequest class. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "CDCSetControlLineStateRequest.h" + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Notifies if the given request indicates that the DTE signal is present. +/// \param request Pointer to a USBGenericRequest instance. +/// \return 1 if the DTE signal is present, otherwise 0. +//------------------------------------------------------------------------------ +unsigned char CDCSetControlLineStateRequest_IsDtePresent( + const USBGenericRequest *request) +{ + if ((USBGenericRequest_GetValue(request) & 0x0001) != 0) { + + return 1; + } + else { + + return 0; + } +} + +//------------------------------------------------------------------------------ +/// Notifies if the given request indicates that the device carrier should +/// be activated. +/// \param request Pointer to a USBGenericRequest instance. +/// \return 1 is the device should activate its carrier, 0 otherwise. +//------------------------------------------------------------------------------ +unsigned char CDCSetControlLineStateRequest_ActivateCarrier( + const USBGenericRequest *request) +{ + if ((USBGenericRequest_GetValue(request) & 0x0002) != 0) { + + return 1; + } + else { + + return 0; + } +} + diff --git a/usb/common/cdc/CDCSetControlLineStateRequest.h b/usb/common/cdc/CDCSetControlLineStateRequest.h new file mode 100644 index 0000000..5d6c661 --- /dev/null +++ b/usb/common/cdc/CDCSetControlLineStateRequest.h @@ -0,0 +1,59 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of a class for manipulating SetControlLineState requests. +*/ + +#ifndef CDCSETCONTROLLINESTATE_H +#define CDCSETCONTROLLINESTATE_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char CDCSetControlLineStateRequest_IsDtePresent( + const USBGenericRequest *request); + + +extern unsigned char CDCSetControlLineStateRequest_ActivateCarrier( + const USBGenericRequest *request); + +#endif //#ifndef CDCSETCONTROLLINESTATE_H + diff --git a/usb/common/cdc/CDCUnionDescriptor.h b/usb/common/cdc/CDCUnionDescriptor.h new file mode 100644 index 0000000..0ba9eaa --- /dev/null +++ b/usb/common/cdc/CDCUnionDescriptor.h @@ -0,0 +1,79 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of a class for manipulating CDC union descriptors. + + !!!Usage + + Should be included in the list of USB descriptor used for a device + configuration. +*/ + +#ifndef CDCUNIONDESCRIPTOR_H +#define CDCUNIONDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// Describes the relationship between a group of interfaces that can +/// be considered to form a functional unit. +//------------------------------------------------------------------------------ +typedef struct { + + /// Size of the descriptor in bytes. + unsigned char bFunctionLength; + /// Descriptor type (CDCDescriptors_INTERFACE). + unsigned char bDescriptorType; + /// Descriptor subtype (CDCDescriptors_UNION). + unsigned char bDescriptorSubtype; + /// Number of the master interface for this union. + unsigned char bMasterInterface; + /// Number of the first slave interface for this union. + unsigned char bSlaveInterface0; + +} __attribute__ ((packed)) CDCUnionDescriptor; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +#endif //#ifndef CDCUNIONDESCRIPTOR_H + diff --git a/usb/common/cdc/cdc.dir b/usb/common/cdc/cdc.dir new file mode 100644 index 0000000..8d9e99b --- /dev/null +++ b/usb/common/cdc/cdc.dir @@ -0,0 +1,39 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// !Purpose +/// +/// This directory contains structures and definitions related to the USB CDC +/// specification. They can be divided into two groups: +/// - CDC-specific descriptors, prefixed with CDC and suffixed with Descriptor. +/// - CDC-specific requests, prefixed with CDC and suffixed with Request. +//------------------------------------------------------------------------------ + diff --git a/usb/common/common.dir b/usb/common/common.dir new file mode 100644 index 0000000..239696c --- /dev/null +++ b/usb/common/common.dir @@ -0,0 +1,55 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// !!!Purpose +/// +/// This directory containes highly re-usable code from USB standard and some +/// classes specifications for general use. +/// +/// !!!Contents +/// This dircetory provides two sections of definitions: +/// -# Definitions, structures and functions from USB specification, +/// commonly used for all USB classes and projects. +/// - core: for USB specification +/// -# Definitions, structures and functions from class-specific +/// specification commonly used for class related project ONLY. +/// - cdc: for USB Communication Devie Class (CDC) +/// - hid: for USB Humen Interface Device Class (HID) +/// - massstorage: for USB Mass Storage Class (MS) +/// - audio: for USB Audio Class (AUD) +/// +/// For more information about what a particular group contains, please refer to +/// its documentation page. +/// +/// \note +/// Depending on the project, not all the subdirectories will be available +/// (i.e. the #cdc# directory will not be in non-CDC projects). +//------------------------------------------------------------------------------ \ No newline at end of file diff --git a/usb/common/core/USBConfigurationDescriptor.c b/usb/common/core/USBConfigurationDescriptor.c new file mode 100644 index 0000000..503dceb --- /dev/null +++ b/usb/common/core/USBConfigurationDescriptor.c @@ -0,0 +1,162 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: USBConfigurationDescriptor implementation + + About: Purpose + Implementation of the USBConfigurationDescriptor class. +*/ + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include "USBConfigurationDescriptor.h" + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Returns the total length of a configuration, i.e. including the +/// descriptors following it. +/// \param configuration Pointer to a USBConfigurationDescriptor instance. +/// \return Total length (in bytes) of the configuration. +//----------------------------------------------------------------------------- +unsigned int USBConfigurationDescriptor_GetTotalLength( + const USBConfigurationDescriptor *configuration) +{ + return configuration->wTotalLength; +} + +//----------------------------------------------------------------------------- +/// Returns the number of interfaces in a configuration. +/// \param configuration Pointer to a USBConfigurationDescriptor instance. +/// \return Number of interfaces in configuration. +//----------------------------------------------------------------------------- +unsigned char USBConfigurationDescriptor_GetNumInterfaces( + const USBConfigurationDescriptor *configuration) +{ + return configuration->bNumInterfaces; +} + +//----------------------------------------------------------------------------- +/// Indicates if the device is self-powered when in a given configuration. +/// \param configuration Pointer to a USBConfigurationDescriptor instance. +/// \return 1 if the device is self-powered when in the given configuration; +/// otherwise 0. +//----------------------------------------------------------------------------- +unsigned char USBConfigurationDescriptor_IsSelfPowered( + const USBConfigurationDescriptor *configuration) +{ + if ((configuration->bmAttributes & (1 << 6)) != 0) { + + return 1; + } + else { + + return 0; + } +} + +//----------------------------------------------------------------------------- +/// Parses the given Configuration descriptor (followed by relevant +/// interface, endpoint and class-specific descriptors) into three arrays. +/// *Each array must have its size equal or greater to the number of +/// descriptors it stores plus one*. A null-value is inserted after the last +/// descriptor of each type to indicate the array end. +/// +/// Note that if the pointer to an array is null (0), nothing is stored in +/// it. +/// \param configuration Pointer to the start of the whole Configuration +/// descriptor. +/// \param interfaces Pointer to the Interface descriptor array. +/// \param endpoints Pointer to the Endpoint descriptor array. +/// \param others Pointer to the class-specific descriptor array. +//----------------------------------------------------------------------------- +void USBConfigurationDescriptor_Parse( + const USBConfigurationDescriptor *configuration, + USBInterfaceDescriptor **interfaces, + USBEndpointDescriptor **endpoints, + USBGenericDescriptor **others) +{ + // Get size of configuration to parse + int size = USBConfigurationDescriptor_GetTotalLength(configuration); + size -= sizeof(USBConfigurationDescriptor); + + // Start parsing descriptors + USBGenericDescriptor *descriptor = (USBGenericDescriptor *) configuration; + while (size > 0) { + + // Get next descriptor + descriptor = USBGenericDescriptor_GetNextDescriptor(descriptor); + size -= USBGenericDescriptor_GetLength(descriptor); + + // Store descriptor in correponding array + if (USBGenericDescriptor_GetType(descriptor) + == USBGenericDescriptor_INTERFACE) { + + if (interfaces) { + + *interfaces = (USBInterfaceDescriptor *) descriptor; + interfaces++; + } + } + else if (USBGenericDescriptor_GetType(descriptor) + == USBGenericDescriptor_ENDPOINT) { + + if (endpoints) { + + *endpoints = (USBEndpointDescriptor *) descriptor; + endpoints++; + } + } + else if (others) { + + *others = descriptor; + others++; + } + } + + // Null-terminate arrays + if (interfaces) { + + *interfaces = 0; + } + if (endpoints) { + + *endpoints = 0; + } + if (others) { + + *others = 0; + } +} + diff --git a/usb/common/core/USBConfigurationDescriptor.h b/usb/common/core/USBConfigurationDescriptor.h new file mode 100644 index 0000000..150e656 --- /dev/null +++ b/usb/common/core/USBConfigurationDescriptor.h @@ -0,0 +1,150 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + !!!Purpose + + Definitions and methods for USB configuration descriptor structures + described by the USB specification. + + !!!Usage + + -# Declare USBConfigurationDescriptor instance as a part + of the configuration descriptors of a USB device. + -# To get useful information (field values) from the defined USB device + configuration descriptor, use + - USBConfigurationDescriptor_GetTotalLength + - USBConfigurationDescriptor_GetNumInterfaces + - USBConfigurationDescriptor_IsSelfPowered + -# To pase the defined USB device configuration descriptor, use + - USBConfigurationDescriptor_Parse +*/ + +#ifndef USBCONFIGURATIONDESCRIPTOR_H +#define USBCONFIGURATIONDESCRIPTOR_H + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include "USBGenericDescriptor.h" +#include "USBInterfaceDescriptor.h" +#include "USBEndpointDescriptor.h" + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// \page "USB device Attributes" +/// +/// This page lists the codes of the usb attributes. +/// +/// !Attributes +/// - USBConfigurationDescriptor_BUSPOWERED_NORWAKEUP +/// - USBConfigurationDescriptor_SELFPOWERED_NORWAKEUP +/// - USBConfigurationDescriptor_BUSPOWERED_RWAKEUP +/// - USBConfigurationDescriptor_SELFPOWERED_RWAKEUP +/// - USBConfigurationDescriptor_POWER + +/// Device is bus-powered and not support remote wake-up. +#define USBConfigurationDescriptor_BUSPOWERED_NORWAKEUP 0x80 +/// Device is self-powered and not support remote wake-up. +#define USBConfigurationDescriptor_SELFPOWERED_NORWAKEUP 0xC0 +/// Device is bus-powered and supports remote wake-up. +#define USBConfigurationDescriptor_BUSPOWERED_RWAKEUP 0xA0 +/// Device is self-powered and supports remote wake-up. +#define USBConfigurationDescriptor_SELFPOWERED_RWAKEUP 0xE0 + +/// Calculates the value of the power consumption field given the value in mA. +/// \param power The power consumption value in mA +/// \return The value that should be set to the field in descriptor +#define USBConfigurationDescriptor_POWER(power) (power / 2) +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Types +//----------------------------------------------------------------------------- + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//----------------------------------------------------------------------------- +/// USB standard configuration descriptor structure. +//----------------------------------------------------------------------------- +typedef struct { + + /// Size of the descriptor in bytes. + unsigned char bLength; + /// Descriptor type (USBDESC_CONFIGURATION of "USB Descriptor types"). + unsigned char bDescriptorType; + /// Length of all descriptors returned along with this configuration + /// descriptor. + unsigned short wTotalLength; + /// Number of interfaces in this configuration. + unsigned char bNumInterfaces; + /// Value for selecting this configuration. + unsigned char bConfigurationValue; + /// Index of the configuration string descriptor. + unsigned char iConfiguration; + /// Configuration characteristics. + unsigned char bmAttributes; + /// Maximum power consumption of the device when in this configuration. + unsigned char bMaxPower; + +} __attribute__ ((packed)) USBConfigurationDescriptor; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +extern unsigned int USBConfigurationDescriptor_GetTotalLength( + const USBConfigurationDescriptor *configuration); + +extern unsigned char USBConfigurationDescriptor_GetNumInterfaces( + const USBConfigurationDescriptor *configuration); + +extern unsigned char USBConfigurationDescriptor_IsSelfPowered( + const USBConfigurationDescriptor *configuration); + +extern void USBConfigurationDescriptor_Parse( + const USBConfigurationDescriptor *configuration, + USBInterfaceDescriptor **interfaces, + USBEndpointDescriptor **endpoints, + USBGenericDescriptor **others); + +#endif //#ifndef USBCONFIGURATIONDESCRIPTOR_H + diff --git a/usb/common/core/USBConfigurationOTG.c b/usb/common/core/USBConfigurationOTG.c new file mode 100644 index 0000000..c875790 --- /dev/null +++ b/usb/common/core/USBConfigurationOTG.c @@ -0,0 +1,51 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//----------------------------------------------------------------------------- +// Includes +//----------------------------------------------------------------------------- + +#include "USBConfigurationOTG.h" + + +USBGenericOTGDescriptor *pOTGDescriptor; + +//----------------------------------------------------------------------------- +// Internal functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// External functions +//----------------------------------------------------------------------------- +void OTG_Initialize(USBGenericOTGDescriptor *pOTGDesc) +{ + pOTGDescriptor = pOTGDesc; +} + + diff --git a/usb/common/core/USBConfigurationOTG.h b/usb/common/core/USBConfigurationOTG.h new file mode 100644 index 0000000..d0d3b05 --- /dev/null +++ b/usb/common/core/USBConfigurationOTG.h @@ -0,0 +1,118 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !Purpose +/// +/// Methods and definitions for configuring OTG. +/// +/// !Usage +/// +/// -# +/// -# +/// +//------------------------------------------------------------------------------ + +#ifndef USBCONFIGURATIONOTG_H +#define USBCONFIGURATIONOTG_H + +#include + + +/// OTG specific configuration +typedef struct { + + /// USB MODE CONFIGURATION + + /// ENABLE to activate the host software library support + /// Possible values ENABLE or DISABLE + unsigned char bOTGUsbHostFeature; + + /// ENABLE to activate the device software library support + /// Possible values ENABLE or DISABLE + unsigned char bOTGUsbDeviceFeature; + /// OTG MODE CONFIGURATION + /// ENABLE to enable OTG module (support A- and B- Device roles) + /// Possible values ENABLE or DISABLE + unsigned char bOTGFeature; + + /// For reduced host only allows to control VBUS generator with PIO PE.7 + unsigned char bOTGSoftwareVbusCtrl; + + /// Selects the messaging method for OTG No Silent Failure spec. + /// + /// A compliant OTG device must at least handle 3 Failure messages : + /// "Device No Response", "Unsupported Device" and "Unsupported Hub" + /// Functions must be defined for communicating messages to user (LCD display, + /// LEDs...) + /// The values available for this parameter are : + /// - OTGMSG_ALL : all messages (events and failures) are displayed + /// In this case, the following functions must be defined in user application firmware : + /// # "void Otg_messaging_init(void)", this function is called at start up to initialize the messaging peripheral + /// # "void Otg_output_failure_msg(U8)", displays the failure message choosen by ID number (see "usb_task.h") + /// # "void Otg_output_failure_clear(void)", clears the current failure message + /// # "void Otg_output_event_msg(U8)", displays the event message choosen by ID number + /// # "void Otg_output_event_clear(void)", clears the current event message + /// - OTGMSG_FAIL : only failure messages are displayed + /// In this case, the following functions must be defined in user application firmware : + /// # "void Otg_messaging_init(void)", this function is called at start up to initialize the messaging peripheral + /// # "void Otg_output_failure_msg(U8)", displays the failure message choosen by ID number (see "usb_task.h") + /// # "void Otg_output_failure_clear(void)", clears the current failure message + /// - OTGMSG_NONE : messages are not displayed (not OTG compliant device) + unsigned char bOTGMessagingOutput; + + /// ENABLE to make the A-Device send a SetFeature(b_hnp_enable) just after a SRP + /// has been received + /// This feature must be ENABLE to pass the OTG compliance program + /// Possible values ENABLE or DISABLE + unsigned char bOTGEnableHNPAfterSRP; + + /// Selects the SRP pulse for which the A Device will react and rise Vbus + /// The value is VBUS_PULSE or DATA_PULSE + unsigned char bOTGADevSRPReaction; + +} USBGenericOTGDescriptor; + +#define OTGMSG_NONE 0 // no messages displayed +#define OTGMSG_FAIL 1 // only failure messages displayed +#define OTGMSG_ALL 2 // all messages displayed + +#define VBUS_PULSE 1 // no more used +#define DATA_PULSE 0 + + +extern USBGenericOTGDescriptor *pOTGDescriptor; + +extern void OTG_Initialize(USBGenericOTGDescriptor *pOTGDesc); + + +#endif //#ifndef USBCONFIGURATIONOTG_H + diff --git a/usb/common/core/USBDeviceDescriptor.h b/usb/common/core/USBDeviceDescriptor.h new file mode 100644 index 0000000..ce8d199 --- /dev/null +++ b/usb/common/core/USBDeviceDescriptor.h @@ -0,0 +1,125 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + !!!Purpose + + Class for manipulating USB device descriptors. + + !!!Usage + + - Declare a USBDeviceDescriptor instance as the device descriptor of a + USB device. +*/ + +#ifndef USBDEVICEDESCRIPTOR_H +#define USBDEVICEDESCRIPTOR_H + +#include +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB release numbers" +/// +/// This page lists the codes of USB release numbers. +/// +/// !Code +/// - USBDeviceDescriptor_USB2_00 + +/// The device supports USB 2.00. +#define USBDeviceDescriptor_USB2_00 0x0200 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// USB standard device descriptor structure. +//------------------------------------------------------------------------------ +typedef struct { + + /// Size of this descriptor in bytes. + unsigned char bLength; + /// Descriptor type (USBGenericDescriptor_DEVICE). + unsigned char bDescriptorType; + /// USB specification release number in BCD format. + unsigned short bcdUSB; + /// Device class code. + unsigned char bDeviceClass; + /// Device subclass code. + unsigned char bDeviceSubClass; + /// Device protocol code. + unsigned char bDeviceProtocol; + /// Maximum packet size of endpoint 0 (in bytes). + unsigned char bMaxPacketSize0; + /// Vendor ID. + unsigned short idVendor; + /// Product ID. + unsigned short idProduct; + /// Device release number in BCD format. + unsigned short bcdDevice; + /// Index of the manufacturer string descriptor. + unsigned char iManufacturer; + /// Index of the product string descriptor. + unsigned char iProduct; + /// Index of the serial number string descriptor. + unsigned char iSerialNumber; + /// Number of possible configurations for the device. + unsigned char bNumConfigurations; + +} __attribute__ ((packed)) USBDeviceDescriptor; // GCC + +#if defined(CHIP_USB_OTGHS) +typedef struct { + + /// Size of this descriptor in bytes. + unsigned char bLength; + /// Descriptor type (USBGenericDescriptor_OTG). + unsigned char bDescriptorType; + /// Attribute Fields D7…2: Reserved D1: HNP support D0: SRP support + unsigned char bmAttributes; + +} __attribute__ ((packed)) USBOtgDescriptor; // GCC +#endif + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +#endif //#ifndef USBDEVICEDESCRIPTOR_H + diff --git a/usb/common/core/USBDeviceQualifierDescriptor.h b/usb/common/core/USBDeviceQualifierDescriptor.h new file mode 100644 index 0000000..3728865 --- /dev/null +++ b/usb/common/core/USBDeviceQualifierDescriptor.h @@ -0,0 +1,89 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Class for manipulating USB device qualifier descriptors. + + !!!Usage + + - Declare a USBDeviceQualifierDescriptor instance as the device qualifier + descriptor of a USB device. +*/ + +#ifndef USBDEVICEQUALIFIERDESCRIPTOR_H +#define USBDEVICEQUALIFIERDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// Alternate device descriptor indicating the capabilities of the device +/// in full-speed, if currently in high-speed; or in high-speed, if it is +/// currently in full-speed. Only relevant for devices supporting the +/// high-speed mode. +//------------------------------------------------------------------------------ +typedef struct { + + /// Size of the descriptor in bytes. + unsigned char bLength; + /// Descriptor type (USBDESC_DEVICE_QUALIFIER or "USB device types"). + unsigned char bDescriptorType; + /// USB specification release number (in BCD format). + unsigned short bcdUSB; + /// Device class code. + unsigned char bDeviceClass; + /// Device subclass code. + unsigned char bDeviceSubClass; + /// Device protocol code. + unsigned char bDeviceProtocol; + /// Maximum packet size of endpoint 0. + unsigned char bMaxPacketSize0; + /// Number of possible configurations for the device. + unsigned char bNumConfigurations; + /// Reserved. + unsigned char bReserved; + +} __attribute__ ((packed)) USBDeviceQualifierDescriptor; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +#endif //#ifndef USBDEVICEQUALIFIERDESCRIPTOR_H + diff --git a/usb/common/core/USBEndpointDescriptor.c b/usb/common/core/USBEndpointDescriptor.c new file mode 100644 index 0000000..6300ade --- /dev/null +++ b/usb/common/core/USBEndpointDescriptor.c @@ -0,0 +1,109 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: USBEndpointDescriptor implementation + + About: Purpose + Implementation of the USBEndpointDescriptor class. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBEndpointDescriptor.h" + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Returns the number of an endpoint given its descriptor. +/// \param endpoint Pointer to a USBEndpointDescriptor instance. +/// \return Endpoint number. +//------------------------------------------------------------------------------ +unsigned char USBEndpointDescriptor_GetNumber( + const USBEndpointDescriptor *endpoint) +{ + return endpoint->bEndpointAddress & 0xF; +} + +//------------------------------------------------------------------------------ +/// Returns the direction of an endpoint given its descriptor. +/// \param endpoint Pointer to a USBEndpointDescriptor instance. +/// \return Endpoint direction (see ). +//------------------------------------------------------------------------------ +unsigned char USBEndpointDescriptor_GetDirection( + const USBEndpointDescriptor *endpoint) +{ + if ((endpoint->bEndpointAddress & 0x80) != 0) { + + return USBEndpointDescriptor_IN; + } + else { + + return USBEndpointDescriptor_OUT; + } +} + +//------------------------------------------------------------------------------ +/// Returns the type of an endpoint given its descriptor. +/// \param endpoint Pointer to a USBEndpointDescriptor instance. +/// \return Endpoint type (see ). +//------------------------------------------------------------------------------ +unsigned char USBEndpointDescriptor_GetType( + const USBEndpointDescriptor *endpoint) +{ + return endpoint->bmAttributes & 0x3; +} + +//------------------------------------------------------------------------------ +/// Returns the maximum size of a packet (in bytes) on an endpoint given +/// its descriptor. +/// \param endpoint - Pointer to a USBEndpointDescriptor instance. +/// \return Maximum packet size of endpoint. +//------------------------------------------------------------------------------ +unsigned short USBEndpointDescriptor_GetMaxPacketSize( + const USBEndpointDescriptor *endpoint) +{ + return endpoint->wMaxPacketSize; +} + +//------------------------------------------------------------------------------ +/// Returns the polling interval on an endpoint given its descriptor. +/// \param endpoint - Pointer to a USBEndpointDescriptor instance. +/// \return Polling interval of endpoint. +//------------------------------------------------------------------------------ +unsigned char USBEndpointDescriptor_GetInterval( + const USBEndpointDescriptor *endpoint) +{ + return endpoint->bInterval; +} + diff --git a/usb/common/core/USBEndpointDescriptor.h b/usb/common/core/USBEndpointDescriptor.h new file mode 100644 index 0000000..d49e028 --- /dev/null +++ b/usb/common/core/USBEndpointDescriptor.h @@ -0,0 +1,224 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of a class for handling USB endpoint descriptors. + + !!!Usage + + -# Declare USBEndpointDescriptor instance as a part of the + configuration descriptors of a USB device. + -# To get useful information (field values) from the defined USB device + endpoint descriptor (to configure hardware for endpoints, etc), use + - USBEndpointDescriptor_GetNumber + - USBEndpointDescriptor_GetDirection + - USBEndpointDescriptor_GetType + - USBEndpointDescriptor_GetMaxPacketSize +*/ + +#ifndef USBENDPOINTDESCRIPTOR_H +#define USBENDPOINTDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Endpoint definitions" +/// +/// This page lists definitions and macro for endpoint descriptors. +/// +/// - USB Endpoint directions +/// - USBEndpointDescriptor_OUT +/// - USBEndpointDescriptor_IN +/// +/// - USB Endpoint types +/// - USBEndpointDescriptor_CONTROL +/// - USBEndpointDescriptor_ISOCHRONOUS +/// - USBEndpointDescriptor_BULK +/// - USBEndpointDescriptor_INTERRUPT +/// +/// - USB Endpoint maximun sizes +/// - USBEndpointDescriptor_MAXCTRLSIZE_FS +/// - USBEndpointDescriptor_MAXCTRLSIZE_HS +/// - USBEndpointDescriptor_MAXBULKSIZE_FS +/// - USBEndpointDescriptor_MAXBULKSIZE_HS +/// - USBEndpointDescriptor_MAXINTERRUPTSIZE_FS +/// - USBEndpointDescriptor_MAXINTERRUPTSIZE_HS +/// - USBEndpointDescriptor_MAXISOCHRONOUSSIZE_FS +/// - USBEndpointDescriptor_MAXISOCHRONOUSSIZE_HS +/// +/// - USB Endpoint address define +/// - USBEndpointDescriptor_ADDRESS +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Endpoint directions" +/// +/// This page lists definitions of USB endpoint directions. +/// +/// !Directions +/// - USBEndpointDescriptor_OUT +/// - USBEndpointDescriptor_IN + +/// Endpoint receives data from the host. +#define USBEndpointDescriptor_OUT 0 +/// Endpoint sends data to the host. +#define USBEndpointDescriptor_IN 1 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Endpoint types" +/// +/// This page lists definitions of USB endpoint types. +/// +/// !Types +/// - USBEndpointDescriptor_CONTROL +/// - USBEndpointDescriptor_ISOCHRONOUS +/// - USBEndpointDescriptor_BULK +/// - USBEndpointDescriptor_INTERRUPT + +/// Control endpoint type. +#define USBEndpointDescriptor_CONTROL 0 +/// Isochronous endpoint type. +#define USBEndpointDescriptor_ISOCHRONOUS 1 +/// Bulk endpoint type. +#define USBEndpointDescriptor_BULK 2 +/// Interrupt endpoint type. +#define USBEndpointDescriptor_INTERRUPT 3 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Endpoint maximun sizes" +/// +/// This page lists definitions of USB endpoint maximun sizes. +/// +/// !Sizes +/// - USBEndpointDescriptor_MAXCTRLSIZE_FS +/// - USBEndpointDescriptor_MAXCTRLSIZE_HS +/// - USBEndpointDescriptor_MAXBULKSIZE_FS +/// - USBEndpointDescriptor_MAXBULKSIZE_HS +/// - USBEndpointDescriptor_MAXINTERRUPTSIZE_FS +/// - USBEndpointDescriptor_MAXINTERRUPTSIZE_HS +/// - USBEndpointDescriptor_MAXISOCHRONOUSSIZE_FS +/// - USBEndpointDescriptor_MAXISOCHRONOUSSIZE_HS + +/// Maximum size for a full-speed control endpoint. +#define USBEndpointDescriptor_MAXCTRLSIZE_FS 64 +/// Maximum size for a high-speed control endpoint. +#define USBEndpointDescriptor_MAXCTRLSIZE_HS 64 +/// Maximum size for a full-speed bulk endpoint. +#define USBEndpointDescriptor_MAXBULKSIZE_FS 64 +/// Maximum size for a high-speed bulk endpoint. +#define USBEndpointDescriptor_MAXBULKSIZE_HS 512 +/// Maximum size for a full-speed interrupt endpoint. +#define USBEndpointDescriptor_MAXINTERRUPTSIZE_FS 64 +/// Maximum size for a high-speed interrupt endpoint. +#define USBEndpointDescriptor_MAXINTERRUPTSIZE_HS 1024 +/// Maximum size for a full-speed isochronous endpoint. +#define USBEndpointDescriptor_MAXISOCHRONOUSSIZE_FS 1023 +/// Maximum size for a high-speed isochronous endpoint. +#define USBEndpointDescriptor_MAXISOCHRONOUSSIZE_HS 1024 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Endpoint address define" +/// +/// This page lists macro for USB endpoint address definition. +/// +/// !Macro +/// - USBEndpointDescriptor_ADDRESS + +/// Calculates the address of an endpoint given its number and direction +/// \param direction USB endpoint direction definition +/// \param number USB endpoint number +/// \return The value used to set the endpoint descriptor based on input number +/// and direction +#define USBEndpointDescriptor_ADDRESS(direction, number) \ + (((direction & 0x01) << 7) | (number & 0xF)) +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// USB standard endpoint descriptor structure. +//------------------------------------------------------------------------------ +typedef struct { + + /// Size of the descriptor in bytes. + unsigned char bLength; + /// Descriptor type (). + unsigned char bDescriptorType; + /// Address and direction of the endpoint. + unsigned char bEndpointAddress; + /// Endpoint type and additional characteristics (for isochronous endpoints). + unsigned char bmAttributes; + /// Maximum packet size (in bytes) of the endpoint. + unsigned short wMaxPacketSize; + /// Polling rate of the endpoint. + unsigned char bInterval; + +} __attribute__ ((packed)) USBEndpointDescriptor; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char USBEndpointDescriptor_GetNumber( + const USBEndpointDescriptor *endpoint); + +extern unsigned char USBEndpointDescriptor_GetDirection( + const USBEndpointDescriptor *endpoint); + +extern unsigned char USBEndpointDescriptor_GetType( + const USBEndpointDescriptor *endpoint); + +extern unsigned short USBEndpointDescriptor_GetMaxPacketSize( + const USBEndpointDescriptor *endpoint); + +extern unsigned char USBEndpointDescriptor_GetInterval( + const USBEndpointDescriptor *endpoint); + +#endif //#ifndef USBENDPOINTDESCRIPTOR_H + diff --git a/usb/common/core/USBFeatureRequest.c b/usb/common/core/USBFeatureRequest.c new file mode 100644 index 0000000..1e0422a --- /dev/null +++ b/usb/common/core/USBFeatureRequest.c @@ -0,0 +1,70 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: USBFeatureRequest implementation + + About: Purpose + Implementation of the USBFeatureRequest class. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBFeatureRequest.h" + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Returns the feature selector of a given CLEAR_FEATURE or SET_FEATURE +/// request. +/// \param request Pointer to a USBGenericRequest instance. +/// \return Feature selector. +//------------------------------------------------------------------------------ +unsigned char USBFeatureRequest_GetFeatureSelector( + const USBGenericRequest *request) +{ + return USBGenericRequest_GetValue(request); +} + +//------------------------------------------------------------------------------ +/// Indicates the test that the device must undertake following a +/// SET_FEATURE request. +/// \param request Pointer to a USBGenericRequest instance. +/// \return Test selector. +//------------------------------------------------------------------------------ +unsigned char USBFeatureRequest_GetTestSelector( + const USBGenericRequest *request) +{ + return (USBGenericRequest_GetIndex(request) >> 8) & 0xFF; +} + diff --git a/usb/common/core/USBFeatureRequest.h b/usb/common/core/USBFeatureRequest.h new file mode 100644 index 0000000..0454ffb --- /dev/null +++ b/usb/common/core/USBFeatureRequest.h @@ -0,0 +1,146 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of a class for manipulating CLEAR_FEATURE and SET_FEATURE + requests. + + !!!Usage + + - To get USB feature request information (field values) from the + USBGenericRequest instance, use + - USBFeatureRequest_GetFeatureSelector + - USBFeatureRequest_GetTestSelector +*/ + +#ifndef USBFEATUREREQUEST_H +#define USBFEATUREREQUEST_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBGenericRequest.h" + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Feature Request definitions" +/// +/// This page lists codes of USB Feature Request +/// +/// - USB Feature selectors +/// - USBFeatureRequest_ENDPOINTHALT +/// - USBFeatureRequest_DEVICEREMOTEWAKEUP +/// - USBFeatureRequest_TESTMODE +/// +/// - USB Test mode selectors +/// - USBFeatureRequest_TESTJ +/// - USBFeatureRequest_TESTK +/// - USBFeatureRequest_TESTSE0NAK +/// - USBFeatureRequest_TESTPACKET +/// - USBFeatureRequest_TESTFORCEENABLE +/// - USBFeatureRequest_TESTSENDZLP +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Feature selectors" +/// +/// This page lists codes of USB feature selectors. +/// +/// !Selectors +/// - USBFeatureRequest_ENDPOINTHALT +/// - USBFeatureRequest_DEVICEREMOTEWAKEUP +/// - USBFeatureRequest_TESTMODE + +/// Halt feature of an endpoint. +#define USBFeatureRequest_ENDPOINTHALT 0 +/// Remote wake-up feature of the device. +#define USBFeatureRequest_DEVICEREMOTEWAKEUP 1 +/// Test mode of the device. +#define USBFeatureRequest_TESTMODE 2 +/// OTG set feature +#define USBFeatureRequest_OTG 0x0B +//------------------------------------------------------------------------------ + +/// On The Go Feature Selectors +/// b_hnp_enable 3 +/// a_hnp_support 4 +/// a_alt_hnp_support 5 +#define USBFeatureRequest_OTG_B_HNP_ENABLE 3 +#define USBFeatureRequest_OTG_A_HNP_SUPPORT 4 +#define USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT 5 + +//------------------------------------------------------------------------------ +/// \page "USB Test mode selectors" +/// +/// This page lists codes of USB high speed test mode selectors. +/// +/// !Selectors +/// - USBFeatureRequest_TESTJ +/// - USBFeatureRequest_TESTK +/// - USBFeatureRequest_TESTSE0NAK +/// - USBFeatureRequest_TESTPACKET +/// - USBFeatureRequest_TESTFORCEENABLE +/// - USBFeatureRequest_TESTSENDZLP + +/// Tests the high-output drive level on the D+ line. +#define USBFeatureRequest_TESTJ 1 +/// Tests the high-output drive level on the D- line. +#define USBFeatureRequest_TESTK 2 +/// Tests the output impedance, low-level output voltage and loading +/// characteristics. +#define USBFeatureRequest_TESTSE0NAK 3 +/// Tests rise and fall times, eye patterns and jitter. +#define USBFeatureRequest_TESTPACKET 4 +/// Tests the hub disconnect detection. +#define USBFeatureRequest_TESTFORCEENABLE 5 +/// Send a ZLP in Test Mode. +#define USBFeatureRequest_TESTSENDZLP 6 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char USBFeatureRequest_GetFeatureSelector( + const USBGenericRequest *request); + + +extern unsigned char USBFeatureRequest_GetTestSelector( + const USBGenericRequest *request); + +#endif //#ifndef USBFEATUREREQUEST_H + diff --git a/usb/common/core/USBGenericDescriptor.c b/usb/common/core/USBGenericDescriptor.c new file mode 100644 index 0000000..99ed6f9 --- /dev/null +++ b/usb/common/core/USBGenericDescriptor.c @@ -0,0 +1,80 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: USBGenericDescriptor implementation + + About: Purpose + Implementation of the USBGenericDescriptor class. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBGenericDescriptor.h" + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Returns the length of a descriptor. +/// \param descriptor Pointer to a USBGenericDescriptor instance. +/// \return Length of descriptor in bytes. +//------------------------------------------------------------------------------ +unsigned int USBGenericDescriptor_GetLength( + const USBGenericDescriptor *descriptor) +{ + return descriptor->bLength; +} + +//------------------------------------------------------------------------------ +/// Returns the type of a descriptor. +/// \param descriptor Pointer to a USBGenericDescriptor instance. +/// \return Type of descriptor. +//------------------------------------------------------------------------------ +unsigned char USBGenericDescriptor_GetType( + const USBGenericDescriptor *descriptor) +{ + return descriptor->bDescriptorType; +} + +//------------------------------------------------------------------------------ +/// Returns a pointer to the descriptor right after the given one, when +/// parsing a Configuration descriptor. +/// \param descriptor - Pointer to a USBGenericDescriptor instance. +/// \return Pointer to the next descriptor. +//------------------------------------------------------------------------------ +USBGenericDescriptor *USBGenericDescriptor_GetNextDescriptor( + const USBGenericDescriptor *descriptor) +{ + return (USBGenericDescriptor *) + (((char *) descriptor) + USBGenericDescriptor_GetLength(descriptor)); +} diff --git a/usb/common/core/USBGenericDescriptor.h b/usb/common/core/USBGenericDescriptor.h new file mode 100644 index 0000000..b1237ae --- /dev/null +++ b/usb/common/core/USBGenericDescriptor.h @@ -0,0 +1,133 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !!!Purpose +/// +/// Definition of a generic USB descriptor class. +/// +/// !!!Usage +/// +/// -# Declare or access USB descriptors by USBGenericDescriptor instance. +/// -# To get usful information (field values) from the USB descriptors, use +/// - USBGenericDescriptor_GetLength +/// - USBGenericDescriptor_GetType +/// -# To scan the descriptors, use +/// - USBGenericDescriptor_GetNextDescriptor +//------------------------------------------------------------------------------ + +#ifndef USBGENERICDESCRIPTOR_H +#define USBGENERICDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Descriptor types" +/// +/// This page lists the codes of the usb descriptor types +/// +/// !Types +/// - USBGenericDescriptor_DEVICE +/// - USBGenericDescriptor_CONFIGURATION +/// - USBGenericDescriptor_STRING +/// - USBGenericDescriptor_INTERFACE +/// - USBGenericDescriptor_ENDPOINT +/// - USBGenericDescriptor_DEVICEQUALIFIER +/// - USBGenericDescriptor_OTHERSPEEDCONFIGURATION +/// - USBGenericDescriptor_INTERFACEPOWER +/// - USBGenericDescriptor_OTG +/// - USBGenericDescriptor_DEBUG +/// - USBGenericDescriptor_INTERFACEASSOCIATION + +/// Device descriptor type. +#define USBGenericDescriptor_DEVICE 1 +/// Configuration descriptor type. +#define USBGenericDescriptor_CONFIGURATION 2 +/// String descriptor type. +#define USBGenericDescriptor_STRING 3 +/// Interface descriptor type. +#define USBGenericDescriptor_INTERFACE 4 +/// Endpoint descriptor type. +#define USBGenericDescriptor_ENDPOINT 5 +/// Device qualifier descriptor type. +#define USBGenericDescriptor_DEVICEQUALIFIER 6 +/// Other speed configuration descriptor type. +#define USBGenericDescriptor_OTHERSPEEDCONFIGURATION 7 +/// Interface power descriptor type. +#define USBGenericDescriptor_INTERFACEPOWER 8 +/// On-The-Go descriptor type. +#define USBGenericDescriptor_OTG 9 +/// Debug descriptor type. +#define USBGenericDescriptor_DEBUG 10 +/// Interface association descriptor type. +#define USBGenericDescriptor_INTERFACEASSOCIATION 11 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +/// Holds the few fields shared by all USB descriptors. +typedef struct { + + /// Length of the descriptor in bytes. + unsigned char bLength; + /// Descriptor type. + unsigned char bDescriptorType; + +} __attribute__ ((packed)) USBGenericDescriptor; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned int USBGenericDescriptor_GetLength( + const USBGenericDescriptor *descriptor); + +extern unsigned char USBGenericDescriptor_GetType( + const USBGenericDescriptor *descriptor); + +extern USBGenericDescriptor *USBGenericDescriptor_GetNextDescriptor( + const USBGenericDescriptor *descriptor); + +#endif //#ifndef USBGENERICDESCRIPTOR_H + diff --git a/usb/common/core/USBGenericRequest.c b/usb/common/core/USBGenericRequest.c new file mode 100644 index 0000000..a3bbbfd --- /dev/null +++ b/usb/common/core/USBGenericRequest.c @@ -0,0 +1,138 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: USBGenericRequest implementation + + About: Purpose + Implementation of the USBGenericRequest class. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBGenericRequest.h" + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +/// Returns the type of the given request. +/// \param request Pointer to a USBGenericRequest instance. +/// \return "USB Request Types" +//------------------------------------------------------------------------------ +extern unsigned char USBGenericRequest_GetType(const USBGenericRequest *request) +{ + return ((request->bmRequestType >> 5) & 0x3); +} + +//------------------------------------------------------------------------------ +/// Returns the request code of the given request. +/// \param request Pointer to a USBGenericRequest instance. +/// \return Request code. +/// \sa "USB Request Codes" +//------------------------------------------------------------------------------ +unsigned char USBGenericRequest_GetRequest(const USBGenericRequest *request) +{ + return request->bRequest; +} + +//------------------------------------------------------------------------------ +/// Returns the wValue field of the given request. +/// \param request - Pointer to a USBGenericRequest instance. +/// \return Request value. +//------------------------------------------------------------------------------ +unsigned short USBGenericRequest_GetValue(const USBGenericRequest *request) +{ + return request->wValue; +} + +//------------------------------------------------------------------------------ +/// Returns the wIndex field of the given request. +/// \param request Pointer to a USBGenericRequest instance. +/// \return Request index; +//------------------------------------------------------------------------------ +unsigned short USBGenericRequest_GetIndex(const USBGenericRequest *request) +{ + return request->wIndex; +} + +//------------------------------------------------------------------------------ +/// Returns the expected length of the data phase following a request. +/// \param request Pointer to a USBGenericRequest instance. +/// \return Length of data phase. +//------------------------------------------------------------------------------ +unsigned short USBGenericRequest_GetLength(const USBGenericRequest *request) +{ + return request->wLength; +} + +//------------------------------------------------------------------------------ +/// Returns the endpoint number targetted by a given request. +/// \param request Pointer to a USBGenericRequest instance. +/// \return Endpoint number. +//------------------------------------------------------------------------------ +unsigned char USBGenericRequest_GetEndpointNumber( + const USBGenericRequest *request) +{ + return USBGenericRequest_GetIndex(request) & 0xF; +} + +//------------------------------------------------------------------------------ +/// Returns the intended recipient of a given request. +/// \param request Pointer to a USBGenericRequest instance. +/// \return Request recipient. +/// \sa "USB Request Recipients" +//------------------------------------------------------------------------------ +unsigned char USBGenericRequest_GetRecipient(const USBGenericRequest *request) +{ + // Recipient is in bits [0..4] of the bmRequestType field + return request->bmRequestType & 0xF; +} + +//------------------------------------------------------------------------------ +/// Returns the direction of the data transfer following the given request. +/// \param request Pointer to a USBGenericRequest instance. +/// \return Transfer direction. +/// \sa "USB Request Directions" +//------------------------------------------------------------------------------ +unsigned char USBGenericRequest_GetDirection(const USBGenericRequest *request) +{ + // Transfer direction is located in bit D7 of the bmRequestType field + if ((request->bmRequestType & 0x80) != 0) { + + return USBGenericRequest_IN; + } + else { + + return USBGenericRequest_OUT; + } +} + diff --git a/usb/common/core/USBGenericRequest.h b/usb/common/core/USBGenericRequest.h new file mode 100644 index 0000000..77f8ca5 --- /dev/null +++ b/usb/common/core/USBGenericRequest.h @@ -0,0 +1,244 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of the USBGenericRequest class and its methods. + + !!!Usage + + -# Declare or access USB requests by USBGenericRequest instance. + -# To get usful information (field values) from the USB requests, use + - USBGenericRequest_GetType + - USBGenericRequest_GetRequest + - USBGenericRequest_GetValue + - USBGenericRequest_GetIndex + - USBGenericRequest_GetLength + - USBGenericRequest_GetEndpointNumber + - USBGenericRequest_GetRecipient + - USBGenericRequest_GetDirection +*/ + +#ifndef USBGENERICREQUEST_H +#define USBGENERICREQUEST_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Generic Request definitions" +/// +/// This page lists the codes of USB generic request. +/// +/// - USB Request codes +/// - USBGenericRequest_GETSTATUS +/// - USBGenericRequest_CLEARFEATURE +/// - USBGenericRequest_SETFEATURE +/// - USBGenericRequest_SETADDRESS +/// - USBGenericRequest_GETDESCRIPTOR +/// - USBGenericRequest_SETDESCRIPTOR +/// - USBGenericRequest_GETCONFIGURATION +/// - USBGenericRequest_SETCONFIGURATION +/// - USBGenericRequest_GETINTERFACE +/// - USBGenericRequest_SETINTERFACE +/// - USBGenericRequest_SYNCHFRAME +/// +/// - USB Request Recipients +/// - USBGenericRequest_DEVICE +/// - USBGenericRequest_INTERFACE +/// - USBGenericRequest_ENDPOINT +/// - USBGenericRequest_OTHER +/// +/// - USB Request Types +/// - USBGenericRequest_STANDARD +/// - USBGenericRequest_CLASS +/// - USBGenericRequest_VENDOR +/// +/// - USB Request Directions +/// - USBGenericRequest_IN +/// - USBGenericRequest_OUT +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Request codes" +/// +/// This page lists the USB generic request codes. +/// +/// !Codes +/// - USBGenericRequest_GETSTATUS +/// - USBGenericRequest_CLEARFEATURE +/// - USBGenericRequest_SETFEATURE +/// - USBGenericRequest_SETADDRESS +/// - USBGenericRequest_GETDESCRIPTOR +/// - USBGenericRequest_SETDESCRIPTOR +/// - USBGenericRequest_GETCONFIGURATION +/// - USBGenericRequest_SETCONFIGURATION +/// - USBGenericRequest_GETINTERFACE +/// - USBGenericRequest_SETINTERFACE +/// - USBGenericRequest_SYNCHFRAME + +/// GET_STATUS request code. +#define USBGenericRequest_GETSTATUS 0 +/// CLEAR_FEATURE request code. +#define USBGenericRequest_CLEARFEATURE 1 +/// SET_FEATURE request code. +#define USBGenericRequest_SETFEATURE 3 +/// SET_ADDRESS request code. +#define USBGenericRequest_SETADDRESS 5 +/// GET_DESCRIPTOR request code. +#define USBGenericRequest_GETDESCRIPTOR 6 +/// SET_DESCRIPTOR request code. +#define USBGenericRequest_SETDESCRIPTOR 7 +/// GET_CONFIGURATION request code. +#define USBGenericRequest_GETCONFIGURATION 8 +/// SET_CONFIGURATION request code. +#define USBGenericRequest_SETCONFIGURATION 9 +/// GET_INTERFACE request code. +#define USBGenericRequest_GETINTERFACE 10 +/// SET_INTERFACE request code. +#define USBGenericRequest_SETINTERFACE 11 +/// SYNCH_FRAME request code. +#define USBGenericRequest_SYNCHFRAME 12 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Request Recipients" +/// +/// This page lists codes of USB request recipients. +/// +/// !Recipients +/// - USBGenericRequest_DEVICE +/// - USBGenericRequest_INTERFACE +/// - USBGenericRequest_ENDPOINT +/// - USBGenericRequest_OTHER + +/// Recipient is the whole device. +#define USBGenericRequest_DEVICE 0 +/// Recipient is an interface. +#define USBGenericRequest_INTERFACE 1 +/// Recipient is an endpoint. +#define USBGenericRequest_ENDPOINT 2 +/// Recipient is another entity. +#define USBGenericRequest_OTHER 3 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Request Types" +/// +/// This page lists codes of USB request types. +/// +/// !Types +/// - USBGenericRequest_STANDARD +/// - USBGenericRequest_CLASS +/// - USBGenericRequest_VENDOR + +/// Request is standard. +#define USBGenericRequest_STANDARD 0 +/// Request is class-specific. +#define USBGenericRequest_CLASS 1 +/// Request is vendor-specific. +#define USBGenericRequest_VENDOR 2 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB Request Directions" +/// +/// This page lists codes of USB request directions. +/// +/// !Directions +/// - USBGenericRequest_IN +/// - USBGenericRequest_OUT + +/// Transfer occurs from device to the host. +#define USBGenericRequest_OUT 0 +/// Transfer occurs from the host to the device. +#define USBGenericRequest_IN 1 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Generic USB SETUP request sent over Control endpoints. +//------------------------------------------------------------------------------ +typedef struct { + + /// Type of request + /// \sa "USB Request Recipients" + /// \sa "USB Request Types" + /// \sa "USB Request Directions" + unsigned char bmRequestType:8; + /// Request code + /// \sa "USB Request Codes" + unsigned char bRequest:8; + /// Request-specific value parameter. + unsigned short wValue:16; + /// Request-specific index parameter. + unsigned short wIndex:16; + /// Expected length (in bytes) of the data phase. + unsigned short wLength:16; + +} USBGenericRequest; + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char USBGenericRequest_GetType( + const USBGenericRequest *request); + + +extern unsigned char USBGenericRequest_GetRequest( + const USBGenericRequest *request); + +extern unsigned short USBGenericRequest_GetValue( + const USBGenericRequest *request); + +extern unsigned short USBGenericRequest_GetIndex( + const USBGenericRequest *request); + +extern unsigned short USBGenericRequest_GetLength( + const USBGenericRequest *request); + +extern unsigned char USBGenericRequest_GetEndpointNumber( + const USBGenericRequest *request); + +extern unsigned char USBGenericRequest_GetRecipient( + const USBGenericRequest *request); + +extern unsigned char USBGenericRequest_GetDirection( + const USBGenericRequest *request); + +#endif //#ifndef USBGENERICREQUEST_H + diff --git a/usb/common/core/USBGetDescriptorRequest.c b/usb/common/core/USBGetDescriptorRequest.c new file mode 100644 index 0000000..2937929 --- /dev/null +++ b/usb/common/core/USBGetDescriptorRequest.c @@ -0,0 +1,72 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: USBGetDescriptorRequest implementation + + About: Purpose + Implementation of the USBGetDescriptorRequest class. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBGetDescriptorRequest.h" + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Returns the type of the descriptor requested by the host given the +/// corresponding GET_DESCRIPTOR request. +/// \param request Pointer to a USBGenericDescriptor instance. +/// \return Type of the requested descriptor. +//------------------------------------------------------------------------------ +unsigned char USBGetDescriptorRequest_GetDescriptorType( + const USBGenericRequest *request) +{ + // Requested descriptor type is in the high-byte of the wValue field + return (USBGenericRequest_GetValue(request) >> 8) & 0xFF; +} + +//------------------------------------------------------------------------------ +/// Returns the index of the requested descriptor, given the corresponding +/// GET_DESCRIPTOR request. +/// \param request Pointer to a USBGenericDescriptor instance. +/// \return Index of the requested descriptor. +//------------------------------------------------------------------------------ +unsigned char USBGetDescriptorRequest_GetDescriptorIndex( + const USBGenericRequest *request) +{ + // Requested descriptor index if in the low byte of the wValue field + return USBGenericRequest_GetValue(request) & 0xFF; +} + diff --git a/usb/common/core/USBGetDescriptorRequest.h b/usb/common/core/USBGetDescriptorRequest.h new file mode 100644 index 0000000..43f6afd --- /dev/null +++ b/usb/common/core/USBGetDescriptorRequest.h @@ -0,0 +1,67 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of the USBGetDescriptorRequest class. + + !!!Usage + + - After a GET_DESCRIPTOR request has been received, retrive the useful + values with following functions: + - USBGetDescriptorRequest_GetDescriptorType: the descriptor type + - USBGetDescriptorRequest_GetDescriptorIndex: the index of the requested + descriptor + +*/ + +#ifndef USBGETDESCRIPTORREQUEST_H +#define USBGETDESCRIPTORREQUEST_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBGenericRequest.h" + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char USBGetDescriptorRequest_GetDescriptorType( + const USBGenericRequest *request); + +extern unsigned char USBGetDescriptorRequest_GetDescriptorIndex( + const USBGenericRequest *request); + +#endif //#ifndef USBGETDESCRIPTORREQUEST_H + diff --git a/usb/common/core/USBInterfaceAssociationDescriptor.h b/usb/common/core/USBInterfaceAssociationDescriptor.h new file mode 100644 index 0000000..5f3dd21 --- /dev/null +++ b/usb/common/core/USBInterfaceAssociationDescriptor.h @@ -0,0 +1,86 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + * \page USBInterfaceAssociateDescriptor + * !!!Purpose + * + * Class for manipulating USB IAD descriptors. + * + * !!!Usage + * + * -# Test + */ + +#ifndef USBDIADDESCRIPTOR_H +#define USBDIADDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +/* + Type: USBDeviceDescriptor + USB standard device descriptor structure. + + Variables: + bLength - Size of this descriptor in bytes. + bDescriptorType - Descriptor type (). + bFirstInterface - Interface number of the first interface that is + associated with this function. + bInterfaceCount - Number of contiguous interfaces that are + associated with this function. + bFunctionClass - Class code (assigned by USB-IF). + bFunctionSubClass - Subclass code (assigned by USB-IF). + bFunctionProtocol - Protocol code (assigned by USB-IF) + iFunction - Index of string descriptor describing this function. +*/ +typedef struct { + + unsigned char bLength; + unsigned char bDescriptorType; + unsigned char bFirstInterface; + unsigned char bInterfaceCount; + unsigned char bFunctionClass; + unsigned char bFunctionSubClass; + unsigned char bFunctionProtocol; + unsigned char iFunction; +} __attribute__ ((packed)) USBInterfaceAssociationDescriptor; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +#endif //#ifndef USBDIADDESCRIPTOR_H + diff --git a/usb/common/core/USBInterfaceDescriptor.h b/usb/common/core/USBInterfaceDescriptor.h new file mode 100644 index 0000000..63910bf --- /dev/null +++ b/usb/common/core/USBInterfaceDescriptor.h @@ -0,0 +1,87 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of a class for manipulating USB interface descriptors. + + !!!Usage + + - Declare USBInterfaceDescriptor instance as a part of the configuration + descriptors of a USB device. + +*/ + +#ifndef USBINTERFACEDESCRIPTOR_H +#define USBINTERFACEDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// USB standard interface descriptor structure. +//------------------------------------------------------------------------------ +typedef struct { + + /// Size of the descriptor in bytes. + unsigned char bLength; + /// Descriptor type (USBGenericDescriptor_INTERFACE). + unsigned char bDescriptorType; + /// Number of the interface in its configuration. + unsigned char bInterfaceNumber; + /// Value to select this alternate interface setting. + unsigned char bAlternateSetting; + /// Number of endpoints used by the inteface (excluding endpoint 0). + unsigned char bNumEndpoints; + /// Interface class code. + unsigned char bInterfaceClass; + /// Interface subclass code. + unsigned char bInterfaceSubClass; + /// Interface protocol code. + unsigned char bInterfaceProtocol; + /// Index of the interface string descriptor. + unsigned char iInterface; + +} __attribute__ ((packed)) USBInterfaceDescriptor; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +#endif //#ifndef USBINTERFACEDESCRIPTOR_H + diff --git a/usb/common/core/USBInterfaceRequest.c b/usb/common/core/USBInterfaceRequest.c new file mode 100644 index 0000000..61bf6ed --- /dev/null +++ b/usb/common/core/USBInterfaceRequest.c @@ -0,0 +1,69 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: USBInterfaceRequest + + About: Purpose + Implementation of USBInterfaceRequest class methods. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBInterfaceRequest.h" + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Indicates which interface is targetted by a GET_INTERFACE or +/// SET_INTERFACE request. +/// \param request Pointer to a USBGenericRequest instance. +/// \return Interface number. +//------------------------------------------------------------------------------ +unsigned char USBInterfaceRequest_GetInterface(const USBGenericRequest *request) +{ + return (USBGenericRequest_GetIndex(request) & 0xFF); +} + +//------------------------------------------------------------------------------ +/// Indicates the new alternate setting that the interface targetted by a +/// SET_INTERFACE request should use. +/// \param request Pointer to a USBGenericRequest instance. +/// \return New active setting for the interface. +//------------------------------------------------------------------------------ +unsigned char USBInterfaceRequest_GetAlternateSetting( + const USBGenericRequest *request) +{ + return (USBGenericRequest_GetValue(request) & 0xFF); +} + diff --git a/usb/common/core/USBInterfaceRequest.h b/usb/common/core/USBInterfaceRequest.h new file mode 100644 index 0000000..bd4cddd --- /dev/null +++ b/usb/common/core/USBInterfaceRequest.h @@ -0,0 +1,68 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definitions for manipulating SET_INTERFACE and GET_INTERFACE request. + + !!!Usage + + -# After a SET_INTERFACE request has been received, retrieve the + target interface using USBInterfaceRequest_GetInterface and its + new alternate setting with USBInterfaceRequest_GetAlternateSetting. + -# After a GET_INTERFACE request has been received, retrieve the target + interface using USBInterfaceRequest_GetInterface. + +*/ + +#ifndef USBINTERFACEREQUEST_H +#define USBINTERFACEREQUEST_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBGenericRequest.h" + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char USBInterfaceRequest_GetInterface( + const USBGenericRequest *request); + + +extern unsigned char USBInterfaceRequest_GetAlternateSetting( + const USBGenericRequest *request); + +#endif //#ifndef USBINTERFACEREQUEST_H + diff --git a/usb/common/core/USBIrqHandler.c b/usb/common/core/USBIrqHandler.c new file mode 100644 index 0000000..386ebd2 --- /dev/null +++ b/usb/common/core/USBIrqHandler.c @@ -0,0 +1,62 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: USBIrqHandler implementation + + About: Purpose + Implementation of the USB Interrupt Handler. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ +#include +#include + +#include + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +/// Call Arbitrer, device and host interrupt handler. +/// The IRQ functions are defined with weak and can be surcharged if needed. +//------------------------------------------------------------------------------ +void USB_IrqHandler( void ) +{ + // Most arbitrer interrupt + usb_general_interrupt(); + // Device interrupt + USBD_IrqHandler(); + // Host interrupt + usb_pipe_interrupt(); +} + + diff --git a/usb/common/core/USBIrqHandler.h b/usb/common/core/USBIrqHandler.h new file mode 100644 index 0000000..77d2679 --- /dev/null +++ b/usb/common/core/USBIrqHandler.h @@ -0,0 +1,52 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Implementation of the USB Interrupt Handler. + + !!!Usage + + -# The IRQ functions are defined with weak and can be surcharged if needed. + +*/ + +#ifndef USBIRQHANDLER_H +#define USBIRQHANDLER_H + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ +extern void USB_IrqHandler( void ); + +#endif //#ifndef USBIRQHANDLER_H + diff --git a/usb/common/core/USBSetAddressRequest.c b/usb/common/core/USBSetAddressRequest.c new file mode 100644 index 0000000..0e82a7f --- /dev/null +++ b/usb/common/core/USBSetAddressRequest.c @@ -0,0 +1,56 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: USBSetAddressRequest implementation + + About: Purpose + Implementation of the USBSetAddressRequest class. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBSetAddressRequest.h" + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +/// Returns the address that the device must take in response to a +/// SET_ADDRESS request. +/// \param request Pointer to a USBGenericRequest instance. +/// \return New device address. +//------------------------------------------------------------------------------ +unsigned char USBSetAddressRequest_GetAddress(const USBGenericRequest *request) +{ + return USBGenericRequest_GetValue(request) & 0x7F; +} + diff --git a/usb/common/core/USBSetAddressRequest.h b/usb/common/core/USBSetAddressRequest.h new file mode 100644 index 0000000..78034c3 --- /dev/null +++ b/usb/common/core/USBSetAddressRequest.h @@ -0,0 +1,60 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of a class for manipulating SET_ADDRESS USB requests. + + !!!Usage + + - After a SET_ADDRESS request has been received, retrive the new address + value with USBSetAddressRequest_GetAddress. +*/ + +#ifndef USBSETADDRESSREQUEST_H +#define USBSETADDRESSREQUEST_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBGenericRequest.h" + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char USBSetAddressRequest_GetAddress( + const USBGenericRequest *request); + +#endif //#ifndef USBSETADDRESSREQUEST_H + diff --git a/usb/common/core/USBSetConfigurationRequest.c b/usb/common/core/USBSetConfigurationRequest.c new file mode 100644 index 0000000..3aa747d --- /dev/null +++ b/usb/common/core/USBSetConfigurationRequest.c @@ -0,0 +1,58 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: USBSetConfigurationRequest implementation + + About: Purpose + Implementation of the USBSetConfigurationRequest class. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBSetConfigurationRequest.h" + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Returns the number of the configuration that should be set in response +/// to the given SET_CONFIGURATION request. +/// \param request Pointer to a USBGenericRequest instance. +/// \return Number of the requested configuration. +//------------------------------------------------------------------------------ +unsigned char USBSetConfigurationRequest_GetConfiguration( + const USBGenericRequest *request) +{ + return USBGenericRequest_GetValue(request); +} + diff --git a/usb/common/core/USBSetConfigurationRequest.h b/usb/common/core/USBSetConfigurationRequest.h new file mode 100644 index 0000000..aa1fa17 --- /dev/null +++ b/usb/common/core/USBSetConfigurationRequest.h @@ -0,0 +1,61 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of a class for the Set Configuration request. + + !!!Usage + + - After a SET_CONFIGURATION request has been received, retrive the new + configuration value with USBSetConfigurationRequest_GetConfiguration. + +*/ + +#ifndef USBSETCONFIGURATIONREQUEST_H +#define USBSETCONFIGURATIONREQUEST_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBGenericRequest.h" + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char USBSetConfigurationRequest_GetConfiguration( + const USBGenericRequest *request); + +#endif //#ifndef USBSETCONFIGURATIONREQUEST_H + diff --git a/usb/common/core/USBStringDescriptor.h b/usb/common/core/USBStringDescriptor.h new file mode 100644 index 0000000..bcf4b83 --- /dev/null +++ b/usb/common/core/USBStringDescriptor.h @@ -0,0 +1,74 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !!!Purpose +/// +/// Definition of a class for manipulating String descriptors. +//------------------------------------------------------------------------------ + +#ifndef USBSTRINGDESCRIPTOR_H +#define USBSTRINGDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB String Descriptor definitions" +/// +/// This page lists the codes and macros for USB string descriptor definition. +/// +/// !Language IDs +/// - USBStringDescriptor_ENGLISH_US +/// +/// !String Descriptor Length +/// - USBStringDescriptor_LENGTH +/// +/// !ASCII to UNICODE convertion +/// - USBStringDescriptor_UNICODE + +/// Language ID for US english. +#define USBStringDescriptor_ENGLISH_US 0x09, 0x04 + +/// Calculates the length of a string descriptor given the number of ascii +/// characters/language IDs in it. +/// \param length The ascii format string length. +/// \return The actual data length in bytes. +#define USBStringDescriptor_LENGTH(length) ((length) * 2 + 2) +/// Converts an ascii character to its unicode representation. +/// \param ascii The ASCII character to convert +/// \return A 2-byte-array for the UNICODE based on given ASCII +#define USBStringDescriptor_UNICODE(ascii) (ascii), 0 +//------------------------------------------------------------------------------ + +#endif //#ifndef USBSTRINGDESCRIPTOR_H + diff --git a/usb/common/core/core.dir b/usb/common/core/core.dir new file mode 100644 index 0000000..7ac93c3 --- /dev/null +++ b/usb/common/core/core.dir @@ -0,0 +1,53 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// !!!Purpose +/// +/// This directory contains definitions, structures and functions described by +/// USB specification. They can be divided into two groups: +/// - USB descriptors, prefixed with USB and suffixed with Descriptor. +/// - USB requests, prefixed with USB and suffixed with Request. +//------------------------------------------------------------------------------ + +/** + \page "Standard USB Structures" + + !!!Standard USB Structures + + The following standard structures is implemented in the USB framework: + - Setup request data: USBGenericRequest + - Descriptor header: USBGenericDescriptor + - Device descriptor: USBDeviceDescriptor + - Configuration descriptor: USBConfigurationDescriptor + - Interface descriptor: USBInterfaceDescriptor + - %Endpoint descriptor: USBEndpointDescriptor + - Device_Qualifier descriptor: USBDeviceQualifierDescriptor +*/ diff --git a/usb/common/hid/HIDButton.h b/usb/common/hid/HIDButton.h new file mode 100644 index 0000000..ea2557a --- /dev/null +++ b/usb/common/hid/HIDButton.h @@ -0,0 +1,55 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: HIDButton + + About: Purpose + Definitions of constants and methods for the HID Button usage page. + + About: Usage + 1 - Use the constants declared in this file when instanciating a + Report descriptor instance. + 2 - When implementing the functionality of an HID Mouse, use the + key codes defined here to indicate keys that are being pressed and + released. +*/ + +#ifndef _HIDBUTTON_H +#define _HIDBUTTON_H + +//------------------------------------------------------------------------------ +// Constants +//------------------------------------------------------------------------------ + +/// Identifier for the HID button usage page +#define HIDButton_PAGEID 0x09 + + +#endif diff --git a/usb/common/hid/HIDDescriptor.h b/usb/common/hid/HIDDescriptor.h new file mode 100644 index 0000000..ae00102 --- /dev/null +++ b/usb/common/hid/HIDDescriptor.h @@ -0,0 +1,93 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Methods and definitions for manipulating a HID descriptor. +*/ + +#ifndef HIDDESCRIPTOR_H +#define HIDDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Release Numbers" +/// ... +/// +/// !Numbers +/// - HIDDescriptor_HID1_11 + +/// Identifies version 1.11 of the HID specification. +#define HIDDescriptor_HID1_11 0x0111 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// Identifies the length of type of subordinate descriptors of a HID +/// device. This particular type only supports one subordinate descriptor. +//------------------------------------------------------------------------------ +typedef struct { + + /// Size of descriptor in bytes. + unsigned char bLength; + /// Descriptor type (HIDGenericDescriptor_HID). + unsigned char bDescriptorType; + /// HID class specification release number in BCD format. + unsigned short bcdHID; + /// Country code of the device if it is localized. + unsigned char bCountryCode; + /// Number of subordinate descriptors. + unsigned char bNumDescriptors; + /// Type of the first subordinate descriptor. + unsigned char bDescriptorType0; + /// Size in bytes of the first subordinate descriptor. + unsigned short wDescriptorLength0; + +} __attribute__ ((packed)) HIDDescriptor; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +#endif //#ifndef HIDDESCRIPTOR_H + diff --git a/usb/common/hid/HIDDeviceDescriptor.h b/usb/common/hid/HIDDeviceDescriptor.h new file mode 100644 index 0000000..267c73e --- /dev/null +++ b/usb/common/hid/HIDDeviceDescriptor.h @@ -0,0 +1,68 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definitions used for declaring the device descriptor of a HID device. + + !!!Usage + + Use this constants when defining an instance of USBDeviceDescriptor for + an HID device. +*/ + +#ifndef HIDDEVICEDESCRIPTOR_H +#define HIDDEVICEDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Device Descriptor Codes" +/// This page lists HID device class, subclass and protocol codes. +/// +/// !Codes +/// - HIDDeviceDescriptor_CLASS +/// - HIDDeviceDescriptor_SUBCLASS +/// - HIDDeviceDescriptor_PROTOCOL + +/// Class code for a HID device. +#define HIDDeviceDescriptor_CLASS 0 +/// Subclass code for a HID device. +#define HIDDeviceDescriptor_SUBCLASS 0 +/// Protocol code for a HID device. +#define HIDDeviceDescriptor_PROTOCOL 0 +//------------------------------------------------------------------------------ + +#endif //#ifndef HIDDEVICEDESCRIPTOR_H + diff --git a/usb/common/hid/HIDGenericDescriptor.h b/usb/common/hid/HIDGenericDescriptor.h new file mode 100644 index 0000000..2324d53 --- /dev/null +++ b/usb/common/hid/HIDGenericDescriptor.h @@ -0,0 +1,63 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definitions for using HID-specific descriptors. +*/ + +#ifndef HIDGENERICDESCRIPTOR_H +#define HIDGENERICDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Descriptors Types" +/// ... +/// +/// !Types +/// - HIDGenericDescriptor_HID +/// - HIDGenericDescriptor_REPORT +/// - HIDGenericDescriptor_PHYSICAL + +/// HID descriptor type. +#define HIDGenericDescriptor_HID 0x21 +/// Report descriptor type. +#define HIDGenericDescriptor_REPORT 0x22 +/// Physical descriptor type. +#define HIDGenericDescriptor_PHYSICAL 0x23 +//------------------------------------------------------------------------------ + +#endif //#ifndef HIDGENERICDESCRIPTOR_H + diff --git a/usb/common/hid/HIDGenericDesktop.h b/usb/common/hid/HIDGenericDesktop.h new file mode 100644 index 0000000..ac1165c --- /dev/null +++ b/usb/common/hid/HIDGenericDesktop.h @@ -0,0 +1,98 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Constants for using the HID generic desktop usage page. + + !!!Usage + + Use these constants when declaring a Report descriptor which references + the generic desktop page. +*/ + +#ifndef HIDGENERICDESKTOP_H +#define HIDGENERICDESKTOP_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID GenericDesktop Page ID" +/// ... +/// +/// !ID +/// - HIDGenericDesktop_PAGEID + +/// ID for the HID generic desktop usage page. +#define HIDGenericDesktop_PAGEID 0x01 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID GenericDesktop Usages" +/// ... +/// +/// !Usages +/// - HIDGenericDesktop_POINTER +/// - HIDGenericDesktop_MOUSE +/// - HIDGenericDesktop_JOYSTICK +/// - HIDGenericDesktop_GAMEPAD +/// - HIDGenericDesktop_KEYBOARD +/// - HIDGenericDesktop_KEYPAD +/// - HIDGenericDesktop_MULTIAXIS +/// - HIDGenericDesktop_X +/// - HIDGenericDesktop_Y + +/// Pointer usage ID. +#define HIDGenericDesktop_POINTER 0x01 +/// Mouse usage ID. +#define HIDGenericDesktop_MOUSE 0x02 +/// Joystick usage ID. +#define HIDGenericDesktop_JOYSTICK 0x04 +/// Gamepad usage ID. +#define HIDGenericDesktop_GAMEPAD 0x05 +/// Keyboard usage ID. +#define HIDGenericDesktop_KEYBOARD 0x06 +/// Keypad usage ID. +#define HIDGenericDesktop_KEYPAD 0x07 +/// Multi-axis controller usage ID. +#define HIDGenericDesktop_MULTIAXIS 0x08 + +/// Axis Usage X direction ID. +#define HIDGenericDesktop_X 0x30 +/// Axis Usage Y direction ID. +#define HIDGenericDesktop_Y 0x31 +//------------------------------------------------------------------------------ + +#endif //#ifndef HIDGENERICDESKTOP_H + diff --git a/usb/common/hid/HIDGenericRequest.h b/usb/common/hid/HIDGenericRequest.h new file mode 100644 index 0000000..356f498 --- /dev/null +++ b/usb/common/hid/HIDGenericRequest.h @@ -0,0 +1,75 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: HIDGenericRequest + + About: Purpose + Definition of constants for using HID-specific requests. + + About: Usage + When constructing or receiving an HID SETUP request, use the request + codes provided by this header file. +*/ + +#ifndef HIDGENERICREQUEST_H +#define HIDGENERICREQUEST_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Request Codes" +/// ... +/// +/// !Codes +/// - HIDGenericRequest_GETREPORT +/// - HIDGenericRequest_GETIDLE +/// - HIDGenericRequest_GETPROTOCOL +/// - HIDGenericRequest_SETREPORT +/// - HIDGenericRequest_SETIDLE +/// - HIDGenericRequest_SETPROTOCOL + +/// GetReport request code. +#define HIDGenericRequest_GETREPORT 0x01 +/// GetIdle request code. +#define HIDGenericRequest_GETIDLE 0x02 +/// GetProtocol request code. +#define HIDGenericRequest_GETPROTOCOL 0x03 +/// SetReport request code. +#define HIDGenericRequest_SETREPORT 0x09 +/// SetIdle request code. +#define HIDGenericRequest_SETIDLE 0x0A +/// SetProtocol request code. +#define HIDGenericRequest_SETPROTOCOL 0x0B +//------------------------------------------------------------------------------ + +#endif //#ifndef HIDGENERICREQUEST_H + diff --git a/usb/common/hid/HIDIdleRequest.c b/usb/common/hid/HIDIdleRequest.c new file mode 100644 index 0000000..640f2d5 --- /dev/null +++ b/usb/common/hid/HIDIdleRequest.c @@ -0,0 +1,56 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: HIDIdleRequest implementation + + About: Purpose + Implementation of the HIDIdleRequest methods. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "HIDIdleRequest.h" + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Retrieves the Idle rate (in milliseconds) indicated by a SET_IDLE +/// request. +/// \param request Pointer to a USBGenericRequest instance. +/// \return New idle rate for the report. +//------------------------------------------------------------------------------ +unsigned char HIDIdleRequest_GetIdleRate(const USBGenericRequest *request) +{ + return ((USBGenericRequest_GetValue(request) >> 8) & 0xFF); +} diff --git a/usb/common/hid/HIDIdleRequest.h b/usb/common/hid/HIDIdleRequest.h new file mode 100644 index 0000000..1f9a361 --- /dev/null +++ b/usb/common/hid/HIDIdleRequest.h @@ -0,0 +1,68 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Methods and constants for manipulating HID-specific GET_IDLE and SET_IDLE + requests. + + !!!Usage + + -# Retrieve the idle rate indicated by a GET_IDLE or SET_IDLE request + with HIDIdleRequest_GetIdleRate. +*/ + +#ifndef HIDIDLEREQUEST_H +#define HIDIDLEREQUEST_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +/// Infinite idle rate. +#define HIDIdleRequest_INFINITE 0 + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char HIDIdleRequest_GetIdleRate( + const USBGenericRequest *request); + +#endif //#ifndef HIDIDLEREQUEST_H + diff --git a/usb/common/hid/HIDInterfaceDescriptor.h b/usb/common/hid/HIDInterfaceDescriptor.h new file mode 100644 index 0000000..4ef1bc7 --- /dev/null +++ b/usb/common/hid/HIDInterfaceDescriptor.h @@ -0,0 +1,77 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Constants used when declaring an HID interface. + + !!!Usage + + Use the constants defined here when declaring a USBInterfaceDescriptor + instance for a HID interface. +*/ + +#ifndef HIDINTERFACEDESCRIPTOR_H +#define HIDINTERFACEDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Interface Descriptor Codes" +/// This page lists HID Interface class, subclass and protocol codes. +/// +/// !Codes +/// - HIDInterfaceDescriptor_CLASS +/// - HIDInterfaceDescriptor_SUBCLASS_NONE +/// - HIDInterfaceDescriptor_SUBCLASS_BOOT +/// - HIDInterfaceDescriptor_PROTOCOL_NONE +/// - HIDInterfaceDescriptor_PROTOCOL_KEYBOARD +/// - HIDInterfaceDescriptor_PROTOCOL_MOUSE + +/// HID interface class code. +#define HIDInterfaceDescriptor_CLASS 0x03 +/// Indicates the interface does not implement a particular subclass. +#define HIDInterfaceDescriptor_SUBCLASS_NONE 0x00 +/// Indicates the interface is compliant with the boot specification. +#define HIDInterfaceDescriptor_SUBCLASS_BOOT 0x01 +/// Indicates the interface does not implement a particular protocol. +#define HIDInterfaceDescriptor_PROTOCOL_NONE 0x00 +/// Indicates the interface supports the boot specification as a keyboard. +#define HIDInterfaceDescriptor_PROTOCOL_KEYBOARD 0x01 +/// Indicates the interface supports the boot specification as a mouse. +#define HIDInterfaceDescriptor_PROTOCOL_MOUSE 0x02 +//------------------------------------------------------------------------------ + +#endif //#ifndef HIDINTERFACEDESCRIPTOR_H + diff --git a/usb/common/hid/HIDKeypad.c b/usb/common/hid/HIDKeypad.c new file mode 100644 index 0000000..19f533e --- /dev/null +++ b/usb/common/hid/HIDKeypad.c @@ -0,0 +1,56 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: HIDKeypad implementation + + About: Purpose + Implementation of HID keypad usage page methods. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "HIDKeypad.h" + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Indicates if the given key code is associated with a modified key. +/// \param key Key code. +/// \return 1 if the key code represents a modifier key; otherwise 0. +//------------------------------------------------------------------------------ +unsigned char HIDKeypad_IsModifierKey(unsigned char key) +{ + return ((key >= HIDKeypad_LEFTCONTROL) && (key <= HIDKeypad_RIGHTGUI)); +} + diff --git a/usb/common/hid/HIDKeypad.h b/usb/common/hid/HIDKeypad.h new file mode 100644 index 0000000..06ad747 --- /dev/null +++ b/usb/common/hid/HIDKeypad.h @@ -0,0 +1,276 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + +!!!Purpose + + Definitions of constants and methods for the HID keypad usage page. + + !!!Usage + + -# Use the constants declared in this file when instanciating a + Report descriptor instance. + -# When implementing the functionality of an HID keyboard, use the + key codes defined here to indicate keys that are being pressed and + released. +*/ + +#ifndef HIDKEYPAD_H +#define HIDKEYPAD_H + +//------------------------------------------------------------------------------ +// Constants +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Keypad Page ID" +/// This page lists HID Keypad page ID. +/// +/// !ID +/// - HIDKeypad_PAGEID + +/// Identifier for the HID keypad usage page +#define HIDKeypad_PAGEID 0x07 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Alphabetic Keys" +/// ... +/// +/// !Keys +/// - HIDKeypad_A +/// - HIDKeypad_B +/// - HIDKeypad_C +/// - HIDKeypad_D +/// - HIDKeypad_E +/// - HIDKeypad_F +/// - HIDKeypad_G +/// - HIDKeypad_H +/// - HIDKeypad_I +/// - HIDKeypad_J +/// - HIDKeypad_K +/// - HIDKeypad_L +/// - HIDKeypad_M +/// - HIDKeypad_N +/// - HIDKeypad_O +/// - HIDKeypad_P +/// - HIDKeypad_Q +/// - HIDKeypad_R +/// - HIDKeypad_S +/// - HIDKeypad_T +/// - HIDKeypad_U +/// - HIDKeypad_V +/// - HIDKeypad_W +/// - HIDKeypad_X +/// - HIDKeypad_Y +/// - HIDKeypad_Z + +/// Key code for 'a' and 'A'. +#define HIDKeypad_A 4 +/// Key code for 'b' and 'B'. +#define HIDKeypad_B 5 +/// Key code for 'c' and 'C'. +#define HIDKeypad_C 6 +/// Key code for 'd' and 'D'. +#define HIDKeypad_D 7 +/// Key code for 'e' and 'E'. +#define HIDKeypad_E 8 +/// Key code for 'f' and 'F'. +#define HIDKeypad_F 9 +/// Key code for 'g' and 'G'. +#define HIDKeypad_G 10 +/// Key code for 'h' and 'H'. +#define HIDKeypad_H 11 +/// Key code for 'i' and 'I'. +#define HIDKeypad_I 12 +/// Key code for 'j' and 'J'. +#define HIDKeypad_J 13 +/// Key code for 'k' and 'K'. +#define HIDKeypad_K 14 +/// Key code for 'l' and 'L'. +#define HIDKeypad_L 15 +/// Key code for 'm' and 'M'. +#define HIDKeypad_M 16 +/// Key code for 'n' and 'N'. +#define HIDKeypad_N 17 +/// Key code for 'o' and 'O'. +#define HIDKeypad_O 18 +/// Key code for 'p' and 'P'. +#define HIDKeypad_P 19 +/// Key code for 'q' and 'Q'. +#define HIDKeypad_Q 20 +/// Key code for 'r' and 'R'. +#define HIDKeypad_R 21 +/// Key code for 's' and 'S'. +#define HIDKeypad_S 22 +/// Key code for 't' and 'T'. +#define HIDKeypad_T 23 +/// Key code for 'u' and 'U'. +#define HIDKeypad_U 24 +/// Key code for 'v' and 'V'. +#define HIDKeypad_V 25 +/// Key code for 'w' and 'W'. +#define HIDKeypad_W 26 +/// Key code for 'x' and 'X'. +#define HIDKeypad_X 27 +/// Key code for 'y' and 'Y'. +#define HIDKeypad_Y 28 +/// Key code for 'z' and 'Z'. +#define HIDKeypad_Z 29 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Numeric Keys" +/// ... +/// +/// !Keys +/// - HIDKeypad_1 +/// - HIDKeypad_2 +/// - HIDKeypad_3 +/// - HIDKeypad_4 +/// - HIDKeypad_5 +/// - HIDKeypad_6 +/// - HIDKeypad_7 +/// - HIDKeypad_8 +/// - HIDKeypad_9 +/// - HIDKeypad_0 + +/// Key code for '1' and '!'. +#define HIDKeypad_1 30 +/// Key code for '2' and '@'. +#define HIDKeypad_2 31 +/// Key code for '3' and '#'. +#define HIDKeypad_3 32 +/// Key code for '4' and '$'. +#define HIDKeypad_4 33 +/// Key code for '5' and '%'. +#define HIDKeypad_5 34 +/// Key code for '6' and '^'. +#define HIDKeypad_6 35 +/// Key code for '7' and '&'. +#define HIDKeypad_7 36 +/// Key code for '8' and '*'. +#define HIDKeypad_8 37 +/// Key code for '9' and '('. +#define HIDKeypad_9 38 +/// Key code for '0' and ')'. +#define HIDKeypad_0 39 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Special Keys" +/// ... +/// +/// !Keys +/// - HIDKeypad_ENTER +/// - HIDKeypad_ESCAPE +/// - HIDKeypad_BACKSPACE +/// - HIDKeypad_TAB +/// - HIDKeypad_SPACEBAR +/// - HIDKeypad_PRINTSCREEN +/// - HIDKeypad_SCROLLLOCK +/// - HIDKeypad_NUMLOCK + +/// Enter key code. +#define HIDKeypad_ENTER 40 +/// Escape key code. +#define HIDKeypad_ESCAPE 41 +/// Backspace key code. +#define HIDKeypad_BACKSPACE 42 +/// Tab key code. +#define HIDKeypad_TAB 43 +/// Spacebar key code. +#define HIDKeypad_SPACEBAR 44 +/// Printscreen key code. +#define HIDKeypad_PRINTSCREEN 70 +/// Scroll lock key code. +#define HIDKeypad_SCROLLLOCK 71 +/// Num lock key code. +#define HIDKeypad_NUMLOCK 83 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Modified Keys" +/// ... +/// +/// !Keys +/// - HIDKeypad_LEFTCONTROL +/// - HIDKeypad_LEFTSHIFT +/// - HIDKeypad_LEFTALT +/// - HIDKeypad_LEFTGUI +/// - HIDKeypad_RIGHTCONTROL +/// - HIDKeypad_RIGHTSHIFT +/// - HIDKeypad_RIGHTALT +/// - HIDKeypad_RIGHTGUI + +/// Key code for the left 'Control' key. +#define HIDKeypad_LEFTCONTROL 224 +/// Key code for the left 'Shift' key. +#define HIDKeypad_LEFTSHIFT 225 +/// Key code for the left 'Alt' key. +#define HIDKeypad_LEFTALT 226 +/// Key code for the left 'GUI' (e.g. Windows) key. +#define HIDKeypad_LEFTGUI 227 +/// Key code for the right 'Control' key. +#define HIDKeypad_RIGHTCONTROL 228 +/// Key code for the right 'Shift' key. +#define HIDKeypad_RIGHTSHIFT 229 +/// Key code for the right 'Alt' key. +#define HIDKeypad_RIGHTALT 230 +/// Key code for the right 'GUI' key. +#define HIDKeypad_RIGHTGUI 231 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Error Codes" +/// ... +/// +/// !Codes +/// - HIDKeypad_ERRORROLLOVER +/// - HIDKeypad_POSTFAIL +/// - HIDKeypad_ERRORUNDEFINED + +/// Indicates that too many keys have been pressed at the same time. +#define HIDKeypad_ERRORROLLOVER 1 +/// ? +#define HIDKeypad_POSTFAIL 2 +/// Indicates an undefined error. +#define HIDKeypad_ERRORUNDEFINED 3 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char HIDKeypad_IsModifierKey(unsigned char key); + +#endif //#ifndef HIDKEYPAD_H + diff --git a/usb/common/hid/HIDLeds.h b/usb/common/hid/HIDLeds.h new file mode 100644 index 0000000..22ee54d --- /dev/null +++ b/usb/common/hid/HIDLeds.h @@ -0,0 +1,79 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition for the HID LEDs usage page. + + !!!Usage + + Uses the constants defined in this header file when declaring a Report + descriptor which references the LEDs usage page. +*/ + +#ifndef HIDLEDS_H +#define HIDLEDS_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID LEDs Page ID" +/// This page lists the page ID of the HID LEDs usage page. +/// +/// !ID +/// - HIDLeds_PAGEID + +/// ID of the HID LEDs usage page. +#define HIDLeds_PAGEID 0x08 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID LEDs Usages" +/// This page lists the Usages of the HID LEDs. +/// +/// !Usages +/// - HIDLeds_NUMLOCK +/// - HIDLeds_CAPSLOCK +/// - HIDLeds_SCROLLLOCK + +/// Num lock LED usage. +#define HIDLeds_NUMLOCK 0x01 +/// Caps lock LED usage. +#define HIDLeds_CAPSLOCK 0x02 +/// Scroll lock LED usage. +#define HIDLeds_SCROLLLOCK 0x03 +//------------------------------------------------------------------------------ + +#endif //#ifndef HIDLEDS_H + diff --git a/usb/common/hid/HIDReport.h b/usb/common/hid/HIDReport.h new file mode 100644 index 0000000..ec02ded --- /dev/null +++ b/usb/common/hid/HIDReport.h @@ -0,0 +1,231 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definitions used when declaring an HID report descriptor. + + !!!Usage + + Use the definitions provided here when declaring a report descriptor, + which shall be an unsigned char array. +*/ + +#ifndef HIDREPORT_H +#define HIDREPORT_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Main Item Tags" +/// This page lists the Main Item Tags defined for HID %device. +/// ( HID Spec. 6.2.2 ) +/// +/// !Tags +/// - HIDReport_INPUT +/// - HIDReport_OUPUT +/// - HIDReport_FEATURE +/// - HIDReport_COLLECTION +/// - HIDReport_ENDCOLLECTION + +/// Input item. +#define HIDReport_INPUT 0x80 +/// Output item. +#define HIDReport_OUTPUT 0x90 +/// Feature item. +#define HIDReport_FEATURE 0xB0 +/// Collection item. +#define HIDReport_COLLECTION 0xA0 +/// End of collection item. +#define HIDReport_ENDCOLLECTION 0xC0 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Items for Data Fields" +/// This page lists defintions for HID Input, Output and Feature items that +/// are used to create the data fields within a report. +/// ( HID Spec. 6.2.2.5 ) +/// +/// !Items +/// - HIDReport_CONSTANT +/// - HIDReport_VARIABLE +/// - HIDReport_RELATIVE +/// - HIDReport_WRAP +/// - HIDReport_NONLINEAR +/// - HIDReport_NOPREFERRED +/// - HIDReport_NULLSTATE +/// - HIDReport_VOLATILE +/// - HIDReport_BUFFEREDBYTES + +/// The report value is constant (vs. variable). +#define HIDReport_CONSTANT (1 << 0) +/// Data reported is a variable (vs. array). +#define HIDReport_VARIABLE (1 << 1) +/// Data is relative (vs. absolute). +#define HIDReport_RELATIVE (1 << 2) +/// Value rolls over when it reach a maximum/minimum. +#define HIDReport_WRAP (1 << 3) +/// Indicates that the data reported has been processed and is no longuer +/// linear with the original measurements. +#define HIDReport_NONLINEAR (1 << 4) +/// Device has no preferred state to which it automatically returns. +#define HIDReport_NOPREFERRED (1 << 5) +/// Device has a null state, in which it does not report meaningful +/// information. +#define HIDReport_NULLSTATE (1 << 6) +/// Indicates data can change without the host intervention. +#define HIDReport_VOLATILE (1 << 7) +/// Indicates the device produces a fixed-length stream of bytes. +#define HIDReport_BUFFEREDBYTES (1 << 8) +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Collection Items" +/// This page lists definitions for HID Collection Items. +/// ( HID Spec. 6.2.2.6 ) +/// +/// !Items +/// - HIDReport_COLLECTION_PHYSICAL +/// - HIDReport_COLLECTION_APPLICATION +/// - HIDReport_COLLECTION_LOGICAL +/// - HIDReport_COLLECTION_REPORT +/// - HIDReport_COLLECTION_NAMEDARRAY +/// - HIDReport_COLLECTION_USAGESWITCH +/// - HIDReport_COLLECTION_USAGEMODIFIER + +/// Physical collection. +#define HIDReport_COLLECTION_PHYSICAL 0x00 +/// Application collection. +#define HIDReport_COLLECTION_APPLICATION 0x01 +/// Logical collection. +#define HIDReport_COLLECTION_LOGICAL 0x02 +/// Report collection. +#define HIDReport_COLLECTION_REPORT 0x03 +/// Named array collection. +#define HIDReport_COLLECTION_NAMEDARRAY 0x04 +/// Usage switch collection. +#define HIDReport_COLLECTION_USAGESWITCH 0x05 +/// Usage modifier collection +#define HIDReport_COLLECTION_USAGEMODIFIER 0x06 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Global Items" +/// This page lists HID Global Items. +/// ( HID Spec. 6.2.2.7 ) +/// +/// !Items +/// - HIDReport_GLOBAL_USAGEPAGE +/// - HIDReport_GLOBAL_LOGICALMINIMUM +/// - HIDReport_GLOBAL_LOGICALMAXIMUM +/// - HIDReport_GLOBAL_PHYSICALMINIMUM +/// - HIDReport_GLOBAL_PHYSICALMAXIMUM +/// - HIDReport_GLOBAL_UNITEXPONENT +/// - HIDReport_GLOBAL_UNIT +/// - HIDReport_GLOBAL_REPORTSIZE +/// - HIDReport_GLOBAL_REPORTID +/// - HIDReport_GLOBAL_REPORTCOUNT +/// - HIDReport_GLOBAL_PUSH +/// - HIDReport_GLOBAL_POP + +/// Current usage page. +#define HIDReport_GLOBAL_USAGEPAGE 0x04 +/// Minimum value that a variable or array item will report. +#define HIDReport_GLOBAL_LOGICALMINIMUM 0x14 +/// Maximum value that a variable or array item will report. +#define HIDReport_GLOBAL_LOGICALMAXIMUM 0x24 +/// Minimum value for the physical extent of a variable item. +#define HIDReport_GLOBAL_PHYSICALMINIMUM 0x34 +/// Maximum value for the physical extent of a variable item. +#define HIDReport_GLOBAL_PHYSICALMAXIMUM 0x44 +/// Value of the unit exponent in base 10. +#define HIDReport_GLOBAL_UNITEXPONENT 0x54 +/// Unit values. +#define HIDReport_GLOBAL_UNIT 0x64 +/// Size of the report fields in bits. +#define HIDReport_GLOBAL_REPORTSIZE 0x74 +/// Specifies the report ID. +#define HIDReport_GLOBAL_REPORTID 0x84 +/// Number of data fields for an item. +#define HIDReport_GLOBAL_REPORTCOUNT 0x94 +/// Places a copy of the global item state table on the stack. +#define HIDReport_GLOBAL_PUSH 0xA4 +/// Replaces the item state table with the top structure from the stack. +#define HIDReport_GLOBAL_POP 0xB4 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Local Items" +/// This page lists definitions for HID Local Items. +/// +/// !Items +/// - HIDReport_LOCAL_USAGE +/// - HIDReport_LOCAL_USAGEMINIMUM +/// - HIDReport_LOCAL_USAGEMAXIMUM +/// - HIDReport_LOCAL_DESIGNATORINDEX +/// - HIDReport_LOCAL_DESIGNATORMINIMUM +/// - HIDReport_LOCAL_DESIGNATORMAXIMUM +/// - HIDReport_LOCAL_STRINGINDEX +/// - HIDReport_LOCAL_STRINGMINIMUM +/// - HIDReport_LOCAL_STRINGMAXIMUM +/// - HIDReport_LOCAL_DELIMITER + +/// Suggested usage for an item or collection. +#define HIDReport_LOCAL_USAGE 0x08 +/// Defines the starting usage associated with an array or bitmap. +#define HIDReport_LOCAL_USAGEMINIMUM 0x18 +/// Defines the ending usage associated with an array or bitmap. +#define HIDReport_LOCAL_USAGEMAXIMUM 0x28 +/// Determines the body part used for a control. +#define HIDReport_LOCAL_DESIGNATORINDEX 0x38 +/// Defines the index of the starting designator associated with an array or +/// bitmap. +#define HIDReport_LOCAL_DESIGNATORMINIMUM 0x48 +/// Defines the index of the ending designator associated with an array or +/// bitmap. +#define HIDReport_LOCAL_DESIGNATORMAXIMUM 0x58 +/// String index for a string descriptor. +#define HIDReport_LOCAL_STRINGINDEX 0x78 +/// Specifies the first string index when assigning a group of sequential +/// strings to controls in an array or bitmap. +#define HIDReport_LOCAL_STRINGMINIMUM 0x88 +/// Specifies the last string index when assigning a group of sequential +/// strings to controls in an array or bitmap. +#define HIDReport_LOCAL_STRINGMAXIMUM 0x98 +/// Defines the beginning or end of a set of local items. +#define HIDReport_LOCAL_DELIMITER 0xA8 +//------------------------------------------------------------------------------ + +#endif //#ifndef HIDREPORT_H + diff --git a/usb/common/hid/HIDReportRequest.c b/usb/common/hid/HIDReportRequest.c new file mode 100644 index 0000000..3e9d2e8 --- /dev/null +++ b/usb/common/hid/HIDReportRequest.c @@ -0,0 +1,68 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: HIDReportRequest implementation + + About: Purpose + Implementation of the HIDReportRequest methods. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "HIDReportRequest.h" + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Indicates the type of report targetted by a SET_REPORT or GET_REPORT +/// request. +/// \param request Pointer to a USBGenericRequest instance. +/// \return Requested report type (see "HID Report Types"). +//------------------------------------------------------------------------------ +unsigned char HIDReportRequest_GetReportType(const USBGenericRequest *request) +{ + return ((USBGenericRequest_GetValue(request) >> 8) & 0xFF); +} + +//------------------------------------------------------------------------------ +/// Indicates the ID of the report targetted by a SET_REPORT or GET_REPORT +/// request. This value should be 0 if report IDs are not used. +/// \param request Pointer to a USBGenericRequest instance. +/// \return Requested report ID. +//------------------------------------------------------------------------------ +unsigned char HIDReportRequest_GetReportId(const USBGenericRequest *request) +{ + return (USBGenericRequest_GetValue(request) & 0xFF); +} + diff --git a/usb/common/hid/HIDReportRequest.h b/usb/common/hid/HIDReportRequest.h new file mode 100644 index 0000000..75ea379 --- /dev/null +++ b/usb/common/hid/HIDReportRequest.h @@ -0,0 +1,86 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of a class for manipulating HID-specific GET_REPORT and + SET_REPORT requests. + + !!!Usage + + -# Receive a GET_REPORT or SET_REPORT request from the host. + -# Retrieve the report type using HIDReportRequest_GetReportType. + -# Retrieve the report ID using HIDReportRequest_GetReportId. +*/ + +#ifndef HIDREPORTREQUEST_H +#define HIDREPORTREQUEST_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Report Types" +/// This page lists the types for USB HID Reports. +/// +/// !Types +/// - HIDReportRequest_INPUT +/// - HIDReportRequest_OUTPUT +/// - HIDReportRequest_FEATURE + +/// Input report. +#define HIDReportRequest_INPUT 1 +/// Output report. +#define HIDReportRequest_OUTPUT 2 +/// Feature report. +#define HIDReportRequest_FEATURE 3 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char HIDReportRequest_GetReportType( + const USBGenericRequest *request); + +extern unsigned char HIDReportRequest_GetReportId( + const USBGenericRequest *request); + +#endif //#ifndef HIDREPORTREQUEST_H + diff --git a/usb/common/hid/hid.dir b/usb/common/hid/hid.dir new file mode 100644 index 0000000..d46589b --- /dev/null +++ b/usb/common/hid/hid.dir @@ -0,0 +1,39 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// !Purpose +/// +/// This directory contains structures and definitions related to the USB HID +/// specification. They can be divided into two groups: +/// - HID-specific descriptors, prefixed with HID and suffixed with Descriptor. +/// - HID-specific requests, prefixed with HID and suffixed with Request. +//------------------------------------------------------------------------------ + diff --git a/usb/common/massstorage/MSDeviceDescriptor.h b/usb/common/massstorage/MSDeviceDescriptor.h new file mode 100644 index 0000000..9f4f700 --- /dev/null +++ b/usb/common/massstorage/MSDeviceDescriptor.h @@ -0,0 +1,73 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// !Purpose +/// +/// Declaration of constants for using Device Descriptors with a Mass Storage +/// driver. +/// +/// !Usage +/// +/// - For a USB device: +/// -# When declaring a USBDeviceDescriptor instance, use the Mass Storage +/// codes defined in this file (see "MS device codes"). +//------------------------------------------------------------------------------ + +#ifndef MSDEVICEDESCRIPTOR_H +#define MSDEVICEDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "MS device codes" +/// This page lists the class, subclass & protocol codes used by a device with +/// a Mass Storage driver. +/// +/// !Codes +/// +/// - MSDeviceDescriptor_CLASS +/// - MSDeviceDescriptor_SUBCLASS +/// - MSDeviceDescriptor_PROTOCOL + +/// Class code for a Mass Storage device. +#define MSDeviceDescriptor_CLASS 0 + +/// Subclass code for a Mass Storage device. +#define MSDeviceDescriptor_SUBCLASS 0 + +/// Protocol code for a Mass Storage device. +#define MSDeviceDescriptor_PROTOCOL 0 +//------------------------------------------------------------------------------ + +#endif //#ifndef MSDEVICEDESCRIPTOR_H + diff --git a/usb/common/massstorage/MSInterfaceDescriptor.h b/usb/common/massstorage/MSInterfaceDescriptor.h new file mode 100644 index 0000000..e51dba6 --- /dev/null +++ b/usb/common/massstorage/MSInterfaceDescriptor.h @@ -0,0 +1,75 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// !Purpose +/// +/// Definition of several constants used when manipulating Mass Storage interface +/// descriptors. +/// +/// !Usage +/// +/// - For a USB device: +/// -# When declaring an interface descriptor for a Mass Storage device, use +/// the class, subclass and protocol codes defined here (see +/// "MS interface codes"). +//------------------------------------------------------------------------------ + +#ifndef MSINTERFACEDESCRIPTOR_H +#define MSINTERFACEDESCRIPTOR_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "MS interface codes" +/// This page lists the available class, subclass & protocol codes for a Mass +/// Storage interface. +/// +/// !Codes +/// +/// - MSInterfaceDescriptor_CLASS +/// - MSInterfaceDescriptor_SCSI +/// - MSInterfaceDescriptor_BULKONLY + +/// Class code for a Mass Storage interface. +#define MSInterfaceDescriptor_CLASS 0x08 + +/// Subclass code for a Mass Storage interface using the SCSI protocol. +#define MSInterfaceDescriptor_SCSI 0x06 + +/// Protocol code for a Mass Storage interface using Bulk-Only Transport. +#define MSInterfaceDescriptor_BULKONLY 0x50 +//------------------------------------------------------------------------------ + + +#endif //#ifndef MSINTERFACEDESCRIPTOR_H + diff --git a/usb/common/massstorage/massstorage.dir b/usb/common/massstorage/massstorage.dir new file mode 100644 index 0000000..f9474f1 --- /dev/null +++ b/usb/common/massstorage/massstorage.dir @@ -0,0 +1,39 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// !Purpose +/// +/// This directory contains structures and definitions related to the USB mass +/// storage specification. +/// - Mass-storage-specific descriptors, prefixed with MS and suffixed with +/// Descriptor. +//------------------------------------------------------------------------------ + diff --git a/usb/device/USBDCallbackInvocationFlowchart.png b/usb/device/USBDCallbackInvocationFlowchart.png new file mode 100644 index 0000000..af8028e Binary files /dev/null and b/usb/device/USBDCallbackInvocationFlowchart.png differ diff --git a/usb/device/USBDeviceStateDiagram.png b/usb/device/USBDeviceStateDiagram.png new file mode 100644 index 0000000..eacdd41 Binary files /dev/null and b/usb/device/USBDeviceStateDiagram.png differ diff --git a/usb/device/audio-looprec/AUDDLoopRecChannel.c b/usb/device/audio-looprec/AUDDLoopRecChannel.c new file mode 100644 index 0000000..c6d9a08 --- /dev/null +++ b/usb/device/audio-looprec/AUDDLoopRecChannel.c @@ -0,0 +1,129 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: AUDDLoopRecChannel implementation + + About: Purpose + Implementation of the AUDDLoopRecChannel functions. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "AUDDLoopRecChannel.h" +#include + +//------------------------------------------------------------------------------ +// Callbacks +//------------------------------------------------------------------------------ +/* + Function: AUDDLoopRecChannel_MuteChanged + Callback triggered when the mute status of a channel changes. This is + a default implementation which does nothing and must be overriden. + + Parameters: + channel - Pointer to a AUDDLoopRecChannel instance. + muted - New mute status. +*/ +//__attribute__ ((weak)) void AUDDLoopRecChannel_MuteChanged( +// AUDDLoopRecChannel *channel, +// unsigned char muted) +//{ +// TRACE_DEBUG("MuteChanged(%d, %d) ", channel->number, muted); +//} + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes the member variables of an AUDDLoopRecChannel object to the +/// given values. +/// \param channel Pointer to an AUDDLoopRecChannel instance. +/// \param number Channel number in the audio function. +/// \param muted Indicates if the channel is muted. +//------------------------------------------------------------------------------ +void AUDDLoopRecChannel_Initialize(AUDDLoopRecChannel *channel, + unsigned char number, + unsigned char muted) +{ + channel->number = number; + channel->muted = muted; +} + +//------------------------------------------------------------------------------ +/// Indicates the number of a channel. +/// \param channel Pointer to an AUDDLoopRecChannel instance. +/// \return Channel number. +//------------------------------------------------------------------------------ +unsigned char AUDDLoopRecChannel_GetNumber(const AUDDLoopRecChannel *channel) +{ + return channel->number; +} + +//------------------------------------------------------------------------------ +/// Mutes the given channel and triggers the MuteChanged callback if +/// necessary. +/// \param channel Pointer to an AUDDLoopRecChannelInstance. +//------------------------------------------------------------------------------ +void AUDDLoopRecChannel_Mute(AUDDLoopRecChannel *channel) +{ + if (!channel->muted) { + + channel->muted = 1; + AUDDLoopRecChannel_MuteChanged(channel, 1); + } +} + +//------------------------------------------------------------------------------ +/// Unmutes the given channel and triggers the MuteChanged callback if +/// necessary. +/// \param channel Pointer to an AUDDLoopRecChannelInstance. +//------------------------------------------------------------------------------ +void AUDDLoopRecChannel_Unmute(AUDDLoopRecChannel *channel) +{ + if (channel->muted) { + + channel->muted = 0; + AUDDLoopRecChannel_MuteChanged(channel, 0); + } +} + +//------------------------------------------------------------------------------ +/// Indicates if the given channel is currently muted or not. +/// \param channel Pointer an AUDDLoopRecChannel instance. +/// \return 1 if the channel is muted; otherwise 0. +//------------------------------------------------------------------------------ +unsigned char AUDDLoopRecChannel_IsMuted(const AUDDLoopRecChannel *channel) +{ + return channel->muted; +} + diff --git a/usb/device/audio-looprec/AUDDLoopRecChannel.h b/usb/device/audio-looprec/AUDDLoopRecChannel.h new file mode 100644 index 0000000..6cfad6b --- /dev/null +++ b/usb/device/audio-looprec/AUDDLoopRecChannel.h @@ -0,0 +1,92 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !Purpose + + Manipulation of the channels of an USB audio LoopRec device. + + !Usage + + -# Initialize a AUDDLoopRecChannel instance using + AUDDLoopRecChannel_Initialize. + -# Retrieves the current status of a channel with the + AUDDLoopRecChannel_IsMuted method. + -# Re-implement the AUDDLoopRecChannel_MuteChanged callback to get + notified when the status of a channel changes. +*/ + +#ifndef AUDDLOOPRECCHANNEL_H +#define AUDDLOOPRECCHANNEL_H + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Modelizes a channel of an USB audio LoopRec device. +//------------------------------------------------------------------------------ +typedef struct { + + /// Zero-based channel number in the audio function. + unsigned char number; + /// Indicates if the channel is currently muted. + unsigned char muted; + +} AUDDLoopRecChannel; + +//------------------------------------------------------------------------------ +// Callbacks +//------------------------------------------------------------------------------ + +extern void AUDDLoopRecChannel_MuteChanged(AUDDLoopRecChannel *channel, + unsigned char muted); + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern void AUDDLoopRecChannel_Initialize(AUDDLoopRecChannel *channel, + unsigned char number, + unsigned char muted); + +extern unsigned char AUDDLoopRecChannel_GetNumber( + const AUDDLoopRecChannel *channel); + +extern void AUDDLoopRecChannel_Mute(AUDDLoopRecChannel *channel); + +extern void AUDDLoopRecChannel_Unmute(AUDDLoopRecChannel *channel); + +extern unsigned char AUDDLoopRecChannel_IsMuted( + const AUDDLoopRecChannel *channel); + +#endif //#ifndef AUDDLOOPRECCHANNEL_H + diff --git a/usb/device/audio-looprec/AUDDLoopRecDriver.c b/usb/device/audio-looprec/AUDDLoopRecDriver.c new file mode 100644 index 0000000..45534b5 --- /dev/null +++ b/usb/device/audio-looprec/AUDDLoopRecDriver.c @@ -0,0 +1,493 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "AUDDLoopRecDriver.h" +#include "AUDDLoopRecDriverDescriptors.h" +#include "AUDDLoopRecChannel.h" +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Internal types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Audio LoopRec driver internal state. +//------------------------------------------------------------------------------ +typedef struct { + + /// USB device driver instance. + USBDDriver usbdDriver; + #if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + /// Multi-Buffer-Transfer List + USBDTransferBuffer * pMbl; + /// List Size + unsigned short listSize; + /// Current buffer + unsigned short currBuffer; + #endif + /// Callback for ISO IN + AUDDFrameTransferCallback fWrCallback; + /// List of AUDDLoopRecChannel instances for playback. + AUDDLoopRecChannel channels[AUDDLoopRecDriver_NUMCHANNELS+1]; + /// List of AUDDLoopRecChannel instances for record. + AUDDLoopRecChannel recChannels[1]; + +} AUDDLoopRecDriver; + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +/// Global USB audio LoopRec driver instance. +static AUDDLoopRecDriver auddLoopRecDriver; +/// Array for storing the current setting of each interface. +static unsigned char auddLoopRecDriverInterfaces[3]; +/// Intermediate storage variable for the mute status of a channel. +static unsigned char muted; + +//------------------------------------------------------------------------------ +// Internal functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Callback triggered after the new mute status of a channel has been read +/// by AUDDLoopRecDriver_SetFeatureCurrentValue. Changes the mute status +/// of the given channel accordingly. +/// \param channel Number of the channel whose mute status has changed. +//------------------------------------------------------------------------------ +static void AUDDLoopRecDriver_MuteReceived(unsigned int channel) +{ + AUDDLoopRecChannel * pChannel; + if ((unsigned char)(channel >> 8) == + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL_REC) { + pChannel = &auddLoopRecDriver.recChannels[0]; + } + else { + pChannel = &auddLoopRecDriver.channels[channel]; + } + if (muted) { + + AUDDLoopRecChannel_Mute(pChannel); + } + else { + + AUDDLoopRecChannel_Unmute(pChannel); + } + + USBD_Write(0, 0, 0, 0, 0); +} + +//------------------------------------------------------------------------------ +/// Sets the current value of a particular Feature control of a channel. +/// \param entity Entity number. +/// \param channel Channel number. +/// \param control Control selector value (see TODO). +/// \param length Length of the data containing the new value. +//------------------------------------------------------------------------------ +static void AUDDLoopRecDriver_SetFeatureCurrentValue(unsigned char entity, + unsigned char channel, + unsigned char control, + unsigned short length) +{ + TRACE_INFO_WP("sFeature "); + TRACE_DEBUG("\b(E%d, CS%d, CN%d, L%d) ", + entity, control, channel, length); + + // Check the the requested control is supported + // Control/channel combination not supported + if ((control != AUDFeatureUnitRequest_MUTE) || + (length != 1) || + ((entity == AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL) && + (channel > AUDDLoopRecDriver_NUMCHANNELS)) || + ((entity == AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL_REC) && + (channel > 0))) { + + USBD_Stall(0); + } + // Mute control on master channel / speakerphone + else { + + unsigned int argument = channel | (entity << 8); + USBD_Read(0, // Endpoint #0 + &muted, + sizeof(muted), + (TransferCallback) AUDDLoopRecDriver_MuteReceived, + (void *) argument); + } +} + +//------------------------------------------------------------------------------ +/// Sends the current value of a particular channel Feature to the USB host. +/// \param entity Entity number. +/// \param channel Channel number. +/// \param control Control selector value (see TODO). +/// \param length Length of the data to return. +//------------------------------------------------------------------------------ +static void AUDDLoopRecDriver_GetFeatureCurrentValue(unsigned char entity, + unsigned char channel, + unsigned char control, + unsigned char length) +{ + TRACE_INFO_WP("gFeature "); + TRACE_DEBUG("\b(CS%d, CN%d, L%d) ", control, channel, length); + + // Check that the requested control is supported + // Master channel mute control + if ((control == AUDFeatureUnitRequest_MUTE) + && (channel < (AUDDLoopRecDriver_NUMCHANNELS+1)) + && (length == 1)) { + + if (entity == AUDDLoopRecDriverDescriptors_FEATUREUNIT) { + muted = auddLoopRecDriver.channels[channel].muted; + } + else { + muted = auddLoopRecDriver.recChannels[0].muted; + } + USBD_Write(0, &muted, sizeof(muted), 0, 0); + } + else { + + USBD_Stall(0); + } +} + +//------------------------------------------------------------------------------ +/// Callback used by MBL transfer functions (USBD_Read & USBD_Write) to notify +/// that a transaction is complete. +/// \param pArg Pointer to callback arguments. +/// \param status USBD status. +/// \param nbBuffer Number of buffer that is processed. +//------------------------------------------------------------------------------ +void AUDDLoopRecDriver_MblWriteCallback(void *pArg, + unsigned char status, + unsigned int nbBuffer) +{ + char rc = 1; + if (auddLoopRecDriver.fWrCallback) { + + rc = auddLoopRecDriver.fWrCallback(pArg, status); + } + if (rc && status == USBD_STATUS_PARTIAL_DONE) { + + while(nbBuffer --) { + USBD_MblReuse(AUDDLoopRecDriverDescriptors_DATAIN, + 0, 0); + } + } +} + +//------------------------------------------------------------------------------ +// Callback re-implementation +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Triggered when the USB host emits a new SETUP request. The request is +/// forward to . +/// \param request Pointer to a USBGenericRequest instance. +//------------------------------------------------------------------------------ +#if !defined(NOAUTOCALLBACK) +void USBDCallbacks_RequestReceived(const USBGenericRequest *request) +{ + AUDDLoopRecDriver_RequestHandler(request); +} +#endif + +//------------------------------------------------------------------------------ +/// Invoked whenever the active setting of an interface is changed by the +/// host. Changes the status of the third LED accordingly. +/// \param interface Interface number. +/// \param setting Newly active setting. +//------------------------------------------------------------------------------ +void USBDDriverCallbacks_InterfaceSettingChanged(unsigned char interface, + unsigned char setting) +{ + if ((interface == AUDDLoopRecDriverDescriptors_STREAMING) + && (setting == 0)) { + + LED_Clear(USBD_LEDOTHER); + } + else { + + LED_Set(USBD_LEDOTHER); + } +} + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes an USB audio LoopRec device driver, as well as the underlying +/// USB controller. +//------------------------------------------------------------------------------ +void AUDDLoopRecDriver_Initialize() +{ + // Reset callback function + auddLoopRecDriver.fWrCallback = 0; + + // Initialize LoopRec channels + AUDDLoopRecChannel_Initialize(&(auddLoopRecDriver.channels[0]), + AUDDLoopRecDriver_MASTERCHANNEL, + 0); + AUDDLoopRecChannel_Initialize(&(auddLoopRecDriver.channels[1]), + AUDDLoopRecDriver_LEFTCHANNEL, + 0); + AUDDLoopRecChannel_Initialize(&(auddLoopRecDriver.channels[2]), + AUDDLoopRecDriver_RIGHTCHANNEL, + 0); + AUDDLoopRecChannel_Initialize(&(auddLoopRecDriver.recChannels[0]), + AUDDLoopRecDriver_RECCHANNEL, + 0); + + // Initialize the USB driver + USBDDriver_Initialize(&(auddLoopRecDriver.usbdDriver), + &auddLoopRecDriverDescriptors, + auddLoopRecDriverInterfaces); + USBD_Init(); + + // Initialize the third LED to indicate when the audio interface is active + LED_Configure(USBD_LEDOTHER); +} + +//------------------------------------------------------------------------------ +/// Handles audio-specific USB requests sent by the host, and forwards +/// standard ones to the USB device driver. +/// \param request Pointer to a USBGenericRequest instance. +//------------------------------------------------------------------------------ +void AUDDLoopRecDriver_RequestHandler(const USBGenericRequest *request) +{ + unsigned char entity; + unsigned char interface; + + TRACE_INFO_WP("NewReq "); + + // Check if this is a class request + if (USBGenericRequest_GetType(request) == USBGenericRequest_CLASS) { + + // Check if the request is supported + switch (USBGenericRequest_GetRequest(request)) { + + case AUDGenericRequest_SETCUR: + TRACE_INFO_WP( + "sCur(0x%04X) ", + USBGenericRequest_GetIndex(request)); + + // Check the target interface and entity + entity = AUDGenericRequest_GetEntity(request); + interface = AUDGenericRequest_GetInterface(request); + if (((entity == AUDDLoopRecDriverDescriptors_FEATUREUNIT) + ||(entity == AUDDLoopRecDriverDescriptors_FEATUREUNIT_REC)) + && (interface == AUDDLoopRecDriverDescriptors_CONTROL)) { + + AUDDLoopRecDriver_SetFeatureCurrentValue( + entity, + AUDFeatureUnitRequest_GetChannel(request), + AUDFeatureUnitRequest_GetControl(request), + USBGenericRequest_GetLength(request)); + } + else { + + TRACE_WARNING( + "AUDDLoopRecDriver_RequestHandler: Unsupported entity/interface combination (0x%04X)\n\r", + USBGenericRequest_GetIndex(request)); + USBD_Stall(0); + } + break; + + case AUDGenericRequest_GETCUR: + TRACE_INFO_WP( + "gCur(0x%04X) ", + USBGenericRequest_GetIndex(request)); + + // Check the target interface and entity + entity = AUDGenericRequest_GetEntity(request); + interface = AUDGenericRequest_GetInterface(request); + if (((entity == AUDDLoopRecDriverDescriptors_FEATUREUNIT) + ||(entity == AUDDLoopRecDriverDescriptors_FEATUREUNIT_REC)) + && (interface == AUDDLoopRecDriverDescriptors_CONTROL)) { + + AUDDLoopRecDriver_GetFeatureCurrentValue( + entity, + AUDFeatureUnitRequest_GetChannel(request), + AUDFeatureUnitRequest_GetControl(request), + USBGenericRequest_GetLength(request)); + } + else { + + TRACE_WARNING( + "AUDDLoopRecDriver_RequestHandler: Unsupported entity/interface combination (0x%04X)\n\r", + USBGenericRequest_GetIndex(request)); + USBD_Stall(0); + } + break; + + default: + + TRACE_WARNING( + "AUDDLoopRecDriver_RequestHandler: Unsupported request (%d)\n\r", + USBGenericRequest_GetRequest(request)); + USBD_Stall(0); + } + } + // Check if this is a standard request + else if (USBGenericRequest_GetType(request) == USBGenericRequest_STANDARD) { + + // Forward request to the standard handler + USBDDriver_RequestHandler(&(auddLoopRecDriver.usbdDriver), request); + } + // Unsupported request type + else { + + TRACE_WARNING( + "AUDDLoopRecDriver_RequestHandler: Unsupported request type (%d)\n\r", + USBGenericRequest_GetType(request)); + USBD_Stall(0); + } +} + +//------------------------------------------------------------------------------ +/// Reads incoming audio data sent by the USB host into the provided +/// buffer. When the transfer is complete, an optional callback function is +/// invoked. +/// \param buffer Pointer to the data storage buffer. +/// \param length Size of the buffer in bytes. +/// \param callback Optional callback function. +/// \param argument Optional argument to the callback function. +/// \return USBD_STATUS_SUCCESS if the transfer is started successfully; +/// otherwise an error code. +//------------------------------------------------------------------------------ +unsigned char AUDDLoopRecDriver_Read(void *buffer, + unsigned int length, + TransferCallback callback, + void *argument) +{ + return USBD_Read(AUDDLoopRecDriverDescriptors_DATAOUT, + buffer, + length, + callback, + argument); +} + +//------------------------------------------------------------------------------ +/// Initialize Frame List for sending audio data. +/// \param pMultiBufferList Pointer to the transfer list to initialize. +/// \param pBufferList Pointer list to the buffers used for frames sending. +/// \param listSize Number of frames. +/// \param frameSize Size in number of bytes of each frame. +//------------------------------------------------------------------------------ +void AUDDLoopRecDriver_SetupWriteMbl(void * pMultiBufferList, + unsigned char **pBufferList, + unsigned short listSize, + unsigned short frameSize) +{ + int i; + + SANITY_CHECK(pMultiBufferList && pBufferList && listSize && frameSize); + +#if (defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS)) && defined(DMA) + // Initialize for circled DMA LLI + { + USBDDmaDescriptor * pLl = (USBDDmaDescriptor*)pMultiBufferList; + for (i = 0; ; i ++) { + pLl[i].pDataAddr = pBufferList[i]; + pLl[i].bufferLength = frameSize; + if (i < listSize - 1) { + pLl[i].pNxtDesc = &pLl[i + 1]; + } + else { + pLl[i].pNxtDesc = &pLl[0]; + break; + } + } + } +#else + // Initialize for circled multi-buffer-list + { + USBDTransferBuffer * pMbl = (USBDTransferBuffer*)pMultiBufferList; + for (i = 0; i < listSize; i ++) { + pMbl[i].pBuffer = pBufferList[i]; + pMbl[i].size = frameSize; + pMbl[i].transferred = 0; + pMbl[i].buffered = 0; + pMbl[i].remaining = frameSize; + } + } +#endif +} + +//------------------------------------------------------------------------------ +/// Start sending audio data, through MBL window. +/// When any frame is complete, an optional callback function is invoked, return +/// 1 of the callback cause the frame buffer re-used. +/// If callback not assigned, frames always reused. +/// \param buffer Pointer to the data storage buffer. +/// \param length Size of the buffer in bytes. +/// \param callback Optional callback function. +/// \param argument Optional argument to the callback function. +/// \return USBD_STATUS_SUCCESS if the transfer is started successfully; +/// otherwise an error code. +//------------------------------------------------------------------------------ +unsigned char AUDDLoopRecDriver_Write(void * pMbl, + unsigned short listSize, + AUDDFrameTransferCallback callback, + void * argument) +{ + auddLoopRecDriver.fWrCallback = callback; + return USBD_MblWrite(AUDDLoopRecDriverDescriptors_DATAIN, + pMbl, + listSize, + 1, + 0, + AUDDLoopRecDriver_MblWriteCallback, + argument); +} + +//----------------------------------------------------------------------------- +/// Starts a remote wake-up sequence if the host has explicitely enabled it +/// by sending the appropriate SET_FEATURE request. +//----------------------------------------------------------------------------- +void AUDDLoopRecDriver_RemoteWakeUp(void) +{ + // Remote wake-up has been enabled + if (USBDDriver_IsRemoteWakeUpEnabled(&auddLoopRecDriver.usbdDriver)) { + + USBD_RemoteWakeUp(); + } +} + + diff --git a/usb/device/audio-looprec/AUDDLoopRecDriver.h b/usb/device/audio-looprec/AUDDLoopRecDriver.h new file mode 100644 index 0000000..8db30a1 --- /dev/null +++ b/usb/device/audio-looprec/AUDDLoopRecDriver.h @@ -0,0 +1,163 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !Purpose + + Definition of a USB Audio Loop Record Driver with two playback channels + and one record channel. + + !Usage + + -# Enable and setup USB related pins (see pio & board.h). + -# Configure the USB Audio Loop Record driver using + AUDDLoopRecDriver_Initialize + -# To get %audio stream frames from host, use + AUDDLoopRecDriver_Read + -# To send %audio sampling stream to host, use + AUDDLoopRecDriver_Write + +*/ + +#ifndef AUDDLoopRecDriver_H +#define AUDDLoopRecDriver_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "Audio Loop Record stream information" +/// +/// This page lists codes for USB Audio Loop Record stream information. +/// +/// !Code +/// - AUDDLoopRecDriver_SAMPLERATE +/// - AUDDLoopRecDriver_NUMCHANNELS +/// - AUDDLoopRecDriver_BYTESPERSAMPLE +/// - AUDDLoopRecDriver_BITSPERSAMPLE +/// - AUDDLoopRecDriver_SAMPLESPERFRAME +/// - AUDDLoopRecDriver_BYTESPERFRAME + +#if defined(at91sam7s) || defined(at91sam9xe) + /// Sample rate in Hz. + #define AUDDLoopRecDriver_SAMPLERATE 32000 + /// Number of channels in audio stream. + #define AUDDLoopRecDriver_NUMCHANNELS 1 + /// Number of bytes in one sample. + #define AUDDLoopRecDriver_BYTESPERSAMPLE 2 +#else + /// Sample rate in Hz. + #define AUDDLoopRecDriver_SAMPLERATE 48000 + /// Number of channels in audio stream. + #define AUDDLoopRecDriver_NUMCHANNELS 2 + /// Number of bytes in one sample. + #define AUDDLoopRecDriver_BYTESPERSAMPLE 2 +#endif +/// Number of bits in one sample. +#define AUDDLoopRecDriver_BITSPERSAMPLE (AUDDLoopRecDriver_BYTESPERSAMPLE * 8) +/// Number of bytes in one USB subframe. +#define AUDDLoopRecDriver_BYTESPERSUBFRAME (AUDDLoopRecDriver_NUMCHANNELS * \ + AUDDLoopRecDriver_BYTESPERSAMPLE) +/// Number of samples in one USB frame. +#define AUDDLoopRecDriver_SAMPLESPERFRAME (AUDDLoopRecDriver_SAMPLERATE / 1000 \ + * AUDDLoopRecDriver_NUMCHANNELS) +/// Number of bytes in one USB frame. +#define AUDDLoopRecDriver_BYTESPERFRAME (AUDDLoopRecDriver_SAMPLESPERFRAME * \ + AUDDLoopRecDriver_BYTESPERSAMPLE) +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "Audio Loop Record Channel Numbers" +/// +/// This page lists codes for USB Audio Loop Record channel numbers. +/// +/// !Playback channel numbers +/// - AUDDLoopRecDriver_MASTERCHANNEL +/// - AUDDLoopRecDriver_LEFTCHANNEL +/// - AUDDLoopRecDriver_RIGHTCHANNEL +/// +/// !Record channel number +/// - AUDDLoopRecDriver_RECCHANNEL + +/// Master channel of playback. +#define AUDDLoopRecDriver_MASTERCHANNEL 0 +/// Front left channel of playback. +#define AUDDLoopRecDriver_LEFTCHANNEL 1 +/// Front right channel of playback. +#define AUDDLoopRecDriver_RIGHTCHANNEL 2 +/// Channel of record. +#define AUDDLoopRecDriver_RECCHANNEL 0 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Callback function for audio frames. +/// \param pArg Pointer to transfer arguments. +/// \param status Frame transfer status. +/// \return 1 to continue, 0 to stop frames. +//------------------------------------------------------------------------------ +typedef char (*AUDDFrameTransferCallback)(void* pArg, char status); + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern void AUDDLoopRecDriver_Initialize(); + +extern void AUDDLoopRecDriver_RequestHandler(const USBGenericRequest *request); + +extern unsigned char AUDDLoopRecDriver_Read(void *buffer, + unsigned int length, + TransferCallback callback, + void *argument); + +extern void AUDDLoopRecDriver_SetupWriteMbl(void * pMultiBufferList, + unsigned char **pBufferList, + unsigned short listSize, + unsigned short frameSize); + +extern unsigned char AUDDLoopRecDriver_Write(void * pMbl, + unsigned short listSize, + AUDDFrameTransferCallback callback, + void *argument); + +extern void AUDDLoopRecDriver_RemoteWakeUp(void); + +#endif //#ifndef AUDDLoopRecDriver_H + diff --git a/usb/device/audio-looprec/AUDDLoopRecDriverDescriptors.c b/usb/device/audio-looprec/AUDDLoopRecDriverDescriptors.c new file mode 100644 index 0000000..9f961fd --- /dev/null +++ b/usb/device/audio-looprec/AUDDLoopRecDriverDescriptors.c @@ -0,0 +1,1461 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "AUDDLoopRecDriverDescriptors.h" +#include "AUDDLoopRecDriver.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "Audio Loop Record Device Codes" +/// +/// This page lists the %device IDs and release number of the USB Audio Loop Record +/// %device. +/// +/// !Codes +/// - AUDDLoopRecDriverDescriptors_VENDORID +/// - AUDDLoopRecDriverDescriptors_PRODUCTID +/// - AUDDLoopRecDriverDescriptors_RELEASE + +/// Device vendor ID. +#define AUDDLoopRecDriverDescriptors_VENDORID 0x03EB +/// Device product ID. +#define AUDDLoopRecDriverDescriptors_PRODUCTID 0x6128 +/// Device release number in BCD format. +#define AUDDLoopRecDriverDescriptors_RELEASE 0x0100 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Internal types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Audio control header descriptor with one slave interface. +//------------------------------------------------------------------------------ +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// Header descriptor with 1 interface. +//------------------------------------------------------------------------------ +typedef struct { + + /// Header descriptor. + AUDHeaderDescriptor header; + /// Id of the first grouped interface - Speaker. + unsigned char bInterface0; + /// Id of the second grouped interface - Speakerphone. + unsigned char bInterface1; + +} __attribute__ ((packed)) AUDHeaderDescriptor2; // GCC + +//------------------------------------------------------------------------------ +/// Feature unit descriptor with 3 channel controls (master, right, left). +//------------------------------------------------------------------------------ +typedef struct { + + /// Feature unit descriptor. + AUDFeatureUnitDescriptor feature; + /// Available controls for each channel. + unsigned char bmaControls[3]; + /// Index of a string descriptor for the feature unit. + unsigned char iFeature; + +} __attribute__ ((packed)) AUDFeatureUnitDescriptor3; // GCC + +//------------------------------------------------------------------------------ +/// List of descriptors for detailling the audio control interface of a +/// device using a USB Audio Loop Recorder driver. +//------------------------------------------------------------------------------ +typedef struct { + + /// Header descriptor (with one slave interface). + AUDHeaderDescriptor2 header; + /// Input terminal descriptor. + AUDInputTerminalDescriptor inputLoopRec; + /// Output terminal descriptor. + AUDOutputTerminalDescriptor outputLoopRec; + /// Feature unit descriptor - LoopRec. + AUDFeatureUnitDescriptor3 featureLoopRec; + /// Input terminal descriptor. + AUDInputTerminalDescriptor inputRec; + /// Output terminal descriptor. + AUDOutputTerminalDescriptor outputRec; + /// Feature unit descriptor - LoopRecphone. + AUDFeatureUnitDescriptor3 featureRec; + +} __attribute__ ((packed)) AUDDLoopRecDriverAudioControlDescriptors; // GCC + +//------------------------------------------------------------------------------ +/// Format type I descriptor with one discrete sampling frequency. +//------------------------------------------------------------------------------ +typedef struct { + + /// Format type I descriptor. + AUDFormatTypeOneDescriptor formatType; + /// Sampling frequency in Hz. + unsigned char tSamFreq[3]; + +} __attribute__ ((packed)) AUDFormatTypeOneDescriptor1; // GCC + +//------------------------------------------------------------------------------ +/// Holds a list of descriptors returned as part of the configuration of +/// a USB Audio Loop Record device. +//------------------------------------------------------------------------------ +typedef struct { + + /// Standard configuration. + USBConfigurationDescriptor configuration; + /// Audio control interface. + USBInterfaceDescriptor control; + /// Descriptors for the audio control interface. + AUDDLoopRecDriverAudioControlDescriptors controlDescriptors; + //- AUDIO OUT + /// Streaming out interface descriptor (with no endpoint, required). + USBInterfaceDescriptor streamingOutNoIsochronous; + /// Streaming out interface descriptor. + USBInterfaceDescriptor streamingOut; + /// Audio class descriptor for the streaming out interface. + AUDStreamingInterfaceDescriptor streamingOutClass; + /// Stream format descriptor. + AUDFormatTypeOneDescriptor1 streamingOutFormatType; + /// Streaming out endpoint descriptor. + AUDEndpointDescriptor streamingOutEndpoint; + /// Audio class descriptor for the streaming out endpoint. + AUDDataEndpointDescriptor streamingOutDataEndpoint; + //- AUDIO IN + /// Streaming in interface descriptor (with no endpoint, required). + USBInterfaceDescriptor streamingInNoIsochronous; + /// Streaming in interface descriptor. + USBInterfaceDescriptor streamingIn; + /// Audio class descriptor for the streaming in interface. + AUDStreamingInterfaceDescriptor streamingInClass; + /// Stream format descriptor. + AUDFormatTypeOneDescriptor1 streamingInFormatType; + /// Streaming in endpoint descriptor. + AUDEndpointDescriptor streamingInEndpoint; + /// Audio class descriptor for the streaming in endpoint. + AUDDataEndpointDescriptor streamingInDataEndpoint; + +} __attribute__ ((packed)) AUDDLoopRecDriverConfigurationDescriptors; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +/// Device descriptor for a USB Audio Loop Record driver. +const USBDeviceDescriptor deviceDescriptor = { + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + AUDDeviceDescriptor_CLASS, + AUDDeviceDescriptor_SUBCLASS, + AUDDeviceDescriptor_PROTOCOL, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + AUDDLoopRecDriverDescriptors_VENDORID, + AUDDLoopRecDriverDescriptors_PRODUCTID, + AUDDLoopRecDriverDescriptors_RELEASE, + 1, // Manufacturer string descriptor index + 2, // Product string descriptor index + 3, // Index of serial number string descriptor + 1 // One possible configuration +}; + +#if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + +/// USB device qualifier descriptor. +const USBDeviceQualifierDescriptor qualifierDescriptor = { + + sizeof(USBDeviceQualifierDescriptor), + USBGenericDescriptor_DEVICEQUALIFIER, + USBDeviceDescriptor_USB2_00, + AUDDeviceDescriptor_CLASS, + AUDDeviceDescriptor_SUBCLASS, + AUDDeviceDescriptor_PROTOCOL, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + 1, // Device has one possible configuration + 0 // Reserved +}; + +/// HS Configuration descriptors for a USB Audio Loop Record driver. +const AUDDLoopRecDriverConfigurationDescriptors hsConfigurationDescriptors = { + + // Configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(AUDDLoopRecDriverConfigurationDescriptors), + 3, // This configuration has 3 interfaces + 1, // This is configuration #1 + 0, // No string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + // Audio control interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_CONTROL, + 0, // This is alternate setting #0 + 0, // This interface uses no endpoint + AUDControlInterfaceDescriptor_CLASS, + AUDControlInterfaceDescriptor_SUBCLASS, + AUDControlInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio control interface descriptors + { + // Header descriptor + { + { + sizeof(AUDHeaderDescriptor2), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_HEADER, + AUDHeaderDescriptor_AUD1_00, + sizeof(AUDDLoopRecDriverAudioControlDescriptors), + 2 // Two streaming interface + }, + AUDDLoopRecDriverDescriptors_STREAMING, + AUDDLoopRecDriverDescriptors_STREAMINGIN + }, + // Input terminal descriptor ( speaker ) + { + sizeof(AUDInputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_INPUTTERMINAL, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL, + AUDInputTerminalDescriptor_USBSTREAMING, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL, + AUDDLoopRecDriver_NUMCHANNELS, + #if AUDDLoopRecDriver_NUMCHANNELS > 1 + AUDInputTerminalDescriptor_LEFTFRONT + | AUDInputTerminalDescriptor_RIGHTFRONT, + #else + 0, // Mono sets no position bits. + #endif + 0, // No string descriptor for channels + 0 // No string descriptor for input terminal + }, + // Output terminal descriptor ( speaker ) + { + sizeof(AUDOutputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_OUTPUTTERMINAL, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL, + AUDOutputTerminalDescriptor_SPEAKER, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL, + AUDDLoopRecDriverDescriptors_FEATUREUNIT, + 0 // No string descriptor + }, + // Feature unit descriptor ( speaker ) + { + { + sizeof(AUDFeatureUnitDescriptor3), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_FEATUREUNIT, + AUDDLoopRecDriverDescriptors_FEATUREUNIT, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL, + 1, // 1 byte per channel for controls + }, + { + AUDFeatureUnitDescriptor_MUTE, // Master channel controls + 0, // Right channel controls + 0 // Left channel controls + }, + 0 // No string descriptor + }, + // Input terminal descriptor ( speakerphone ) + { + sizeof(AUDInputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_INPUTTERMINAL, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL_REC, + AUDInputTerminalDescriptor_SPEAKERPHONE, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL_REC, + AUDDLoopRecDriver_NUMCHANNELS, + #if AUDDLoopRecDriver_NUMCHANNELS > 1 + AUDInputTerminalDescriptor_LEFTFRONT + | AUDInputTerminalDescriptor_RIGHTFRONT, + #else + 0, // Mono sets no position bits. + #endif + 0, // No string descriptor for channels + 0 // No string descriptor for input terminal + }, + // Output terminal descriptor ( speakerphone ) + { + sizeof(AUDOutputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_OUTPUTTERMINAL, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL_REC, + AUDOutputTerminalDescriptor_USBTREAMING, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL_REC, + AUDDLoopRecDriverDescriptors_FEATUREUNIT_REC, + 0 // No string descriptor + }, + // Feature unit descriptor ( speakerphone ) + { + { + sizeof(AUDFeatureUnitDescriptor3), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_FEATUREUNIT, + AUDDLoopRecDriverDescriptors_FEATUREUNIT_REC, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL_REC, + 1 + }, + { + AUDFeatureUnitDescriptor_MUTE, // Mic controls + 0, + 0 + }, + 0 // No string descriptor + } + }, + // - AUIDO OUT + // Audio streaming interface with 0 endpoints + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_STREAMING, + 0, // This is alternate setting #0 + 0, // This interface uses no endpoints + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming interface with data endpoint + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_STREAMING, + 1, // This is alternate setting #1 + 1, // This interface uses 1 endpoint + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming class-specific descriptor + { + sizeof(AUDStreamingInterfaceDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_GENERAL, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL, + 0, // No internal delay because of data path + AUDFormatTypeOneDescriptor_PCM + }, + // Format type I descriptor + { + { + sizeof(AUDFormatTypeOneDescriptor1), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_FORMATTYPE, + AUDFormatTypeOneDescriptor_FORMATTYPEONE, + AUDDLoopRecDriver_NUMCHANNELS, + AUDDLoopRecDriver_BYTESPERSAMPLE, + AUDDLoopRecDriver_BYTESPERSAMPLE*8, + 1 // One discrete frequency supported + }, + { + AUDDLoopRecDriver_SAMPLERATE & 0xFF, + (AUDDLoopRecDriver_SAMPLERATE >> 8) & 0xFF, + (AUDDLoopRecDriver_SAMPLERATE >> 16) & 0xFF + } + }, + // Audio streaming endpoint standard descriptor + { + sizeof(AUDEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + AUDDLoopRecDriverDescriptors_DATAOUT), + USBEndpointDescriptor_ISOCHRONOUS, + AUDDLoopRecDriver_BYTESPERFRAME, + AUDDLoopRecDriverDescriptors_HS_INTERVAL, // Polling interval = 1 ms + 0, // This is not a synchronization endpoint + 0 // No associated synchronization endpoint + }, + // Audio streaming endpoint class-specific descriptor + { + sizeof(AUDDataEndpointDescriptor), + AUDGenericDescriptor_ENDPOINT, + AUDDataEndpointDescriptor_SUBTYPE, + 0, // No attributes + 0, // Endpoint is not synchronized + 0 // Endpoint is not synchronized + }, + //- AUDIO IN + // Audio streaming interface with 0 endpoints + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_STREAMINGIN, + 0, // This is alternate setting #0 + 0, // This interface uses no endpoints + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming interface with data endpoint + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_STREAMINGIN, + 1, // This is alternate setting #1 + 1, // This interface uses 1 endpoint + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming class-specific descriptor + { + sizeof(AUDStreamingInterfaceDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_GENERAL, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL_REC, + 0, // No internal delay because of data path + AUDFormatTypeOneDescriptor_PCM + }, + // Format type I descriptor + { + { + sizeof(AUDFormatTypeOneDescriptor1), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_FORMATTYPE, + AUDFormatTypeOneDescriptor_FORMATTYPEONE, + AUDDLoopRecDriver_NUMCHANNELS, + AUDDLoopRecDriver_BYTESPERSAMPLE, + AUDDLoopRecDriver_BYTESPERSAMPLE*8, + 1 // One discrete frequency supported + }, + { + AUDDLoopRecDriver_SAMPLERATE & 0xFF, + (AUDDLoopRecDriver_SAMPLERATE >> 8) & 0xFF, + (AUDDLoopRecDriver_SAMPLERATE >> 16) & 0xFF + } + }, + // Audio streaming endpoint standard descriptor + { + sizeof(AUDEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + AUDDLoopRecDriverDescriptors_DATAIN), + USBEndpointDescriptor_ISOCHRONOUS, + AUDDLoopRecDriver_BYTESPERFRAME, + AUDDLoopRecDriverDescriptors_HS_INTERVAL, // Polling interval = 1 ms + 0, // This is not a synchronization endpoint + 0 // No associated synchronization endpoint + }, + // Audio streaming endpoint class-specific descriptor + { + sizeof(AUDDataEndpointDescriptor), + AUDGenericDescriptor_ENDPOINT, + AUDDataEndpointDescriptor_SUBTYPE, + 0, // No attributes + 0, // Endpoint is not synchronized + 0 // Endpoint is not synchronized + } +}; + +/// HS Other Speed Configuration descriptors for a USB Audio Loop Record driver. +const AUDDLoopRecDriverConfigurationDescriptors + fsOtherSpeedConfigurationDescriptors = { + + // Configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_OTHERSPEEDCONFIGURATION, + sizeof(AUDDLoopRecDriverConfigurationDescriptors), + 3, // This configuration has 3 interfaces + 1, // This is configuration #1 + 0, // No string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + // Audio control interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_CONTROL, + 0, // This is alternate setting #0 + 0, // This interface uses no endpoint + AUDControlInterfaceDescriptor_CLASS, + AUDControlInterfaceDescriptor_SUBCLASS, + AUDControlInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio control interface descriptors + { + // Header descriptor + { + { + sizeof(AUDHeaderDescriptor2), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_HEADER, + AUDHeaderDescriptor_AUD1_00, + sizeof(AUDDLoopRecDriverAudioControlDescriptors), + 2 // Two streaming interface + }, + AUDDLoopRecDriverDescriptors_STREAMING, + AUDDLoopRecDriverDescriptors_STREAMINGIN + }, + // Input terminal descriptor ( speaker ) + { + sizeof(AUDInputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_INPUTTERMINAL, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL, + AUDInputTerminalDescriptor_USBSTREAMING, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL, + AUDDLoopRecDriver_NUMCHANNELS, + #if AUDDLoopRecDriver_NUMCHANNELS > 1 + AUDInputTerminalDescriptor_LEFTFRONT + | AUDInputTerminalDescriptor_RIGHTFRONT, + #else + 0, // Mono sets no position bits. + #endif + 0, // No string descriptor for channels + 0 // No string descriptor for input terminal + }, + // Output terminal descriptor ( speaker ) + { + sizeof(AUDOutputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_OUTPUTTERMINAL, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL, + AUDOutputTerminalDescriptor_SPEAKER, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL, + AUDDLoopRecDriverDescriptors_FEATUREUNIT, + 0 // No string descriptor + }, + // Feature unit descriptor ( speaker ) + { + { + sizeof(AUDFeatureUnitDescriptor3), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_FEATUREUNIT, + AUDDLoopRecDriverDescriptors_FEATUREUNIT, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL, + 1, // 1 byte per channel for controls + }, + { + AUDFeatureUnitDescriptor_MUTE, // Master channel controls + 0, // Right channel controls + 0 // Left channel controls + }, + 0 // No string descriptor + }, + // Input terminal descriptor ( speakerphone ) + { + sizeof(AUDInputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_INPUTTERMINAL, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL_REC, + AUDInputTerminalDescriptor_SPEAKERPHONE, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL_REC, + AUDDLoopRecDriver_NUMCHANNELS, + #if AUDDLoopRecDriver_NUMCHANNELS > 1 + AUDInputTerminalDescriptor_LEFTFRONT + | AUDInputTerminalDescriptor_RIGHTFRONT, + #else + 0, // Mono sets no position bits. + #endif + 0, // No string descriptor for channels + 0 // No string descriptor for input terminal + }, + // Output terminal descriptor ( speakerphone ) + { + sizeof(AUDOutputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_OUTPUTTERMINAL, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL_REC, + AUDOutputTerminalDescriptor_USBTREAMING, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL_REC, + AUDDLoopRecDriverDescriptors_FEATUREUNIT_REC, + 0 // No string descriptor + }, + // Feature unit descriptor ( speakerphone ) + { + { + sizeof(AUDFeatureUnitDescriptor3), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_FEATUREUNIT, + AUDDLoopRecDriverDescriptors_FEATUREUNIT_REC, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL_REC, + 1 + }, + { + AUDFeatureUnitDescriptor_MUTE, // Mic controls + 0, + 0 + }, + 0 // No string descriptor + } + }, + // - AUIDO OUT + // Audio streaming interface with 0 endpoints + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_STREAMING, + 0, // This is alternate setting #0 + 0, // This interface uses no endpoints + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming interface with data endpoint + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_STREAMING, + 1, // This is alternate setting #1 + 1, // This interface uses 1 endpoint + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming class-specific descriptor + { + sizeof(AUDStreamingInterfaceDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_GENERAL, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL, + 0, // No internal delay because of data path + AUDFormatTypeOneDescriptor_PCM + }, + // Format type I descriptor + { + { + sizeof(AUDFormatTypeOneDescriptor1), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_FORMATTYPE, + AUDFormatTypeOneDescriptor_FORMATTYPEONE, + AUDDLoopRecDriver_NUMCHANNELS, + AUDDLoopRecDriver_BYTESPERSAMPLE, + AUDDLoopRecDriver_BYTESPERSAMPLE*8, + 1 // One discrete frequency supported + }, + { + AUDDLoopRecDriver_SAMPLERATE & 0xFF, + (AUDDLoopRecDriver_SAMPLERATE >> 8) & 0xFF, + (AUDDLoopRecDriver_SAMPLERATE >> 16) & 0xFF + } + }, + // Audio streaming endpoint standard descriptor + { + sizeof(AUDEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + AUDDLoopRecDriverDescriptors_DATAOUT), + USBEndpointDescriptor_ISOCHRONOUS, + AUDDLoopRecDriver_BYTESPERFRAME, + AUDDLoopRecDriverDescriptors_HS_INTERVAL, // Polling interval = 1 ms + 0, // This is not a synchronization endpoint + 0 // No associated synchronization endpoint + }, + // Audio streaming endpoint class-specific descriptor + { + sizeof(AUDDataEndpointDescriptor), + AUDGenericDescriptor_ENDPOINT, + AUDDataEndpointDescriptor_SUBTYPE, + 0, // No attributes + 0, // Endpoint is not synchronized + 0 // Endpoint is not synchronized + }, + //- AUDIO IN + // Audio streaming interface with 0 endpoints + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_STREAMINGIN, + 0, // This is alternate setting #0 + 0, // This interface uses no endpoints + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming interface with data endpoint + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_STREAMINGIN, + 1, // This is alternate setting #1 + 1, // This interface uses 1 endpoint + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming class-specific descriptor + { + sizeof(AUDStreamingInterfaceDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_GENERAL, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL_REC, + 0, // No internal delay because of data path + AUDFormatTypeOneDescriptor_PCM + }, + // Format type I descriptor + { + { + sizeof(AUDFormatTypeOneDescriptor1), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_FORMATTYPE, + AUDFormatTypeOneDescriptor_FORMATTYPEONE, + AUDDLoopRecDriver_NUMCHANNELS, + AUDDLoopRecDriver_BYTESPERSAMPLE, + AUDDLoopRecDriver_BYTESPERSAMPLE*8, + 1 // One discrete frequency supported + }, + { + AUDDLoopRecDriver_SAMPLERATE & 0xFF, + (AUDDLoopRecDriver_SAMPLERATE >> 8) & 0xFF, + (AUDDLoopRecDriver_SAMPLERATE >> 16) & 0xFF + } + }, + // Audio streaming endpoint standard descriptor + { + sizeof(AUDEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + AUDDLoopRecDriverDescriptors_DATAIN), + USBEndpointDescriptor_ISOCHRONOUS, + AUDDLoopRecDriver_BYTESPERFRAME, + AUDDLoopRecDriverDescriptors_HS_INTERVAL, // Polling interval = 1 ms + 0, // This is not a synchronization endpoint + 0 // No associated synchronization endpoint + }, + // Audio streaming endpoint class-specific descriptor + { + sizeof(AUDDataEndpointDescriptor), + AUDGenericDescriptor_ENDPOINT, + AUDDataEndpointDescriptor_SUBTYPE, + 0, // No attributes + 0, // Endpoint is not synchronized + 0 // Endpoint is not synchronized + } +}; + +/// HS Other Speed Configuration descriptors. +const AUDDLoopRecDriverConfigurationDescriptors + hsOtherSpeedConfigurationDescriptors = { + + // Configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_OTHERSPEEDCONFIGURATION, + sizeof(AUDDLoopRecDriverConfigurationDescriptors), + 3, // This configuration has 3 interfaces + 1, // This is configuration #1 + 0, // No string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + // Audio control interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_CONTROL, + 0, // This is alternate setting #0 + 0, // This interface uses no endpoint + AUDControlInterfaceDescriptor_CLASS, + AUDControlInterfaceDescriptor_SUBCLASS, + AUDControlInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio control interface descriptors + { + // Header descriptor + { + { + sizeof(AUDHeaderDescriptor2), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_HEADER, + AUDHeaderDescriptor_AUD1_00, + sizeof(AUDDLoopRecDriverAudioControlDescriptors), + 2 // Two streaming interface + }, + AUDDLoopRecDriverDescriptors_STREAMING, + AUDDLoopRecDriverDescriptors_STREAMINGIN + }, + // Input terminal descriptor ( speaker ) + { + sizeof(AUDInputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_INPUTTERMINAL, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL, + AUDInputTerminalDescriptor_USBSTREAMING, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL, + AUDDLoopRecDriver_NUMCHANNELS, + #if AUDDLoopRecDriver_NUMCHANNELS > 1 + AUDInputTerminalDescriptor_LEFTFRONT + | AUDInputTerminalDescriptor_RIGHTFRONT, + #else + 0, // Mono sets no position bits. + #endif + 0, // No string descriptor for channels + 0 // No string descriptor for input terminal + }, + // Output terminal descriptor ( speaker ) + { + sizeof(AUDOutputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_OUTPUTTERMINAL, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL, + AUDOutputTerminalDescriptor_SPEAKER, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL, + AUDDLoopRecDriverDescriptors_FEATUREUNIT, + 0 // No string descriptor + }, + // Feature unit descriptor ( speaker ) + { + { + sizeof(AUDFeatureUnitDescriptor3), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_FEATUREUNIT, + AUDDLoopRecDriverDescriptors_FEATUREUNIT, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL, + 1, // 1 byte per channel for controls + }, + { + AUDFeatureUnitDescriptor_MUTE, // Master channel controls + 0, // Right channel controls + 0 // Left channel controls + }, + 0 // No string descriptor + }, + // Input terminal descriptor ( speakerphone ) + { + sizeof(AUDInputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_INPUTTERMINAL, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL_REC, + AUDInputTerminalDescriptor_SPEAKERPHONE, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL_REC, + AUDDLoopRecDriver_NUMCHANNELS, + #if AUDDLoopRecDriver_NUMCHANNELS > 1 + AUDInputTerminalDescriptor_LEFTFRONT + | AUDInputTerminalDescriptor_RIGHTFRONT, + #else + 0, // Mono sets no position bits. + #endif + 0, // No string descriptor for channels + 0 // No string descriptor for input terminal + }, + // Output terminal descriptor ( speakerphone ) + { + sizeof(AUDOutputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_OUTPUTTERMINAL, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL_REC, + AUDOutputTerminalDescriptor_USBTREAMING, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL_REC, + AUDDLoopRecDriverDescriptors_FEATUREUNIT_REC, + 0 // No string descriptor + }, + // Feature unit descriptor ( speakerphone ) + { + { + sizeof(AUDFeatureUnitDescriptor3), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_FEATUREUNIT, + AUDDLoopRecDriverDescriptors_FEATUREUNIT_REC, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL_REC, + 1 + }, + { + AUDFeatureUnitDescriptor_MUTE, // Mic controls + 0, + 0 + }, + 0 // No string descriptor + } + }, + // - AUIDO OUT + // Audio streaming interface with 0 endpoints + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_STREAMING, + 0, // This is alternate setting #0 + 0, // This interface uses no endpoints + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming interface with data endpoint + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_STREAMING, + 1, // This is alternate setting #1 + 1, // This interface uses 1 endpoint + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming class-specific descriptor + { + sizeof(AUDStreamingInterfaceDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_GENERAL, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL, + 0, // No internal delay because of data path + AUDFormatTypeOneDescriptor_PCM + }, + // Format type I descriptor + { + { + sizeof(AUDFormatTypeOneDescriptor1), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_FORMATTYPE, + AUDFormatTypeOneDescriptor_FORMATTYPEONE, + AUDDLoopRecDriver_NUMCHANNELS, + AUDDLoopRecDriver_BYTESPERSAMPLE, + AUDDLoopRecDriver_BYTESPERSAMPLE*8, + 1 // One discrete frequency supported + }, + { + AUDDLoopRecDriver_SAMPLERATE & 0xFF, + (AUDDLoopRecDriver_SAMPLERATE >> 8) & 0xFF, + (AUDDLoopRecDriver_SAMPLERATE >> 16) & 0xFF + } + }, + // Audio streaming endpoint standard descriptor + { + sizeof(AUDEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + AUDDLoopRecDriverDescriptors_DATAOUT), + USBEndpointDescriptor_ISOCHRONOUS, + AUDDLoopRecDriver_BYTESPERFRAME, + AUDDLoopRecDriverDescriptors_FS_INTERVAL, // Polling interval = 1 ms + 0, // This is not a synchronization endpoint + 0 // No associated synchronization endpoint + }, + // Audio streaming endpoint class-specific descriptor + { + sizeof(AUDDataEndpointDescriptor), + AUDGenericDescriptor_ENDPOINT, + AUDDataEndpointDescriptor_SUBTYPE, + 0, // No attributes + 0, // Endpoint is not synchronized + 0 // Endpoint is not synchronized + }, + //- AUDIO IN + // Audio streaming interface with 0 endpoints + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_STREAMINGIN, + 0, // This is alternate setting #0 + 0, // This interface uses no endpoints + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming interface with data endpoint + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_STREAMINGIN, + 1, // This is alternate setting #1 + 1, // This interface uses 1 endpoint + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming class-specific descriptor + { + sizeof(AUDStreamingInterfaceDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_GENERAL, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL_REC, + 0, // No internal delay because of data path + AUDFormatTypeOneDescriptor_PCM + }, + // Format type I descriptor + { + { + sizeof(AUDFormatTypeOneDescriptor1), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_FORMATTYPE, + AUDFormatTypeOneDescriptor_FORMATTYPEONE, + AUDDLoopRecDriver_NUMCHANNELS, + AUDDLoopRecDriver_BYTESPERSAMPLE, + AUDDLoopRecDriver_BYTESPERSAMPLE*8, + 1 // One discrete frequency supported + }, + { + AUDDLoopRecDriver_SAMPLERATE & 0xFF, + (AUDDLoopRecDriver_SAMPLERATE >> 8) & 0xFF, + (AUDDLoopRecDriver_SAMPLERATE >> 16) & 0xFF + } + }, + // Audio streaming endpoint standard descriptor + { + sizeof(AUDEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + AUDDLoopRecDriverDescriptors_DATAIN), + USBEndpointDescriptor_ISOCHRONOUS, + AUDDLoopRecDriver_BYTESPERFRAME, + AUDDLoopRecDriverDescriptors_FS_INTERVAL, // Polling interval = 1 ms + 0, // This is not a synchronization endpoint + 0 // No associated synchronization endpoint + }, + // Audio streaming endpoint class-specific descriptor + { + sizeof(AUDDataEndpointDescriptor), + AUDGenericDescriptor_ENDPOINT, + AUDDataEndpointDescriptor_SUBTYPE, + 0, // No attributes + 0, // Endpoint is not synchronized + 0 // Endpoint is not synchronized + } +}; + +#endif // defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + +/// FS Configuration descriptors for a USB Audio Loop Record driver. +const AUDDLoopRecDriverConfigurationDescriptors fsConfigurationDescriptors = { + + // Configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(AUDDLoopRecDriverConfigurationDescriptors), + 3, // This configuration has 3 interfaces + 1, // This is configuration #1 + 0, // No string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + // Audio control interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_CONTROL, + 0, // This is alternate setting #0 + 0, // This interface uses no endpoint + AUDControlInterfaceDescriptor_CLASS, + AUDControlInterfaceDescriptor_SUBCLASS, + AUDControlInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio control interface descriptors + { + // Header descriptor + { + { + sizeof(AUDHeaderDescriptor2), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_HEADER, + AUDHeaderDescriptor_AUD1_00, + sizeof(AUDDLoopRecDriverAudioControlDescriptors), + 2 // Two streaming interface + }, + AUDDLoopRecDriverDescriptors_STREAMING, + AUDDLoopRecDriverDescriptors_STREAMINGIN + }, + // Input terminal descriptor ( speaker ) + { + sizeof(AUDInputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_INPUTTERMINAL, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL, + AUDInputTerminalDescriptor_USBSTREAMING, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL, + AUDDLoopRecDriver_NUMCHANNELS, + #if AUDDLoopRecDriver_NUMCHANNELS > 1 + AUDInputTerminalDescriptor_LEFTFRONT + | AUDInputTerminalDescriptor_RIGHTFRONT, + #else + 0, // Mono sets no position bits. + #endif + 0, // No string descriptor for channels + 0 // No string descriptor for input terminal + }, + // Output terminal descriptor ( speaker ) + { + sizeof(AUDOutputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_OUTPUTTERMINAL, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL, + AUDOutputTerminalDescriptor_SPEAKER, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL, + AUDDLoopRecDriverDescriptors_FEATUREUNIT, + 0 // No string descriptor + }, + // Feature unit descriptor ( speaker ) + { + { + sizeof(AUDFeatureUnitDescriptor3), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_FEATUREUNIT, + AUDDLoopRecDriverDescriptors_FEATUREUNIT, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL, + 1, // 1 byte per channel for controls + }, + { + AUDFeatureUnitDescriptor_MUTE, // Master channel controls + 0, // Right channel controls + 0 // Left channel controls + }, + 0 // No string descriptor + }, + // Input terminal descriptor ( speakerphone ) + { + sizeof(AUDInputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_INPUTTERMINAL, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL_REC, + AUDInputTerminalDescriptor_SPEAKERPHONE, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL_REC, + AUDDLoopRecDriver_NUMCHANNELS, + #if AUDDLoopRecDriver_NUMCHANNELS > 1 + AUDInputTerminalDescriptor_LEFTFRONT + | AUDInputTerminalDescriptor_RIGHTFRONT, + #else + 0, // Mono sets no position bits. + #endif + 0, // No string descriptor for channels + 0 // No string descriptor for input terminal + }, + // Output terminal descriptor ( speakerphone ) + { + sizeof(AUDOutputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_OUTPUTTERMINAL, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL_REC, + AUDOutputTerminalDescriptor_USBTREAMING, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL_REC, + AUDDLoopRecDriverDescriptors_FEATUREUNIT_REC, + 0 // No string descriptor + }, + // Feature unit descriptor ( speakerphone ) + { + { + sizeof(AUDFeatureUnitDescriptor3), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_FEATUREUNIT, + AUDDLoopRecDriverDescriptors_FEATUREUNIT_REC, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL_REC, + 1 + }, + { + AUDFeatureUnitDescriptor_MUTE, // Mic controls + 0, + 0 + }, + 0 // No string descriptor + } + }, + // - AUIDO OUT + // Audio streaming interface with 0 endpoints + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_STREAMING, + 0, // This is alternate setting #0 + 0, // This interface uses no endpoints + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming interface with data endpoint + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_STREAMING, + 1, // This is alternate setting #1 + 1, // This interface uses 1 endpoint + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming class-specific descriptor + { + sizeof(AUDStreamingInterfaceDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_GENERAL, + AUDDLoopRecDriverDescriptors_INPUTTERMINAL, + 0, // No internal delay because of data path + AUDFormatTypeOneDescriptor_PCM + }, + // Format type I descriptor + { + { + sizeof(AUDFormatTypeOneDescriptor1), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_FORMATTYPE, + AUDFormatTypeOneDescriptor_FORMATTYPEONE, + AUDDLoopRecDriver_NUMCHANNELS, + AUDDLoopRecDriver_BYTESPERSAMPLE, + AUDDLoopRecDriver_BYTESPERSAMPLE*8, + 1 // One discrete frequency supported + }, + { + AUDDLoopRecDriver_SAMPLERATE & 0xFF, + (AUDDLoopRecDriver_SAMPLERATE >> 8) & 0xFF, + (AUDDLoopRecDriver_SAMPLERATE >> 16) & 0xFF + } + }, + // Audio streaming endpoint standard descriptor + { + sizeof(AUDEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + AUDDLoopRecDriverDescriptors_DATAOUT), + USBEndpointDescriptor_ISOCHRONOUS, + AUDDLoopRecDriver_BYTESPERFRAME, + AUDDLoopRecDriverDescriptors_FS_INTERVAL, // Polling interval = 1 ms + 0, // This is not a synchronization endpoint + 0 // No associated synchronization endpoint + }, + // Audio streaming endpoint class-specific descriptor + { + sizeof(AUDDataEndpointDescriptor), + AUDGenericDescriptor_ENDPOINT, + AUDDataEndpointDescriptor_SUBTYPE, + 0, // No attributes + 0, // Endpoint is not synchronized + 0 // Endpoint is not synchronized + }, + //- AUDIO IN + // Audio streaming interface with 0 endpoints + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_STREAMINGIN, + 0, // This is alternate setting #0 + 0, // This interface uses no endpoints + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming interface with data endpoint + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDLoopRecDriverDescriptors_STREAMINGIN, + 1, // This is alternate setting #1 + 1, // This interface uses 1 endpoint + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming class-specific descriptor + { + sizeof(AUDStreamingInterfaceDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_GENERAL, + AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL_REC, + 0, // No internal delay because of data path + AUDFormatTypeOneDescriptor_PCM + }, + // Format type I descriptor + { + { + sizeof(AUDFormatTypeOneDescriptor1), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_FORMATTYPE, + AUDFormatTypeOneDescriptor_FORMATTYPEONE, + AUDDLoopRecDriver_NUMCHANNELS, + AUDDLoopRecDriver_BYTESPERSAMPLE, + AUDDLoopRecDriver_BYTESPERSAMPLE*8, + 1 // One discrete frequency supported + }, + { + AUDDLoopRecDriver_SAMPLERATE & 0xFF, + (AUDDLoopRecDriver_SAMPLERATE >> 8) & 0xFF, + (AUDDLoopRecDriver_SAMPLERATE >> 16) & 0xFF + } + }, + // Audio streaming endpoint standard descriptor + { + sizeof(AUDEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + AUDDLoopRecDriverDescriptors_DATAIN), + USBEndpointDescriptor_ISOCHRONOUS, + AUDDLoopRecDriver_BYTESPERFRAME, + AUDDLoopRecDriverDescriptors_FS_INTERVAL, // Polling interval = 1 ms + 0, // This is not a synchronization endpoint + 0 // No associated synchronization endpoint + }, + // Audio streaming endpoint class-specific descriptor + { + sizeof(AUDDataEndpointDescriptor), + AUDGenericDescriptor_ENDPOINT, + AUDDataEndpointDescriptor_SUBTYPE, + 0, // No attributes + 0, // Endpoint is not synchronized + 0 // Endpoint is not synchronized + } +}; + +/// String descriptor with the supported languages. +const unsigned char languageIdDescriptor[] = { + + USBStringDescriptor_LENGTH(1), + USBGenericDescriptor_STRING, + USBStringDescriptor_ENGLISH_US +}; + +/// Manufacturer name. +const unsigned char manufacturerDescriptor[] = { + + USBStringDescriptor_LENGTH(5), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('t'), + USBStringDescriptor_UNICODE('m'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('l') +}; + +/// Product name. +const unsigned char productDescriptor[] = { + + USBStringDescriptor_LENGTH(15), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('D'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('s'), + USBStringDescriptor_UNICODE('k'), + USBStringDescriptor_UNICODE('t'), + USBStringDescriptor_UNICODE('o'), + USBStringDescriptor_UNICODE('p'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('s'), + USBStringDescriptor_UNICODE('p'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('a'), + USBStringDescriptor_UNICODE('k'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('r') +}; + +/// Product serial number. +const unsigned char serialNumberDescriptor[] = { + + USBStringDescriptor_LENGTH(4), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('0'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE('2'), + USBStringDescriptor_UNICODE('3') +}; + +/// Array of pointers to the four string descriptors. +const unsigned char *stringDescriptors[] = { + + languageIdDescriptor, + manufacturerDescriptor, + productDescriptor, + serialNumberDescriptor, +}; + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +/// List of descriptors required by an USB Audio Loop Recorder device driver. +const USBDDriverDescriptors auddLoopRecDriverDescriptors = { + + &deviceDescriptor, + (const USBConfigurationDescriptor *) &fsConfigurationDescriptors, +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + &qualifierDescriptor, + (const USBConfigurationDescriptor *) &fsOtherSpeedConfigurationDescriptors, + &deviceDescriptor, + (const USBConfigurationDescriptor *) &hsConfigurationDescriptors, + &qualifierDescriptor, + (const USBConfigurationDescriptor *) &hsOtherSpeedConfigurationDescriptors, +#else + 0, 0, 0, 0, 0, 0, +#endif + stringDescriptors, + 4 // Number of string descriptors +}; + diff --git a/usb/device/audio-looprec/AUDDLoopRecDriverDescriptors.h b/usb/device/audio-looprec/AUDDLoopRecDriverDescriptors.h new file mode 100644 index 0000000..4b333d7 --- /dev/null +++ b/usb/device/audio-looprec/AUDDLoopRecDriverDescriptors.h @@ -0,0 +1,148 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Declaration of the descriptors required by a USB audio speaker driver. + + !!!Usage + + -# Initialize a USBDDriver instance using the + auddSpeakerDriverDescriptors list. +*/ + +#ifndef AUDDLOOPRECDESCRIPTORS_H +#define AUDDLOOPRECDESCRIPTORS_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "Audio Speaker Endpoint Numbers" +/// +/// This page lists the endpoint number settings for USB Audio Speaker device. +/// +/// !Endpoints +/// - AUDDLoopRecDriverDescriptors_DATAOUT +/// - AUDDLoopRecDriverDescriptors_DATAIN +/// - AUDDLoopRecDriverDescriptors_HS_INTERVAL +/// - AUDDLoopRecDriverDescriptors_FS_INTERVAL + +#if defined(at91sam7s) || defined(at91sam9xe) + /// Data out endpoint number, size 64B. + #define AUDDLoopRecDriverDescriptors_DATAOUT 0x01 + /// Data in endpoint number, size 64B + #define AUDDLoopRecDriverDescriptors_DATAIN 0x02 +#elif defined(CHIP_USB_UDP) + /// Data out endpoint number, size 192B. + #define AUDDLoopRecDriverDescriptors_DATAOUT 0x04 + /// Data in endpoint number, size 192B. + #define AUDDLoopRecDriverDescriptors_DATAIN 0x05 +#elif defined(at91sam9m10ek) || defined(at91sam9m10ekes) + /// Data out endpoint number, size 192B. + #define AUDDLoopRecDriverDescriptors_DATAOUT 0x01 + /// Data in endpoint number, size 192B + #define AUDDLoopRecDriverDescriptors_DATAIN 0x06 +#else + /// Data out endpoint number, size 192B. + #define AUDDLoopRecDriverDescriptors_DATAOUT 0x05 + /// Data in endpoint number, size 192B + #define AUDDLoopRecDriverDescriptors_DATAIN 0x06 +#endif + +/// Endpoint polling interval 2^(x-1) * 125us +#define AUDDLoopRecDriverDescriptors_HS_INTERVAL 0x04 +/// Endpoint polling interval 2^(x-1) * ms +#define AUDDLoopRecDriverDescriptors_FS_INTERVAL 0x01 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "Audio Speaker Interface IDs" +/// +/// This page lists the interface numbers for USB Audio Speaker device. +/// +/// !Interfaces +/// - AUDDLoopRecDriverDescriptors_CONTROL +/// - AUDDLoopRecDriverDescriptors_STREAMING +/// - AUDDLoopRecDriverDescriptors_STREAMINGIN + +/// Audio control interface ID. +#define AUDDLoopRecDriverDescriptors_CONTROL 0 +/// Audio streaming interface ID (OUT, for playback). +#define AUDDLoopRecDriverDescriptors_STREAMING 1 +/// Audio streaming interface ID (IN, for record). +#define AUDDLoopRecDriverDescriptors_STREAMINGIN 2 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "Audio Speaker Entity IDs" +/// +/// This page lists the entity IDs for USB Audio Speaker device. +/// +/// !Entities +/// - AUDDLoopRecDriverDescriptors_INPUTTERMINAL +/// - AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL +/// - AUDDLoopRecDriverDescriptors_FEATUREUNIT +/// - AUDDLoopRecDriverDescriptors_INPUTTERMINAL_REC +/// - AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL_REC +/// - AUDDLoopRecDriverDescriptors_FEATUREUNIT_REC + +/// Playback input terminal ID. +#define AUDDLoopRecDriverDescriptors_INPUTTERMINAL 0 +/// Playback output terminal ID. +#define AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL 1 +/// Playback feature unit ID. +#define AUDDLoopRecDriverDescriptors_FEATUREUNIT 2 +/// Record input terminal ID. +#define AUDDLoopRecDriverDescriptors_INPUTTERMINAL_REC 3 +/// Record output terminal ID. +#define AUDDLoopRecDriverDescriptors_OUTPUTTERMINAL_REC 4 +/// Record feature unit ID +#define AUDDLoopRecDriverDescriptors_FEATUREUNIT_REC 5 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +extern const USBDDriverDescriptors auddLoopRecDriverDescriptors; + +#endif //#ifndef AUDDLOOPRECDESCRIPTORS_H + diff --git a/usb/device/audio-looprec/audio-looprec.dir b/usb/device/audio-looprec/audio-looprec.dir new file mode 100644 index 0000000..bbd6c6a --- /dev/null +++ b/usb/device/audio-looprec/audio-looprec.dir @@ -0,0 +1,51 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// +/// !!!Purpose +/// +/// This directory provides definitions, structs and functions for a USB Audio +/// Class device - USB audio-looprec demo, to implement an USB desktop speaker +/// which echos audio stream back to host. +/// +/// !!!Contents +/// There are two things for the implement of the audio-speaker device driver: +/// - Implement the audio-looprec driver structs and functions for the device, +/// to initialize, to handle audio class specific requests and dispach +/// standard requests in USBD callbacks, to read/write through assigned USB +/// endpoints, +/// - Create the audio-speaker device's descriptors that should be passed to +/// the USBDDriver instance on initialization, so that the host can +/// recognize the device as a USB audio "desktop speaker" device. +/// +/// This project is simply addon to the audio speaker demo. For more +/// information, please refer to "USB Audio Speaker Device". +//------------------------------------------------------------------------------ \ No newline at end of file diff --git a/usb/device/audio-speaker/AUDDSpeakerChannel.c b/usb/device/audio-speaker/AUDDSpeakerChannel.c new file mode 100644 index 0000000..30f39c5 --- /dev/null +++ b/usb/device/audio-speaker/AUDDSpeakerChannel.c @@ -0,0 +1,129 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: AUDDSpeakerChannel implementation + + About: Purpose + Implementation of the AUDDSpeakerChannel functions. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "AUDDSpeakerChannel.h" +#include + +//------------------------------------------------------------------------------ +// Callbacks +//------------------------------------------------------------------------------ +/* + Function: AUDDSpeakerChannel_MuteChanged + Callback triggered when the mute status of a channel changes. This is + a default implementation which does nothing and must be overriden. + + Parameters: + channel - Pointer to a AUDDSpeakerChannel instance. + muted - New mute status. +*/ +//__attribute__ ((weak)) void AUDDSpeakerChannel_MuteChanged( +// AUDDSpeakerChannel *channel, +// unsigned char muted) +//{ +// TRACE_DEBUG("MuteChanged(%d, %d) ", channel->number, muted); +//} + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes the member variables of an AUDDSpeakerChannel object to the +/// given values. +/// \param channel Pointer to an AUDDSpeakerChannel instance. +/// \param number Channel number in the audio function. +/// \param muted Indicates if the channel is muted. +//------------------------------------------------------------------------------ +void AUDDSpeakerChannel_Initialize(AUDDSpeakerChannel *channel, + unsigned char number, + unsigned char muted) +{ + channel->number = number; + channel->muted = muted; +} + +//------------------------------------------------------------------------------ +/// Indicates the number of a channel. +/// \param channel Pointer to an AUDDSpeakerChannel instance. +/// \return Channel number. +//------------------------------------------------------------------------------ +unsigned char AUDDSpeakerChannel_GetNumber(const AUDDSpeakerChannel *channel) +{ + return channel->number; +} + +//------------------------------------------------------------------------------ +/// Mutes the given channel and triggers the MuteChanged callback if +/// necessary. +/// \param channel Pointer to an AUDDSpeakerChannelInstance. +//------------------------------------------------------------------------------ +void AUDDSpeakerChannel_Mute(AUDDSpeakerChannel *channel) +{ + if (!channel->muted) { + + channel->muted = 1; + AUDDSpeakerChannel_MuteChanged(channel, 1); + } +} + +//------------------------------------------------------------------------------ +/// Unmutes the given channel and triggers the MuteChanged callback if +/// necessary. +/// \param channel Pointer to an AUDDSpeakerChannelInstance. +//------------------------------------------------------------------------------ +void AUDDSpeakerChannel_Unmute(AUDDSpeakerChannel *channel) +{ + if (channel->muted) { + + channel->muted = 0; + AUDDSpeakerChannel_MuteChanged(channel, 0); + } +} + +//------------------------------------------------------------------------------ +/// Indicates if the given channel is currently muted or not. +/// \param channel Pointer an AUDDSpeakerChannel instance. +/// \return 1 if the channel is muted; otherwise 0. +//------------------------------------------------------------------------------ +unsigned char AUDDSpeakerChannel_IsMuted(const AUDDSpeakerChannel *channel) +{ + return channel->muted; +} + diff --git a/usb/device/audio-speaker/AUDDSpeakerChannel.h b/usb/device/audio-speaker/AUDDSpeakerChannel.h new file mode 100644 index 0000000..5eeca7e --- /dev/null +++ b/usb/device/audio-speaker/AUDDSpeakerChannel.h @@ -0,0 +1,92 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !Purpose + + Manipulation of the channels of an USB audio speaker device. + + !Usage + + -# Initialize a AUDDSpeakerChannel instance using + AUDDSpeakerChannel_Initialize. + -# Retrieves the current status of a channel with the + AUDDSpeakerChannel_IsMuted method. + -# Re-implement the AUDDSpeakerChannel_MuteChanged callback to get + notified when the status of a channel changes. +*/ + +#ifndef AUDDSPEAKERCHANNEL_H +#define AUDDSPEAKERCHANNEL_H + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Modelizes a channel of an USB audio speaker device. +//------------------------------------------------------------------------------ +typedef struct { + + /// Zero-based channel number in the audio function. + unsigned char number; + /// Indicates if the channel is currently muted. + unsigned char muted; + +} AUDDSpeakerChannel; + +//------------------------------------------------------------------------------ +// Callbacks +//------------------------------------------------------------------------------ + +extern void AUDDSpeakerChannel_MuteChanged(AUDDSpeakerChannel *channel, + unsigned char muted); + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern void AUDDSpeakerChannel_Initialize(AUDDSpeakerChannel *channel, + unsigned char number, + unsigned char muted); + +extern unsigned char AUDDSpeakerChannel_GetNumber( + const AUDDSpeakerChannel *channel); + +extern void AUDDSpeakerChannel_Mute(AUDDSpeakerChannel *channel); + +extern void AUDDSpeakerChannel_Unmute(AUDDSpeakerChannel *channel); + +extern unsigned char AUDDSpeakerChannel_IsMuted( + const AUDDSpeakerChannel *channel); + +#endif //#ifndef AUDDSPEAKERCHANNEL_H + diff --git a/usb/device/audio-speaker/AUDDSpeakerDriver.c b/usb/device/audio-speaker/AUDDSpeakerDriver.c new file mode 100644 index 0000000..7ca58bd --- /dev/null +++ b/usb/device/audio-speaker/AUDDSpeakerDriver.c @@ -0,0 +1,378 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "AUDDSpeakerDriver.h" +#include "AUDDSpeakerDriverDescriptors.h" +#include "AUDDSpeakerChannel.h" +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Internal types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Audio speaker driver internal state. +//------------------------------------------------------------------------------ +typedef struct { + + /// USB device driver instance. + USBDDriver usbdDriver; + /// List of AUDDSpeakerChannel instances for playback. + AUDDSpeakerChannel channels[AUDDSpeakerDriver_NUMCHANNELS+1]; + +} AUDDSpeakerDriver; + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +/// Global USB audio speaker driver instance. +static AUDDSpeakerDriver auddSpeakerDriver; +/// Array for storing the current setting of each interface. +static unsigned char auddSpeakerDriverInterfaces[2]; +/// Intermediate storage variable for the mute status of a channel. +static unsigned char muted; + +//------------------------------------------------------------------------------ +// Internal functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Callback triggered after the new mute status of a channel has been read +/// by AUDDSpeakerDriver_SetFeatureCurrentValue. Changes the mute status +/// of the given channel accordingly. +/// \param channel Number of the channel whose mute status has changed. +//------------------------------------------------------------------------------ +static void AUDDSpeakerDriver_MuteReceived(unsigned int channel) +{ + if (muted) { + + AUDDSpeakerChannel_Mute(&(auddSpeakerDriver.channels[channel])); + } + else { + + AUDDSpeakerChannel_Unmute(&(auddSpeakerDriver.channels[channel])); + } + + USBD_Write(0, 0, 0, 0, 0); +} + +//------------------------------------------------------------------------------ +/// Sets the current value of a particular Feature control of a channel. +/// \param entity Entity number. +/// \param channel Channel number. +/// \param control Control selector value (see TODO). +/// \param length Length of the data containing the new value. +//------------------------------------------------------------------------------ +static void AUDDSpeakerDriver_SetFeatureCurrentValue(unsigned char entity, + unsigned char channel, + unsigned char control, + unsigned short length) +{ + TRACE_INFO_WP("sFeature "); + TRACE_DEBUG("\b(E%d, CS%d, CN%d, L%d) ", + entity, control, channel, length); + + // Check the the requested control is supported + // Control/channel combination not supported + if ((control == AUDFeatureUnitRequest_MUTE) + && (channel < (AUDDSpeakerDriver_NUMCHANNELS+1)) + && (length == 1)) { + + unsigned int argument = channel; // Avoids compiler warning + USBD_Read(0, // Endpoint #0 + &muted, + sizeof(muted), + (TransferCallback) AUDDSpeakerDriver_MuteReceived, + (void *) argument); + } + // Control/channel combination not supported + else { + + USBD_Stall(0); + } +} + +//------------------------------------------------------------------------------ +/// Sends the current value of a particular channel Feature to the USB host. +/// \param entity Entity number. +/// \param channel Channel number. +/// \param control Control selector value (see TODO). +/// \param length Length of the data to return. +//------------------------------------------------------------------------------ +static void AUDDSpeakerDriver_GetFeatureCurrentValue(unsigned char entity, + unsigned char channel, + unsigned char control, + unsigned char length) +{ + TRACE_INFO_WP("gFeature "); + TRACE_DEBUG("\b(CS%d, CN%d, L%d) ", control, channel, length); + + // Check that the requested control is supported + // Master channel mute control + if ((control == AUDFeatureUnitRequest_MUTE) + && (channel < (AUDDSpeakerDriver_NUMCHANNELS+1)) + && (length == 1)) { + + muted = AUDDSpeakerChannel_IsMuted(&(auddSpeakerDriver.channels[channel])); + USBD_Write(0, &muted, sizeof(muted), 0, 0); + } + else { + + USBD_Stall(0); + } +} + +///* +// Function: AUDDSpeakerDriver_SetInterface +// Changes the current active alternate setting of the given interface. +// +// Parameters: +// +//*/ +//TRACE_DEBUG_M("SetInterface(%d,%d) ", setup->wIndex, setup->wValue); +// +// /* Check that interface is AudioStreaming OUT */ +// if (setup->wIndex == INTERFACE_ID_AUDIOSTREAMING_OUT) { +// +// /* Check desired alternate setting */ +// switch (setup->wValue) { +// case 0: +// case 1: +// if (speakerDriver->isOutStreamEnabled != setup->wValue) { +// +// speakerDriver->isOutStreamEnabled = setup->wValue; +// SPK_OutStreamStatusChanged(speakerDriver); +// LED_SetGlowing(LED_OTHER, setup->wValue); +// } +// USB_SendZLP0(usbDriver, 0, 0); +// break; +// +// default: +// USB_Stall(usbDriver, 0); +// } +// } +// else { +// +// USB_Stall(usbDriver, 0); +// } +// + +//------------------------------------------------------------------------------ +// Callback re-implementation +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Triggered when the USB host emits a new SETUP request. The request is +/// forward to . +/// \param request Pointer to a USBGenericRequest instance. +//------------------------------------------------------------------------------ +#if !defined(NOAUTOCALLBACK) +void USBDCallbacks_RequestReceived(const USBGenericRequest *request) +{ + AUDDSpeakerDriver_RequestHandler(request); +} +#endif + +//------------------------------------------------------------------------------ +/// Invoked whenever the active setting of an interface is changed by the +/// host. Changes the status of the third LED accordingly. +/// \param interface Interface number. +/// \param setting Newly active setting. +//------------------------------------------------------------------------------ +void USBDDriverCallbacks_InterfaceSettingChanged(unsigned char interface, + unsigned char setting) +{ + if ((interface == AUDDSpeakerDriverDescriptors_STREAMING) + && (setting == 0)) { + + LED_Clear(USBD_LEDOTHER); + } + else { + + LED_Set(USBD_LEDOTHER); + } +} + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes an USB audio speaker device driver, as well as the underlying +/// USB controller. +//------------------------------------------------------------------------------ +void AUDDSpeakerDriver_Initialize() +{ + // Initialize speaker channels + AUDDSpeakerChannel_Initialize(&(auddSpeakerDriver.channels[0]), + AUDDSpeakerDriver_MASTERCHANNEL, + 0); + AUDDSpeakerChannel_Initialize(&(auddSpeakerDriver.channels[1]), + AUDDSpeakerDriver_LEFTCHANNEL, + 0); + AUDDSpeakerChannel_Initialize(&(auddSpeakerDriver.channels[2]), + AUDDSpeakerDriver_RIGHTCHANNEL, + 0); + + // Initialize the USB driver + USBDDriver_Initialize(&(auddSpeakerDriver.usbdDriver), + &auddSpeakerDriverDescriptors, + auddSpeakerDriverInterfaces); + USBD_Init(); + + // Initialize the third LED to indicate when the audio interface is active + LED_Configure(USBD_LEDOTHER); +} + +//------------------------------------------------------------------------------ +/// Handles audio-specific USB requests sent by the host, and forwards +/// standard ones to the USB device driver. +/// \param request Pointer to a USBGenericRequest instance. +//------------------------------------------------------------------------------ +void AUDDSpeakerDriver_RequestHandler(const USBGenericRequest *request) +{ + unsigned char entity; + unsigned char interface; + + TRACE_INFO_WP("NewReq "); + + // Check if this is a class request + if (USBGenericRequest_GetType(request) == USBGenericRequest_CLASS) { + + // Check if the request is supported + switch (USBGenericRequest_GetRequest(request)) { + + case AUDGenericRequest_SETCUR: + TRACE_INFO_WP( + "sCur(0x%04X) ", + USBGenericRequest_GetIndex(request)); + + // Check the target interface and entity + entity = AUDGenericRequest_GetEntity(request); + interface = AUDGenericRequest_GetInterface(request); + if ((entity == AUDDSpeakerDriverDescriptors_FEATUREUNIT) + && (interface == AUDDSpeakerDriverDescriptors_CONTROL)) { + + AUDDSpeakerDriver_SetFeatureCurrentValue( + entity, + AUDFeatureUnitRequest_GetChannel(request), + AUDFeatureUnitRequest_GetControl(request), + USBGenericRequest_GetLength(request)); + } + else { + + TRACE_WARNING( + "AUDDSpeakerDriver_RequestHandler: Unsupported entity/interface combination (0x%04X)\n\r", + USBGenericRequest_GetIndex(request)); + USBD_Stall(0); + } + break; + + case AUDGenericRequest_GETCUR: + TRACE_INFO_WP( + "gCur(0x%04X) ", + USBGenericRequest_GetIndex(request)); + + // Check the target interface and entity + entity = AUDGenericRequest_GetEntity(request); + interface = AUDGenericRequest_GetInterface(request); + if ((entity == AUDDSpeakerDriverDescriptors_FEATUREUNIT) + && (interface == AUDDSpeakerDriverDescriptors_CONTROL)) { + + AUDDSpeakerDriver_GetFeatureCurrentValue( + entity, + AUDFeatureUnitRequest_GetChannel(request), + AUDFeatureUnitRequest_GetControl(request), + USBGenericRequest_GetLength(request)); + } + else { + + TRACE_WARNING( + "AUDDSpeakerDriver_RequestHandler: Unsupported entity/interface combination (0x%04X)\n\r", + USBGenericRequest_GetIndex(request)); + USBD_Stall(0); + } + break; + + default: + + TRACE_WARNING( + "AUDDSpeakerDriver_RequestHandler: Unsupported request (%d)\n\r", + USBGenericRequest_GetRequest(request)); + USBD_Stall(0); + } + } + // Check if this is a standard request + else if (USBGenericRequest_GetType(request) == USBGenericRequest_STANDARD) { + + // Forward request to the standard handler + USBDDriver_RequestHandler(&(auddSpeakerDriver.usbdDriver), request); + } + // Unsupported request type + else { + + TRACE_WARNING( + "AUDDSpeakerDriver_RequestHandler: Unsupported request type (%d)\n\r", + USBGenericRequest_GetType(request)); + USBD_Stall(0); + } +} + +//------------------------------------------------------------------------------ +/// Reads incoming audio data sent by the USB host into the provided +/// buffer. When the transfer is complete, an optional callback function is +/// invoked. +/// \param buffer Pointer to the data storage buffer. +/// \param length Size of the buffer in bytes. +/// \param callback Optional callback function. +/// \param argument Optional argument to the callback function. +/// \return USBD_STATUS_SUCCESS if the transfer is started successfully; +/// otherwise an error code. +//------------------------------------------------------------------------------ +unsigned char AUDDSpeakerDriver_Read(void *buffer, + unsigned int length, + TransferCallback callback, + void *argument) +{ + return USBD_Read(AUDDSpeakerDriverDescriptors_DATAOUT, + buffer, + length, + callback, + argument); +} + diff --git a/usb/device/audio-speaker/AUDDSpeakerDriver.h b/usb/device/audio-speaker/AUDDSpeakerDriver.h new file mode 100644 index 0000000..133d6df --- /dev/null +++ b/usb/device/audio-speaker/AUDDSpeakerDriver.h @@ -0,0 +1,201 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !Purpose + + Definition of a USB Audio Speaker Driver with two playback channels and one + record channel. + + !Usage + + -# Enable and setup USB related pins (see pio & board.h). + -# Configure the USB Audio Speaker driver using + AUDDSpeakerDriver_Initialize + -# To get %audio stream frames from host, use + AUDDSpeakerDriver_Read + -# To send %audio sampling stream to host, use + AUDDSpeakerDriver_Write + +*/ + +#ifndef AUDDSPEAKERDRIVER_H +#define AUDDSPEAKERDRIVER_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "Audio Speaker stream information" +/// +/// This page lists codes for USB Audio Speaker stream information. +/// +/// !Code +/// - AUDDSpeakerDriver_SAMPLERATE +/// - AUDDSpeakerDriver_NUMCHANNELS +/// - AUDDSpeakerDriver_BYTESPERSAMPLE +/// - AUDDSpeakerDriver_BITSPERSAMPLE +/// - AUDDSpeakerDriver_SAMPLESPERFRAME +/// - AUDDSpeakerDriver_BYTESPERFRAME + +#if defined(at91sam7s) + /// Sample rate in Hz. + #define AUDDSpeakerDriver_SAMPLERATE 32000 + /// Number of channels in audio stream. + #define AUDDSpeakerDriver_NUMCHANNELS 1 + /// Number of bytes in one sample. + #define AUDDSpeakerDriver_BYTESPERSAMPLE 2 +#else + /// Sample rate in Hz. + #define AUDDSpeakerDriver_SAMPLERATE 48000 + /// Number of channels in audio stream. + #define AUDDSpeakerDriver_NUMCHANNELS 2 + /// Number of bytes in one sample. + #define AUDDSpeakerDriver_BYTESPERSAMPLE 2 +#endif +/// Number of bits in one sample. +#define AUDDSpeakerDriver_BITSPERSAMPLE (AUDDSpeakerDriver_BYTESPERSAMPLE * 8) +/// Number of bytes in one USB subframe. +#define AUDDSpeakerDriver_BYTESPERSUBFRAME (AUDDSpeakerDriver_NUMCHANNELS * \ + AUDDSpeakerDriver_BYTESPERSAMPLE) +/// Number of samples in one USB frame. +#define AUDDSpeakerDriver_SAMPLESPERFRAME (AUDDSpeakerDriver_SAMPLERATE / 1000 \ + * AUDDSpeakerDriver_NUMCHANNELS) +/// Number of bytes in one USB frame. +#define AUDDSpeakerDriver_BYTESPERFRAME (AUDDSpeakerDriver_SAMPLESPERFRAME * \ + AUDDSpeakerDriver_BYTESPERSAMPLE) +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "Audio Speaker Channel Numbers" +/// +/// This page lists codes for USB Audio Speaker channel numbers. +/// +/// !Playback channel numbers +/// - AUDDSpeakerDriver_MASTERCHANNEL +/// - AUDDSpeakerDriver_LEFTCHANNEL +/// - AUDDSpeakerDriver_RIGHTCHANNEL +/// +/// !Record channel number +/// - AUDDSpeakerDriver_RECCHANNEL + +/// Master channel of playback. +#define AUDDSpeakerDriver_MASTERCHANNEL 0 +/// Front left channel of playback. +#define AUDDSpeakerDriver_LEFTCHANNEL 1 +/// Front right channel of playback. +#define AUDDSpeakerDriver_RIGHTCHANNEL 2 +/// Channel of record. +#define AUDDSpeakerDriver_RECCHANNEL 0 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern void AUDDSpeakerDriver_Initialize(); + +extern void AUDDSpeakerDriver_RequestHandler(const USBGenericRequest *request); + +extern unsigned char AUDDSpeakerDriver_Read(void *buffer, + unsigned int length, + TransferCallback callback, + void *argument); + +#endif //#ifndef AUDDSPEAKERDRIVER_H + +//#ifndef SPEAKER_DRIVER_H +//#define SPEAKER_DRIVER_H +// +////------------------------------------------------------------------------------ +//// Definitions +////------------------------------------------------------------------------------ +// +///*! Sampling frequency in Hz */ +//#define SPEAKER_SAMPLERATE 48000 +///*! Number of samples in one isochronous packet (1ms frame) */ +//#define SPEAKER_SAMPLESPERPACKET (SPEAKER_SAMPLERATE / 1000) +///*! Size of one sample (in bytes) */ +//#define SPEAKER_SAMPLESIZE 2 +///*! Number of channels */ +//#define SPEAKER_NUMCHANNELS 2 +///*! Size of one frame (number of bytes sent for one sample on all channels) */ +//#define SPEAKER_FRAMESIZE (SPEAKER_SAMPLESIZE * SPEAKER_NUMCHANNELS) +///*! Required bit rate given the sample frequency, sample size and number of +// channels. */ +//#define SPEAKER_BITRATE (SPEAKER_SAMPLERATE * SPEAKER_FRAMESIZE) +///*! Size of one isochronous packet */ +//#define SPEAKER_PACKETSIZE (SPEAKER_SAMPLESPERPACKET * SPEAKER_FRAMESIZE) +// +////------------------------------------------------------------------------------ +//// Structures +////------------------------------------------------------------------------------ +///*! +// Holds the speaker driver state. +// */ +//typedef struct { +// +// S_std_class standardDriver; +// +// unsigned char isOutStreamEnabled; +// unsigned char isChannelMuted[SPEAKER_NUMCHANNELS+1]; +// +// Callback_f outStreamStatusChanged; +// Callback_f outStreamMuteChanged; +// +//} __attribute__((packed)) S_speaker; +// +////------------------------------------------------------------------------------ +//// Exported functions +////------------------------------------------------------------------------------ +// +//extern void SPK_Init(S_speaker *speakerDriver, const S_usb *usbDriver); +//extern void SPK_SetCallbacks(S_speaker *speakerDriver, +// Callback_f outStreamStatusChanged, +// Callback_f outStreamMuteChanged); +//extern void SPK_RequestHandler(S_speaker *speakerDriver); +//extern char SPK_Read(S_speaker *speakerDriver, +// void *buffer, +// unsigned int length, +// Callback_f callback, +// void *argument); +// +//#endif //#ifndef SPEAKER_DRIVER_H +// diff --git a/usb/device/audio-speaker/AUDDSpeakerDriverDescriptors.c b/usb/device/audio-speaker/AUDDSpeakerDriverDescriptors.c new file mode 100644 index 0000000..2501120 --- /dev/null +++ b/usb/device/audio-speaker/AUDDSpeakerDriverDescriptors.c @@ -0,0 +1,620 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "AUDDSpeakerDriverDescriptors.h" +#include "AUDDSpeakerDriver.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "Audio Speaker Device Codes" +/// +/// This page lists the %device IDs and release number of the USB Audio Speaker +/// %device. +/// +/// !Codes +/// - AUDDSpeakerDriverDescriptors_VENDORID +/// - AUDDSpeakerDriverDescriptors_PRODUCTID +/// - AUDDSpeakerDriverDescriptors_RELEASE + +/// Device vendor ID. +#define AUDDSpeakerDriverDescriptors_VENDORID 0x03EB +/// Device product ID. +#define AUDDSpeakerDriverDescriptors_PRODUCTID 0x6128 +/// Device release number in BCD format. +#define AUDDSpeakerDriverDescriptors_RELEASE 0x0100 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Internal types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Audio control header descriptor with one slave interface. +//------------------------------------------------------------------------------ +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// Header descriptor with 1 interface. +//------------------------------------------------------------------------------ +typedef struct { + + /// Header descriptor. + AUDHeaderDescriptor header; + /// Id of the first grouped interface - Speaker. + unsigned char bInterface0; + +} __attribute__ ((packed)) AUDHeaderDescriptor1; // GCC + +//------------------------------------------------------------------------------ +/// Feature unit descriptor with 3 channel controls (master, right, left). +//------------------------------------------------------------------------------ +typedef struct { + + /// Feature unit descriptor. + AUDFeatureUnitDescriptor feature; + /// Available controls for each channel. + unsigned char bmaControls[3]; + /// Index of a string descriptor for the feature unit. + unsigned char iFeature; + +} __attribute__ ((packed)) AUDFeatureUnitDescriptor3; // GCC + +//------------------------------------------------------------------------------ +/// List of descriptors for detailling the audio control interface of a +/// device using a USB audio speaker driver. +//------------------------------------------------------------------------------ +typedef struct { + + /// Header descriptor (with one slave interface). + AUDHeaderDescriptor1 header; + /// Input terminal descriptor. + AUDInputTerminalDescriptor input; + /// Output terminal descriptor. + AUDOutputTerminalDescriptor output; + /// Feature unit descriptor. + AUDFeatureUnitDescriptor3 feature; + +} __attribute__ ((packed)) AUDDSpeakerDriverAudioControlDescriptors; // GCC + +//------------------------------------------------------------------------------ +/// Format type I descriptor with one discrete sampling frequency. +//------------------------------------------------------------------------------ +typedef struct { + + /// Format type I descriptor. + AUDFormatTypeOneDescriptor formatType; + /// Sampling frequency in Hz. + unsigned char tSamFreq[3]; + +} __attribute__ ((packed)) AUDFormatTypeOneDescriptor1; // GCC + +//------------------------------------------------------------------------------ +/// Holds a list of descriptors returned as part of the configuration of +/// a USB audio speaker device. +//------------------------------------------------------------------------------ +typedef struct { + + /// Standard configuration. + USBConfigurationDescriptor configuration; + /// Audio control interface. + USBInterfaceDescriptor control; + /// Descriptors for the audio control interface. + AUDDSpeakerDriverAudioControlDescriptors controlDescriptors; + //- AUDIO OUT + /// Streaming out interface descriptor (with no endpoint, required). + USBInterfaceDescriptor streamingOutNoIsochronous; + /// Streaming out interface descriptor. + USBInterfaceDescriptor streamingOut; + /// Audio class descriptor for the streaming out interface. + AUDStreamingInterfaceDescriptor streamingOutClass; + /// Stream format descriptor. + AUDFormatTypeOneDescriptor1 streamingOutFormatType; + /// Streaming out endpoint descriptor. + AUDEndpointDescriptor streamingOutEndpoint; + /// Audio class descriptor for the streaming out endpoint. + AUDDataEndpointDescriptor streamingOutDataEndpoint; + +} __attribute__ ((packed)) AUDDSpeakerDriverConfigurationDescriptors; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +/// Device descriptor for a USB audio speaker driver. +const USBDeviceDescriptor deviceDescriptor = { + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + AUDDeviceDescriptor_CLASS, + AUDDeviceDescriptor_SUBCLASS, + AUDDeviceDescriptor_PROTOCOL, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + AUDDSpeakerDriverDescriptors_VENDORID, + AUDDSpeakerDriverDescriptors_PRODUCTID, + AUDDSpeakerDriverDescriptors_RELEASE, + 1, // Manufacturer string descriptor index + 2, // Product string descriptor index + 3, // Index of serial number string descriptor + 1 // One possible configuration +}; + +#if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + +/// USB device qualifier descriptor. +const USBDeviceQualifierDescriptor qualifierDescriptor = { + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + AUDDeviceDescriptor_CLASS, + AUDDeviceDescriptor_SUBCLASS, + AUDDeviceDescriptor_PROTOCOL, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + 1, // Device has one possible configuration + 0 // Reserved +}; + +#endif + +/// Configuration descriptors for a USB audio speaker driver. +const AUDDSpeakerDriverConfigurationDescriptors fsConfigurationDescriptors = { + + // Configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(AUDDSpeakerDriverConfigurationDescriptors), + 2, // This configuration has 2 interfaces + 1, // This is configuration #1 + 0, // No string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + // Audio control interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDSpeakerDriverDescriptors_CONTROL, + 0, // This is alternate setting #0 + 0, // This interface uses no endpoint + AUDControlInterfaceDescriptor_CLASS, + AUDControlInterfaceDescriptor_SUBCLASS, + AUDControlInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio control interface descriptors + { + // Header descriptor + { + { + sizeof(AUDHeaderDescriptor1), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_HEADER, + AUDHeaderDescriptor_AUD1_00, + sizeof(AUDDSpeakerDriverAudioControlDescriptors), + 1 // One streaming interface + }, + AUDDSpeakerDriverDescriptors_STREAMING + }, + // Input terminal descriptor + { + sizeof(AUDInputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_INPUTTERMINAL, + AUDDSpeakerDriverDescriptors_INPUTTERMINAL, + AUDInputTerminalDescriptor_USBSTREAMING, + AUDDSpeakerDriverDescriptors_OUTPUTTERMINAL, + AUDDSpeakerDriver_NUMCHANNELS, + AUDInputTerminalDescriptor_LEFTFRONT + | AUDInputTerminalDescriptor_RIGHTFRONT, + 0, // No string descriptor for channels + 0 // No string descriptor for input terminal + }, + // Output terminal descriptor + { + sizeof(AUDOutputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_OUTPUTTERMINAL, + AUDDSpeakerDriverDescriptors_OUTPUTTERMINAL, + AUDOutputTerminalDescriptor_SPEAKER, + AUDDSpeakerDriverDescriptors_INPUTTERMINAL, + AUDDSpeakerDriverDescriptors_FEATUREUNIT, + 0 // No string descriptor + }, + // Feature unit descriptor + { + { + sizeof(AUDFeatureUnitDescriptor3), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_FEATUREUNIT, + AUDDSpeakerDriverDescriptors_FEATUREUNIT, + AUDDSpeakerDriverDescriptors_INPUTTERMINAL, + 1, // 1 byte per channel for controls + }, + { + AUDFeatureUnitDescriptor_MUTE, // Master channel controls + 0, // Right channel controls + 0 // Left channel controls + }, + 0 // No string descriptor + } + }, + // Audio streaming interface with 0 endpoints + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDSpeakerDriverDescriptors_STREAMING, + 0, // This is alternate setting #0 + 0, // This interface uses no endpoints + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming interface with data endpoint + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDSpeakerDriverDescriptors_STREAMING, + 1, // This is alternate setting #1 + 1, // This interface uses 1 endpoint + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming class-specific descriptor + { + sizeof(AUDStreamingInterfaceDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_GENERAL, + AUDDSpeakerDriverDescriptors_INPUTTERMINAL, + 0, // No internal delay because of data path + AUDFormatTypeOneDescriptor_PCM + }, + // Format type I descriptor + { + { + sizeof(AUDFormatTypeOneDescriptor1), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_FORMATTYPE, + AUDFormatTypeOneDescriptor_FORMATTYPEONE, + AUDDSpeakerDriver_NUMCHANNELS, + AUDDSpeakerDriver_BYTESPERSAMPLE, + AUDDSpeakerDriver_BYTESPERSAMPLE*8, + 1 // One discrete frequency supported + }, + { + AUDDSpeakerDriver_SAMPLERATE & 0xFF, + (AUDDSpeakerDriver_SAMPLERATE >> 8) & 0xFF, + (AUDDSpeakerDriver_SAMPLERATE >> 16) & 0xFF + } + }, + // Audio streaming endpoint standard descriptor + { + sizeof(AUDEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + AUDDSpeakerDriverDescriptors_DATAOUT), + USBEndpointDescriptor_ISOCHRONOUS, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(AUDDSpeakerDriverDescriptors_DATAOUT), + AUDDSpeakerDriverDescriptors_FS_INTERVAL, // Polling interval = 1 ms + 0, // This is not a synchronization endpoint + 0 // No associated synchronization endpoint + }, + // Audio streaming endpoint class-specific descriptor + { + sizeof(AUDDataEndpointDescriptor), + AUDGenericDescriptor_ENDPOINT, + AUDDataEndpointDescriptor_SUBTYPE, + 0, // No attributes + 0, // Endpoint is not synchronized + 0 // Endpoint is not synchronized + } +}; + +#if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) +/// Configuration descriptors for a USB audio speaker driver. +const AUDDSpeakerDriverConfigurationDescriptors hsConfigurationDescriptors = { + + // Configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(AUDDSpeakerDriverConfigurationDescriptors), + 2, // This configuration has 2 interfaces + 1, // This is configuration #1 + 0, // No string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + // Audio control interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDSpeakerDriverDescriptors_CONTROL, + 0, // This is alternate setting #0 + 0, // This interface uses no endpoint + AUDControlInterfaceDescriptor_CLASS, + AUDControlInterfaceDescriptor_SUBCLASS, + AUDControlInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio control interface descriptors + { + // Header descriptor + { + { + sizeof(AUDHeaderDescriptor1), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_HEADER, + AUDHeaderDescriptor_AUD1_00, + sizeof(AUDDSpeakerDriverAudioControlDescriptors), + 1 // One streaming interface + }, + AUDDSpeakerDriverDescriptors_STREAMING + }, + // Input terminal descriptor + { + sizeof(AUDInputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_INPUTTERMINAL, + AUDDSpeakerDriverDescriptors_INPUTTERMINAL, + AUDInputTerminalDescriptor_USBSTREAMING, + AUDDSpeakerDriverDescriptors_OUTPUTTERMINAL, + AUDDSpeakerDriver_NUMCHANNELS, + AUDInputTerminalDescriptor_LEFTFRONT + | AUDInputTerminalDescriptor_RIGHTFRONT, + 0, // No string descriptor for channels + 0 // No string descriptor for input terminal + }, + // Output terminal descriptor + { + sizeof(AUDOutputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_OUTPUTTERMINAL, + AUDDSpeakerDriverDescriptors_OUTPUTTERMINAL, + AUDOutputTerminalDescriptor_SPEAKER, + AUDDSpeakerDriverDescriptors_INPUTTERMINAL, + AUDDSpeakerDriverDescriptors_FEATUREUNIT, + 0 // No string descriptor + }, + // Feature unit descriptor + { + { + sizeof(AUDFeatureUnitDescriptor3), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_FEATUREUNIT, + AUDDSpeakerDriverDescriptors_FEATUREUNIT, + AUDDSpeakerDriverDescriptors_INPUTTERMINAL, + 1, // 1 byte per channel for controls + }, + { + AUDFeatureUnitDescriptor_MUTE, // Master channel controls + 0, // Right channel controls + 0 // Left channel controls + }, + 0 // No string descriptor + } + }, + // Audio streaming interface with 0 endpoints + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDSpeakerDriverDescriptors_STREAMING, + 0, // This is alternate setting #0 + 0, // This interface uses no endpoints + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming interface with data endpoint + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDDSpeakerDriverDescriptors_STREAMING, + 1, // This is alternate setting #1 + 1, // This interface uses 1 endpoint + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming class-specific descriptor + { + sizeof(AUDStreamingInterfaceDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_GENERAL, + AUDDSpeakerDriverDescriptors_INPUTTERMINAL, + 0, // No internal delay because of data path + AUDFormatTypeOneDescriptor_PCM + }, + // Format type I descriptor + { + { + sizeof(AUDFormatTypeOneDescriptor1), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_FORMATTYPE, + AUDFormatTypeOneDescriptor_FORMATTYPEONE, + AUDDSpeakerDriver_NUMCHANNELS, + AUDDSpeakerDriver_BYTESPERSAMPLE, + AUDDSpeakerDriver_BYTESPERSAMPLE*8, + 1 // One discrete frequency supported + }, + { + AUDDSpeakerDriver_SAMPLERATE & 0xFF, + (AUDDSpeakerDriver_SAMPLERATE >> 8) & 0xFF, + (AUDDSpeakerDriver_SAMPLERATE >> 16) & 0xFF + } + }, + // Audio streaming endpoint standard descriptor + { + sizeof(AUDEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + AUDDSpeakerDriverDescriptors_DATAOUT), + USBEndpointDescriptor_ISOCHRONOUS, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(AUDDSpeakerDriverDescriptors_DATAOUT), + AUDDSpeakerDriverDescriptors_HS_INTERVAL, // Polling interval = 1 ms + 0, // This is not a synchronization endpoint + 0 // No associated synchronization endpoint + }, + // Audio streaming endpoint class-specific descriptor + { + sizeof(AUDDataEndpointDescriptor), + AUDGenericDescriptor_ENDPOINT, + AUDDataEndpointDescriptor_SUBTYPE, + 0, // No attributes + 0, // Endpoint is not synchronized + 0 // Endpoint is not synchronized + } +}; +#endif // defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + +/// String descriptor with the supported languages. +const unsigned char languageIdDescriptor[] = { + + USBStringDescriptor_LENGTH(1), + USBGenericDescriptor_STRING, + USBStringDescriptor_ENGLISH_US +}; + +/// Manufacturer name. +const unsigned char manufacturerDescriptor[] = { + + USBStringDescriptor_LENGTH(5), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('t'), + USBStringDescriptor_UNICODE('m'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('l') +}; + +/// Product name. +const unsigned char productDescriptor[] = { + + USBStringDescriptor_LENGTH(15), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('D'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('s'), + USBStringDescriptor_UNICODE('k'), + USBStringDescriptor_UNICODE('t'), + USBStringDescriptor_UNICODE('o'), + USBStringDescriptor_UNICODE('p'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('s'), + USBStringDescriptor_UNICODE('p'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('a'), + USBStringDescriptor_UNICODE('k'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('r') +}; + +/// Product serial number. +const unsigned char serialNumberDescriptor[] = { + + USBStringDescriptor_LENGTH(4), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('0'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE('2'), + USBStringDescriptor_UNICODE('3') +}; + +/// Array of pointers to the four string descriptors. +const unsigned char *stringDescriptors[] = { + + languageIdDescriptor, + manufacturerDescriptor, + productDescriptor, + serialNumberDescriptor, +}; + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +/// List of descriptors required by an USB audio speaker device driver. +const USBDDriverDescriptors auddSpeakerDriverDescriptors = { + + &deviceDescriptor, + (const USBConfigurationDescriptor *) &fsConfigurationDescriptors, +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + &qualifierDescriptor, + (const USBConfigurationDescriptor *) &hsConfigurationDescriptors, + &deviceDescriptor, + (const USBConfigurationDescriptor *) &hsConfigurationDescriptors, + &qualifierDescriptor, + (const USBConfigurationDescriptor *) &hsConfigurationDescriptors, +#else + 0, 0, 0, 0, 0, 0, +#endif + stringDescriptors, + 4 // Number of string descriptors +}; + diff --git a/usb/device/audio-speaker/AUDDSpeakerDriverDescriptors.h b/usb/device/audio-speaker/AUDDSpeakerDriverDescriptors.h new file mode 100644 index 0000000..7bc7352 --- /dev/null +++ b/usb/device/audio-speaker/AUDDSpeakerDriverDescriptors.h @@ -0,0 +1,146 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Declaration of the descriptors required by a USB audio speaker driver. + + !!!Usage + + -# Initialize a USBDDriver instance using the + auddSpeakerDriverDescriptors list. +*/ + +#ifndef AUDDSPEAKERDRIVERDESCRIPTORS_H +#define AUDDSPEAKERDRIVERDESCRIPTORS_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "Audio Speaker Endpoint Numbers" +/// +/// This page lists the endpoint number settings for USB Audio Speaker device. +/// +/// !Endpoints +/// - AUDDSpeakerDriverDescriptors_DATAOUT +/// - AUDDSpeakerDriverDescriptors_DATAIN +/// - AUDDSpeakerDriverDescriptors_FS_INTERVAL +/// - AUDDSpeakerDriverDescriptors_HS_INTERVAL +/// +/// \note for UDP, uses IN EPs that support double buffer; for UDPHS, uses +/// IN EPs that support DMA and High bandwidth. + +#if defined(at91sam7s) || defined(at91sam9xe) + /// Data out endpoint number. + #define AUDDSpeakerDriverDescriptors_DATAOUT 0x01 + /// Data in endpoint number. + #define AUDDSpeakerDriverDescriptors_DATAIN 0x02 +#elif defined(CHIP_USB_UDP) + /// Data out endpoint number. + #define AUDDSpeakerDriverDescriptors_DATAOUT 0x04 + /// Data in endpoint number. + #define AUDDSpeakerDriverDescriptors_DATAIN 0x05 +#else + /// Data out endpoint number. + #define AUDDSpeakerDriverDescriptors_DATAOUT 0x05 + /// Data in endpoint number. + #define AUDDSpeakerDriverDescriptors_DATAIN 0x06 +#endif + +/// Endpoint polling interval 2^(x-1) * 125us +#define AUDDSpeakerDriverDescriptors_HS_INTERVAL 0x04 +/// Endpoint polling interval 2^(x-1) * ms +#define AUDDSpeakerDriverDescriptors_FS_INTERVAL 0x01 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "Audio Speaker Interface IDs" +/// +/// This page lists the interface numbers for USB Audio Speaker device. +/// +/// !Interfaces +/// - AUDDSpeakerDriverDescriptors_CONTROL +/// - AUDDSpeakerDriverDescriptors_STREAMING +/// - AUDDSpeakerDriverDescriptors_STREAMINGIN + +/// Audio control interface ID. +#define AUDDSpeakerDriverDescriptors_CONTROL 0 +/// Audio streaming interface ID (OUT, for playback). +#define AUDDSpeakerDriverDescriptors_STREAMING 1 +/// Audio streaming interface ID (IN, for record). +#define AUDDSpeakerDriverDescriptors_STREAMINGIN 2 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "Audio Speaker Entity IDs" +/// +/// This page lists the entity IDs for USB Audio Speaker device. +/// +/// !Entities +/// - AUDDSpeakerDriverDescriptors_INPUTTERMINAL +/// - AUDDSpeakerDriverDescriptors_OUTPUTTERMINAL +/// - AUDDSpeakerDriverDescriptors_FEATUREUNIT +/// - AUDDSpeakerDriverDescriptors_INPUTTERMINAL_REC +/// - AUDDSpeakerDriverDescriptors_OUTPUTTERMINAL_REC +/// - AUDDSpeakerDriverDescriptors_FEATUREUNIT_REC + +/// Playback input terminal ID. +#define AUDDSpeakerDriverDescriptors_INPUTTERMINAL 0 +/// Playback output terminal ID. +#define AUDDSpeakerDriverDescriptors_OUTPUTTERMINAL 1 +/// Playback feature unit ID. +#define AUDDSpeakerDriverDescriptors_FEATUREUNIT 2 +/// Record input terminal ID. +#define AUDDSpeakerDriverDescriptors_INPUTTERMINAL_REC 3 +/// Record output terminal ID. +#define AUDDSpeakerDriverDescriptors_OUTPUTTERMINAL_REC 4 +/// Record feature unit ID +#define AUDDSpeakerDriverDescriptors_FEATUREUNIT_REC 5 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +extern const USBDDriverDescriptors auddSpeakerDriverDescriptors; + +#endif //#ifndef AUDDSPEAKERDRIVERDESCRIPTORS_H + diff --git a/usb/device/audio-speaker/USBAudioSpeaker.png b/usb/device/audio-speaker/USBAudioSpeaker.png new file mode 100644 index 0000000..bcae300 Binary files /dev/null and b/usb/device/audio-speaker/USBAudioSpeaker.png differ diff --git a/usb/device/audio-speaker/USBAudioSpeakerDescriptors.png b/usb/device/audio-speaker/USBAudioSpeakerDescriptors.png new file mode 100644 index 0000000..251a2d1 Binary files /dev/null and b/usb/device/audio-speaker/USBAudioSpeakerDescriptors.png differ diff --git a/usb/device/audio-speaker/USBAudioSpeakerRecorder.png b/usb/device/audio-speaker/USBAudioSpeakerRecorder.png new file mode 100644 index 0000000..ddbd234 Binary files /dev/null and b/usb/device/audio-speaker/USBAudioSpeakerRecorder.png differ diff --git a/usb/device/audio-speaker/USBAudioSpeakerRecorderDescriptors.png b/usb/device/audio-speaker/USBAudioSpeakerRecorderDescriptors.png new file mode 100644 index 0000000..c5c3324 Binary files /dev/null and b/usb/device/audio-speaker/USBAudioSpeakerRecorderDescriptors.png differ diff --git a/usb/device/audio-speaker/audio-speaker.dir b/usb/device/audio-speaker/audio-speaker.dir new file mode 100644 index 0000000..be90df0 --- /dev/null +++ b/usb/device/audio-speaker/audio-speaker.dir @@ -0,0 +1,617 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// +/// !!!Purpose +/// +/// This directory provides definitions, structs and functions for a USB Audio +/// Class device - USB audio-speaker demo, to implement an USB desktop speaker. +/// +/// !!!Contents +/// There are two things for the implement of the audio-speaker device driver: +/// - Implement the audio-speaker driver structs and functions for the device, +/// to initialize, to handle audio class specific requests and dispach +/// standard requests in USBD callbacks, to read/write through assigned USB +/// endpoints, +/// - Create the audio-speaker device's descriptors that should be passed to +/// the USBDDriver instance on initialization, so that the host can +/// recognize the device as a USB audio "desktop speaker" device. +/// +/// For more information about what a particular group contains, please refer to +/// "USB Audio Speaker Device". +//------------------------------------------------------------------------------ + +/** + \page "USB Audio Speaker Device" + This page describes how to use the USB framework to produce a USB Audio Class + Device driver. + + !!!References + - "AT91 USB device framework" + - "USB Device Enumeration" + - + Universal Serial Bus Revision 2.0 specification + (.zip file format, size 9.80 MB) + - + Audio Device Document 1.0 + - + Audio Data Formats 1.0 + - + Autio Terminal Types 1.0 + + !!!Audio Speaker Driver API + - AUDDSpeakerDriver_Initialize + - AUDDSpeakerDriver_RequestHandler + - AUDDSpeakerDriver_Read + + !!!Audio Desktop Speaker Description + The %device described here is a USB desktop speaker. It receives a stero + %audio data stream from the Host over its Audio Streaming interface. The used + Audio Data Format is 16-bit 48KHz 2-channel PCM (or mono 16-bit 32KHz PCM for + sam7s chips). The following is the internal topology of the speaker. + + \image USBAudioSpeaker.png "USB Desktop Speaker Topology" + + The %audio function contains one Onput Terminal that represents the actual + speaker output element, followed by the Digital-to-Analog Converter (DAC). + The digital input stream of the host enters the %audio function through the + single Input %Pin of the Output terminal. There is a Feature Unit on the + %audio stream, to mute or unmute the speaker. The Input Terminal is the + representation within the %audio fucntion of the USB OUT endpoint that + eventually receives the %audio data stream from the Host. The internals of the + %audio function are presented to the Host through the (mandatory) AudioControl + interface wheras the USB OUT endpoint resides in the AudioStreaming interface. + + !!!Descriptor Hierarchy + This USB Desktop Speaker %device includes the AudioControl interface + (interface 0) and a single AudioStreaming interface (interface 1). The + AudioStreaming interface features two alternate settings. The first alternate + setting (Alternate Setting 0) has zero bandwidth associated with it so that + switching to this alternate setting effectively frees all allocated bandwidth + on the USB for this device. Zero bandwidth is indicated by the lack of a + streaming endpoint. Alternate Setting 1 is the operational part of the + interface and it has one isochronous OUT endpoint. Figure presents the + descriptor hierarchy. + + \image UsbAudioSpeakerDescriptors.png "USB Desktop Speaker Hierarchy" + + !!!Descriptors + The following sections present all the descriptors that are used to describe + the %device. + + All descriptors are combined into a list and pass to USBDDriver_Initialize + invoked in AUDDSpeakerDriver_Initialize. + +\code +const USBDDriverDescriptors auddSpeakerDriverDescriptors; +\endcode + + !!Device Descriptor +\code +const USBDeviceDescriptor deviceDescriptor; +\endcode +||Offset||Field||Size||Value||Description +|0|bLength|1|0x12|Size of this descriptor, in bytes. +|1|bDescriptorType|1|0x01|DEVICE descriptor (USBGenericDescriptor_DEVICE). +|2|bcdUSB|2|0x0200|2.00 - current revision of USB specification. +|4|bDeviceClass|1|0x00|Device defined at interface level. +|5|bDeviceSubClass|1|0x00|Unused. +|6|bDeviceProtocol|1|0x00|Unused. +|7|bMaxPacketSize0|1|0x08|8 bytes (BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0)). +|8|idVendor|2|0x03EB|Atmel Vendor ID (AUDDSpeakerDriverDescriptors_VENDORID). +|10|idProduct|2|0x6128|Product ID (AUDDSpeakerDriverDescriptors_PRODUCTID). +|12|bcdDevice|2|0x0100|Device Release Code\n + (AUDDSpeakerDriverDescriptors_RELEASE). +|14|iManufacturer|1|0x01|Index to manufacture name in Unicode\n + (manufacturerDescriptor). +|15|iProduct|1|0x02|Index to product name in Unicode (productDescriptor). +|16|iSerialNumber|1|0x03|Index to serial number in Unicode\n + (serialNumberDescriptor). +|17|bNumConfigurations|1|0x01|One configuration. + + !!Configuration Descriptor +\code +const AUDDSpeakerDriverConfigurationDescriptors configurationDescriptors; +\endcode +||Offset||Field||Size||Value||Description +|0|bLength|1|0x09|Size of this descriptor, in bytes. +|1|bDescriptorType|1|0x02|CONFIGURATION descriptor\n + (USBGenericDescriptor_CONFIGURATION). +|2|wTotalLength|2|0x????|Length of the total configuration block in bytes\n + including this descriptor\n + (AUDDSpeakerDriverConfigurationDescriptors) +|4|bNumInterfaces|1|0x02|Two interfaces. +|5|bConfigurationValue|1|0x01|ID of this configuration. +|6|iConfiguration|1|0x00|Unused. +|7|bmAttributes|1|0x??|BOARD_USB_BMATTRIBUTES +|8|bMaxPower|1|0x32|100mA Max. %power consumption.\n + USBConfigurationDescriptor_POWER(100) + + !!AudioControl Interface Descriptor + The AudioControl interface describes the %device structure (%audio function + topology) and is used to manipulate the Audio Controls. + + !Standard AC Interface Descriptor + The AudioControl interface has no dedicated endpoints associated with it. It + uses the default pipe (endpoint 0) for all communication purposes. Class- + specific AudioControl Requests are sent using the default pipe. There is no + Status Interrupt endpoint provided. + + See USBInterfaceDescriptor. +||Offset||Field||Size||Value||Description +|0|bLength|1|0x09|Size of this descriptor, in bytes. +|1|bDescriptorType|1|0x04|INTERFACE descriptor\n + (USBGenericDescriptor_INTERFACE). +|2|bInterfaceNumber|1|0x00|Index of this interface. +|3|bAlternateSetting|1|0x00|Index of this setting. +|4|bNumEndpoints|1|0x00|0 endpoints. +|5|bInterfaceClass|1|0x01|AUDIO (AUDControlInterfaceDescriptor_CLASS). +|6|bInterfaceSubClass|1|0x01|AUDIO_CONTROL\n + (AUDControlInterfaceDescriptor_SUBCLASS). +|7|bInterfaceProtocol|1|0x00|Unused. +|8|iInterface|1|0x00|Unused. + + !Class-specific AC Interface Descriptor + The Class-specific AC interface descriptor is always headed by a Header + descriptor that contains general information about the AudioControl interface. + It contains all the pointers needed to describe the AudioInterface Collection, + associated with the described %audio function. +||Offset||Field||Size||Value||Description +|0|bLength|1|0x09|Size of this descriptor, in bytes. +|1|bDescriptorType|1|0x24|CS_INTERFACE descriptor\n + (AUDGenericDescriptor_INTERFACE). +|2|bDescriptorSubtype|1|0x01|HEADER subtype (AUDGenericDescriptor_HEADER). +|3|bcdADC|2|0x0100|Revision of class specification - 1.0 +|5|wTotalLength|2|0x????|Total size of class specific descriptors\n + (AUDDSpeakerDriverAudioControlDescriptors). +|7|bInCollection|1|0x01|Number of streaming interfaces. +|8|baInterfaceNr(1)|1|0x01|AudioStreaming interface 1 belongs to this AudioControl interface. + + !Input Terminal Descriptor for playback + This descriptor describes the Input Terminal that represents the USB pipe from + the Host PC. Its Output Pin is connected to the Input Pin of the Feature Unit + ... +||Offset||Field||Size||Value||Description +|0|bLength|1|0x0C|Size of this descriptor, in bytes. +|1|bDescriptorType|1|0x24|CS_INTERFACE descriptor\n + (AUDGenericDescriptor_INTERFACE). +|2|bDescriptorSubType|1|0x02|INPUT_TERMINAL subtype\n + (AUDGenericDescriptor_INPUTTERMINAL). +|3|bTerminalID|1|0x00|ID of this Input Terminal\n + (AUDDSpeakerDriverDescriptors_INPUTTERMINAL). +|4|wTerminalType|2|0x0101|Terminal is USB stream\n + (AUDInputTerminalDescriptor_USBSTREAMING). +|6|bAssocTerminal|1|0x01|Associated to Output Terminal\n + (AUDDSpeakerDriverDescriptors_OUTPUTTERMINAL). +|7|bNrChannels|1|0x02|Two channel. +|8|wChannelConfig|2|0x0003|Left plus right front channel. +|10|iChannelNames|1|0x00|Unused. +|11|iTerminal|1|0x00|Unused. + + !Output Terminal Descriptor for playback + ... +||Offset||Field||Size||Value||Description +|0|bLength|1|0x09|Size of this descriptor, in bytes. +|1|bDescriptorType|1|0x24|CS_INTERFACE descriptor\n + (AUDGenericDescriptor_INTERFACE). +|2|bDescriptorSubType|1|0x03|OUTPUT_TERMINAL subtype\n + (AUDGenericDescriptor_OUTPUTTERMINAL). +|3|bTerminalID|1|0x01|ID of this Output Terminal\n + (AUDDSpeakerDriverDescriptors_OUTPUTTERMINAL). +|4|wTerminalType|2|0x0301|Terminal is Desktop speaker. +|6|bAssocTerminal|1|0x01|Associated to Input Terminal\n + (AUDDSpeakerDriverDescriptors_INPUTTERMINAL). +|7|bSourceID|1|0x02|From Feature Unit\n + (AUDDSpeakerDriverDescriptors_FEATUREUNIT). +|8|iTerminal|1|0x00|Unused. + + !Feature Unit Descriptor for playback + ... +||Offset||Field||Size||Value||Description +|0|bLength|1|0x0A|Size of this descriptor, in bytes. +|1|bDescriptorType|1|0x24|CS_INTERFACE descriptor\n + (AUDGenericDescriptor_INTERFACE). +|2|bDescriptorSubType|1|0x02|FEATURE_UNIT subtype\n + (AUDGenericDescriptor_FEATUREUNIT). +|3|bUnitID|1|0x02|ID of this Feature Unit\n + (AUDDSpeakerDriverDescriptors_FEATUREUNIT). +|4|bSourceID|1|0x00|From Input Terminal\n + (AUDDSpeakerDriverDescriptors_INPUTTERMINAL). +|5|bControlSize|1|0x01|1 byte per channel for controls +|6|bmaControls|3|0x000001|Master channel mute control, no other controls. +|9|iFeature|1|0x00|Unused. + + !!AudioStreaming Interface Descriptor + The AudioStreaming interface has two possible alternate settings. + + !Zero-bandwidth Alternate Setting 0 + Alternate setting 0 is a zero-bandwidth setting, used to relinquish the + claimed bandwidth on the bus when the microphone is not in use. It is the + default setting after power-up. The zero bandwidth is implemented by + specifying that this alternate setting of the interface has no endpoints + associated with it (bNumEndpoints=0). The collection of descriptors for this + alternate setting reduces to the standard interface descriptor. + + Standard AS Interface Descriptor (USBInterfaceDescriptor) +||Offset||Field||Size||Value||Description +|0|bLength|1|0x09|Size of this descriptor, in bytes. +|1|bDescriptorType|1|0x04|INTERFACE descriptor\n + (USBGenericDescriptor_INTERFACE). +|2|bInterfaceNumber|1|0x01|Index of this interface. +|3|bAlternateSetting|1|0x00|Index of this setting. +|4|bNumEndpoints|1|0x00|0 endpoint. +|5|bInterfaceClass|1|0x01|AUDIO (AUDStreamingInterfaceDescriptor_CLASS). +|6|bInterfaceSubClass|1|0x02|AUDIO_STREAMING\n + (AUDStreamingInterfaceDescriptor_SUBCLASS). +|7|bInterfaceProtocol|1|0x00|Unused (AUDStreamingInterfaceDescriptor_PROTOCOL). +|8|iInterface|1|0x00|Unused. + + !Operational Alternate Setting 1 + Alternate setting 1 is the operational setting of the interface. It contains + the standard and class-specific interface and endpoint descriptors. + + Standard AS Interface Descriptor (USBInterfaceDescriptor) +||Offset||Field||Size||Value||Description +|0|bLength|1|0x09|Size of USBInterfaceDescriptor in bytes. +|1|bDescriptorType|1|0x04|INTERFACE descriptor\n + (USBGenericDescriptor_INTERFACE). +|2|bInterfaceNumber|1|0x01|Index of this interface. +|3|bAlternateSetting|1|0x01|Index of this setting. +|4|bNumEndpoints|1|0x01|1 endpoint. +|5|bInterfaceClass|1|0x01|AUDIO (AUDStreamingInterfaceDescriptor_CLASS). +|6|bInterfaceSubClass|1|0x02|AUDIO_STREAMING\n + (AUDStreamingInterfaceDescriptor_SUBCLASS). +|7|bInterfaceProtocol|1|0x00|Unused (AUDStreamingInterfaceDescriptor_PROTOCOL). +|8|iInterface|1|0x00|Unused. + + Class-specific AS General Interface Descriptor (AUDStreamingInterfaceDescriptor) +||Offset||Field||Size||Value||Description +|0|bLength|1|0x06|Size of AUDStreamingInterfaceDescriptor in bytes. +|1|bDescriptorType|1|0x24|CS_INTERFACE descriptor\n + (AUDGenericDescriptor_INTERFACE). +|2|bDescriptorSubType|1|0x01|GENERAL subtype\n + (AUDStreamingInterfaceDescriptor_GENERAL). +|3|bTerminalLink|1|0x02|Unit ID of the Input Terminal\n + (AUDDSpeakerDriverDescriptors_INPUTTERMINAL). +|4|bDelay|1|0x00|No interface delay. +|5|wFormatTag|2|0x0001|PCM Format (AUDFormatTypeOneDescriptor_PCM). + + Type I Format Type Descriptor (AUDFormatTypeOneDescriptor1) +||Offset||Field||Size||Value||Description +|0|bLength|1|0x0B|Size of AUDFormatTypeOneDescriptor1 in bytes. +|1|bDescriptorType|1|0x24|CS_INTERFACE descriptor\ + (AUDGenericDescriptor_INTERFACE). +|2|bDescriptorSubType|1|0x02|FORMAT_TYPE subtype\n + (AUDStreamingInterfaceDescriptor_FORMATTYPE). +|3|bFormatType|1|0x01|FORMAT_TYPE_I (AUDFormatTypeOneDescriptor_FORMATTYPEONE). +|4|bNrChannels|1|0x02|2 channels (AUDDSpeakerDriver_NUMCHANNELS). +|5|bSubFrameSize|1|0x02|Two bytes per audio subframe\n + (AUDDSpeakerDriver_BYTESPERSAMPLE). +|6|bBitResolution|1|0x10|16 bits per sample\n + (AUDDSpeakerDriver_BYTESPERSAMPLE * 2). +|7|bSamFreqType|1|0x01|One frequency supported. +|8|tSamFreq|3|4800|4800Hz (AUDDSpeakerDriver_SAMPLERATE). + + Standard %Endpoint Descriptor (AUDEndpointDescriptor) +||Offset||Field||Size||Value||Description +|0|bLength|1|0x09|Size of AUDFormatTypeOneDescriptor1 in bytes. +|1|bDescriptorType|1|0x24|ENDPOINT descriptor (USBGenericDescriptor_ENDPOINT). +|2|bEndpointAddress|1|0x04\nTest|OUT endpoint 4\n + See USBEndpointDescriptor_ADDRESS\n + See AUDDSpeakerDriverDescriptors_DATAOUT. +|3|bmAttributes|1|0x01|Isochronous, not shared\n + (USBEndpointDescriptor_ISOCHRONOUS). +|4|wMaxPacketSize|2|0x????|BOARD_USB_ENDPOINTS_MAXPACKETSIZE(). +|6|bInterval|1|0x01|One packet per frame. +|7|bRefresh|1|0x00|Unused. +|8|bSynchAddress|1|0x00|Unused. + + Class-specific Isochronous Audio Data Endpoint Descriptor + (AUDDataEndpointDescriptor) +||Offset||Field||Size||Value||Description +|0|bLength|1|0x07|Size of AUDDataEndpointDescriptor in bytes. +|1|bDescriptorType|1|0x25|CS_ENDPOINT descriptor\n + (AUDGenericDescriptor_ENDPOINT). +|2|bDescriptorSubType|1|0x01|GENERAL subtype\n + (AUDDataEndpointDescriptor_SUBTYPE). +|3|bmAttributes|1|0x00|No sampling frequency control\n + no pitch control\n + no packet padding. +|4|bLockDelayUnits|1|0x00|Unused. +|5|wLockDelay|2|0x0000|Unused. + + !!String Descriptors + There are three string descriptors available. The Manufacturer, Product and + Serial Number descriptor. + + See manufacturerDescriptor, productDescriptor, serialNumberDescriptor. + + !!!Requests + The Audio Speaker Driver supports all necessary standard requests, and some + class-specific requests. + + USBDCallbacks_RequestReceived is used to filter all requests, + AUDDSpeakerDriver_RequestHandler is invoked to handle Audio Class requests + and forward standard request to AUDDSpeakerDriver_RequestHandler. + + !!Standard requests + Set Interface request should be processed to control bandwidth allocation. + + !Set Interface + USBDDriverCallbacks_InterfaceSettingChanged is re-implemented to handle the + event. +||Offset||Field||Size||Value||Description +|0|bmRequestType|1|0x01|D7:0=Host to Device.\n + D6..5:00=Standard Request.\n + D4..0:00001=Recipient is interface. +|1|bRequest|1|0x0B|SET_INTERFACE. +|2|wValue|2|0x0000\n + or\n + 0x0001|Zero bandwidth or normal isochronous operation. +|4|wIndex|2|0x0001|Interface number of the AudioStreaming interface. +|6|wLength|2|0x0000|No Parameter Block. + + !!Class-specific requests + The only class-specific Request supported is the Set/Get Feature Unit Control + Request. For mute control of the Feature Unit. + + !Set Feature Unit Control Request +||Offset||Field||Size||Value||Description +|0|bmRequestType|1|0x01|D7:0=Host to Device.\n + D6..5:01=Class Request.\n + D4..0:00001=Recipient is interface. +|1|bRequest|1|0x01|SET_CUR. +|2|wValue|2|0x0100|Mute control (AUDFeatureUnitRequest_MUTE) of\n + Master channel (AUDDSpeakerDriver_MASTERCHANNEL). +|4|wIndex|2|0x0200|Feature Unit (AUDDSpeakerDriverDescriptors_FEATUREUNIT)\n + and\n + AudioControl Interface (AUDDSpeakerDriverDescriptors_CONTROL). +|6|wLength|2|0x0001|Paramter Block Length + + The one-byte Parameter Block contains the new bMuted value for Feature + Control. + + !Get Feature Unit Control Request +||Offset||Field||Size||Value||Description +|0|bmRequestType|1|0x01|D7:0=Host to Device.\n + D6..5:01=Class Request.\n + D4..0:00001=Recipient is interface. +|1|bRequest|1|0x81|GET_CUR. +|2|wValue|2|0x0100|Mute control (AUDFeatureUnitRequest_MUTE) of\n + Master channel (AUDDSpeakerDriver_MASTERCHANNEL). +|4|wIndex|2|0x0200|Feature Unit (AUDDSpeakerDriverDescriptors_FEATUREUNIT)\n + and\n + AudioControl Interface (AUDDSpeakerDriverDescriptors_CONTROL). +|6|wLength|2|0x0001|Paramter Block Length + + The one-byte Parameter Block contains the new bMuted value for Feature + Control. + + !!!Modify the Device Driver + You can modify your project from the USB Audio Demoes: + - usb-device-audio-speaker-ac97-project + - usb-device-audio-speaker-project + + !!Change Device ID and Display + All Device ID and Display Strings are in AUDDSpeakerDriverDescriptors.c. + + !Device IDs + You can find "Audio Speaker Device Codes" + - AUDDSpeakerDriverDescriptors_VENDORID + - AUDDSpeakerDriverDescriptors_PRODUCTID + - AUDDSpeakerDriverDescriptors_RELEASE + + !Display Strings + You can modify the string descriptors + - manufacturerDescriptor + - productDescriptor + - serialNumberDescriptor + + !!!Add Recorder Function + See "USB Audio Recorder". + +*/ + +/** + \page "USB Audio Recorder" + This page describes how to add recorder function into the + "USB Audio Speaker Device", So that you can learn how to extend your audio + device driver from current Audio Speaker demo. + + !!!Description + To add %audio record function, new Input Terminal, Output Termnial and Feature + Unit is added. + + \image UsbAudioSpeakerRecorder.png "USB Desktop Speaker Hierarchy" + + + !!!Modify the configuration descriptor: + New descriptor for the terminals and unit should be added, and according + interface, too. + + \image UsbAudioSpeakerRecorderDescriptors.png "USB Desktop Speaker Descriptors" + + + + !!Terminal Descriptors and Unit Descriptor + ... + !Input Terminal Descriptor for recording + ... +||Offset||Field||Size||Value||Description +|0|bLength|1|0x0C|Size of this descriptor, in bytes. +|1|bDescriptorType|1|0x24|CS_INTERFACE descriptor\n + (AUDGenericDescriptor_INTERFACE). +|2|bDescriptorSubType|1|0x03|INPUT_TERMINAL subtype\n + (AUDGenericDescriptor_INPUTTERMINAL). +|3|bTerminalID|1|0x03|ID of this Input Terminal\n + (AUDDSpeakerDriverDescriptors_INPUTTERMINAL_REC). +|4|wTerminalType|2|0x0403|Terminal is Speaker Phone\n + (AUDInputTerminalDescriptor_SPEAKERPHONE). +|6|bAssocTerminal|1|0x04|Associated to Output Terminal\n + (AUDDSpeakerDriverDescriptors_OUTPUTTERMINAL_REC). +|7|bNrChannels|1|0x02|Two channel. +|8|wChannelConfig|2|0x0003|Left plus right front channel. +|10|iChannelNames|1|0x00|Unused. +|11|iTerminal|1|0x00|Unused. + + !Output Terminal Descriptor for recording + ... +||Offset||Field||Size||Value||Description +|0|bLength|1|0x09|Size of this descriptor, in bytes. +|1|bDescriptorType|1|0x24|CS_INTERFACE descriptor\n + (AUDGenericDescriptor_INTERFACE). +|2|bDescriptorSubType|1|0x04|OUTPUT_TERMINAL subtype\n + (AUDGenericDescriptor_OUTPUTTERMINAL). +|3|bTerminalID|1|0x04|ID of this Output Terminal\n + (AUDDSpeakerDriverDescriptors_OUTPUTTERMINAL_REC). +|4|wTerminalType|2|0x0301|Terminal is USB stream\n + (AUDOutputTerminalDescriptor_USBTREAMING). +|6|bAssocTerminal|1|0x03|Associated to Input Terminal\n + (AUDDSpeakerDriverDescriptors_INPUTTERMINAL_REC). +|7|bSourceID|1|0x05|From Feature Unit\n + (AUDDSpeakerDriverDescriptors_FEATUREUNIT_REC). +|8|iTerminal|1|0x00|Unused. + + !Feature Unit Descriptor for recording + ... +||Offset||Field||Size||Value||Description +|0|bLength|1|0x0A|Size of this descriptor, in bytes. +|1|bDescriptorType|1|0x24|CS_INTERFACE descriptor\n + (AUDGenericDescriptor_INTERFACE). +|2|bDescriptorSubType|1|0x02|FEATURE_UNIT subtype\n + (AUDGenericDescriptor_FEATUREUNIT). +|3|bUnitID|1|0x05|ID of this Feature Unit\n + (AUDDSpeakerDriverDescriptors_FEATUREUNIT_REC). +|4|bSourceID|1|0x03|From Input Terminal\n + (AUDDSpeakerDriverDescriptors_INPUTTERMINAL_REC). +|5|bControlSize|1|0x01|1 byte per channel for controls +|6|bmaControls|3|0x000001|Master channel mute control, no other controls. +|9|iFeature|1|0x00|Unused. + + !!Interface Descriptor and Endpoint Descriptor for recording + ... + + !Zero-bandwidth Alternate Setting 0 + Standard AS Interface Descriptor (USBInterfaceDescriptor) +||Offset||Field||Size||Value||Description +|0|bLength|1|0x09|Size of this descriptor, in bytes. +|1|bDescriptorType|1|0x04|INTERFACE descriptor\n + (USBGenericDescriptor_INTERFACE). +|2|bInterfaceNumber|1|0x02|Index of this interface. +|3|bAlternateSetting|1|0x00|Index of this setting. +|4|bNumEndpoints|1|0x00|0 endpoint. +|5|bInterfaceClass|1|0x01|AUDIO (AUDStreamingInterfaceDescriptor_CLASS). +|6|bInterfaceSubClass|1|0x02|AUDIO_STREAMING\n + (AUDStreamingInterfaceDescriptor_SUBCLASS). +|7|bInterfaceProtocol|1|0x00|Unused (AUDStreamingInterfaceDescriptor_PROTOCOL). +|8|iInterface|1|0x00|Unused. + + !Operational Alternate Setting 1 + Standard AS Interface Descriptor (USBInterfaceDescriptor) +||Offset||Field||Size||Value||Description +|0|bLength|1|0x09|Size of USBInterfaceDescriptor in bytes. +|1|bDescriptorType|1|0x04|INTERFACE descriptor\n + (USBGenericDescriptor_INTERFACE). +|2|bInterfaceNumber|1|0x02|Index of this interface. +|3|bAlternateSetting|1|0x01|Index of this setting. +|4|bNumEndpoints|1|0x01|1 endpoint. +|5|bInterfaceClass|1|0x01|AUDIO (AUDStreamingInterfaceDescriptor_CLASS). +|6|bInterfaceSubClass|1|0x02|AUDIO_STREAMING\n + (AUDStreamingInterfaceDescriptor_SUBCLASS). +|7|bInterfaceProtocol|1|0x00|Unused (AUDStreamingInterfaceDescriptor_PROTOCOL). +|8|iInterface|1|0x00|Unused. + + Class-specific AS General Interface Descriptor (AUDStreamingInterfaceDescriptor) +||Offset||Field||Size||Value||Description +|0|bLength|1|0x06|Size of AUDStreamingInterfaceDescriptor in bytes. +|1|bDescriptorType|1|0x24|CS_INTERFACE descriptor\n + (AUDGenericDescriptor_INTERFACE). +|2|bDescriptorSubType|1|0x01|GENERAL subtype\n + (AUDStreamingInterfaceDescriptor_GENERAL). +|3|bTerminalLink|1|0x02|Unit ID of the Input Terminal\n + (AUDDSpeakerDriverDescriptors_INPUTTERMINAL). +|4|bDelay|1|0x00|No interface delay. +|5|wFormatTag|2|0x0001|PCM Format (AUDFormatTypeOneDescriptor_PCM). + + Type I Format Type Descriptor (AUDFormatTypeOneDescriptor1) +||Offset||Field||Size||Value||Description +|0|bLength|1|0x0B|Size of AUDFormatTypeOneDescriptor1 in bytes. +|1|bDescriptorType|1|0x24|CS_INTERFACE descriptor\n + (AUDGenericDescriptor_INTERFACE). +|2|bDescriptorSubType|1|0x02|FORMAT_TYPE subtype\n + (AUDStreamingInterfaceDescriptor_FORMATTYPE). +|3|bFormatType|1|0x01|FORMAT_TYPE_I (AUDFormatTypeOneDescriptor_FORMATTYPEONE). +|4|bNrChannels|1|0x02|2 channels (AUDDSpeakerDriver_NUMCHANNELS). +|5|bSubFrameSize|1|0x02|Two bytes per audio subframe\n + (AUDDSpeakerDriver_BYTESPERSAMPLE). +|6|bBitResolution|1|0x10|16 bits per sample\n + (AUDDSpeakerDriver_BYTESPERSAMPLE * 2). +|7|bSamFreqType|1|0x01|One frequency supported. +|8|tSamFreq|3|4800|4800Hz (AUDDSpeakerDriver_SAMPLERATE). + + Standard %Endpoint Descriptor (AUDEndpointDescriptor) +||Offset||Field||Size||Value||Description +|0|bLength|1|0x09|Size of AUDFormatTypeOneDescriptor1 in bytes. +|1|bDescriptorType|1|0x24|ENDPOINT descriptor (USBGenericDescriptor_ENDPOINT). +|2|bEndpointAddress|1|0x85|IN endpoint 5\n + USBEndpointDescriptor_ADDRESS()\n + AUDDSpeakerDriverDescriptors_DATAIN +|3|bmAttributes|1|0x01|Isochronous, not shared\n + (USBEndpointDescriptor_ISOCHRONOUS). +|4|wMaxPacketSize|2|0x????|BOARD_USB_ENDPOINTS_MAXPACKETSIZE(5). +|6|bInterval|1|0x01|One packet per frame. +|7|bRefresh|1|0x00|Unused. +|8|bSynchAddress|1|0x00|Unused. + + Class-specific Isochronous Audio Data Endpoint Descriptor + (AUDDataEndpointDescriptor) +||Offset||Field||Size||Value||Description +|0|bLength|1|0x07|Size of AUDDataEndpointDescriptor in bytes. +|1|bDescriptorType|1|0x25|CS_ENDPOINT descriptor\n + (AUDGenericDescriptor_ENDPOINT). +|2|bDescriptorSubType|1|0x01|GENERAL subtype\n + (AUDDataEndpointDescriptor_SUBTYPE). +|3|bmAttributes|1|0x00|No sampling frequency control\n + no pitch control\n + no packet padding +|4|bLockDelayUnits|1|0x00|Unused. +|5|wLockDelay|2|0x0000|Unused. + + !!!Modified methods for new function + Several methods modified for new recorder function. + + !!Request handlers callbacks + Add handler for new Interface, Terminal and Unit IDs. + See AUDDSpeakerDriver_RequestHandler. + + !!Add function for recording USB stream + See AUDDSpeakerDriver_Write. +*/ diff --git a/usb/device/ccid/cciddriver.c b/usb/device/ccid/cciddriver.c new file mode 100644 index 0000000..d72b4ab --- /dev/null +++ b/usb/device/ccid/cciddriver.c @@ -0,0 +1,1503 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !Purpose +/// +/// CCID driver +/// +/// !Usage +/// +/// Explanation on the usage of the code made available through the header file. +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Local definition +//------------------------------------------------------------------------------ + +/// Constants: IDs: Device product ID. +#define CCIDDriverDescriptors_PRODUCTID 0x6129 +/// Constants: IDs: Device vendor ID. +#define CCIDDriverDescriptors_VENDORID 0x03EB +/// Constants: IDs: Device release number. +#define CCIDDriverDescriptors_RELEASE 0x0100 + +/// Returns the minimum between two values. +#define MIN(a, b) ((a < b) ? a : b) + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +/// CCIDDriverConfiguration Descriptors +/// List of descriptors that make up the configuration descriptors of a +/// device using the CCID driver. +typedef struct { + + /// Configuration descriptor + USBConfigurationDescriptor configuration; + /// Interface descriptor + USBInterfaceDescriptor interface; + /// CCID descriptor + CCIDDescriptor ccid; + /// Bulk OUT endpoint descriptor + USBEndpointDescriptor bulkOut; + /// Bulk IN endpoint descriptor + USBEndpointDescriptor bulkIn; + /// Interrupt OUT endpoint descriptor + USBEndpointDescriptor interruptIn; + +} __attribute__ ((packed)) CCIDDriverConfigurationDescriptors; + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +/// Driver structure for an CCID device +typedef struct { + + /// Standard USB device driver instance + USBDDriver usbdDriver; + /// CCID message + S_ccid_bulk_in_header sCcidMessage; + /// CCID command + S_ccid_bulk_out_header sCcidCommand; + /// Interrupt message answer + unsigned char BufferINT[4]; + /// Buffer data of message + unsigned char ProtocolDataStructure[10]; + /// Protocol used + unsigned char bProtocol; + /// SlotStatus + /// Bit 0 = Slot 0 current state + /// Bit 1 = Slot 0 changed status + /// Bit 2 = Slot 1 current state + /// Bit 3 = Slot 1 changed status + /// Bit 4 = Slot 2 current state + /// Bit 5 = Slot 2 changed status + unsigned char SlotStatus; + +} CCIDDriver; + +//------------------------------------------------------------------------------ +// Local variables +//------------------------------------------------------------------------------ + +/// Static instance of the CCID device driver. +static CCIDDriver ccidDriver; + +/// Standard USB device descriptor. +static const USBDeviceDescriptor deviceDescriptor = { + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + 0, + 0, + 0, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + CCIDDriverDescriptors_VENDORID, + CCIDDriverDescriptors_PRODUCTID, + CCIDDriverDescriptors_RELEASE, + 1, // Index of manufacturer description + 2, // Index of product description + 3, // Index of serial number description + 1 // One possible configuration +}; + + +/// List of configuration descriptors. +static const CCIDDriverConfigurationDescriptors configurationDescriptorsFS = { + + // Standard USB configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(CCIDDriverConfigurationDescriptors), + 1, // One interface in this configuration + 1, // This is configuration #1 + 0, // No associated string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + // CCID interface descriptor + // Table 4.3-1 Interface Descriptor + // Interface descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // Interface 0 + 0, // No alternate settings + 3, // uses bulk-IN, bulk-OUT and interrupt–IN + SMART_CARD_DEVICE_CLASS, + 0, // Subclass code + 0, // bulk transfers optional interrupt-IN + 0 // No associated string descriptor + }, + { + sizeof(CCIDDescriptor), // bLength: Size of this descriptor in bytes + CCID_DECRIPTOR_TYPE, // bDescriptorType:Functional descriptor type + CCID1_10, // bcdCCID: CCID version + 0, // bMaxSlotIndex: Value 0 indicates that one slot is supported + VOLTS_5_0, // bVoltageSupport + PROTOCOL_TO, // dwProtocols + 3580, // dwDefaultClock + 3580, // dwMaxClock + 0, // bNumClockSupported + 9600, // dwDataRate : 9600 bauds + 9600, // dwMaxDataRate : 9600 bauds + 0, // bNumDataRatesSupported + 0xfe, // dwMaxIFSD + 0, // dwSynchProtocols + 0, // dwMechanical + //0x00010042, // dwFeatures: Short APDU level exchanges + CCID_FEATURES_AUTO_PCONF | CCID_FEATURES_AUTO_PNEGO | CCID_FEATURES_EXC_TPDU, + 0x0000010F, // dwMaxCCIDMessageLength: For extended APDU level the value shall be between 261 + 10 + 0xFF, // bClassGetResponse: Echoes the class of the APDU + 0xFF, // bClassEnvelope: Echoes the class of the APDU + 0, // wLcdLayout: no LCD + 0, // bPINSupport: No PIN + 1 // bMaxCCIDBusySlot + }, + // Bulk-OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_OUT, CCID_EPT_DATA_OUT ), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_DATA_OUT), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0x00 // Does not apply to Bulk endpoints + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_IN, CCID_EPT_DATA_IN ), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_DATA_IN), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0x00 // Does not apply to Bulk endpoints + }, + // Notification endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_IN, CCID_EPT_NOTIFICATION ), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_NOTIFICATION), + USBEndpointDescriptor_MAXINTERRUPTSIZE_FS), + 0x10 + } +}; + +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) +static const CCIDDriverConfigurationDescriptors configurationDescriptorsHS = { + + // Standard USB configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(CCIDDriverConfigurationDescriptors), + 1, // One interface in this configuration + 1, // This is configuration #1 + 0, // No associated string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + // CCID interface descriptor + // Table 4.3-1 Interface Descriptor + // Interface descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // Interface 0 + 0, // No alternate settings + 3, // uses bulk-IN, bulk-OUT and interrupt–IN + SMART_CARD_DEVICE_CLASS, + 0, // Subclass code + 0, // bulk transfers optional interrupt-IN + 0 // No associated string descriptor + }, + { + sizeof(CCIDDescriptor), // bLength: Size of this descriptor in bytes + CCID_DECRIPTOR_TYPE, // bDescriptorType:Functional descriptor type + CCID1_10, // bcdCCID: CCID version + 0, // bMaxSlotIndex: Value 0 indicates that one slot is supported + VOLTS_5_0, // bVoltageSupport + PROTOCOL_TO, // dwProtocols + 3580, // dwDefaultClock + 3580, // dwMaxClock + 0, // bNumClockSupported + 9600, // dwDataRate : 9600 bauds + 9600, // dwMaxDataRate : 9600 bauds + 0, // bNumDataRatesSupported + 0xfe, // dwMaxIFSD + 0, // dwSynchProtocols + 0, // dwMechanical + //0x00010042, // dwFeatures: Short APDU level exchanges + CCID_FEATURES_AUTO_PCONF | CCID_FEATURES_AUTO_PNEGO | CCID_FEATURES_EXC_TPDU, + 0x0000010F, // dwMaxCCIDMessageLength: For extended APDU level the value shall be between 261 + 10 + 0xFF, // bClassGetResponse: Echoes the class of the APDU + 0xFF, // bClassEnvelope: Echoes the class of the APDU + 0, // wLcdLayout: no LCD + 0, // bPINSupport: No PIN + 1 // bMaxCCIDBusySlot + }, + // Bulk-OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_OUT, CCID_EPT_DATA_OUT ), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_DATA_OUT), + USBEndpointDescriptor_MAXBULKSIZE_HS), + 0x00 // Does not apply to Bulk endpoints + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_IN, CCID_EPT_DATA_IN ), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_DATA_IN), + USBEndpointDescriptor_MAXBULKSIZE_HS), + 0x00 // Does not apply to Bulk endpoints + }, + // Notification endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_IN, CCID_EPT_NOTIFICATION ), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_NOTIFICATION), + USBEndpointDescriptor_MAXINTERRUPTSIZE_HS), + 0x10 + } +}; + +/// Qualifier descriptor +const USBDeviceQualifierDescriptor deviceQualifierDescriptor = { + + sizeof(USBDeviceQualifierDescriptor), // Size of this descriptor in bytes + USBGenericDescriptor_DEVICEQUALIFIER, // Qualifier Descriptor Type + USBDeviceDescriptor_USB2_00, // USB specification 2.00 + 0x00, // Class is specified in interface + 0x00, // Subclass is specified in interface + 0x00, // Protocol is specified in interface + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + 0x01, // One possible configuration + 0x00 // Reserved for future use, must be zero +}; + +/// OtherSpeed configuration descriptor in Full Speed mode +static const CCIDDriverConfigurationDescriptors sOtherSpeedConfigurationFS = { + + // Standard USB configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_OTHERSPEEDCONFIGURATION, + sizeof(CCIDDriverConfigurationDescriptors), + 1, // One interface in this configuration + 1, // This is configuration #1 + 0, // No associated string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + // CCID interface descriptor + // Table 4.3-1 Interface Descriptor + // Interface descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // Interface 0 + 0, // No alternate settings + 3, // uses bulk-IN, bulk-OUT and interrupt–IN + SMART_CARD_DEVICE_CLASS, + 0, // Subclass code + 0, // bulk transfers optional interrupt-IN + 0 // No associated string descriptor + }, + { + sizeof(CCIDDescriptor), // bLength: Size of this descriptor in bytes + CCID_DECRIPTOR_TYPE, // bDescriptorType:Functional descriptor type + CCID1_10, // bcdCCID: CCID version + 0, // bMaxSlotIndex: Value 0 indicates that one slot is supported + VOLTS_5_0, // bVoltageSupport + PROTOCOL_TO, // dwProtocols + 3580, // dwDefaultClock + 3580, // dwMaxClock + 0, // bNumClockSupported + 9600, // dwDataRate : 9600 bauds + 9600, // dwMaxDataRate : 9600 bauds + 0, // bNumDataRatesSupported + 0xfe, // dwMaxIFSD + 0, // dwSynchProtocols + 0, // dwMechanical + //0x00010042, // dwFeatures: Short APDU level exchanges + CCID_FEATURES_AUTO_PCONF | CCID_FEATURES_AUTO_PNEGO | CCID_FEATURES_EXC_TPDU, + 0x0000010F, // dwMaxCCIDMessageLength: For extended APDU level the value shall be between 261 + 10 + 0xFF, // bClassGetResponse: Echoes the class of the APDU + 0xFF, // bClassEnvelope: Echoes the class of the APDU + 0, // wLcdLayout: no LCD + 0, // bPINSupport: No PIN + 1 // bMaxCCIDBusySlot + }, + // Bulk-OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_OUT, CCID_EPT_DATA_OUT ), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_DATA_OUT), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0x00 // Does not apply to Bulk endpoints + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_IN, CCID_EPT_DATA_IN ), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_DATA_IN), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0x00 // Does not apply to Bulk endpoints + }, + // Notification endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_IN, CCID_EPT_NOTIFICATION ), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_NOTIFICATION), + USBEndpointDescriptor_MAXINTERRUPTSIZE_FS), + 0x10 + } +}; + +/// OtherSpeed configuration descriptor in High Speed mode +static const CCIDDriverConfigurationDescriptors sOtherSpeedConfigurationHS = { + + // Standard USB configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_OTHERSPEEDCONFIGURATION, + sizeof(CCIDDriverConfigurationDescriptors), + 1, // One interface in this configuration + 1, // This is configuration #1 + 0, // No associated string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + // CCID interface descriptor + // Table 4.3-1 Interface Descriptor + // Interface descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // Interface 0 + 0, // No alternate settings + 3, // uses bulk-IN, bulk-OUT and interrupt–IN + SMART_CARD_DEVICE_CLASS, + 0, // Subclass code + 0, // bulk transfers optional interrupt-IN + 0 // No associated string descriptor + }, + { + sizeof(CCIDDescriptor), // bLength: Size of this descriptor in bytes + CCID_DECRIPTOR_TYPE, // bDescriptorType:Functional descriptor type + CCID1_10, // bcdCCID: CCID version + 0, // bMaxSlotIndex: Value 0 indicates that one slot is supported + VOLTS_5_0, // bVoltageSupport + PROTOCOL_TO, // dwProtocols + 3580, // dwDefaultClock + 3580, // dwMaxClock + 0, // bNumClockSupported + 9600, // dwDataRate : 9600 bauds + 9600, // dwMaxDataRate : 9600 bauds + 0, // bNumDataRatesSupported + 0xfe, // dwMaxIFSD + 0, // dwSynchProtocols + 0, // dwMechanical + //0x00010042, // dwFeatures: Short APDU level exchanges + CCID_FEATURES_AUTO_PCONF | CCID_FEATURES_AUTO_PNEGO | CCID_FEATURES_EXC_TPDU, + 0x0000010F, // dwMaxCCIDMessageLength: For extended APDU level the value shall be between 261 + 10 + 0xFF, // bClassGetResponse: Echoes the class of the APDU + 0xFF, // bClassEnvelope: Echoes the class of the APDU + 0, // wLcdLayout: no LCD + 0, // bPINSupport: No PIN + 1 // bMaxCCIDBusySlot + }, + // Bulk-OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_OUT, CCID_EPT_DATA_OUT ), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_DATA_OUT), + USBEndpointDescriptor_MAXBULKSIZE_HS), + 0x00 // Does not apply to Bulk endpoints + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_IN, CCID_EPT_DATA_IN ), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_DATA_IN), + USBEndpointDescriptor_MAXBULKSIZE_HS), + 0x00 // Does not apply to Bulk endpoints + }, + // Notification endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( USBEndpointDescriptor_IN, CCID_EPT_NOTIFICATION ), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CCID_EPT_NOTIFICATION), + USBEndpointDescriptor_MAXINTERRUPTSIZE_HS), + 0x10 + } +}; +#endif + +/// Language ID string descriptor. +static const unsigned char languageIdDescriptor[] = { + + USBStringDescriptor_LENGTH(1), + USBGenericDescriptor_STRING, + USBStringDescriptor_ENGLISH_US +}; + +/// Manufacturer name. +static const unsigned char manufacturerDescriptor[] = { + + USBStringDescriptor_LENGTH(5), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('M'), + USBStringDescriptor_UNICODE('E'), + USBStringDescriptor_UNICODE('L') +}; + +/// Product name. +static const unsigned char productDescriptor[] = { + + USBStringDescriptor_LENGTH(23), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('M'), + USBStringDescriptor_UNICODE('E'), + USBStringDescriptor_UNICODE('L'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('9'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('C'), + USBStringDescriptor_UNICODE('C'), + USBStringDescriptor_UNICODE('I'), + USBStringDescriptor_UNICODE('D'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('D'), + USBStringDescriptor_UNICODE('R'), + USBStringDescriptor_UNICODE('I'), + USBStringDescriptor_UNICODE('V'), + USBStringDescriptor_UNICODE('E'), + USBStringDescriptor_UNICODE('R'), + USBStringDescriptor_UNICODE(' ') +}; + +/// Product serial number. +static const unsigned char serialNumberDescriptor[] = { + + USBStringDescriptor_LENGTH(12), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('0'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE('2'), + USBStringDescriptor_UNICODE('3'), + USBStringDescriptor_UNICODE('4'), + USBStringDescriptor_UNICODE('5'), + USBStringDescriptor_UNICODE('6'), + USBStringDescriptor_UNICODE('7'), + USBStringDescriptor_UNICODE('8'), + USBStringDescriptor_UNICODE('9'), + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('F') +}; + +/// Array of pointers to string descriptors. +static const unsigned char *stringDescriptors[] = { + + languageIdDescriptor, + manufacturerDescriptor, + productDescriptor, + serialNumberDescriptor +}; + + +/// List of standard descriptors for the serial driver. +const USBDDriverDescriptors ccidDriverDescriptors = { + + &deviceDescriptor, // FS + (USBConfigurationDescriptor *) &configurationDescriptorsFS, +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + (USBDeviceQualifierDescriptor *) &deviceQualifierDescriptor, // FS + (USBConfigurationDescriptor *) &sOtherSpeedConfigurationFS, + &deviceDescriptor, // HS + (USBConfigurationDescriptor *) &configurationDescriptorsHS, + (USBDeviceQualifierDescriptor *) &deviceQualifierDescriptor, // HS + (USBConfigurationDescriptor *) &sOtherSpeedConfigurationHS, +#else + 0, // No qualifier descriptor FS + 0, // No other-speed configuration FS + 0, // No device descriptor HS + 0, // No configuration HS + 0, // No qualifier descriptor HS + 0, // No other-speed configuration HS +#endif + stringDescriptors, + 4 // Four string descriptors in array +}; + +//------------------------------------------------------------------------------ +// Internal functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Response Pipe, Bulk-IN Messages +/// Return the Slot Status to the host +/// Answer to: +/// PC_to_RDR_IccPowerOff +/// PC_to_RDR_GetSlotStatus +/// PC_to_RDR_IccClock +/// PC_to_RDR_T0APDU +/// PC_to_RDR_Mechanical +/// PC_to_RDR_Abort and Class specific ABORT request +//------------------------------------------------------------------------------ +static void RDRtoPCSlotStatus( void ) +{ + TRACE_DEBUG("RDRtoPCSlotStatus\n\r"); + + // Header fields settings + ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_SLOTSTATUS; + ccidDriver.sCcidMessage.wLength = 0; + ccidDriver.sCcidMessage.bStatus = ccidDriver.SlotStatus; + ccidDriver.sCcidMessage.bError = 0; + // 00h Clock running + // 01h Clock stopped in state L + // 02h Clock stopped in state H + // 03h Clock stopped in an unknown state + // All other values are Reserved for Future Use. + ccidDriver.sCcidMessage.bSpecific = 0; +} + +//------------------------------------------------------------------------------ +/// Response Pipe, Bulk-IN Messages +/// Answer to PC_to_RDR_IccPowerOn +//------------------------------------------------------------------------------ +static void RDRtoPCDatablock_ATR( void ) +{ + unsigned char i; + unsigned char Atr[ATR_SIZE_MAX]; + unsigned char length; + + //TRACE_DEBUG("RDRtoPCDatablock\n\r"); + + ISO7816_Datablock_ATR( Atr, &length ); + + if( length > 5 ) { + ccidDriver.ProtocolDataStructure[1] = Atr[5]&0x0F; // TD(1) + ccidDriver.bProtocol = Atr[5]&0x0F; // TD(1) + } + + // S_ccid_protocol_t0 + // bmFindexDindex + ccidDriver.ProtocolDataStructure[0] = Atr[2]; // TA(1) + + // bmTCCKST0 + // For T=0 ,B0 – 0b, B7-2 – 000000b + // B1 – Convention used (b1=0 for direct, b1=1 for inverse) + + // bGuardTimeT0 + // Extra Guardtime between two characters. Add 0 to 254 etu to the normal + // guardtime of 12etu. FFh is the same as 00h. + ccidDriver.ProtocolDataStructure[2] = Atr[4]; // TC(1) + // AT91C_BASE_US0->US_TTGR = 0; // TC1 + + // bWaitingIntegerT0 + // WI for T=0 used to define WWT + ccidDriver.ProtocolDataStructure[3] = Atr[7]; // TC(2) + + // bClockStop + // ICC Clock Stop Support + // 00 = Stopping the Clock is not allowed + // 01 = Stop with Clock signal Low + // 02 = Stop with Clock signal High + // 03 = Stop with Clock either High or Low + ccidDriver.ProtocolDataStructure[4] = 0x00; // 0 to 3 + + // Header fields settings + ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_DATABLOCK; + ccidDriver.sCcidMessage.wLength = length; // Size of ATR + ccidDriver.sCcidMessage.bSizeToSend += length; // Size of ATR + // bChainParameter: 00 the response APDU begins and ends in this command + ccidDriver.sCcidMessage.bSpecific = 0; + + for( i=0; i (configurationDescriptorsFS.ccid.dwMaxCCIDMessageLength-10) ) { + + ccidDriver.sCcidMessage.bStatus = 1; + ccidDriver.sCcidMessage.bError = 0; + } + // check bBWI + else if ( 0 != ccidDriver.sCcidCommand.bSpecific_0 ) { + + TRACE_ERROR("Bad bBWI\n\r"); + } + else { + + // APDU or TPDU + switch(configurationDescriptorsFS.ccid.dwFeatures + & (CCID_FEATURES_EXC_TPDU|CCID_FEATURES_EXC_SAPDU|CCID_FEATURES_EXC_APDU)) { + + case CCID_FEATURES_EXC_TPDU: + if (ccidDriver.ProtocolDataStructure[1] == PROTOCOL_TO) { + + // Send commande APDU + indexMessage = ISO7816_XfrBlockTPDU_T0( ccidDriver.sCcidCommand.APDU , + ccidDriver.sCcidMessage.abData, + ccidDriver.sCcidCommand.wLength ); + } + else { + if (ccidDriver.ProtocolDataStructure[1] == PROTOCOL_T1) { + TRACE_INFO("Not supported T=1\n\r"); + } + else { + TRACE_INFO("Not supported\n\r"); + } + } + break; + + case CCID_FEATURES_EXC_APDU: + TRACE_INFO("Not supported\n\r"); + break; + + default: + break; + } + + } + + ccidDriver.sCcidMessage.wLength = indexMessage; + TRACE_DEBUG("USB: 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n\r", ccidDriver.sCcidMessage.abData[0], + ccidDriver.sCcidMessage.abData[1], + ccidDriver.sCcidMessage.abData[2], + ccidDriver.sCcidMessage.abData[3], + ccidDriver.sCcidMessage.abData[4] ); + RDRtoPCDatablock(); + +} + +//------------------------------------------------------------------------------ +/// Command Pipe, Bulk-OUT Messages +/// return parameters by the command: RDR_to_PC_Parameters +//------------------------------------------------------------------------------ +static void PCtoRDRGetParameters( void ) +{ + TRACE_DEBUG("PCtoRDRGetParameters\n\r"); + + // We support only one slot + + // bmIccStatus + if( ISO7816_StatusReset() ) { + // 0: An ICC is present and active (power is on and stable, RST is inactive + ccidDriver.sCcidMessage.bStatus = 0; + } + else { + // 1: An ICC is present and inactive (not activated or shut down by hardware error) + ccidDriver.sCcidMessage.bStatus = 1; + } + + RDRtoPCParameters(); +} + +//------------------------------------------------------------------------------ +/// Command Pipe, Bulk-OUT Messages +/// This command resets the slot parameters to their default values +//------------------------------------------------------------------------------ +static void PCtoRDRResetParameters( void ) +{ + TRACE_DEBUG("PCtoRDRResetParameters\n\r"); + + ccidDriver.SlotStatus = ICC_NOT_PRESENT; + ccidDriver.sCcidMessage.bStatus = ccidDriver.SlotStatus; + + RDRtoPCParameters(); +} + +//------------------------------------------------------------------------------ +/// Command Pipe, Bulk-OUT Messages +/// This command is used to change the parameters for a given slot. +//------------------------------------------------------------------------------ +static void PCtoRDRSetParameters( void ) +{ + TRACE_DEBUG("PCtoRDRSetParameters\n\r"); + + ccidDriver.SlotStatus = ccidDriver.sCcidCommand.bSlot; + ccidDriver.sCcidMessage.bStatus = ccidDriver.SlotStatus; + // Not all feature supported + + RDRtoPCParameters(); +} + +//------------------------------------------------------------------------------ +/// Command Pipe, Bulk-OUT Messages +/// This command allows the CCID manufacturer to define and access extended +/// features. +/// Information sent via this command is processed by the CCID control logic. +//------------------------------------------------------------------------------ +static void PCtoRDREscape( void ) +{ + TRACE_DEBUG("PCtoRDREscape\n\r"); + + // If needed by the user + ISO7816_Escape(); + + // stub, return all value send + RDRtoPCEscape( ccidDriver.sCcidCommand.wLength, ccidDriver.sCcidCommand.APDU); +} + +//------------------------------------------------------------------------------ +/// Command Pipe, Bulk-OUT Messages +/// This command stops or restarts the clock. +//------------------------------------------------------------------------------ +static void PCtoRDRICCClock( void ) +{ + TRACE_DEBUG("PCtoRDRICCClock\n\r"); + + if( 0 == ccidDriver.sCcidCommand.bSpecific_0 ) { + // restarts the clock + ISO7816_RestartClock(); + } + else { + // stop clock in the state shown in the bClockStop field + ISO7816_StopClock(); + } + + RDRtoPCSlotStatus( ); +} + +//------------------------------------------------------------------------------ +/// Command Pipe, Bulk-OUT Messages +/// This command changes the parameters used to perform the transportation of +/// APDU messages by the T=0 protocol. +//------------------------------------------------------------------------------ +static void PCtoRDRtoAPDU( void ) +{ + unsigned char bmChanges; + unsigned char bClassGetResponse; + unsigned char bClassEnvelope; + + TRACE_DEBUG("PCtoRDRtoAPDU\n\r"); + + if( configurationDescriptorsFS.ccid.dwFeatures == (CCID_FEATURES_EXC_SAPDU|CCID_FEATURES_EXC_APDU) ) { + + bmChanges = ccidDriver.sCcidCommand.bSpecific_0; + bClassGetResponse = ccidDriver.sCcidCommand.bSpecific_1; + bClassEnvelope = ccidDriver.sCcidCommand.bSpecific_2; + + ISO7816_toAPDU(); + } + + RDRtoPCSlotStatus(); +} + +//------------------------------------------------------------------------------ +/// Command Pipe, Bulk-OUT Messages +/// This is a command message to allow entering the PIN for verification or +/// modification. +//------------------------------------------------------------------------------ +static void PCtoRDRSecure( void ) +{ + TRACE_DEBUG("PCtoRDRSecure\n\r"); + + TRACE_DEBUG("For user\n\r"); +} + +//------------------------------------------------------------------------------ +/// Command Pipe, Bulk-OUT Messages +/// This command is used to manage motorized type CCID functionality. +/// The Lock Card function is used to hold the ICC. +/// This prevents an ICC from being easily removed from the CCID. +/// The Unlock Card function is used to remove the hold initiated by the Lock +/// Card function +//------------------------------------------------------------------------------ +static void PCtoRDRMechanical( void ) +{ + TRACE_DEBUG("PCtoRDRMechanical\n\r"); + TRACE_DEBUG("Not implemented\n\r"); + + RDRtoPCSlotStatus(); +} + +//------------------------------------------------------------------------------ +/// Command Pipe, Bulk-OUT Messages +/// This command is used with the Control pipe Abort request to tell the CCID +/// to stop any current transfer at the specified slot and return to a state +/// where the slot is ready to accept a new command pipe Bulk-OUT message. +//------------------------------------------------------------------------------ +static void PCtoRDRAbort( void ) +{ + TRACE_DEBUG("PCtoRDRAbort\n\r"); + + RDRtoPCSlotStatus(); +} + +//------------------------------------------------------------------------------ +/// Command Pipe, Bulk-OUT Messages +/// This command is used to manually set the data rate and clock frequency of +/// a specific slot. +//------------------------------------------------------------------------------ +static void PCtoRDRSetDataRateAndClockFrequency( void ) +{ + unsigned int dwClockFrequency; + unsigned int dwDataRate; + + TRACE_DEBUG("PCtoRDRSetDatarateandClockFrequency\n\r"); + + dwClockFrequency = ccidDriver.sCcidCommand.APDU[0] + + (ccidDriver.sCcidCommand.APDU[1]<<8) + + (ccidDriver.sCcidCommand.APDU[2]<<16) + + (ccidDriver.sCcidCommand.APDU[3]<<24); + + dwDataRate = ccidDriver.sCcidCommand.APDU[4] + + (ccidDriver.sCcidCommand.APDU[5]<<8) + + (ccidDriver.sCcidCommand.APDU[6]<<16) + + (ccidDriver.sCcidCommand.APDU[7]<<24); + + ISO7816_SetDataRateandClockFrequency( dwClockFrequency, dwDataRate ); + + RDRtoPCDataRateAndClockFrequency( dwClockFrequency, dwDataRate ); + +} + +//------------------------------------------------------------------------------ +/// Report the CMD_NOT_SUPPORTED error to the host +//------------------------------------------------------------------------------ +static void vCCIDCommandNotSupported( void ) +{ + // Command not supported + // vCCIDReportError(CMD_NOT_SUPPORTED); + + TRACE_DEBUG("CMD_NOT_SUPPORTED\n\r"); + + // Header fields settings + ccidDriver.sCcidMessage.bMessageType = RDR_TO_PC_SLOTSTATUS; + ccidDriver.sCcidMessage.wLength = 0; + ccidDriver.sCcidMessage.bSpecific = 0; + + ccidDriver.sCcidMessage.bStatus |= ICC_CS_FAILED; + + // Send the response to the host + //vCCIDSendResponse(); +} + +//------------------------------------------------------------------------------ +/// Sent CCID response on USB +//------------------------------------------------------------------------------ +static void vCCIDSendResponse( void ) +{ + unsigned char bStatus; + + do { + bStatus = USBD_Write( CCID_EPT_DATA_IN, (void*)&ccidDriver.sCcidMessage, + ccidDriver.sCcidMessage.bSizeToSend, 0, 0 ); + } + while (bStatus != USBD_STATUS_SUCCESS); +} + + +//------------------------------------------------------------------------------ +/// Description: CCID Command dispatcher +//------------------------------------------------------------------------------ +static void CCIDCommandDispatcher( void ) +{ + unsigned char MessageToSend = 0; + + //TRACE_DEBUG("Command: 0x%X 0x%x 0x%X 0x%X 0x%X 0x%X 0x%X\n\r\n\r", + // (unsigned int)ccidDriver.sCcidCommand.bMessageType, + // (unsigned int)ccidDriver.sCcidCommand.wLength, + // (unsigned int)ccidDriver.sCcidCommand.bSlot, + // (unsigned int)ccidDriver.sCcidCommand.bSeq, + // (unsigned int)ccidDriver.sCcidCommand.bSpecific_0, + // (unsigned int)ccidDriver.sCcidCommand.bSpecific_1, + // (unsigned int)ccidDriver.sCcidCommand.bSpecific_2); + + // Check the slot number + if ( ccidDriver.sCcidCommand.bSlot > 0 ) { + + TRACE_ERROR("BAD_SLOT_NUMBER\n\r"); + } + + TRACE_DEBUG("typ=0x%X\n\r", ccidDriver.sCcidCommand.bMessageType); + + ccidDriver.sCcidMessage.bStatus = 0; + + ccidDriver.sCcidMessage.bSeq = ccidDriver.sCcidCommand.bSeq; + ccidDriver.sCcidMessage.bSlot = ccidDriver.sCcidCommand.bSlot; + + ccidDriver.sCcidMessage.bSizeToSend = sizeof(S_ccid_bulk_in_header)-(ABDATA_SIZE+1); + + + // Command dispatcher + switch ( ccidDriver.sCcidCommand.bMessageType ) { + + case PC_TO_RDR_ICCPOWERON: + PCtoRDRIccPowerOn(); + MessageToSend = 1; + break; + + case PC_TO_RDR_ICCPOWEROFF: + PCtoRDRIccPowerOff(); + MessageToSend = 1; + break; + + case PC_TO_RDR_GETSLOTSTATUS: + PCtoRDRGetSlotStatus(); + MessageToSend = 1; + break; + + case PC_TO_RDR_XFRBLOCK: + PCtoRDRXfrBlock(); + MessageToSend = 1; + break; + + case PC_TO_RDR_GETPARAMETERS: + PCtoRDRGetParameters(); + MessageToSend = 1; + break; + + case PC_TO_RDR_RESETPARAMETERS: + PCtoRDRResetParameters(); + MessageToSend = 1; + break; + + case PC_TO_RDR_SETPARAMETERS: + PCtoRDRSetParameters(); + MessageToSend = 1; + break; + + case PC_TO_RDR_ESCAPE: + PCtoRDREscape(); + MessageToSend = 1; + break; + + case PC_TO_RDR_ICCCLOCK: + PCtoRDRICCClock(); + MessageToSend = 1; + break; + + case PC_TO_RDR_T0APDU: + // Only CCIDs reporting a short or extended APDU level in the dwFeatures + // field of the CCID class descriptor may take this command into account. + if( (CCID_FEATURES_EXC_SAPDU == (CCID_FEATURES_EXC_SAPDU&configurationDescriptorsFS.ccid.dwFeatures)) + || (CCID_FEATURES_EXC_APDU == (CCID_FEATURES_EXC_APDU &configurationDescriptorsFS.ccid.dwFeatures)) ) { + + // command supported + PCtoRDRtoAPDU(); + } + else { + // command not supported + TRACE_DEBUG("PC_TO_RDR_T0APDU\n\r"); + vCCIDCommandNotSupported(); + } + MessageToSend = 1; + break; + + case PC_TO_RDR_SECURE: + PCtoRDRSecure(); + MessageToSend = 1; + break; + + case PC_TO_RDR_MECHANICAL: + PCtoRDRMechanical(); + MessageToSend = 1; + break; + + case PC_TO_RDR_ABORT: + PCtoRDRAbort(); + MessageToSend = 1; + break; + + case PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY: + PCtoRDRSetDataRateAndClockFrequency(); + MessageToSend = 1; + break; + + default: + TRACE_DEBUG("default: 0x%X\n\r", ccidDriver.sCcidCommand.bMessageType); + vCCIDCommandNotSupported(); + MessageToSend = 1; + break; + + } + + if( MessageToSend == 1 ) { + vCCIDSendResponse(); + } +} + + +//------------------------------------------------------------------------------ +/// SETUP request handler for a CCID device +/// \param pRequest Pointer to a USBGenericRequest instance +//------------------------------------------------------------------------------ +static void CCID_RequestHandler(const USBGenericRequest *pRequest) +{ + TRACE_DEBUG("CCID_RHl\n\r"); + + // Check if this is a class request + if (USBGenericRequest_GetType(pRequest) == USBGenericRequest_CLASS) { + + // Check if the request is supported + switch (USBGenericRequest_GetRequest(pRequest)) { + + case CCIDGenericRequest_ABORT: + TRACE_DEBUG("CCIDGenericRequest_ABORT\n\r"); + break; + + case CCIDGenericRequest_GET_CLOCK_FREQUENCIES: + TRACE_DEBUG("Not supported\n\r"); + // A CCID with bNumClockSupported equal to 00h does not have + // to support this request + break; + + case CCIDGenericRequest_GET_DATA_RATES: + TRACE_DEBUG("Not supported\n\r"); + // A CCID with bNumDataRatesSupported equal to 00h does not have + // to support this request. + break; + + default: + TRACE_WARNING( "CCIDDriver_RequestHandler: Unsupported request (%d)\n\r", + USBGenericRequest_GetRequest(pRequest)); + USBD_Stall(0); + } + } + + else if (USBGenericRequest_GetType(pRequest) == USBGenericRequest_STANDARD) { + + // Forward request to the standard handler + USBDDriver_RequestHandler(&(ccidDriver.usbdDriver), pRequest); + } + else { + + // Unsupported request type + TRACE_WARNING( "CCIDDriver_RequestHandler: Unsupported request type (%d)\n\r", + USBGenericRequest_GetType(pRequest)); + USBD_Stall(0); + } +} + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Optional callback re-implementation +//------------------------------------------------------------------------------ +#if !defined(NOAUTOCALLBACK) +// not static function +void USBDCallbacks_RequestReceived(const USBGenericRequest *request) +{ + CCID_RequestHandler(request); +} +#endif + + +//------------------------------------------------------------------------------ +/// Handles SmartCart request +//------------------------------------------------------------------------------ +void CCID_SmartCardRequest( void ) +{ + unsigned char bStatus; + + do { + + bStatus = CCID_Read( (void*)&ccidDriver.sCcidCommand, + sizeof(S_ccid_bulk_out_header), + (TransferCallback)&CCIDCommandDispatcher, + (void*)0 ); + } + while (bStatus != USBD_STATUS_SUCCESS); + +} + +//------------------------------------------------------------------------------ +/// Initializes the CCID device driver. +//------------------------------------------------------------------------------ +void CCIDDriver_Initialize( void ) +{ + TRACE_DEBUG("CCID_Init\n\r"); + USBDDriver_Initialize(&(ccidDriver.usbdDriver), + &ccidDriverDescriptors, + 0); // Multiple interface settings not supported + USBD_Init(); +} + +//------------------------------------------------------------------------------ +/// Reads data from the Data OUT endpoint +/// \param pBuffer Buffer to store the received data +/// \param dLength data buffer length +/// \param fCallback Optional callback function +/// \param pArgument Optional parameter for the callback function +/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS +//------------------------------------------------------------------------------ +unsigned char CCID_Read(void *pBuffer, + unsigned int dLength, + TransferCallback fCallback, + void *pArgument) +{ + return USBD_Read(CCID_EPT_DATA_OUT, pBuffer, dLength, fCallback, pArgument); +} + +//------------------------------------------------------------------------------ +/// Sends data through the Data IN endpoint +/// \param pBuffer Buffer holding the data to transmit +/// \param dLength Length of data buffer +/// \param fCallback Optional callback function +/// \param pArgument Optional parameter for the callback function +/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS +//------------------------------------------------------------------------------ +unsigned char CCID_Write(void *pBuffer, + unsigned int dLength, + TransferCallback fCallback, + void *pArgument) +{ + return USBD_Write(CCID_EPT_DATA_IN, pBuffer, dLength, fCallback, pArgument); +} + +//------------------------------------------------------------------------------ +/// Sends data through the interrupt endpoint, ICC insertion event +/// RDR_to_PC_NotifySlotChange +/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS +//------------------------------------------------------------------------------ +unsigned char CCID_Insertion( void ) +{ + TRACE_DEBUG("CCID_Insertion\n\r"); + + // Build the Interrupt-IN message + ccidDriver.BufferINT[0] = RDR_TO_PC_NOTIFYSLOTCHANGE; + ccidDriver.BufferINT[1] = ICC_INSERTED_EVENT; + ccidDriver.SlotStatus = ICC_INSERTED_EVENT; + + // Notify the host that a ICC is inserted + return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 2, 0, 0 ); +} + +//------------------------------------------------------------------------------ +/// Sends data through the interrupt endpoint, ICC removal event +/// RDR_to_PC_NotifySlotChange +/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS +//------------------------------------------------------------------------------ +unsigned char CCID_Removal( void ) +{ + TRACE_DEBUG("CCID_Removal\n\r"); + + // Build the Interrupt-IN message + ccidDriver.BufferINT[0] = RDR_TO_PC_NOTIFYSLOTCHANGE; + ccidDriver.BufferINT[1] = ICC_NOT_PRESENT; + ccidDriver.SlotStatus = ICC_NOT_PRESENT; + + // Notify the host that a ICC is inserted + return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 2, 0, 0 ); +} + +//------------------------------------------------------------------------------ +/// Interrupt-IN Messages +/// This message is sent when any bit in the bHardwareErrorCode field is set. +/// If this message is sent when there is no “outstanding” command, the bSeq +/// field will be undefined. +/// \param bSlot ICC slot number +/// \param bSeq Sequence number of the bulk OUT command when the hardware error +/// occured +/// \param bHardwareErrorCode Hardware error code +/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS +//------------------------------------------------------------------------------ +unsigned char RDRtoPCHardwareError( unsigned char bSlot, + unsigned char bSeq, + unsigned char bHardwareErrorCode ) +{ + TRACE_DEBUG("RDRtoPCHardwareError\n\r"); + + // Build the Interrupt-IN message + ccidDriver.BufferINT[0] = RDR_TO_PC_HARDWAREERROR; + ccidDriver.BufferINT[1] = bSlot; + ccidDriver.BufferINT[2] = bSeq; + ccidDriver.BufferINT[3] = bHardwareErrorCode; + + // Notify the host that a ICC is inserted + return USBD_Write( CCID_EPT_NOTIFICATION, ccidDriver.BufferINT, 4, 0, 0 ); +} + + diff --git a/usb/device/ccid/cciddriver.h b/usb/device/ccid/cciddriver.h new file mode 100644 index 0000000..8bac286 --- /dev/null +++ b/usb/device/ccid/cciddriver.h @@ -0,0 +1,378 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !Purpose +/// +/// Definition of methods for using a CCID device driver. +/// +/// !Usage +/// +/// -# CCIDDriver_Initialize +/// -# CCID_Read +/// -# CCID_Write +/// -# CCID_SmartCardRequest +/// -# CCID_Insertion +/// -# CCID_Removal +/// -# RDRtoPCHardwareError +//------------------------------------------------------------------------------ + +#ifndef CCID_DRIVER_H +#define CCID_DRIVER_H + +/// For reference, the absolute maximum block size +/// for a TPDU T=0 block is 260 bytes (5 bytes command; 255 bytes data), or +/// for a TPDU T=1 block is 259 bytes, or +/// for a short APDU T=1 block is 261 bytes, or +/// for an extended APDU T=1 block is 65544 bytes. +#define ABDATA_SIZE 260 + +/// define protocol T=0 +#define PROTOCOL_TO 0 +/// define protocol T=1 +#define PROTOCOL_T1 1 + +/// define for dwFeatures see Table 5.1-1 Smart Card Device Class Descriptors +/// No special characteristics +#define CCID_FEATURES_NADA 0x00000000 +/// Automatic parameter configuration based on ATR data +#define CCID_FEATURES_AUTO_PCONF 0x00000002 +/// Automatic activation of ICC on inserting +#define CCID_FEATURES_AUTO_ACTIV 0x00000004 +/// Automatic ICC voltage selection +#define CCID_FEATURES_AUTO_VOLT 0x00000008 +/// Automatic ICC clock frequency change according to active parameters provided +/// by the Host or self determined +#define CCID_FEATURES_AUTO_CLOCK 0x00000010 +/// Automatic baud rate change according to active parameters provided by the +/// Host or self determined +#define CCID_FEATURES_AUTO_BAUD 0x00000020 +/// Automatic parameters negotiation made by the CCID (use of warm or cold +/// resets or PPS according to a manufacturer proprietary algorithm to select +/// the communication parameters with the ICC) +#define CCID_FEATURES_AUTO_PNEGO 0x00000040 +/// Automatic PPS made by the CCID according to the active parameters +#define CCID_FEATURES_AUTO_PPS 0x00000080 +/// CCID can set ICC in clock stop mode +#define CCID_FEATURES_ICCSTOP 0x00000100 +/// NAD value other than 00 accepted (T=1 protocol in use) +#define CCID_FEATURES_NAD 0x00000200 +/// Automatic IFSD exchange as first exchange (T=1 protocol in use) +#define CCID_FEATURES_AUTO_IFSD 0x00000400 +/// TPDU level exchanges with CCID +#define CCID_FEATURES_EXC_TPDU 0x00010000 +/// Short APDU level exchange with CCID +#define CCID_FEATURES_EXC_SAPDU 0x00020000 +/// Short and Extended APDU level exchange with CCID +#define CCID_FEATURES_EXC_APDU 0x00040000 +/// USB Wake up signaling supported on card insertion and removal +#define CCID_FEATURES_WAKEUP 0x00100000 + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +/// Bulk CCID Message header structure +typedef struct +{ + unsigned char bMessageType; + /// Message-specific data length + unsigned long wLength; + /// Identifies the slot number for this command + unsigned char bSlot; + /// Sequence number for command. + unsigned char bSeq; + /// Slot status register + unsigned char bStatus; + /// Slot error + unsigned char bError; + /// specific register + unsigned char bSpecific; + /// Data block sent to the CCID. + unsigned char abData[ABDATA_SIZE]; + unsigned char bSizeToSend; +} __attribute__ ((packed)) S_ccid_bulk_in_header; + +/// 6.1 Bulk Transfers +typedef struct +{ + unsigned char bMessageType; + /// Message-specific data length + unsigned long wLength; + /// Identifies the slot number for this command + unsigned char bSlot; + /// Sequence number for command. + unsigned char bSeq; + /// specific register + unsigned char bSpecific_0; + unsigned char bSpecific_1; + unsigned char bSpecific_2; + /// Application Protocol Data Unit + unsigned char APDU[ABDATA_SIZE]; +} __attribute__ ((packed)) S_ccid_bulk_out_header; + + +/// 6.1.11.2 PIN Verification Data Structure +typedef struct +{ + /// Number of seconds. + unsigned char bTimerOut; + /// Several parameters for the PIN format options + unsigned char bmFormatString; + /// Define the length of the PIN to present in the APDU command + unsigned char bmPINBlockString; + /// Allows the length PIN insertion in the APDU command + unsigned char bmPINLengthFormat; + /// Minimum PIN size in digit and Maximum PIN size in digit + unsigned char wPINMaxExtraDigit; + /// The value is a bit wise OR operation. + unsigned char bEntryValidationCondition; + /// Number of messages to display for the PIN modify command + unsigned char bNumberMessage; + /// Language used to display the messages. + unsigned char wLangId; + /// Message index in the Reader message table + unsigned char bMsgIndex; + /// T=1 I-block prologue field to use + unsigned char bTeoPrologue[3]; + /// APDU to send to the ICC + unsigned char abPINApdu[255]; +}__attribute__ ((packed)) S_ccid_PIN_Verification; + + +/// 6.1.11.7 PIN Modification Data Structure +typedef struct +{ + /// Number of seconds. If 00h then CCID default value is used. + unsigned char bTimeOut; + /// Several parameters for the PIN format options (defined in § 6.1.11.4) + unsigned char bmFormatString4; + /// Define the length of the PIN to present in the APDU command + unsigned char bmPINBlockString; + /// Allows the length PIN insertion in the APDU command (defined in § 6.1.11.6) + unsigned char bmPinLengthFormat; + /// Insertion position offset in byte for the current PIN + unsigned char bInsertionOffsetOld; + /// Insertion position offset in byte for the new PIN + unsigned char bInsertionOffsetNew; + /// XXYYh + /// XX: Minimum PIN size in digit + /// YY: Maximum PIN size in digit + unsigned char wPINMaxExtraDigit; + /// 00h,01h,02h,03h + /// Indicates if a confirmation is requested before acceptance of a new PIN (meaning that the user has to enter this new PIN twice before it is accepted) + /// Indicates if the current PIN must be entered and set in the same APDU field of not. + unsigned char bConfirmPIN; + /// The value is a bit wise OR operation. + /// 01h Max size reached + /// 02h Validation key pressed + /// 04h Timeout occurred + unsigned char bEntryValidationCondition; + /// 00h,01h,02h,03h,or FFh + /// Number of messages to display for the PIN modify command. + unsigned char bNumberMessage; + /// Language used to display the messages. The 16 bit + unsigned char wLangId; + /// Message index in the Reader message table (should be 00h or 01h). + unsigned char bMsgIndex1; + /// Message index in the Reader message table (should be 01h or 02h). + unsigned char bMsgIndex2; + /// Message index in the Reader message table (should be 02h). + unsigned char bMsgIndex3; + /// T=1 I-block prologue field to use. Significant only if protocol in use is T=1. + unsigned char bTeoPrologue[3]; + /// Byte array APDU to send to the ICC + unsigned char abPINApdu[255]; +}__attribute__ ((packed)) S_ccid_PIN_Modification; + +/// Protocol Data Structure for Protocol T=0 (bProtocolNum=0, dwLength=00000005h) +typedef struct +{ + /// B7-4 – FI – Index into the table 7 in ISO/IEC 7816-3:1997 selecting a + /// clock rate conversion factor + /// B3-0 – DI - Index into the table 8 in ISO/IEC 7816-3:1997 selecting a + /// baud rate conversion factor + unsigned char bmFindexDindex; + /// For T=0 ,B0 – 0b, B7-2 – 000000b + /// B1 – Convention used (b1=0 for direct, b1=1 for inverse) + unsigned char bmTCCKST0; // 0 to 2 + /// Extra Guardtime between two characters. Add 0 to 254 etu to the normal + /// guardtime of 12etu. FFh is the same as 00h. + unsigned char bGuardTimeT0; // 0 to FF + /// WI for T=0 used to define WWT + unsigned char bWaitingIntegerT0; // 0 to FF + /// ICC Clock Stop Support + /// 00 = Stopping the Clock is not allowed + /// 01 = Stop with Clock signal Low + /// 02 = Stop with Clock signal High + /// 03 = Stop with Clock either High or Low + unsigned char bClockStop; // 0 to 3 +} __attribute__ ((packed)) S_ccid_protocol_t0; + + +/// Protocol Data Structure for Protocol T=1 (bProtocolNum=1, dwLength=00000007h) +typedef struct +{ + /// B7-4 – FI – Index into the table 7 in ISO/IEC 7816-3:1997 selecting a + /// clock rate conversion factor + /// B3-0 – DI - Index into the table 8 in ISO/IEC 7816-3:1997 selecting a + /// baud rate conversion factor + unsigned char bmFindexDindex; + /// For T=1, B7-2 – 000100b + /// B0 – Checksum type (b0=0 for LRC, b0=1 for CRC + /// B1 – Convention used (b1=0 for direct, b1=1 for inverse) + unsigned char bmTCCKST1; // 10h, 11h, 12h, 13h + /// Extra Guardtime (0 to 254 etu between two characters). + /// If value is FFh, then guardtime is reduced by 1. + unsigned char bGuardTimeT1; // 0 to FF + /// B7-4 = BWI + /// B3-0 = CWI + unsigned char bmWaitingIntegersT1; // 0 to 9 + /// ICC Clock Stop Support + /// 00 = Stopping the Clock is not allowed + /// 01 = Stop with Clock signal Low + /// 02 = Stop with Clock signal High + /// 03 = Stop with Clock either High or Low + unsigned char bClockStop; // 0 to 3 + /// Size of negotiated IFSC + unsigned char bIFSC; // 0 to FE + /// Nad value used by CCID + unsigned char bNadValue; // 0 to FF +} __attribute__ ((packed)) S_ccid_protocol_t1; + + +/// Identifies the length of type of subordinate descriptors of a CCID device +/// Table 5.1-1 Smart Card Device Class descriptors +typedef struct +{ + /// Size of this descriptor, in bytes. + unsigned char bLength; + /// Functional Descriptor type + unsigned char bDescriptorType; + /// Integrated Circuit(s) Cards Interface Devices (CCID) Specification + /// Release Number + unsigned short bcdCCID; + /// Index of the highest available slot. An USB-ICC is regarded as a single + /// slot CCID. + unsigned char bMaxSlotIndex; + /// This value indicates what voltages the CCID can supply to its slots. + /// It is a bitwise OR operation performed on the following values: + /// - 01h 5.0V + /// - 02h 3.0V + /// - 04h 1.8V + /// Other bits are RFU. + unsigned char bVoltageSupport; + /// RRRR –Upper Word- is RFU = 0000h + /// PPPP –Lower Word- Encodes the supported protocol types. A ‘1’ in a given + /// bit position indicates support for the associated ISO protocol. + /// 0001h = Protocol T=0 + /// 0002h = Protocol T=1 + /// All other bits are reserved and must be set to zero. The field is + /// intended to correspond to the PCSC specification definitions. + unsigned long dwProtocols; + /// Default ICC clock frequency in KHz. This is an integer value. + unsigned long dwDefaultClock; + /// Maximum supported ICC clock frequency in KHz. This is an integer value. + unsigned long dwMaximumClock; + /// The number of clock frequencies that are supported by the CCID. If the + /// value is 00h, the supported clock frequencies are assumed to be the + /// default clock frequency defined by dwDefaultClock and the maximum clock + /// frequency defined by dwMaximumClock. + unsigned char bNumClockSupported; + /// Default ICC I/O data rate in bps. This is an integer value + unsigned long dwDataRate; + /// Maximum supported ICC I/O data rate in bps + unsigned long dwMaxDataRate; + /// The number of data rates that are supported by the CCID. + unsigned char bNumDataRatesSupported; + /// Indicates the maximum IFSD supported by CCID for protocol T=1. + unsigned long dwMaxIFSD; + /// - RRRR-Upper Word- is RFU = 0000h + /// - PPPP-Lower Word- encodes the supported protocol types. A ‘1’ in a given + /// bit position indicates support for the associated protocol. + /// 0001h indicates support for the 2-wire protocol 1 + /// 0002h indicates support for the 3-wire protocol 1 + /// 0004h indicates support for the I2C protocol 1 + /// All other values are outside of this specification, and must be handled + /// by vendor-supplied drivers. + unsigned long dwSynchProtocols; + /// The value is a bitwise OR operation performed on the following values: + /// - 00000000h No special characteristics + /// - 00000001h Card accept mechanism 2 + /// - 00000002h Card ejection mechanism 2 + /// - 00000004h Card capture mechanism 2 + /// - 00000008h Card lock/unlock mechanism + unsigned long dwMechanical; + /// This value indicates what intelligent features the CCID has. + unsigned long dwFeatures; + /// For extended APDU level the value shall be between 261 + 10 (header) and + /// 65544 +10, otherwise the minimum value is the wMaxPacketSize of the + /// Bulk-OUT endpoint. + unsigned long dwMaxCCIDMessageLength; + /// Significant only for CCID that offers an APDU level for exchanges. + unsigned char bClassGetResponse; + /// Significant only for CCID that offers an extended APDU level for exchanges. + unsigned char bClassEnvelope; + /// Number of lines and characters for the LCD display used to send messages for PIN entry. + unsigned short wLcdLayout; + /// This value indicates what PIN support features the CCID has. + unsigned char bPINSupport; + /// Maximum number of slots which can be simultaneously busy. + unsigned char bMaxCCIDBusySlots; + +} __attribute__ ((packed)) CCIDDescriptor; + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char RDRtoPCHardwareError( unsigned char bSlot, + unsigned char bSeq, + unsigned char bHardwareErrorCode ); + +#if !defined(NOAUTOCALLBACK) +extern void USBDCallbacks_RequestReceived(const USBGenericRequest *pRequest); +#endif +extern void CCID_SmartCardRequest( void ); +extern void CCIDDriver_Initialize( void ); +extern unsigned char CCID_Read(void *pBuffer, + unsigned int dLength, + TransferCallback fCallback, + void *pArgument); +extern unsigned char CCID_Write(void *pBuffer, + unsigned int dLength, + TransferCallback fCallback, + void *pArgument); +extern unsigned char CCID_Insertion( void ); +extern unsigned char CCID_Removal( void ); + +#endif //#ifndef CCID_DRIVER_H + diff --git a/usb/device/ccid/cciddriverdescriptors.h b/usb/device/ccid/cciddriverdescriptors.h new file mode 100644 index 0000000..2daea67 --- /dev/null +++ b/usb/device/ccid/cciddriverdescriptors.h @@ -0,0 +1,152 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Title: cciddriverdescriptors.h +// +// About: Purpose +// Definitions of the descriptors required by the ccid device driver. +// DWG_Smart-Card_CCID_Rev110.pdf +//------------------------------------------------------------------------------ + +#ifndef CCID_DRIVER_DESCRIPTORS_H +#define CCID_DRIVER_DESCRIPTORS_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Constants: Endpoints +// CCID_EPT_DATA_OUT endpoint data out bulk 1 +// CCID_EPT_DATA_IN endpoint data in bulk 2 +// CCID_EPT_NOTIFICATION endpoint data interupt 3 +//------------------------------------------------------------------------------ +#define CCID_EPT_DATA_OUT 1 +#define CCID_EPT_DATA_IN 2 +#define CCID_EPT_NOTIFICATION 3 + +//------------------------------------------------------------------------------ +// USB-ICC protocol +//------------------------------------------------------------------------------ +// CCID specification version 1.10 +#define CCID1_10 0x0110 + +#define SMART_CARD_DEVICE_CLASS 0x0B +// Smart Card Device Class Descriptor Type +#define CCID_DECRIPTOR_TYPE 0x21 + +// Table 5.3-1 Summary of CCID Class Specific Request +#define CCIDGenericRequest_ABORT 0x01 +#define CCIDGenericRequest_GET_CLOCK_FREQUENCIES 0x02 +#define CCIDGenericRequest_GET_DATA_RATES 0x03 + +// 6.1 Command Pipe, Bulk-OUT Messages +#define PC_TO_RDR_ICCPOWERON 0x62 +#define PC_TO_RDR_ICCPOWEROFF 0x63 +#define PC_TO_RDR_GETSLOTSTATUS 0x65 +#define PC_TO_RDR_XFRBLOCK 0x6F +#define PC_TO_RDR_GETPARAMETERS 0x6C +#define PC_TO_RDR_RESETPARAMETERS 0x6D +#define PC_TO_RDR_SETPARAMETERS 0x61 +#define PC_TO_RDR_ESCAPE 0x6B +#define PC_TO_RDR_ICCCLOCK 0x6E +#define PC_TO_RDR_T0APDU 0x6A +#define PC_TO_RDR_SECURE 0x69 +#define PC_TO_RDR_MECHANICAL 0x71 +#define PC_TO_RDR_ABORT 0x72 +#define PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY 0x73 + +// 6.2 Response Pipe, Bulk-IN Messages +#define RDR_TO_PC_DATABLOCK 0x80 +#define RDR_TO_PC_SLOTSTATUS 0x81 +#define RDR_TO_PC_PARAMETERS 0x82 +#define RDR_TO_PC_ESCAPE 0x83 +#define RDR_TO_PC_DATARATEANDCLOCKFREQUENCY 0x84 + +// 6.3 Interrupt-IN Messages +#define RDR_TO_PC_NOTIFYSLOTCHANGE 0x50 +#define RDR_TO_PC_HARDWAREERROR 0x51 + +// Table 6.2-2 Slot error register when bmCommandStatus = 1 +#define CMD_ABORTED 0xFF +#define ICC_MUTE 0xFE +#define XFR_PARITY_ERROR 0xFD +#define XFR_OVERRUN 0xFC +#define HW_ERROR 0xFB +#define BAD_ATR_TS 0xF8 +#define BAD_ATR_TCK 0xF7 +#define ICC_PROTOCOL_NOT_SUPPORTED 0xF6 +#define ICC_CLASS_NOT_SUPPORTED 0xF5 +#define PROCEDURE_BYTE_CONFLICT 0xF4 +#define DEACTIVATED_PROTOCOL 0xF3 +#define BUSY_WITH_AUTO_SEQUENCE 0xF2 +#define PIN_TIMEOUT 0xF0 +#define PIN_CANCELLED 0xEF +#define CMD_SLOT_BUSY 0xE0 +// User defined 0xC0 to 0x81 +// Reserved for futur use 0x80 +// not supported incorrect message parameter 0x7F to 0x01 +// Command not supported 0x00 + +// CCID rev 1.1, p.27 +#define VOLTS_AUTO 0x00 +#define VOLTS_5_0 0x01 +#define VOLTS_3_0 0x02 +#define VOLTS_1_8 0x03 + +// 6.3.1 RDR_to_PC_NotifySlotChange +#define ICC_NOT_PRESENT 0x00 +#define ICC_PRESENT 0x01 +#define ICC_CHANGE 0x02 +#define ICC_INSERTED_EVENT ICC_PRESENT+ICC_CHANGE + +// ICCD: Table 6.1-8 Bitmap for bStatus field +#define ICC_BS_PRESENT_ACTIVATED 0x00 // USB-ICC is present and activated +#define ICC_BS_PRESENT_NOTACTIVATED 0x01 // USB-ICC is present but not activated +#define ICC_BS_NOTPRESENT 0x02 // USB-ICC is virtually not present +#define ICC_BS_RFU 0x03 // RFU +#define ICC_CS_NO_ERROR (0x00<<6) // Processed without error +#define ICC_CS_FAILED (0x01<<6) // Failed, error condition given by bError +#define ICC_CS_TIME_EXT (0x02<<6) // Time extension is requested +#define ICC_CS_RFU (0x03<<6) // RFU + +/* +#define NO_ERROR 0x00 +#define NO_EXTRA_BYTES 0x00 +#define CCID_FLAG_INITIAL_VALUE 0x05 +#define CCID_EVENT_SIZE 0x02 +#define STATUS_MASK 0x41 +*/ +//------------------------------------------------------------------------------ +// Structures +//------------------------------------------------------------------------------ + +#endif //#ifndef CCID_DRIVER_DESCRIPTORS_H + diff --git a/usb/device/cdc-serial/CDCDSerialDriver.c b/usb/device/cdc-serial/CDCDSerialDriver.c new file mode 100644 index 0000000..3e58592 --- /dev/null +++ b/usb/device/cdc-serial/CDCDSerialDriver.c @@ -0,0 +1,300 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: CDCDSerialDriver implementation + + About: Purpose + Implementation of the CDCDSerialDriver class methods. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "CDCDSerialDriver.h" +#include "CDCDSerialDriverDescriptors.h" +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// USB driver for a CDC class implementing a virtual COM serial connection. +//------------------------------------------------------------------------------ +typedef struct { + + /// Standard USBDDriver instance. + USBDDriver usbdDriver; + /// Current line coding (baudrate, parity, stop bits). + CDCLineCoding lineCoding; + /// Indicates if the RS232 carrier is active. + unsigned char isCarrierActivated; + /// Current serial port states + unsigned short serialState; + +} CDCDSerialDriver; + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +/// Static instance of the CDC serial driver. +static CDCDSerialDriver cdcdSerialDriver; + +//------------------------------------------------------------------------------ +// Internal functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Callback function which should be invoked after the data of a +/// SetLineCoding request has been retrieved. Sends a zero-length packet +/// to the host for acknowledging the request. +//------------------------------------------------------------------------------ +static void CDCDSerialDriver_SetLineCodingCallback() +{ + USBD_Write(0, 0, 0, 0, 0); +} + +//------------------------------------------------------------------------------ +/// Receives new line coding information from the USB host. +//------------------------------------------------------------------------------ +static void CDCDSerialDriver_SetLineCoding() +{ + TRACE_INFO_WP("sLineCoding "); + + USBD_Read(0, + (void *) &(cdcdSerialDriver.lineCoding), + sizeof(CDCLineCoding), + (TransferCallback) CDCDSerialDriver_SetLineCodingCallback, + 0); +} + +//------------------------------------------------------------------------------ +/// Sends the current line coding information to the host through Control +/// endpoint 0. +//------------------------------------------------------------------------------ +static void CDCDSerialDriver_GetLineCoding() +{ + TRACE_INFO_WP("gLineCoding "); + + USBD_Write(0, + (void *) &(cdcdSerialDriver.lineCoding), + sizeof(CDCLineCoding), + 0, + 0); +} + +//------------------------------------------------------------------------------ +/// Changes the state of the serial driver according to the information +/// sent by the host via a SetControlLineState request, and acknowledges +/// the request with a zero-length packet. +//------------------------------------------------------------------------------ +static void CDCDSerialDriver_SetControlLineState(unsigned char activateCarrier, + unsigned char isDTEPresent) +{ + TRACE_INFO_WP( + "sControlLineState(%d, %d) ", + activateCarrier, + isDTEPresent); + + cdcdSerialDriver.isCarrierActivated = activateCarrier; + USBD_Write(0, 0, 0, 0, 0); +} + +//------------------------------------------------------------------------------ +// Optional RequestReceived() callback re-implementation +//------------------------------------------------------------------------------ +#if !defined(NOAUTOCALLBACK) + +//------------------------------------------------------------------------------ +/// Re-implemented callback, invoked when a new USB Request is received. +//------------------------------------------------------------------------------ +void USBDCallbacks_RequestReceived(const USBGenericRequest *request) +{ + CDCDSerialDriver_RequestHandler(request); +} + +#endif + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes the USB Device CDC serial driver & USBD Driver. +//------------------------------------------------------------------------------ +void CDCDSerialDriver_Initialize() +{ + TRACE_INFO("CDCDSerialDriver_Initialize\n\r"); + + // Initialize Abstract Control Model attributes + CDCLineCoding_Initialize(&(cdcdSerialDriver.lineCoding), + 115200, + CDCLineCoding_ONESTOPBIT, + CDCLineCoding_NOPARITY, + 8); + cdcdSerialDriver.isCarrierActivated = 0; + cdcdSerialDriver.serialState = 0; + + // Initialize the standard driver + USBDDriver_Initialize(&(cdcdSerialDriver.usbdDriver), + &cdcdSerialDriverDescriptors, + 0); // Multiple settings for interfaces not supported + + // Initialize the USB driver + USBD_Init(); +} + +//------------------------------------------------------------------------------ +/// Handles CDC-specific SETUP requests. Should be called from a +/// re-implementation of USBDCallbacks_RequestReceived() method. +/// \param Pointer to a USBGenericRequest instance. +//------------------------------------------------------------------------------ +void CDCDSerialDriver_RequestHandler(const USBGenericRequest *request) +{ + TRACE_INFO_WP("NewReq "); + + // Handle the request + switch (USBGenericRequest_GetRequest(request)) { + + case CDCGenericRequest_SETLINECODING: + + CDCDSerialDriver_SetLineCoding(); + break; + + case CDCGenericRequest_GETLINECODING: + + CDCDSerialDriver_GetLineCoding(); + break; + + case CDCGenericRequest_SETCONTROLLINESTATE: + + CDCDSerialDriver_SetControlLineState( + CDCSetControlLineStateRequest_ActivateCarrier(request), + CDCSetControlLineStateRequest_IsDtePresent(request)); + + break; + + default: + + USBDDriver_RequestHandler(&(cdcdSerialDriver.usbdDriver), request); + break; + } +} + +//------------------------------------------------------------------------------ +/// Receives data from the host through the virtual COM port created by +/// the CDC device serial driver. This function behaves like USBD_Read. +/// \param data Pointer to the data buffer to put received data. +/// \param size Size of the data buffer in bytes. +/// \param callback Optional callback function to invoke when the transfer +/// finishes. +/// \param argument Optional argument to the callback function. +/// \return USBD_STATUS_SUCCESS if the read operation has been started normally; +/// otherwise, the corresponding error code. +//------------------------------------------------------------------------------ +unsigned char CDCDSerialDriver_Read(void *data, + unsigned int size, + TransferCallback callback, + void *argument) +{ + return USBD_Read(CDCDSerialDriverDescriptors_DATAOUT, + data, + size, + callback, + argument); +} + +//------------------------------------------------------------------------------ +/// Sends a data buffer through the virtual COM port created by the CDC +/// device serial driver. This function behaves exactly like USBD_Write. +/// \param data Pointer to the data buffer to send. +/// \param size Size of the data buffer in bytes. +/// \param callback Optional callback function to invoke when the transfer +/// finishes. +/// \param argument Optional argument to the callback function. +/// \return USBD_STATUS_SUCCESS if the read operation has been started normally; +/// otherwise, the corresponding error code. +//------------------------------------------------------------------------------ +unsigned char CDCDSerialDriver_Write(void *data, + unsigned int size, + TransferCallback callback, + void *argument) +{ + return USBD_Write(CDCDSerialDriverDescriptors_DATAIN, + data, + size, + callback, + argument); +} + +//------------------------------------------------------------------------------ +/// Returns the current status of the RS-232 line. +//------------------------------------------------------------------------------ +unsigned short CDCDSerialDriver_GetSerialState() +{ + return cdcdSerialDriver.serialState; +} + +//------------------------------------------------------------------------------ +/// Sets the current serial state of the device to the given value. +/// \param serialState New device state. +//------------------------------------------------------------------------------ +void CDCDSerialDriver_SetSerialState(unsigned short serialState) +{ + ASSERT((serialState & 0xFF80) == 0, + "CDCDSerialDriver_SetSerialState: Bits D7-D15 are reserved\n\r"); + + // If new state is different from previous one, send a notification to the + // host + if (cdcdSerialDriver.serialState != serialState) { + + cdcdSerialDriver.serialState = serialState; + USBD_Write(CDCDSerialDriverDescriptors_NOTIFICATION, + &(cdcdSerialDriver.serialState), + 2, + 0, + 0); + + // Reset one-time flags + cdcdSerialDriver.serialState &= ~(CDCDSerialDriver_STATE_OVERRUN + | CDCDSerialDriver_STATE_PARITY + | CDCDSerialDriver_STATE_FRAMING + | CDCDSerialDriver_STATE_RINGSIGNAL + | CDCDSerialDriver_STATE_BREAK); + } +} + diff --git a/usb/device/cdc-serial/CDCDSerialDriver.h b/usb/device/cdc-serial/CDCDSerialDriver.h new file mode 100644 index 0000000..5ccc901 --- /dev/null +++ b/usb/device/cdc-serial/CDCDSerialDriver.h @@ -0,0 +1,117 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of a class for implementing a USB device CDC serial driver. + + !!!Usage + + -# Re-implement the USBDCallbacks_RequestReceived method to pass + received requests to CDCDSerialDriver_RequestHandler. *This is + automatically done unless the NOAUTOCALLBACK symbol is defined*. + -# Initialize the CDC serial and USB drivers using + CDCDSerialDriver_Initialize. + -# Logically connect the device to the host using USBD_Connect. + -# Send serial data to the USB host using CDCDSerialDriver_Write. + -# Receive serial data from the USB host using CDCDSerialDriver_Read. +*/ + +#ifndef CDCDSERIALDRIVER_H +#define CDCDSERIALDRIVER_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "CDC Serial Port States" +/// This page lists the bit map for CDC Serial Port States. +/// +/// !BitMaps +/// - CDCDSerialDriver_STATE_RXDRIVER +/// - CDCDSerialDriver_STATE_TXCARRIER +/// - CDCDSerialDriver_STATE_BREAK +/// - CDCDSerialDriver_STATE_RINGSIGNAL +/// - CDCDSerialDriver_STATE_FRAMING +/// - CDCDSerialDriver_STATE_PARITY +/// - CDCDSerialDriver_STATE_OVERRUN + +/// Indicates the receiver carrier signal is present. +#define CDCDSerialDriver_STATE_RXDRIVER (1 << 0) +/// Indicates the transmission carrier signal is present. +#define CDCDSerialDriver_STATE_TXCARRIER (1 << 1) +/// Indicates a break has been detected. +#define CDCDSerialDriver_STATE_BREAK (1 << 2) +/// Indicates a ring signal has been detected. +#define CDCDSerialDriver_STATE_RINGSIGNAL (1 << 3) +/// Indicates a framing error has occured. +#define CDCDSerialDriver_STATE_FRAMING (1 << 4) +/// Indicates a parity error has occured. +#define CDCDSerialDriver_STATE_PARITY (1 << 5) +/// Indicates a data overrun error has occured. +#define CDCDSerialDriver_STATE_OVERRUN (1 << 6) +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern void CDCDSerialDriver_Initialize(); + +extern void CDCDSerialDriver_RequestHandler(const USBGenericRequest *request); + +extern unsigned char CDCDSerialDriver_Write( + void *data, + unsigned int size, + TransferCallback callback, + void *argument); + +extern unsigned char CDCDSerialDriver_Read( + void *data, + unsigned int size, + TransferCallback callback, + void *argument); + +extern unsigned short CDCDSerialDriver_GetSerialState(); + +extern void CDCDSerialDriver_SetSerialState(unsigned short serialState); + +#endif //#ifndef CDCSERIALDRIVER_H + diff --git a/usb/device/cdc-serial/CDCDSerialDriverDescriptors.c b/usb/device/cdc-serial/CDCDSerialDriverDescriptors.c new file mode 100644 index 0000000..8864451 --- /dev/null +++ b/usb/device/cdc-serial/CDCDSerialDriverDescriptors.c @@ -0,0 +1,661 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "CDCDSerialDriverDescriptors.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "CDC Serial Device IDs" +/// This page lists the IDs used in the CDC Serial Device Descriptor. +/// +/// !IDs +/// - CDCDSerialDriverDescriptors_PRODUCTID +/// - CDCDSerialDriverDescriptors_VENDORID +/// - CDCDSerialDriverDescriptors_RELEASE + +/// Device product ID. +#define CDCDSerialDriverDescriptors_PRODUCTID 0x6119 +/// Device vendor ID (Atmel). +#define CDCDSerialDriverDescriptors_VENDORID 0x03EB +/// Device release number. +#define CDCDSerialDriverDescriptors_RELEASE 0x0100 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Macros +//------------------------------------------------------------------------------ + +/// Returns the minimum between two values. +#define MIN(a, b) ((a < b) ? a : b) + +//------------------------------------------------------------------------------ +// Internal structures +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Configuration descriptor list for a device implementing a CDC serial driver. +//------------------------------------------------------------------------------ +typedef struct { + + /// Standard configuration descriptor. + USBConfigurationDescriptor configuration; +#if defined(CHIP_USB_OTGHS) + // OTG descriptor + USBOtgDescriptor otgDescriptor; +#endif + /// Communication interface descriptor. + USBInterfaceDescriptor communication; + /// CDC header functional descriptor. + CDCHeaderDescriptor header; + /// CDC call management functional descriptor. + CDCCallManagementDescriptor callManagement; + /// CDC abstract control management functional descriptor. + CDCAbstractControlManagementDescriptor abstractControlManagement; + /// CDC union functional descriptor (with one slave interface). + CDCUnionDescriptor union1; + /// Notification endpoint descriptor. + USBEndpointDescriptor notification; + /// Data interface descriptor. + USBInterfaceDescriptor data; + /// Data OUT endpoint descriptor. + USBEndpointDescriptor dataOut; + /// Data IN endpoint descriptor. + USBEndpointDescriptor dataIn; + +} __attribute__ ((packed)) CDCDSerialDriverConfigurationDescriptors; + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +/// Standard USB device descriptor for the CDC serial driver +const USBDeviceDescriptor deviceDescriptor = { + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + CDCDeviceDescriptor_CLASS, + CDCDeviceDescriptor_SUBCLASS, + CDCDeviceDescriptor_PROTOCOL, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + CDCDSerialDriverDescriptors_VENDORID, + CDCDSerialDriverDescriptors_PRODUCTID, + CDCDSerialDriverDescriptors_RELEASE, + 0, // No string descriptor for manufacturer + 1, // Index of product string descriptor is #1 + 0, // No string descriptor for serial number + 1 // Device has 1 possible configuration +}; + +#if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + +/// USB device qualifier descriptor. +const USBDeviceQualifierDescriptor qualifierDescriptor = { + + sizeof(USBDeviceQualifierDescriptor), + USBGenericDescriptor_DEVICEQUALIFIER, + USBDeviceDescriptor_USB2_00, + CDCDeviceDescriptor_CLASS, + CDCDeviceDescriptor_SUBCLASS, + CDCDeviceDescriptor_PROTOCOL, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + 1, // Device has one possible configuration + 0 // Reserved +}; + +#endif + +/// Standard USB configuration descriptor for the CDC serial driver +const CDCDSerialDriverConfigurationDescriptors configurationDescriptorsFS = { + + // Standard configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(CDCDSerialDriverConfigurationDescriptors), + 2, // There are two interfaces in this configuration + 1, // This is configuration #1 + 0, // No string descriptor for this configuration + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, +#if defined(CHIP_USB_OTGHS) + // OTG descriptor + { + sizeof(USBOtgDescriptor), + USBGenericDescriptor_OTG, + USBOTGDescriptor_HNP_SRP + }, +#endif + // Communication class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0 + 0, // This is alternate setting #0 for this interface + 1, // This interface uses 1 endpoint + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Class-specific header functional descriptor + { + sizeof(CDCHeaderDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_HEADER, + CDCGenericDescriptor_CDC1_10 + }, + // Class-specific call management functional descriptor + { + sizeof(CDCCallManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_CALLMANAGEMENT, + CDCCallManagementDescriptor_SELFCALLMANAGEMENT, + 0 // No associated data interface + }, + // Class-specific abstract control management functional descriptor + { + sizeof(CDCAbstractControlManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_ABSTRACTCONTROLMANAGEMENT, + CDCAbstractControlManagementDescriptor_LINE + }, + // Class-specific union functional descriptor with one slave interface + { + sizeof(CDCUnionDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_UNION, + 0, // Number of master interface is #0 + 1 // First slave interface is #1 + }, + // Notification endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCDSerialDriverDescriptors_NOTIFICATION), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCDSerialDriverDescriptors_NOTIFICATION), + USBEndpointDescriptor_MAXINTERRUPTSIZE_FS), + 10 // Endpoint is polled every 10ms + }, + // Data class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 1, // This is interface #1 + 0, // This is alternate setting #0 for this interface + 2, // This interface uses 2 endpoints + CDCDataInterfaceDescriptor_CLASS, + CDCDataInterfaceDescriptor_SUBCLASS, + CDCDataInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Bulk-OUT endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, + CDCDSerialDriverDescriptors_DATAOUT), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCDSerialDriverDescriptors_DATAOUT), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed bulk endpoints + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCDSerialDriverDescriptors_DATAIN), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCDSerialDriverDescriptors_DATAIN), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed bulk endpoints + } +}; + +/// Language ID string descriptor +const unsigned char languageIdStringDescriptor[] = { + + USBStringDescriptor_LENGTH(1), + USBGenericDescriptor_STRING, + USBStringDescriptor_ENGLISH_US +}; + +#if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) +/// Other-speed configuration descriptor (when in full-speed). +const CDCDSerialDriverConfigurationDescriptors otherSpeedDescriptorsFS = { + + // Standard configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_OTHERSPEEDCONFIGURATION, + sizeof(CDCDSerialDriverConfigurationDescriptors), + 2, // There are two interfaces in this configuration + 1, // This is configuration #1 + 0, // No string descriptor for this configuration + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, +#if defined(CHIP_USB_OTGHS) + // OTG descriptor + { + sizeof(USBOtgDescriptor), + USBGenericDescriptor_OTG, + USBOTGDescriptor_HNP_SRP + }, +#endif + // Communication class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0 + 0, // This is alternate setting #0 for this interface + 1, // This interface uses 1 endpoint + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Class-specific header functional descriptor + { + sizeof(CDCHeaderDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_HEADER, + CDCGenericDescriptor_CDC1_10 + }, + // Class-specific call management functional descriptor + { + sizeof(CDCCallManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_CALLMANAGEMENT, + CDCCallManagementDescriptor_SELFCALLMANAGEMENT, + 0 // No associated data interface + }, + // Class-specific abstract control management functional descriptor + { + sizeof(CDCAbstractControlManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_ABSTRACTCONTROLMANAGEMENT, + CDCAbstractControlManagementDescriptor_LINE + }, + // Class-specific union functional descriptor with one slave interface + { + sizeof(CDCUnionDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_UNION, + 0, // Number of master interface is #0 + 1 // First slave interface is #1 + }, + // Notification endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCDSerialDriverDescriptors_NOTIFICATION), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCDSerialDriverDescriptors_NOTIFICATION), + USBEndpointDescriptor_MAXINTERRUPTSIZE_HS), + 10 // Endpoint is polled every 10ms + }, + // Data class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 1, // This is interface #1 + 0, // This is alternate setting #0 for this interface + 2, // This interface uses 2 endpoints + CDCDataInterfaceDescriptor_CLASS, + CDCDataInterfaceDescriptor_SUBCLASS, + CDCDataInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Bulk-OUT endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, + CDCDSerialDriverDescriptors_DATAOUT), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCDSerialDriverDescriptors_DATAOUT), + USBEndpointDescriptor_MAXBULKSIZE_HS), + 0 // Must be 0 for full-speed bulk endpoints + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCDSerialDriverDescriptors_DATAIN), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCDSerialDriverDescriptors_DATAIN), + USBEndpointDescriptor_MAXBULKSIZE_HS), + 0 // Must be 0 for full-speed bulk endpoints + } +}; + + +/// Configuration descriptor (when in high-speed). +const CDCDSerialDriverConfigurationDescriptors configurationDescriptorsHS = { + + // Standard configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(CDCDSerialDriverConfigurationDescriptors), + 2, // There are two interfaces in this configuration + 1, // This is configuration #1 + 0, // No string descriptor for this configuration + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, +#if defined(CHIP_USB_OTGHS) + // OTG descriptor + { + sizeof(USBOtgDescriptor), + USBGenericDescriptor_OTG, + USBOTGDescriptor_HNP_SRP + }, +#endif + // Communication class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0 + 0, // This is alternate setting #0 for this interface + 1, // This interface uses 1 endpoint + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Class-specific header functional descriptor + { + sizeof(CDCHeaderDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_HEADER, + CDCGenericDescriptor_CDC1_10 + }, + // Class-specific call management functional descriptor + { + sizeof(CDCCallManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_CALLMANAGEMENT, + CDCCallManagementDescriptor_SELFCALLMANAGEMENT, + 0 // No associated data interface + }, + // Class-specific abstract control management functional descriptor + { + sizeof(CDCAbstractControlManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_ABSTRACTCONTROLMANAGEMENT, + CDCAbstractControlManagementDescriptor_LINE + }, + // Class-specific union functional descriptor with one slave interface + { + sizeof(CDCUnionDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_UNION, + 0, // Number of master interface is #0 + 1 // First slave interface is #1 + }, + // Notification endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCDSerialDriverDescriptors_NOTIFICATION), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCDSerialDriverDescriptors_NOTIFICATION), + USBEndpointDescriptor_MAXINTERRUPTSIZE_HS), + 8 // Endpoint is polled every 16ms + }, + // Data class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 1, // This is interface #1 + 0, // This is alternate setting #0 for this interface + 2, // This interface uses 2 endpoints + CDCDataInterfaceDescriptor_CLASS, + CDCDataInterfaceDescriptor_SUBCLASS, + CDCDataInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Bulk-OUT endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, + CDCDSerialDriverDescriptors_DATAOUT), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCDSerialDriverDescriptors_DATAOUT), + USBEndpointDescriptor_MAXBULKSIZE_HS), + 0 // Must be 0 for full-speed bulk endpoints + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCDSerialDriverDescriptors_DATAIN), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCDSerialDriverDescriptors_DATAIN), + USBEndpointDescriptor_MAXBULKSIZE_HS), + 0 // Must be 0 for full-speed bulk endpoints + } +}; + +/// Other-speed configuration descriptor (when in high-speed). +const CDCDSerialDriverConfigurationDescriptors otherSpeedDescriptorsHS = { + + // Standard configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_OTHERSPEEDCONFIGURATION, + sizeof(CDCDSerialDriverConfigurationDescriptors), + 2, // There are two interfaces in this configuration + 1, // This is configuration #1 + 0, // No string descriptor for this configuration + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, +#if defined(CHIP_USB_OTGHS) + // OTG descriptor + { + sizeof(USBOtgDescriptor), + USBGenericDescriptor_OTG, + USBOTGDescriptor_HNP_SRP + }, +#endif + // Communication class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0 + 0, // This is alternate setting #0 for this interface + 1, // This interface uses 1 endpoint + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Class-specific header functional descriptor + { + sizeof(CDCHeaderDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_HEADER, + CDCGenericDescriptor_CDC1_10 + }, + // Class-specific call management functional descriptor + { + sizeof(CDCCallManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_CALLMANAGEMENT, + CDCCallManagementDescriptor_SELFCALLMANAGEMENT, + 0 // No associated data interface + }, + // Class-specific abstract control management functional descriptor + { + sizeof(CDCAbstractControlManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_ABSTRACTCONTROLMANAGEMENT, + CDCAbstractControlManagementDescriptor_LINE + }, + // Class-specific union functional descriptor with one slave interface + { + sizeof(CDCUnionDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_UNION, + 0, // Number of master interface is #0 + 1 // First slave interface is #1 + }, + // Notification endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCDSerialDriverDescriptors_NOTIFICATION), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCDSerialDriverDescriptors_NOTIFICATION), + USBEndpointDescriptor_MAXINTERRUPTSIZE_FS), + 10 // Endpoint is polled every 10ms + }, + // Data class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 1, // This is interface #1 + 0, // This is alternate setting #0 for this interface + 2, // This interface uses 2 endpoints + CDCDataInterfaceDescriptor_CLASS, + CDCDataInterfaceDescriptor_SUBCLASS, + CDCDataInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Bulk-OUT endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, + CDCDSerialDriverDescriptors_DATAOUT), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCDSerialDriverDescriptors_DATAOUT), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed bulk endpoints + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCDSerialDriverDescriptors_DATAIN), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCDSerialDriverDescriptors_DATAIN), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed bulk endpoints + } +}; +#endif + +/// Product string descriptor +const unsigned char productStringDescriptor[] = { + + USBStringDescriptor_LENGTH(13), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('9'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE('U'), + USBStringDescriptor_UNICODE('S'), + USBStringDescriptor_UNICODE('B'), + USBStringDescriptor_UNICODE('S'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('r'), + USBStringDescriptor_UNICODE('i'), + USBStringDescriptor_UNICODE('a'), + USBStringDescriptor_UNICODE('l') +}; + +/// List of string descriptors used by the device +const unsigned char *stringDescriptors[] = { + + languageIdStringDescriptor, + productStringDescriptor, +}; + +/// List of standard descriptors for the serial driver. +USBDDriverDescriptors cdcdSerialDriverDescriptors = { + + &deviceDescriptor, + (USBConfigurationDescriptor *) &(configurationDescriptorsFS), +#if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + &qualifierDescriptor, + (USBConfigurationDescriptor *) &(otherSpeedDescriptorsFS), + &deviceDescriptor, + (USBConfigurationDescriptor *) &(configurationDescriptorsHS), + &qualifierDescriptor, + (USBConfigurationDescriptor *) &(otherSpeedDescriptorsHS), +#else + 0, // No full-speed device qualifier descriptor + 0, // No full-speed other speed configuration + 0, // No high-speed device descriptor + 0, // No high-speed configuration descriptor + 0, // No high-speed device qualifier descriptor + 0, // No high-speed other speed configuration descriptor + +#endif + stringDescriptors, + 2 // 2 string descriptors in list +}; + diff --git a/usb/device/cdc-serial/CDCDSerialDriverDescriptors.h b/usb/device/cdc-serial/CDCDSerialDriverDescriptors.h new file mode 100644 index 0000000..8ab4edf --- /dev/null +++ b/usb/device/cdc-serial/CDCDSerialDriverDescriptors.h @@ -0,0 +1,77 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of the USB descriptors required by a CDC device serial + driver. +*/ + +#ifndef CDCDSERIALDRIVERDESCRIPTORS_H +#define CDCDSERIALDRIVERDESCRIPTORS_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "CDC Serial Endpoints" +/// This page lists the endpoints used in CDC Serial Device. +/// +/// !Endpoints +/// - CDCDSerialDriverDescriptors_DATAOUT +/// - CDCDSerialDriverDescriptors_DATAIN +/// - CDCDSerialDriverDescriptors_NOTIFICATION + +/// Data OUT endpoint number. +#define CDCDSerialDriverDescriptors_DATAOUT 1 +/// Data IN endpoint number. +#define CDCDSerialDriverDescriptors_DATAIN 2 +/// Notification endpoint number. +#define CDCDSerialDriverDescriptors_NOTIFICATION 3 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +/// List of descriptors for a CDC device serial driver. +extern USBDDriverDescriptors cdcdSerialDriverDescriptors; + +#endif //#ifndef CDCDDRIVERDESCRIPTORS_H + diff --git a/usb/device/cdc-serial/CDCarchitecture.png b/usb/device/cdc-serial/CDCarchitecture.png new file mode 100644 index 0000000..9d0e924 Binary files /dev/null and b/usb/device/cdc-serial/CDCarchitecture.png differ diff --git a/usb/device/cdc-serial/USB-SerialConverter.png b/usb/device/cdc-serial/USB-SerialConverter.png new file mode 100644 index 0000000..bc05c1f Binary files /dev/null and b/usb/device/cdc-serial/USB-SerialConverter.png differ diff --git a/usb/device/cdc-serial/cdc-serial.dir b/usb/device/cdc-serial/cdc-serial.dir new file mode 100644 index 0000000..ff18ab0 --- /dev/null +++ b/usb/device/cdc-serial/cdc-serial.dir @@ -0,0 +1,646 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// +/// !!!Purpose +/// +/// This directory provides definitions, structs and functions for a USB CDC +/// %device - USB CDC Serial Converter demo, to implement an USB Serial COM port +/// driver. +/// +/// !!!Contents +/// +/// There are two things for the implement of the USB CDC Serial %device driver: +/// - Implement the CDC Serial driver structs and functions for the %device, +/// to initialize, to handle CDC-specific requests and dispach +/// standard requests in USBD callbacks, to read/write through assigned USB +/// endpoints, +/// - Create the CDC Serial device's descriptors that should be passed to +/// the USBDDriver instance on initialization, so that the host can +/// recognize the %device as a USB CDC Serial COM port %device. +/// +/// For more information about what a particular group contains, please refer to +/// "USB CDC Serial Device". +//------------------------------------------------------------------------------ + +/** + \page "USB CDC Serial Device" + This page describes how to use the USB framework to produce a USB CDC Serial + Device driver, which appears as a virtual COM port on host. + + !!!References + - "AT91 USB device framework" + - "USB Device Enumeration" + - + Universal Serial Bus Revision 2.0 specification + (.zip file format, size 9.80 MB) + - + Communication Device Class Documents (.zip file format) + - Abstract Control Model Serial Emulation (USB Class Definitions for + Communication Devices, section 3.6.2.1). + + !!!Communication Device Class + + You can get some basic information about the Communication Device Class. + + !!Purpose + + CDC is used to connect communication devices, such as modems (digital or + analog), telephones or networking devices. Its generic framework supports a + wide variety of physical layers (xDSL, ATM, etc.) and protocols. + + In this document, CDC is used to implement a USB to a serial data converter. + A USB to serial converter can be used in this case to bridge a legacy RS-232 + interface with a USB port. + + !!Architecture + ... + + !Communication Class Interface + The #Communication Class Interface# is used for %device management. It + includes requests to manage the %device state, its responses, as well as + event notifications. This interface can also be optionally used for call + management, i.e., setting up and terminating calls as well as managing + their parameters. + + The interface requires at least one endpoint (#Default EP0#) to used for + %device management. Optionally, another endpoint can be dedicated to + event notification. This will usually be an #Interrupt IN# endpoint. + + !Data Class Interface + The #Data Class Interface# is used for generic data transmissions. It provides + a means for a communication %device to actually transfer data to and from the + host. In addition, it also enables the multiplexing of data and commands on + the same interface, through the use of wrappers. + + %Endpoints for this interface must exist in pairs of the same type. This is + necessary to allow both IN and OUT communication. Only the #Bulk# and + #Isochronous# types can be used for these %endpoints. + + \image CDCArchitecture.png "CDC Class Driver Architecture" + + !Models + To account for the wide variety of existing communication devices, several + #models# have been defined, for more details you can refer to CDC spec. 1.1. + - POTS (Plain Old Telephone Service) + - Direct Line Control Model + - Datapump Model + - Abstract Control Model (ACM) + - Telephone + - Telephone Control Model + - ISDN + - Multi-Channel Model + - USB CAPI Model + - Networking + - Ethernet Networking Model + - ATM Networking Control Model + + !Class-specific Descriptors + CDC-specific information is described using Functional Descriptors. They + define various parameters of an interface, such as how the %device handles + call management, or model-specific attributes. + + Since the CDC specification defines quite a number of functional descriptors, + they are not detailed here. Instead, they are presented in the various case + studies of this document in which they are used. + + !!Host Drivers + Most Operating Systems (OS) now include generic drivers for a wide variety of + USB classes. This makes developing a %device simpler, since the host complexity + is now handled by the OS. Manufacturers can thus concentrate on the %device + itself, not on developing specific host drivers. + + Here is a brief list of the various CDC implementations supported by several + OS: + - Windows + - Abstract Control Model + - Remote NDIS + - Linux + - Abstract Control Model + - Ethernet Model + + !!!USB to Serial Converter + This section describes the implementation of the USB to serial converter using + the CDC class and the AT91 USB Device Framework. + + !!Bridging a Legacy Device and a Host with USB-Serial Converter + \image USB-SerialConverter.png + + !!Model + The CDC specification defines a model which suits this application perfectly: + the #Abstract Control Model (ACM)#. It implements the requests and + notifications necessary to communicate with an RS-232 interface. + + The Abstract Control Model requires two interfaces, one #Communication Class + Interface# and one #Data Class Interface#. Each of them must have two + associated endpoints. The former shall have one endpoint dedicated to %device + management (default Control endpoint 0) and one for events notification + (additional Interrupt IN endpoint). + + The Data Class Interface needs two endpoints through which to carry data to + and from the host. Depending on the application, these endpoints can either + be Bulk or Isochronous. In the case of a USB to serial converter, using Bulk + endpoints is probably more appropriate, since the reliability of the + transmission is important and the data transfers are not time-critical. + + !!Descriptors + The descriptors are modtly standard ones. The following code examples thus + use the structures described in the "AT91 USB device framework". + + For CDC-specific descriptors, some new types are defined: + - CDCHeaderDescriptor + - CDCCallManagementDescriptor + - CDCAbstractControlManagementDescriptor + - CDCUnionDescriptor + + All the descriptors can be found in CDCDSerialDriverDescriptors.c. + + !Device Descriptor + \code +const USBDeviceDescriptor deviceDescriptor = { + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + CDCDeviceDescriptor_CLASS, + CDCDeviceDescriptor_SUBCLASS, + CDCDeviceDescriptor_PROTOCOL, + BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0), + CDCDSerialDriverDescriptors_VENDORID, + CDCDSerialDriverDescriptors_PRODUCTID, + CDCDSerialDriverDescriptors_RELEASE, + 0, // No string descriptor for manufacturer + 1, // Index of product string descriptor is #1 + 0, // No string descriptor for serial number + 1 // Device has 1 possible configuration +}; + \endcode + The Vendor ID and Product ID fields are used to determine which driver to use + when the %device is enumerated. The Vendor ID is provided by the USB-IF + organization after registration; the product ID is completely vendor-specific. + In the example implementation provided with this document, the Atmel vendor ID + (03EBh) is used along with a custom product ID (6119h). + + The configuration descriptor is followed by interface, endpoint and class- + specific descriptors. +\code +const CDCDSerialDriverConfigurationDescriptors configurationDescriptors[]; +\endcode + + !Configuration Descriptor +\code + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(CDCDSerialDriverConfigurationDescriptors), + 2, // There are two interfaces in this configuration + 1, // This is configuration #1 + 0, // No string descriptor for this configuration + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, +\endcode + + !Communication Class Interface Descriptor + The bInterfaceClass should be set to 0x02 and bInterfaceSubClass should be set + to 0x02. +\code + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0 + 0, // This is alternate setting #0 for this interface + 1, // This interface uses 1 endpoint + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, +\endcode + + !Functional - Header Descriptor +\code + { + sizeof(CDCHeaderDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_HEADER, + CDCGenericDescriptor_CDC1_10 + }, +\endcode + + !Functional - Call Management Descriptor +\code + { + sizeof(CDCCallManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_CALLMANAGEMENT, + CDCCallManagementDescriptor_SELFCALLMANAGEMENT, + 0 // No associated data interface + }, +\endcode + + !Functional - Abstract Control Management Descriptor +\code + { + sizeof(CDCAbstractControlManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_ABSTRACTCONTROLMANAGEMENT, + CDCAbstractControlManagementDescriptor_LINE + }, +\endcode + + !Functional - Union Descriptor +\code + { + sizeof(CDCUnionDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_UNION, + 0, // Number of master interface is #0 + 1 // First slave interface is #1 + }, +\endcode + + !Notification Endpoint Descriptor + The EP is defined as CDCDSerialDriverDescriptors_NOTIFICATION. +\code + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCDSerialDriverDescriptors_NOTIFICATION), + USBEndpointDescriptor_INTERRUPT, + MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE( + CDCDSerialDriverDescriptors_NOTIFICATION), + USBEndpointDescriptor_MAXINTERRUPTSIZE_FS), + 10 // Endpoint is polled every 10ms + }, +\endcode + + !Data Class Interface Descriptor +\code + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 1, // This is interface #1 + 0, // This is alternate setting #0 for this interface + 2, // This interface uses 2 endpoints + CDCDataInterfaceDescriptor_CLASS, + CDCDataInterfaceDescriptor_SUBCLASS, + CDCDataInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, +\endcode + + !Data Endpoint Descriptors + The EPs are defined as CDCDSerialDriverDescriptors_DATAOUT & + CDCDSerialDriverDescriptors_DATAIN. +\code + // Bulk-OUT endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, + CDCDSerialDriverDescriptors_DATAOUT), + USBEndpointDescriptor_BULK, + MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE( + CDCDSerialDriverDescriptors_DATAOUT), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed bulk endpoints + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCDSerialDriverDescriptors_DATAIN), + USBEndpointDescriptor_BULK, + MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE( + CDCDSerialDriverDescriptors_DATAIN), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed bulk endpoints + }, +\endcode + + !String Descriptors + Several descriptors (device, configuration, interface, etc.) can specify the + index of a string descriptor to comment their use. + + The actual string code is defined: + productStringDescriptor. + + !!Class-specific Requests + The CDC specification defines a set of #class-specific requests# for devices + implementing the ACM. This section details these requests. Please refer to + section 3.6.2.1 of the CDC spec. 1.1 for more information. + + !SetLineCoding, GetLineCoding + These requests are sent by the host to modify or retrieve the configuration of + the serial line, which includes: + - Baudrate + - Number of stop bits + - Parity check + - Number of data bits + + When the terminal application (such as HyperTerminal) on the host (PC) side + changes the setting of the COM port, a SetLineCoding request is sent with the + new parameters. The host may also retrieve the current setting using + GetLineCoding, not modifying them if they are correct. + + When a SET_LINE_CODING request is received, the %device should read the new + parameters. Then program the new parameters in the USART. A callback must be + provided to the USBD_Read function. + See CDCDSerialDriver_SetLineCoding. + + The code handling GET_LINE_CODING shall simply invoke the USBD_Write function + to send the current settings of the USART to the host. + See CDCDSerialDriver_GetLineCoding. + + !SetControlLineState + This request is sent by the host to notify the %device of two state changes. + The first bit (D0) of the wValue field of the request indicates whether or not + a terminal is connected to the virtual COM port. Bit D1 indicates that the + USART should enable/disable its carrier signal to start/stop receiving and + transmitting data. + + In practice, the USB to serial converter should operate only when those two + bits are set. Otherwise, it should not transmit or receive data. + + Since the SET_CONTROL_LINE_STATE request does not have a data payload, the + %device only has to acknowledge the request by sending a ZLP (zero-length + packet), using the USBD_Write method. + See CDCDSerialDriver_SetControlLineState. + + Before that, the wValue field should be parsed to retrieve the new control + line state. A single boolean variable can be used to keep track of the + connection state. If both the D0 and D1 bits are set, then the converter + should operate normally, i.e., forward data between the USART and the USB + host. Otherwise, it should stop its activity. + + !!Notifications + Notifications are sent by the %device when an event, such as a serial line + state change, has occurred. In this example, they are transmitted through a + dedicated Interrupt IN endpoint. A special header must precede the data + payload of each notification. This header has the same format of a SETUP + request, so the USBGenericRequest structure defined in the + "AT91 USB device framework" can be used. + + Note that the %device should only send a notification when there is a state + change, and not continuously. This does not really matter in practice, but + only sending notifications sporadically will reduce the stress on the %device. + + When the serial state is changed by CDCDSerialDriver_SetSerialState, the + notification is sent to the host. + + !!!CDC Serial Driver API + - CDCDSerialDriver_Initialize + - CDCDSerialDriver_RequestHandler + - CDCDSerialDriver_Read + - CDCDSerialDriver_Write + - CDCDSerialDriver_GetSerialState + - CDCDSerialDriver_SetSerialState + + !!!Main Application + The job of the main application is to bridge the USART and the USB. This means + that data read from one end must be forwarded to the other end. This section + describes several possibilities to do this. + + !!USB Operation + Reading data coming from the host is done using the CDCDSerialDriver_Read. + Since this is an asynchronous function, it does not block the execution flow. + This means that other actions (like reading data from the USART) can be + performed while the transfer is going on. Whenever some data is sent by the + host, the transfer terminates and the associated callback function is invoked. + This callback (UsbDataReceived) can be programmed to forward the received data + through the USART. + + Likewise, the CDCDSerialDriver_Write function can be called as soon as there + is data to transmit, again without block the program flow. However, there + cannot be two write operations at the same time, so the program must check + whether or not the last transfer is complete. This can be done by checking the + result code of the CDCDSerialDriver_Write method. If USB_STATUS_LOCKED is + returned, then there is already another operation in progress. The %device + will have to buffer the data retrieved from the USART until the endpoint + becomes free again. + + !!USART Operation + The USART peripheral present on AT91 chips can be used in two different ways. + The classic way is to read and write one byte at a time in the correct + registers to send and receive data. + + A more powerful method is available on AT91SAM chips, by using the embedded + Peripheral DMA Controller (PDC). The PDC can take care of transfers between + the processor, memory and %peripherals, thus freeing the processor to perform + other tasks. Since the PDC interrupt happens on the buffer full, Some timer + can be used to check if there is any data frags input from the USART. + + !!!Using a Generic Host Driver + See "USB CDC Serial Host Driver". + + !!!Add two or more ports in one USB device + See "USB Dual Port CDC Serial Device". + +*/ + +/** + \page "USB CDC Serial Host Driver" + Both Microsoft Windows and Linux offer a generic driver for using a USB to + serial converter %device. This page details the steps required to make use + of them. + + !!!Windows + On Microsoft Windows, the standard USB serial driver is named usbser.sys and + is part of the standard set of drivers. It has been available since Windows + 98SE. However, conversely to other generic driver such as the one for Mass + Storage Devices (MSD), usbser.sys is not automatically loaded when a CDC + %device is plugged in. + + !!Writing a Windows Driver File + For Windows to recognize the %device correctly, it is necessary to write a + .inf file. The Windows Driver Development Kit (DDK) contains information on + this topic. A basic driver, named 6119.inf in the example software provided, + will now be described. The driver file is made up of several sections. + + The first section of the .inf file must be the #[Version]# section. It + contains information about the driver version, provider, release data, and so + on. +\code +[Version] +Signature="$Chicago$" +Class=Ports +ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} +Provider=%ATMEL% +DriverVer=09/12/2006,1.1.1.1 +\endcode + + The Signature attribute is mandatory and can be either "$Windows 95$", + "$Windows NT$" or "$Chicago$", depending on which Windows version(s) the + driver supports. "$Chicago$" is used to notify that every Windows version is + supported. Since in this example, the USB to serial converter is a virtual COM + port, the Class attribute should be equal to "Ports". The value of ClassGuid + depends on which class the %device uses. The Provider value indicates that the + string descriptor for the driver provider will be defined further, under the + tag ATMEL. Finally, the last tag show the driver version and release date. For + the version number, each digit is optional (except the first one), but must + not be null if present. + + Next come two sections, #[SourceDisksNames]# and #[SourceDisksFiles]#. They + are used to specify the installation disks required and the location of each + needed files on these disks. But they are not implemented because the file + is offered by windows or its install disk automatically. +\code +;[SourceDisksNames] +;1="Windows Install CD" +;[SourceDisksFiles] +;usbser.sys=1 +\endcode + + The driver file must now specify where copied files will be stored, using the + #[DestinationDirs]# section. +\code +[DestinationDirs] +DefaultDestDir=12 +\endcode + The target directory must be identified by its ID, which is system-defined. + The ID for the drivers directory is 12. + + The #[Manufacturer]# section lists the possible manufacturers for all devices + supported by this driver. In this case, the only supported %device is an ATMEL + one, so this will be the only value. +\code +[Manufacturer] +%ATMEL%=AtmelMfg +\endcode + + The attribute must be a string tag; its value must be the name of the Models + section in which all supported devices from this manufacturer will be listed. + In this case, it will be named AtmelMfg, which is the next section. + + Each Models section must list the hardware ID of each supported %device. For + USB devices, the hardware ID is made up of the Vendor ID, the Product ID and + (optionally) the Device Release Number. Those values are extracted from the + %device descriptor provided during the enumeration phase. +\code +[AtmelMfg] +%USBtoSerialConverter%=USBtoSer.Install,USB\VID_03EB&PID_6119 +\endcode + + The attribute name is again a string tag, which will be used to describe the + %device. The value is comprised of both the %device install section name + (USBtoSer.Install) and the hardware ID. The hardware ID is the same as the one + defined in "CDC Serial Device IDs". + + Now, the .inf file must detail the install section of each %device previously + listed. In this example, there is only one install section, named + #[USBtoSer.Install]#: +\code +[USBtoSer.Install] +CopyFiles=USBtoSer.CopyFiles +AddReg=USBtoSer.AddReg + +[USBtoSer.CopyFiles] +usbser.sys,,,0x00000002 + +[USBtoSer.AddReg] +HKR,,DevLoader,,*ntkern +HKR,,NTMPDriver,,usbser.sys + +[USBtoSer.Install.Services] +AddService=usbser,0x00000002,USBtoSer.AddService + +[USBtoSer.AddService] +DisplayName=%USBSer% +ServiceType=1r +StartType=3 +ServiceBinary=%12%\usbser.sys +\endcode + + The install section is actually divided in five. In the first section, two + other section names are specified: one for the list of files to copy, and one + for the keys to add to the Windows registry. There is only one file to copy, + usbser.sys; a flag (0x00000002) is used to specify that the user cannot skip + copying it. The registry keys are needed to install the driver on older + versions of Windows (such as Windows 98). For newer versions, the + #[USBtoSer.Install.Services]# registers the needed kernel services; each + service is actually listed in a section on its own. + + Finally, the last section, [Strings], defines all the string constants used + through this file: +\code +[Strings] +ATMEL="ATMEL Corp." +USBtoSerialConverter="AT91 USB to Serial Converter" +USBSer="USB Serial Driver" +\endcode + + !!Using the Driver + When a new %device is plugged in for the first time, Windows looks for an + appropriate specific or generic driver to use it. If it does not find one, the + user is asked what to do. + + This is the case with the USB to serial converter, since there is no generic + driver for it. To install the custom driver given in the previous section, + Windows must be told where to look for it. This can be done by selecting the + second option, "Install from a list or specific location", when the driver + installation wizards pops up. It will then ask for the directory where the + driver is located. After that, it should recognize the "AT91 USB to Serial + Converter" driver as an appropriate one and display it in the list. + + During the installation, the wizard asks for the location of the usbser.sys + file. If it is already installed on the system, it can be found in + "C:\Windows\System32\Drivers\". Otherwise, it is present on the Windows + installation CD. + + Once the driver is installed properly, a new COM port is added to the system + and can be used with HyperTerminal, for example. + + !!!Linux + Linux has two different generic drivers which are appropriate for a USB to + serial converter. The first one is an Abstract Control Model driver designed + for modem devices, and is simply named #acm#. The other one is a generic USB + to serial driver named #usbserial#. + + If the support for the #acm# driver has been compiled in the kernel, Linux + will automatically load it. A new terminal %device will be created under + /dev/ttyACMx. + + The usbserial driver must be loaded manually by using the modprobe command + with the vendor ID and product ID values used by the %device: +\code + modprobe usbserial vendor=0x03EB product=0x6119 +\endcode + + Once the driver is loaded, a new terminal entry appears and should be named + /dev/ttyUSBx. +*/ + +/** + \page "USB Dual Port CDC Serial Device" + +*/ diff --git a/usb/device/cdc-serial/drv/6119.inf b/usb/device/cdc-serial/drv/6119.inf new file mode 100644 index 0000000..14bd8d3 --- /dev/null +++ b/usb/device/cdc-serial/drv/6119.inf @@ -0,0 +1,45 @@ +; $Id: 6119.inf,v 1.1.2.1 2006/12/05 08:33:25 danielru Exp $ + +[Version] ; Version section +Signature="$Chicago$" ; All Windows versions +Class=Ports ; This is a serial port driver +ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} ; Associated GUID +Provider=%ATMEL% ; Driver is provided by ATMEL +DriverVer=09/12/2006,1.1.1.5 ; Driver version 1.1.1.5 published on 23 February 2007 + +[DestinationDirs] ; DestinationDirs section +DefaultDestDir=12 ; Default install directory is \drivers or \IOSubSys + +[Manufacturer] ; Manufacturer section +%ATMEL%=AtmelMfg ; Only one manufacturer (ATMEL), models section is named + ; AtmelMfg + +[AtmelMfg] ; Models section corresponding to ATMEL +%USBtoSerialConverter%=USBtoSer.Install,USB\VID_03EB&PID_6119 ; Identifies a device with ATMEL Vendor ID (03EBh) and + ; Product ID equal to 6119h. Corresponding Install section + ; is named USBtoSer.Install + +[USBtoSer.Install] ; Install section +include=mdmcpq.inf +CopyFiles=FakeModemCopyFileSection +AddReg=USBtoSer.AddReg ; Registry keys to add are listed in USBtoSer.AddReg + +[USBtoSer.AddReg] ; AddReg section +HKR,,DevLoader,,*ntkern ; +HKR,,NTMPDriver,,usbser.sys +HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" + +[USBtoSer.Install.Services] ; Services section +AddService=usbser,0x00000002,USBtoSer.AddService ; Assign usbser as the PnP driver for the device + +[USBtoSer.AddService] ; Service install section +DisplayName=%USBSer% ; Name of the serial driver +ServiceType=1 ; Service kernel driver +StartType=3 ; Driver is started by the PnP manager +ErrorControl=1 ; Warn about errors +ServiceBinary=%12%\usbser.sys ; Driver filename + +[Strings] ; Strings section +ATMEL="ATMEL Corp." ; String value for the ATMEL symbol +USBtoSerialConverter="AT91 USB to Serial Converter" ; String value for the USBtoSerialConverter symbol +USBSer="USB Serial Driver" ; String value for the USBSer symbol \ No newline at end of file diff --git a/usb/device/cdc-serial/drv/drv.dir b/usb/device/cdc-serial/drv/drv.dir new file mode 100644 index 0000000..a2ff78a --- /dev/null +++ b/usb/device/cdc-serial/drv/drv.dir @@ -0,0 +1,41 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// +/// !!!Purpose +/// +/// This directory provides install file for a CDC serial port %device. +/// +/// !!!Contents +/// +/// 6119.inf +/// +//------------------------------------------------------------------------------ diff --git a/usb/device/composite/AUDDFunctionDriver.c b/usb/device/composite/AUDDFunctionDriver.c new file mode 100644 index 0000000..a1645aa --- /dev/null +++ b/usb/device/composite/AUDDFunctionDriver.c @@ -0,0 +1,282 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#if defined(usb_CDCAUDIO) || defined(usb_HIDAUDIO) + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +// GENERAL +#include +#include +#include +// USB +#include +// AUDIO +#include +#include + +#include "AUDDFunctionDriver.h" +#include "AUDDFunctionDriverDescriptors.h" + +//----------------------------------------------------------------------------- +// Internal variables +//----------------------------------------------------------------------------- + +/// USB audio speaker driver instance. +static AUDDSpeakerChannel auddSpeakerChannels[AUDD_NUMCHANNELS+1]; +/// Intermediate storage variable for the mute status of a channel. +static unsigned char muted; + +//----------------------------------------------------------------------------- +// Internal functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Changes the mute status of the given channel accordingly. +/// \param channel Number of the channel whose mute status has changed. +//----------------------------------------------------------------------------- +static void AUDD_MuteReceived(unsigned char channel) +{ + AUDDSpeakerChannel *pChannel = &auddSpeakerChannels[channel]; + if (muted) { + + if (!pChannel->muted) { + + pChannel->muted = 1; + AUDDSpeakerChannel_MuteChanged(pChannel, 1); + } + } + else { + + if (pChannel->muted) { + + pChannel->muted = 0; + AUDDSpeakerChannel_MuteChanged(pChannel, 0); + } + } + + USBD_Write(0, 0, 0, 0, 0); +} + +//----------------------------------------------------------------------------- +/// Sets the current value of a particular Feature control of a channel. +/// \param channel Number of the channel whose feature will change. +/// \param control The feature control that will change. +/// \param length The feature data size. +//----------------------------------------------------------------------------- +static void AUDD_SetFeatureCurrentValue(unsigned char channel, + unsigned char control, + unsigned short length) +{ + TRACE_INFO_WP("sFeature "); + TRACE_DEBUG("\b(CS%d, CN%d, L%d) ", control, channel, length); + + // Check the the requested control is supported + // Mute control on master channel + if ((control == AUDFeatureUnitRequest_MUTE) + && (channel < (AUDD_NUMCHANNELS+1)) + && (length == 1)) { + + unsigned int argument = channel; // Avoids compiler warning + USBD_Read(0, // Endpoint #0 + &muted, + sizeof(muted), + (TransferCallback) AUDD_MuteReceived, + (void *) argument); + } + // Control/channel combination not supported + else { + + USBD_Stall(0); + } +} + +//----------------------------------------------------------------------------- +/// Sends the current value of a particular channel Feature to the USB host. +/// \param channel Number of the channel whose feature will be sent. +/// \param control The feature control that will be sent. +/// \param length The feature data size. +//----------------------------------------------------------------------------- +static void AUDD_GetFeatureCurrentValue(unsigned char channel, + unsigned char control, + unsigned char length) +{ + TRACE_INFO_WP("gFeature "); + TRACE_DEBUG("\b(CS%d, CN%d, L%d) ", control, channel, length); + + // Check that the requested control is supported + // Master channel mute control + if ((control == AUDFeatureUnitRequest_MUTE) + && (channel < (AUDD_NUMCHANNELS+1)) + && (length == 1)) { + + muted = auddSpeakerChannels[channel].muted; + USBD_Write(0, &muted, sizeof(muted), 0, 0); + } + else { + + USBD_Stall(0); + } +} + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Initializes an USB audio speaker function driver +//----------------------------------------------------------------------------- +void AUDDFunctionDriver_Initialize() +{ + auddSpeakerChannels[0].muted = 0; + auddSpeakerChannels[0].number = AUDD_MASTERCHANNEL; + auddSpeakerChannels[1].muted = 0; + auddSpeakerChannels[1].number = AUDD_LEFTCHANNEL; + auddSpeakerChannels[2].muted = 0; + auddSpeakerChannels[2].number = AUDD_RIGHTCHANNEL; + + // Initialize the third LED to indicate when the audio interface is active + LED_Configure(USBD_LEDOTHER); +} + +//----------------------------------------------------------------------------- +/// Handles AUDIO-specific USB requests sent by the host +/// \param request Pointer to a USBGenericRequest instance. +/// \return 0 if the request is Unsupported, 1 if the request handled. +//----------------------------------------------------------------------------- +unsigned char AUDDFunctionDriver_RequestHandler( + const USBGenericRequest *request) +{ + unsigned char entity; + unsigned char interface; + + // Check if the request is supported + switch (USBGenericRequest_GetRequest(request)) { + + case AUDGenericRequest_SETCUR: + TRACE_INFO_WP( + "sCur(0x%04X) ", + USBGenericRequest_GetIndex(request)); + + // Check the target interface and entity + entity = AUDGenericRequest_GetEntity(request); + interface = AUDGenericRequest_GetInterface(request); + if ((entity == AUDD_Descriptors_FEATUREUNIT) + && (interface == AUDD_Descriptors_CONTROL)) { + + AUDD_SetFeatureCurrentValue( + AUDFeatureUnitRequest_GetChannel(request), + AUDFeatureUnitRequest_GetControl(request), + USBGenericRequest_GetLength(request)); + } + else { + + TRACE_WARNING( + "AUDDSpeakerDriver_RequestHandler: Unsupported entity/interface combination (0x%04X)\n\r", + USBGenericRequest_GetIndex(request)); + USBD_Stall(0); + } + break; + + case AUDGenericRequest_GETCUR: + TRACE_INFO_WP( + "gCur(0x%04X) ", + USBGenericRequest_GetIndex(request)); + + // Check the target interface and entity + entity = AUDGenericRequest_GetEntity(request); + interface = AUDGenericRequest_GetInterface(request); + if ((entity == AUDD_Descriptors_FEATUREUNIT) + && (interface == AUDD_Descriptors_CONTROL)) { + + AUDD_GetFeatureCurrentValue( + AUDFeatureUnitRequest_GetChannel(request), + AUDFeatureUnitRequest_GetControl(request), + USBGenericRequest_GetLength(request)); + } + else { + + TRACE_WARNING( + "AUDDSpeakerDriver_RequestHandler: Unsupported entity/interface combination (0x%04X)\n\r", + USBGenericRequest_GetIndex(request)); + USBD_Stall(0); + } + break; + + default: + return 0; + } + return 1; +} + +//----------------------------------------------------------------------------- +/// Invoked whenever the active setting of an interface is changed by the +/// host. Changes the status of the third LED accordingly. +/// \param interface Interface number. +/// \param setting Newly active setting. +//----------------------------------------------------------------------------- +void AUDDFunctionCallbacks_InterfaceSettingChanged(unsigned char interface, + unsigned char setting) +{ + if ((interface == AUDD_Descriptors_STREAMING) && (setting == 0)) { + + LED_Clear(USBD_LEDOTHER); + } + else { + + LED_Set(USBD_LEDOTHER); + } +} + +//----------------------------------------------------------------------------- +/// Reads incoming audio data sent by the USB host into the provided buffer. +/// When the transfer is complete, an optional callback function is invoked. +/// \param buffer Pointer to the data storage buffer. +/// \param length Size of the buffer in bytes. +/// \param callback Optional callback function. +/// \param argument Optional argument to the callback function. +/// \return if the transfer is started successfully; +/// otherwise an error code. +//----------------------------------------------------------------------------- +unsigned char AUDDSpeakerDriver_Read(void *buffer, + unsigned int length, + TransferCallback callback, + void *argument) +{ + return USBD_Read(AUDD_Descriptors_DATAOUT, + buffer, + length, + callback, + argument); +} + +#endif // (AUDIO defined) + diff --git a/usb/device/composite/AUDDFunctionDriver.h b/usb/device/composite/AUDDFunctionDriver.h new file mode 100644 index 0000000..637fc67 --- /dev/null +++ b/usb/device/composite/AUDDFunctionDriver.h @@ -0,0 +1,105 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef AUDDFUNCTIONDRIVER_H +#define AUDDFUNCTIONDRIVER_H + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include +#include + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +/// Sample rate in Hz. +#define AUDD_SAMPLERATE 48000 +/// Number of channels in audio stream. +#define AUDD_NUMCHANNELS 2 +/// Number of bytes in one sample. +#define AUDD_BYTESPERSAMPLE 2 +/// Number of bits in one sample. +#define AUDD_BITSPERSAMPLE (AUDD_BYTESPERSAMPLE * 8) +/// Number of samples in one USB subframe. +#define AUDD_BYTESPERSUBFRAME (AUDD_NUMCHANNELS * AUDD_BYTESPERSAMPLE) +/// Number of samples in one USB frame. +#define AUDD_SAMPLESPERFRAME (AUDD_SAMPLERATE / 1000 * AUDD_NUMCHANNELS) +/// Number of bytes in one USB frame. +#define AUDD_BYTESPERFRAME (AUDD_SAMPLESPERFRAME * AUDD_BYTESPERSAMPLE) +/// Master channel. +#define AUDD_MASTERCHANNEL 0 +/// Front left channel. +#define AUDD_LEFTCHANNEL 1 +/// Front right channel. +#define AUDD_RIGHTCHANNEL 2 + +//----------------------------------------------------------------------------- +// Structs +//----------------------------------------------------------------------------- + +/// AUDIO Speaker channel struct +typedef struct { + + unsigned char number; + unsigned char muted; + +} AUDDSpeakerChannel; + +//----------------------------------------------------------------------------- +// Callbacks +//----------------------------------------------------------------------------- +extern void AUDDSpeakerChannel_MuteChanged(AUDDSpeakerChannel *channel, + unsigned char muted); + +extern void AUDDFunctionCallbacks_InterfaceSettingChanged( + unsigned char interface, + unsigned char setting); + + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +//- Function API For composite device +extern void AUDDFunctionDriver_Initialize(); + +extern unsigned char AUDDFunctionDriver_RequestHandler( + const USBGenericRequest * request); + +//- AUDIO Speaker API +extern unsigned char AUDDSpeakerDriver_Read(void *buffer, + unsigned int length, + TransferCallback callback, + void *argument); + +#endif // #define AUDDFUNCTIONDRIVER_H + diff --git a/usb/device/composite/AUDDFunctionDriverDescriptors.h b/usb/device/composite/AUDDFunctionDriverDescriptors.h new file mode 100644 index 0000000..a5a64f4 --- /dev/null +++ b/usb/device/composite/AUDDFunctionDriverDescriptors.h @@ -0,0 +1,69 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef AUDDFUNCTIONDRIVERDESCRIPTORS_H +#define AUDDFUNCTIONDRIVERDESCRIPTORS_H + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include +#include + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +/// COMPOSITE option +#if defined(usb_CDCAUDIO) +#define AUDD_Descriptors_INTERFACE 2 +#elif defined(usb_HIDAUDIO) +#define AUDD_Descriptors_INTERFACE 1 +#endif + +/// - Endpoint numbers +/// Data out endpoint number +#define AUDD_Descriptors_DATAOUT 0x05 + +/// - Interface IDs +/// Audio control interface ID +#define AUDD_Descriptors_CONTROL (AUDD_Descriptors_INTERFACE + 0) +/// Audio streaming interface ID +#define AUDD_Descriptors_STREAMING (AUDD_Descriptors_INTERFACE + 1) + +/// - Entity IDs +/// Input terminal ID. +#define AUDD_Descriptors_INPUTTERMINAL 0 +/// Output terminal ID. +#define AUDD_Descriptors_OUTPUTTERMINAL 1 +/// Feature unit ID. +#define AUDD_Descriptors_FEATUREUNIT 2 + +#endif // #define AUDDFUNCTIONDRIVERDESCRIPTORS_H diff --git a/usb/device/composite/CDCDFunctionDriver.c b/usb/device/composite/CDCDFunctionDriver.c new file mode 100644 index 0000000..4e42015 --- /dev/null +++ b/usb/device/composite/CDCDFunctionDriver.c @@ -0,0 +1,337 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +// GENERAL +#include +#include +// USB +#include +#include +// CDC +#include +#include + +#include "CDCDFunctionDriver.h" +#include "CDCDFunctionDriverDescriptors.h" + +//----------------------------------------------------------------------------- +// Defines +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Types +//----------------------------------------------------------------------------- + +/// CDC Function Driver Struct +typedef struct { + USBDDriver * pUsbdDriver; + CDCDSerialPort * pCdcPorts; + unsigned char numPorts; +} CDCFunDriver; + +//----------------------------------------------------------------------------- +// Internal variables +//----------------------------------------------------------------------------- + +/// CDC Function Driver instance +static CDCFunDriver cdcFunDriver; + +//----------------------------------------------------------------------------- +// Internal functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Callback function which should be invoked after the data of a +/// SetLineCoding request has been retrieved. Sends a zero-length packet +/// to the host for acknowledging the request. +//----------------------------------------------------------------------------- +static void CDCD_SetLineCodingCallback() +{ + USBD_Write(0, 0, 0, 0, 0); +} + +//----------------------------------------------------------------------------- +/// Return the port index that host send this request for. +//----------------------------------------------------------------------------- +static char CDCD_GetSerialPort(const USBGenericRequest *request) +{ + unsigned char i; + for (i = 0; i < cdcFunDriver.numPorts; i ++) { + if (request->wIndex == cdcFunDriver.pCdcPorts[i].interfaceNum + 1) + return i; + } + return 0xFF; +} + +//----------------------------------------------------------------------------- +/// Receives new line coding information from the USB host. +/// \param request Pointer to a USBGenericRequest instance. +//----------------------------------------------------------------------------- +static void CDCD_SetLineCoding(const USBGenericRequest *request) +{ + unsigned char serial; + serial = CDCD_GetSerialPort(request); + + TRACE_INFO_WP("sLineCoding_%d ", serial); + + USBD_Read(0, + (void *) &(cdcFunDriver.pCdcPorts[serial].lineCoding), + sizeof(CDCLineCoding), + (TransferCallback) CDCD_SetLineCodingCallback, + 0); +} + +//----------------------------------------------------------------------------- +/// Sends the current line coding information to the host through Control +/// endpoint 0. +/// \param request Pointer to a USBGenericRequest instance. +//----------------------------------------------------------------------------- +static void CDCD_GetLineCoding(const USBGenericRequest *request) +{ + unsigned char serial; + serial = CDCD_GetSerialPort(request); + + TRACE_INFO_WP("gLineCoding_%d ", serial); + + USBD_Write(0, + (void *) &(cdcFunDriver.pCdcPorts[serial].lineCoding), + sizeof(CDCLineCoding), + 0, + 0); +} + +//----------------------------------------------------------------------------- +/// Changes the state of the serial driver according to the information +/// sent by the host via a SetControlLineState request, and acknowledges +/// the request with a zero-length packet. +/// \param request Pointer to a USBGenericRequest instance. +/// \param activateCarrier The active carrier state to set. +/// \param isDTEPresent The DTE status. +//----------------------------------------------------------------------------- +static void CDCD_SetControlLineState(const USBGenericRequest *request, + unsigned char activateCarrier, + unsigned char isDTEPresent) +{ + unsigned char serial; + serial = CDCD_GetSerialPort(request); + + TRACE_INFO_WP( + "sControlLineState_%d(%d, %d) ", + serial, + activateCarrier, + isDTEPresent); + + cdcFunDriver.pCdcPorts[serial].isCarrierActivated = activateCarrier; + USBD_Write(0, 0, 0, 0, 0); +} + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Initializes the USB device CDC serial function driver. +//----------------------------------------------------------------------------- +void CDCDFunctionDriver_Initialize(USBDDriver * pUsbdDriver, + CDCDSerialPort * pCdcPorts, + unsigned char numPorts) +{ + unsigned char serial; + + TRACE_INFO("CDCDFunctionDriver_Initialize\n\r"); + + cdcFunDriver.pUsbdDriver = pUsbdDriver; + cdcFunDriver.pCdcPorts = pCdcPorts; + cdcFunDriver.numPorts = numPorts; + + for (serial = 0; serial < numPorts; serial ++) { + + CDCDSerialPort * pSerial = &cdcFunDriver.pCdcPorts[serial]; + + // Initialize Abstract Control Model attributes + CDCLineCoding_Initialize(&(pSerial->lineCoding), + 115200, + CDCLineCoding_ONESTOPBIT, + CDCLineCoding_NOPARITY, + 8); + pSerial->isCarrierActivated = 0; + pSerial->serialState = 0; + } +} + +//----------------------------------------------------------------------------- +/// Handles CDC/ACM-specific USB requests sent by the host +/// \param request Pointer to a USBGenericRequest instance. +/// \return 0 if the request is Unsupported, 1 if the request handled. +//----------------------------------------------------------------------------- +unsigned char CDCDFunctionDriver_RequestHandler( + const USBGenericRequest *request) +{ + switch (USBGenericRequest_GetRequest(request)) { + + case CDCGenericRequest_SETLINECODING: + + CDCD_SetLineCoding(request); + break; + + case CDCGenericRequest_GETLINECODING: + + CDCD_GetLineCoding(request); + break; + + case CDCGenericRequest_SETCONTROLLINESTATE: + + CDCD_SetControlLineState(request, + CDCSetControlLineStateRequest_ActivateCarrier(request), + CDCSetControlLineStateRequest_IsDtePresent(request)); + + break; + + // Unsupported request + default: + return 0; + + } + return 1; +} + +//----------------------------------------------------------------------------- +/// Receives data from the host through the virtual COM port created by +/// the CDC function serial driver. This function behaves like . +/// \param Port Port index to receive. +/// \param Pointer to the data buffer to send. +/// \param Size of the data buffer in bytes. +/// \param callback Optional callback function to invoke when the transfer +/// finishes. +/// \param argument Optional argument to the callback function. +/// \return if the read operation started normally; +/// otherwise, the corresponding error code. +//----------------------------------------------------------------------------- +unsigned char CDCDSerialDriver_Read(unsigned char port, + void *data, + unsigned int size, + TransferCallback callback, + void *argument) +{ + unsigned char ep = cdcFunDriver.pCdcPorts[port].bulkOutEndpoint; + + if (port > cdcFunDriver.numPorts) + return USBD_STATUS_INVALID_PARAMETER; + + return USBD_Read(ep, + data, + size, + callback, + argument); +} + +//----------------------------------------------------------------------------- +/// Sends a data buffer through the virtual COM port created by the CDC +/// function serial driver. This function behaves exactly like . +/// \param port Port index to receive. +/// \param data - Pointer to the data buffer to send. +/// \param size - Size of the data buffer in bytes. +/// \param callback - Optional callback function to invoke when the transfer +/// finishes. +/// \param argument - Optional argument to the callback function. +/// \return if the write operation started normally; +/// otherwise, the corresponding error code. +//----------------------------------------------------------------------------- +unsigned char CDCDSerialDriver_Write(unsigned char port, + void *data, + unsigned int size, + TransferCallback callback, + void *argument) +{ + unsigned char ep = cdcFunDriver.pCdcPorts[port].bulkInEndpoint; + + if (port > cdcFunDriver.numPorts) + return USBD_STATUS_INVALID_PARAMETER; + + return USBD_Write(ep, + data, + size, + callback, + argument); +} + +//------------------------------------------------------------------------------ +/// Returns the current status of the RS-232 line. +/// \param port The port number that checked. +//------------------------------------------------------------------------------ +unsigned short CDCDSerialDriver_GetSerialState(unsigned char port) +{ + if (port > cdcFunDriver.numPorts) + return USBD_STATUS_INVALID_PARAMETER; + + return cdcFunDriver.pCdcPorts[port].serialState; +} + +//------------------------------------------------------------------------------ +/// Sets the current serial state of the device to the given value. +/// \param port The port number that the port state should be changed. +/// \param serialState New device state. +//------------------------------------------------------------------------------ +void CDCDSerialDriver_SetSerialState(unsigned char port, + unsigned short serialState) +{ + CDCDSerialPort * pPort; + unsigned char ep; + + ASSERT((serialState & 0xFF80) == 0, + "CDCDSerialDriver_SetSerialState: Bits D7-D15 are reserved!\n\r"); + + if (port > cdcFunDriver.numPorts) + return; + + // If new state is different from previous one, send a notification to the + // host + pPort = &cdcFunDriver.pCdcPorts[port]; + ep = pPort->interruptInEndpoint; + if (pPort->serialState != serialState) { + + pPort->serialState = serialState; + USBD_Write(ep, + &(pPort->serialState), + 2, + 0, + 0); + + // Reset one-time flags + pPort->serialState &= ~(CDCD_STATE_OVERRUN + | CDCD_STATE_PARITY + | CDCD_STATE_FRAMING + | CDCD_STATE_RINGSIGNAL + | CDCD_STATE_BREAK); + } +} diff --git a/usb/device/composite/CDCDFunctionDriver.h b/usb/device/composite/CDCDFunctionDriver.h new file mode 100644 index 0000000..0a9e5d2 --- /dev/null +++ b/usb/device/composite/CDCDFunctionDriver.h @@ -0,0 +1,128 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef CDCDFUNCTIONDRIVER_H +#define CDCDFUNCTIONDRIVER_H + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include +#include +#include + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +/// Indicates the receiver carrier signal is present. +#define CDCD_STATE_RXDRIVER (1 << 0) +/// Indicates the transmission carrier signal is present. +#define CDCD_STATE_TXCARRIER (1 << 1) +/// Indicates a break has been detected. +#define CDCD_STATE_BREAK (1 << 2) +/// Indicates a ring signal has been detected. +#define CDCD_STATE_RINGSIGNAL (1 << 3) +/// Indicates a framing error has occured. +#define CDCD_STATE_FRAMING (1 << 4) +/// Indicates a parity error has occured. +#define CDCD_STATE_PARITY (1 << 5) +/// Indicates a data overrun error has occured. +#define CDCD_STATE_OVERRUN (1 << 6) + +//----------------------------------------------------------------------------- +// Structs +//----------------------------------------------------------------------------- + +/// CDC Serial port struct +typedef struct _CDCDSerialPort{ + + /// USB interface settings + unsigned char interfaceNum; + unsigned char interruptInEndpoint; + unsigned char bulkInEndpoint; + unsigned char bulkOutEndpoint; + /// serial port settings + CDCLineCoding lineCoding; + unsigned char isCarrierActivated; + unsigned short serialState; + +} CDCDSerialPort; + +//----------------------------------------------------------------------------- +// Macros +//----------------------------------------------------------------------------- + +#define CDCDFunctionDriver_ConfigurePort(pPort,ifNum,intIN,bulkIN,bulkOUT) \ +{\ + (pPort)->interfaceNum=(ifNum);(pPort)->interruptInEndpoint=(intIN); \ + (pPort)->bulkInEndpoint=(bulkIN);(pPort)->bulkOutEndpoint=(bulkOUT); \ +} + +//----------------------------------------------------------------------------- +// Callbacks +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +//- Function API for composite device +extern void CDCDFunctionDriver_Initialize(USBDDriver * pUsbdDriver, + CDCDSerialPort * pCdcPorts, + unsigned char numPorts); + +extern unsigned char CDCDFunctionDriver_RequestHandler( + const USBGenericRequest * request); + +//- CDC Serial Port API +extern unsigned char CDCDSerialDriver_Write( + unsigned char port, + void *data, + unsigned int size, + TransferCallback callback, + void *argument); + +extern unsigned char CDCDSerialDriver_Read( + unsigned char port, + void *data, + unsigned int size, + TransferCallback callback, + void *argument); + +extern unsigned short CDCDSerialDriver_GetSerialState(unsigned char port); + +extern void CDCDSerialDriver_SetSerialState( + unsigned char port, + unsigned short serialState); + + +#endif // #define CDCDFUNCTIONDRIVER_H + diff --git a/usb/device/composite/CDCDFunctionDriverDescriptors.h b/usb/device/composite/CDCDFunctionDriverDescriptors.h new file mode 100644 index 0000000..33490ae --- /dev/null +++ b/usb/device/composite/CDCDFunctionDriverDescriptors.h @@ -0,0 +1,65 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef CDCDFUNCTIONDRIVERDESCRIPTORS_H +#define CDCDFUNCTIONDRIVERDESCRIPTORS_H + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include +#include + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +#if defined(usb_CDCAUDIO) +#define CDCD_Descriptors_INTERFACENUM0 0 +#define CDCD_Descriptors_NOTIFICATION0 3 +#define CDCD_Descriptors_DATAIN0 2 +#define CDCD_Descriptors_DATAOUT0 1 +#endif + +/// Default CDC interrupt endpoints max packat size (8). +#define CDCD_Descriptors_INTERRUPT_MAXPACKETSIZE 8 +/// Default CDC bulk endpoints max packat size (128, for HS actually). +#define CDCD_Descriptors_BULK_MAXPACKETSIZE 128 + +/// Default CDC interrupt IN endpoint polling rate of Full Speed (16ms). +#define CDCD_Descriptors_INTERRUPTIN_POLLING_FS 16 +/// Default CDC interrupt IN endpoint polling rate of High Speed (16ms). +#define CDCD_Descriptors_INTERRUPTIN_POLLING_HS 8 +/// Default interrupt OUT endpoint polling rate of Full Speed (16ms). +#define CDCD_Descriptors_INTERRUPTOUT_POLLING_FS 16 +/// Default interrupt OUT endpoint polling rate of High Speed (16ms). +#define CDCD_Descriptors_INTERRUPTOUT_POLLING_HS 8 + +#endif // #define CDCFUNCTIONDRIVERDESCRIPTORS_H diff --git a/usb/device/composite/CDCHIDDDriver.c b/usb/device/composite/CDCHIDDDriver.c new file mode 100644 index 0000000..84c16a6 --- /dev/null +++ b/usb/device/composite/CDCHIDDDriver.c @@ -0,0 +1,227 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +// GENERAL +#include +#include +#include + +// USB +#include +#include + +//- HID +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +//- MSD +#if defined(usb_CDCMSD) || defined(usb_HIDMSD) +#endif + +//- CDCHID +#include "CDCHIDDDriver.h" +#include "CDCHIDDDriverDescriptors.h" + +//----------------------------------------------------------------------------- +// Defines +//----------------------------------------------------------------------------- + +/// Interface setting spaces (4 byte aligned) +#define NUM_INTERFACES ((CDCHIDDDriverDescriptors_NUMINTERFACE+3)&0xFC) + +//----------------------------------------------------------------------------- +// Types +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Internal variables +//----------------------------------------------------------------------------- + +/// USBDDriver instance +static USBDDriver usbdDriver; + +/// CDCDSeriaoPort instance +static CDCDSerialPort cdcdPort; + +/// Array for storing the current setting of each interface +static unsigned char cdchiddDriverInterfaces[NUM_INTERFACES]; + +//----------------------------------------------------------------------------- +// Internal functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Optional RequestReceived() callback re-implementation +//----------------------------------------------------------------------------- +#if !defined(NOAUTOCALLBACK) + +void USBDCallbacks_RequestReceived(const USBGenericRequest *request) +{ + CDCHIDDDriver_RequestHandler(request); +} + +#endif + +//----------------------------------------------------------------------------- +// ConfigurationChanged() callback re-implementation +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Invoked whenever the configuration value of a device is changed by the host +/// \param cfgnum Configuration number. +//----------------------------------------------------------------------------- +void USBDDriverCallbacks_ConfigurationChanged(unsigned char cfgnum) +{ + // HID + HIDDFunctionCallbacks_ConfigurationChanged(cfgnum); +} + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Initializes the USB device composite device driver. +//----------------------------------------------------------------------------- +void CDCHIDDDriver_Initialize() +{ + // CDC + CDCDFunctionDriver_ConfigurePort(&cdcdPort, + CDCD_Descriptors_INTERFACENUM0, + CDCD_Descriptors_NOTIFICATION0, + CDCD_Descriptors_DATAIN0, + CDCD_Descriptors_DATAOUT0); + CDCDFunctionDriver_Initialize(&usbdDriver, + &cdcdPort, + 1); + + // HID + HIDDFunctionDriver_Initialize(&usbdDriver, + HIDD_Descriptors_INTERFACENUM, + HIDD_Descriptors_INTERRUPTIN, + HIDD_Descriptors_INTERRUPTOUT); + + // Initialize the standard USB driver + USBDDriver_Initialize(&usbdDriver, + &cdchiddDriverDescriptors, + cdchiddDriverInterfaces); + + // Initialize the USB driver + USBD_Init(); +} + +//----------------------------------------------------------------------------- +/// Handles composite-specific USB requests sent by the host, and forwards +/// standard ones to the USB device driver. +/// \param request Pointer to a USBGenericRequest instance. +//----------------------------------------------------------------------------- +void CDCHIDDDriver_RequestHandler(const USBGenericRequest *request) +{ + // Check if this is a class request + if (USBGenericRequest_GetType(request) == USBGenericRequest_CLASS) { + + unsigned char rc = 0; + + // CDC class request + if (rc == 0) { + + rc = CDCDFunctionDriver_RequestHandler(request); + } + + // HID class request + if (rc == 0) { + + rc = HIDDFunctionDriver_RequestHandler(request); + } + + if (!rc) { + + TRACE_WARNING( + "CDCHIDDDriver_RequestHandler: Unsupported request (%d)\n\r", + USBGenericRequest_GetRequest(request)); + USBD_Stall(0); + } + + } + // Check if this is a standard request + else if (USBGenericRequest_GetType(request) == USBGenericRequest_STANDARD) { + + unsigned char rc = 0; + + rc = HIDDFunctionDriver_RequestHandler(request); + + // Forward request to the standard handler + if (rc == 0) { + + USBDDriver_RequestHandler(&(usbdDriver), request); + } + } + // Unsupported request type + else { + + TRACE_WARNING( + "CDCHIDDDriver_RequestHandler: Unsupported request type (%d)\n\r", + USBGenericRequest_GetType(request)); + USBD_Stall(0); + } +} + +//----------------------------------------------------------------------------- +/// Starts a remote wake-up sequence if the host has explicitely enabled it +/// by sending the appropriate SET_FEATURE request. +//----------------------------------------------------------------------------- +void CDCHIDDDriver_RemoteWakeUp(void) +{ + // Remote wake-up has been enabled + if (USBDDriver_IsRemoteWakeUpEnabled(&usbdDriver)) { + + USBD_RemoteWakeUp(); + } + // Remote wake-up NOT enabled + else { + + TRACE_WARNING("CDCHIDDDriver_RemoteWakeUp: not enabled\n\r"); + } +} + + diff --git a/usb/device/composite/CDCHIDDDriver.h b/usb/device/composite/CDCHIDDDriver.h new file mode 100644 index 0000000..d7ef755 --- /dev/null +++ b/usb/device/composite/CDCHIDDDriver.h @@ -0,0 +1,78 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//----------------------------------------------------------------------------- +/// \unit +/// +/// !Purpose +/// +/// Definitions and methods for USB composite device implement. +/// +/// !Usage +/// +/// -# Initialize USB function specified driver ( for MSD currently ) +/// - MSDDFunctionDriver_Initialize +/// +/// -# Initialize USB composite driver and USB driver +/// - CDCHIDDDriver_Initialize +/// +/// -# Handle and dispach USB requests +/// - CDCHIDDDriver_RequestHandler +/// +/// -# Try starting a remote wake-up sequence +/// - CDCHIDDDriver_RemoteWakeUp +//----------------------------------------------------------------------------- + +#ifndef CDCHIDDDRIVER_H +#define CDCHIDDDRIVER_H + + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include +#include + +#include "CDCDFunctionDriver.h" +#include "HIDDFunctionDriver.h" + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +// -CDCHID +extern void CDCHIDDDriver_Initialize(); + +extern void CDCHIDDDriver_RequestHandler(const USBGenericRequest *request); + +extern void CDCHIDDDriver_RemoteWakeUp(void); + +#endif //#ifndef CDCHIDDDRIVER_H + diff --git a/usb/device/composite/CDCHIDDDriverDescriptors.c b/usb/device/composite/CDCHIDDDriverDescriptors.c new file mode 100644 index 0000000..e19ba2d --- /dev/null +++ b/usb/device/composite/CDCHIDDDriverDescriptors.c @@ -0,0 +1,592 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include + +//- Composite +#include "CDCHIDDDriver.h" +#include "CDCHIDDDriverDescriptors.h" + +//- USB Generic +#include +#include +#include +#include +#include +#include + +//- CDC +#include +#include +#include +#include +#include +#include +#include +#include +#include "CDCDFunctionDriverDescriptors.h" + +//- HID +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "HIDDFunctionDriverDescriptors.h" + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +/// Device product ID. +#define CDCHIDDDriverDescriptors_PRODUCTID 0x6130 + +/// Device vendor ID (Atmel). +#define CDCHIDDDriverDescriptors_VENDORID 0x03EB + +/// Device release number. +#define CDCHIDDDriverDescriptors_RELEASE 0x0003 + +//----------------------------------------------------------------------------- +// Macros +//----------------------------------------------------------------------------- + +/// Returns the minimum between two values. +#define MIN(a, b) ((a < b) ? a : b) + +//----------------------------------------------------------------------------- +// Internal structures +//----------------------------------------------------------------------------- + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//----------------------------------------------------------------------------- +/// Configuration descriptor list for a device implementing a composite driver. +//----------------------------------------------------------------------------- +typedef struct { + + /// Standard configuration descriptor. + USBConfigurationDescriptor configuration; + + /// --- CDC 0 + /// IAD 0 + USBInterfaceAssociationDescriptor cdcIAD0; + /// Communication interface descriptor + USBInterfaceDescriptor cdcCommunication0; + /// CDC header functional descriptor. + CDCHeaderDescriptor cdcHeader0; + /// CDC call management functional descriptor. + CDCCallManagementDescriptor cdcCallManagement0; + /// CDC abstract control management functional descriptor. + CDCAbstractControlManagementDescriptor cdcAbstractControlManagement0; + /// CDC union functional descriptor (with one slave interface). + CDCUnionDescriptor cdcUnion0; + /// Notification endpoint descriptor. + USBEndpointDescriptor cdcNotification0; + /// Data interface descriptor. + USBInterfaceDescriptor cdcData0; + /// Data OUT endpoint descriptor. + USBEndpointDescriptor cdcDataOut0; + /// Data IN endpoint descriptor. + USBEndpointDescriptor cdcDataIn0; + + /// --- HID + USBInterfaceDescriptor hidInterface; + HIDDescriptor hid; + USBEndpointDescriptor hidInterruptIn; + USBEndpointDescriptor hidInterruptOut; + +} __attribute__ ((packed)) CdcHidDriverConfigurationDescriptors; + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +/// Standard USB device descriptor for the composite device driver +static const USBDeviceDescriptor deviceDescriptor = { + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + 0xEF,// MI + 0x02,// + 0x01,// + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + CDCHIDDDriverDescriptors_VENDORID, + CDCHIDDDriverDescriptors_PRODUCTID, + CDCHIDDDriverDescriptors_RELEASE, + 0, // No string descriptor for manufacturer + 1, // Index of product string descriptor is #1 + 0, // No string descriptor for serial number + 1 // Device has 1 possible configuration +}; + +#if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + +/// USB device qualifier descriptor. +static const USBDeviceQualifierDescriptor qualifierDescriptor = { + + sizeof(USBDeviceQualifierDescriptor), + USBGenericDescriptor_DEVICEQUALIFIER, + USBDeviceDescriptor_USB2_00, + 0xEF,// MI + 0x02,// + 0x01,// + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + 1, // Device has one possible configuration + 0 // Reserved +}; + +/// USB configuration descriptors for the composite device driver +static const CdcHidDriverConfigurationDescriptors configurationDescriptorsHS = +{ + + // Standard configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(CdcHidDriverConfigurationDescriptors), + CDCHIDDDriverDescriptors_NUMINTERFACE, + 1, // This is configuration #1 + 0, // No string descriptor for this configuration + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + + // CDC 0 + // IAD for CDC/ACM port + { + sizeof(USBInterfaceAssociationDescriptor), + USBGenericDescriptor_INTERFACEASSOCIATION, + CDCD_Descriptors_INTERFACENUM0, + 2, + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Communication class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM0, // This is interface #0 + 0, // This is alternate setting #0 for this interface + 1, // This interface uses 1 endpoint + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Class-specific header functional descriptor + { + sizeof(CDCHeaderDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_HEADER, + CDCGenericDescriptor_CDC1_10 + }, + // Class-specific call management functional descriptor + { + sizeof(CDCCallManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_CALLMANAGEMENT, + CDCCallManagementDescriptor_SELFCALLMANAGEMENT, + CDCD_Descriptors_INTERFACENUM0 + 1 // No associated data interface + }, + // Class-specific abstract control management functional descriptor + { + sizeof(CDCAbstractControlManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_ABSTRACTCONTROLMANAGEMENT, + CDCAbstractControlManagementDescriptor_LINE + }, + // Class-specific union functional descriptor with one slave interface + { + sizeof(CDCUnionDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_UNION, + CDCD_Descriptors_INTERFACENUM0, // Number of master interface is #0 + CDCD_Descriptors_INTERFACENUM0 + 1 // First slave interface is #1 + }, + // Notification endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_NOTIFICATION0), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_NOTIFICATION0), + CDCD_Descriptors_INTERRUPT_MAXPACKETSIZE), + CDCD_Descriptors_INTERRUPTOUT_POLLING_HS + }, + // Data class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM0 + 1, // This is interface #1 + 0, // This is alternate setting #0 for this interface + 2, // This interface uses 2 endpoints + CDCDataInterfaceDescriptor_CLASS, + CDCDataInterfaceDescriptor_SUBCLASS, + CDCDataInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Bulk-OUT endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, + CDCD_Descriptors_DATAOUT0), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAOUT0), + CDCD_Descriptors_BULK_MAXPACKETSIZE), + 0 // Must be 0 for full-speed bulk endpoints + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_DATAIN0), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAIN0), + CDCD_Descriptors_BULK_MAXPACKETSIZE), + 0 // Must be 0 for full-speed bulk endpoints + }, + + // HID + // Interface descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + HIDD_Descriptors_INTERFACENUM, + 0, // This is alternate setting #0 + 2, // Two endpoints used + HIDInterfaceDescriptor_CLASS, + HIDInterfaceDescriptor_SUBCLASS_NONE, + HIDInterfaceDescriptor_PROTOCOL_NONE, + 0 // No associated string descriptor + }, + // HID descriptor + { + sizeof(HIDDescriptor), + HIDGenericDescriptor_HID, + HIDDescriptor_HID1_11, + 0, // Device is not localized, no country code + 1, // One HID-specific descriptor (apart from this one) + HIDGenericDescriptor_REPORT, + HIDD_Descriptors_REPORTSIZE + }, + // Interrupt IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + HIDD_Descriptors_INTERRUPTIN), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardInputReport), + HIDD_Descriptors_INTERRUPTIN_POLLING_HS + }, + // Interrupt OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + HIDD_Descriptors_INTERRUPTOUT), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardOutputReport), + HIDD_Descriptors_INTERRUPTOUT_POLLING_HS + } +}; + +#endif + +/// USB configuration descriptors for the composite device driver +static const CdcHidDriverConfigurationDescriptors configurationDescriptorsFS = +{ + + // Standard configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(CdcHidDriverConfigurationDescriptors), + CDCHIDDDriverDescriptors_NUMINTERFACE, + 1, // This is configuration #1 + 0, // No string descriptor for this configuration + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + + // CDC 0 + // IAD for CDC/ACM port + { + sizeof(USBInterfaceAssociationDescriptor), + USBGenericDescriptor_INTERFACEASSOCIATION, + CDCD_Descriptors_INTERFACENUM0, + 2, + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Communication class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM0, // This is interface #0 + 0, // This is alternate setting #0 for this interface + 1, // This interface uses 1 endpoint + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Class-specific header functional descriptor + { + sizeof(CDCHeaderDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_HEADER, + CDCGenericDescriptor_CDC1_10 + }, + // Class-specific call management functional descriptor + { + sizeof(CDCCallManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_CALLMANAGEMENT, + CDCCallManagementDescriptor_SELFCALLMANAGEMENT, + CDCD_Descriptors_INTERFACENUM0 + 1 // No associated data interface + }, + // Class-specific abstract control management functional descriptor + { + sizeof(CDCAbstractControlManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_ABSTRACTCONTROLMANAGEMENT, + CDCAbstractControlManagementDescriptor_LINE + }, + // Class-specific union functional descriptor with one slave interface + { + sizeof(CDCUnionDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_UNION, + CDCD_Descriptors_INTERFACENUM0, // Number of master interface is #0 + CDCD_Descriptors_INTERFACENUM0 + 1 // First slave interface is #1 + }, + // Notification endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_NOTIFICATION0), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_NOTIFICATION0), + USBEndpointDescriptor_MAXINTERRUPTSIZE_FS), + CDCD_Descriptors_INTERRUPTOUT_POLLING_FS + }, + // Data class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM0 + 1, // This is interface #1 + 0, // This is alternate setting #0 for this interface + 2, // This interface uses 2 endpoints + CDCDataInterfaceDescriptor_CLASS, + CDCDataInterfaceDescriptor_SUBCLASS, + CDCDataInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Bulk-OUT endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, + CDCD_Descriptors_DATAOUT0), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAOUT0), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed bulk endpoints + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_DATAIN0), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAIN0), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed bulk endpoints + }, + + // HID + // Interface descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + HIDD_Descriptors_INTERFACENUM, + 0, // This is alternate setting #0 + 2, // Two endpoints used + HIDInterfaceDescriptor_CLASS, + HIDInterfaceDescriptor_SUBCLASS_NONE, + HIDInterfaceDescriptor_PROTOCOL_NONE, + 0 // No associated string descriptor + }, + // HID descriptor + { + sizeof(HIDDescriptor), + HIDGenericDescriptor_HID, + HIDDescriptor_HID1_11, + 0, // Device is not localized, no country code + 1, // One HID-specific descriptor (apart from this one) + HIDGenericDescriptor_REPORT, + HIDD_Descriptors_REPORTSIZE + }, + // Interrupt IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + HIDD_Descriptors_INTERRUPTIN), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardInputReport), + HIDD_Descriptors_INTERRUPTIN_POLLING_FS + }, + // Interrupt OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + HIDD_Descriptors_INTERRUPTOUT), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardOutputReport), + HIDD_Descriptors_INTERRUPTOUT_POLLING_FS + } +}; + +/// String descriptor with the supported languages. +static const unsigned char languageIdDescriptor[] = { + + USBStringDescriptor_LENGTH(1), + USBGenericDescriptor_STRING, + USBStringDescriptor_ENGLISH_US +}; + +/// Manufacturer name. +static const unsigned char manufacturerDescriptor[] = { + + USBStringDescriptor_LENGTH(5), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('t'), + USBStringDescriptor_UNICODE('m'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('l') +}; + +/// Product name. +static const unsigned char productDescriptor[] = { + + USBStringDescriptor_LENGTH(14), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('C'), + USBStringDescriptor_UNICODE('o'), + USBStringDescriptor_UNICODE('m'), + USBStringDescriptor_UNICODE('p'), + USBStringDescriptor_UNICODE('o'), + USBStringDescriptor_UNICODE('s'), + USBStringDescriptor_UNICODE('i'), + USBStringDescriptor_UNICODE('t'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('D'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('m'), + USBStringDescriptor_UNICODE('o') +}; + +/// Product serial number. +static const unsigned char serialNumberDescriptor[] = { + + USBStringDescriptor_LENGTH(4), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('0'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE('2'), + USBStringDescriptor_UNICODE('3') +}; + +/// Array of pointers to the four string descriptors. +static const unsigned char *stringDescriptors[] = { + + languageIdDescriptor, + manufacturerDescriptor, + productDescriptor, + serialNumberDescriptor, +}; + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +/// List of descriptors required by an USB audio speaker device driver. +const USBDDriverDescriptors cdchiddDriverDescriptors = { + + &deviceDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptorsFS, +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + &qualifierDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptorsHS, + &deviceDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptorsHS, + &qualifierDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptorsFS, +#else + 0, 0, 0, 0, 0, 0, +#endif + stringDescriptors, + 4 // Number of string descriptors +}; diff --git a/usb/device/composite/CDCHIDDDriverDescriptors.h b/usb/device/composite/CDCHIDDDriverDescriptors.h new file mode 100644 index 0000000..0a34f8a --- /dev/null +++ b/usb/device/composite/CDCHIDDDriverDescriptors.h @@ -0,0 +1,70 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef CDCHIDDDRIVERDESCRIPTORS_H +#define CDCHIDDDRIVERDESCRIPTORS_H + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include +#include + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +/// Number of interfaces of the device +#define CDCHIDDDriverDescriptors_NUMINTERFACE 3 + +/// Number of the CDC interface. +#define CDCD_Descriptors_INTERFACENUM0 0 +/// Address of the CDC interrupt-in endpoint. +#define CDCD_Descriptors_NOTIFICATION0 3 +/// Address of the CDC bulk-in endpoint. +#define CDCD_Descriptors_DATAIN0 2 +/// Address of the CDC bulk-out endpoint. +#define CDCD_Descriptors_DATAOUT0 1 + +/// Number of the HID interface. +#define HIDD_Descriptors_INTERFACENUM 2 +/// Address of the HID interrupt IN endpoint. +#define HIDD_Descriptors_INTERRUPTIN 4 +/// Address of the HID interrupt OUT endpoint. +#define HIDD_Descriptors_INTERRUPTOUT 5 + + +//----------------------------------------------------------------------------- +// Exported variables +//----------------------------------------------------------------------------- + +extern const USBDDriverDescriptors cdchiddDriverDescriptors; + +#endif //#ifndef CDCHIDDDRIVERDESCRIPTORS_H diff --git a/usb/device/composite/CDCMSDDDriver.c b/usb/device/composite/CDCMSDDDriver.c new file mode 100644 index 0000000..9a605a7 --- /dev/null +++ b/usb/device/composite/CDCMSDDDriver.c @@ -0,0 +1,213 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +// GENERAL +#include +#include +#include + +// USB +#include +#include + +//- CDCMSD +#include "CDCMSDDDriver.h" +#include "CDCMSDDDriverDescriptors.h" + +//----------------------------------------------------------------------------- +// Defines +//----------------------------------------------------------------------------- + +/// Interface setting spaces (4 byte aligned) +#define NUM_INTERFACES ((CDCMSDDDriverDescriptors_NUMINTERFACE+3)&0xFC) + +//----------------------------------------------------------------------------- +// Types +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Internal variables +//----------------------------------------------------------------------------- + +/// USBDDriver instance +static USBDDriver usbdDriver; + +/// CDCDSeriaoPort instance +static CDCDSerialPort cdcdPort; + +/// Array for storing the current setting of each interface +static unsigned char cdcmsddDriverInterfaces[NUM_INTERFACES]; + +//----------------------------------------------------------------------------- +// Internal functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Optional RequestReceived() callback re-implementation +//----------------------------------------------------------------------------- +#if !defined(NOAUTOCALLBACK) + +void USBDCallbacks_RequestReceived(const USBGenericRequest *request) +{ + CDCMSDDDriver_RequestHandler(request); +} + +#endif + +//----------------------------------------------------------------------------- +// ConfigurationChanged() callback re-implementation +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Invoked whenever the configuration value of a device is changed by the host +/// \param cfgnum Configuration number. +//----------------------------------------------------------------------------- +void USBDDriverCallbacks_ConfigurationChanged(unsigned char cfgnum) +{ + // MSD + MSDDFunctionCallbacks_ConfigurationChanged(cfgnum); +} + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Initializes the USB device CDCMSD device driver. +//----------------------------------------------------------------------------- +void CDCMSDDDriver_Initialize(MSDLun *pLuns, unsigned char numLuns) +{ + // CDC + CDCDFunctionDriver_ConfigurePort(&cdcdPort, + CDCD_Descriptors_INTERFACENUM0, + CDCD_Descriptors_NOTIFICATION0, + CDCD_Descriptors_DATAIN0, + CDCD_Descriptors_DATAOUT0); + CDCDFunctionDriver_Initialize(&usbdDriver, + &cdcdPort, + 1); + + // MSD + MSDDFunctionDriver_Initialize(&usbdDriver, + pLuns, numLuns, + MSDD_Descriptors_INTERFACENUM, + MSDD_Descriptors_BULKIN, + MSDD_Descriptors_BULKOUT); + + // Initialize the standard USB driver + USBDDriver_Initialize(&usbdDriver, + &cdcmsddDriverDescriptors, + cdcmsddDriverInterfaces); + + // Initialize the USB driver + USBD_Init(); +} + +//----------------------------------------------------------------------------- +/// Handles CDCMSD-specific USB requests sent by the host, and forwards +/// standard ones to the USB device driver. +/// \param request Pointer to a USBGenericRequest instance. +//----------------------------------------------------------------------------- +void CDCMSDDDriver_RequestHandler(const USBGenericRequest *request) +{ + // Check if this is a class request + if (USBGenericRequest_GetType(request) == USBGenericRequest_CLASS) { + + unsigned char rc = 0; + + // CDC class request + if (rc == 0) { + + rc = CDCDFunctionDriver_RequestHandler(request); + } + + // MSD class request + if (rc == 0) { + + rc = MSDDFunctionDriver_RequestHandler(request); + } + + if (!rc) { + + TRACE_WARNING( + "CDCMSDDDriver_RequestHandler: Unsupported request (%d)\n\r", + USBGenericRequest_GetRequest(request)); + USBD_Stall(0); + } + + } + // Check if this is a standard request + else if (USBGenericRequest_GetType(request) == USBGenericRequest_STANDARD) { + + unsigned char rc = 0; + + if (rc == 0) { + + rc = MSDDFunctionDriver_RequestHandler(request); + } + + // Forward request to the standard handler + if (rc == 0) { + + USBDDriver_RequestHandler(&(usbdDriver), request); + } + } + // Unsupported request type + else { + + TRACE_WARNING( + "CDCMSDDDriver_RequestHandler: Unsupported request type (%d)\n\r", + USBGenericRequest_GetType(request)); + USBD_Stall(0); + } +} + +//----------------------------------------------------------------------------- +/// Starts a remote wake-up sequence if the host has explicitely enabled it +/// by sending the appropriate SET_FEATURE request. +//----------------------------------------------------------------------------- +void CDCMSDDDriver_RemoteWakeUp(void) +{ + // Remote wake-up has been enabled + if (USBDDriver_IsRemoteWakeUpEnabled(&usbdDriver)) { + + USBD_RemoteWakeUp(); + } + // Remote wake-up NOT enabled + else { + + TRACE_WARNING("CDCMSDDDriver_RemoteWakeUp: not enabled\n\r"); + } +} + + diff --git a/usb/device/composite/CDCMSDDDriver.h b/usb/device/composite/CDCMSDDDriver.h new file mode 100644 index 0000000..e6a6834 --- /dev/null +++ b/usb/device/composite/CDCMSDDDriver.h @@ -0,0 +1,77 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//----------------------------------------------------------------------------- +/// \unit +/// +/// !Purpose +/// +/// Definitions and methods for USB CDCMSD device implement. +/// +/// !Usage +/// +/// -# Initialize USB function specified driver ( for MSD currently ) +/// - MSDDFunctionDriver_Initialize +/// +/// -# Initialize USB CDCMSD driver and USB driver +/// - CDCMSDDDriver_Initialize +/// +/// -# Handle and dispach USB requests +/// - CDCMSDDDriver_RequestHandler +/// +/// -# Try starting a remote wake-up sequence +/// - CDCMSDDDriver_RemoteWakeUp +//----------------------------------------------------------------------------- + +#ifndef CDCMSDDDRIVER_H +#define CDCMSDDDRIVER_H + + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include + +#include "CDCDFunctionDriver.h" +#include "MSDDFunctionDriver.h" + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +// -CDCMSD +extern void CDCMSDDDriver_Initialize(MSDLun *pLuns, unsigned char numLuns); + +extern void CDCMSDDDriver_RequestHandler(const USBGenericRequest *request); + +extern void CDCMSDDDriver_RemoteWakeUp(void); + +#endif //#ifndef CDCMSDDDRIVER_H + diff --git a/usb/device/composite/CDCMSDDDriverDescriptors.c b/usb/device/composite/CDCMSDDDriverDescriptors.c new file mode 100644 index 0000000..27932ac --- /dev/null +++ b/usb/device/composite/CDCMSDDDriverDescriptors.c @@ -0,0 +1,568 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "CDCMSDDDriver.h" +#include "CDCMSDDDriverDescriptors.h" +#include + +//- USB Generic +#include +#include +#include +#include +#include +#include + +//- CDC +#include +#include +#include +#include +#include +#include +#include +#include +#include "CDCDFunctionDriverDescriptors.h" + +//- MSD +#include +#include +#include "MSDDFunctionDriverDescriptors.h" + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +/// Device product ID. +#define CDCMSDDDriverDescriptors_PRODUCTID 0x6132 + +/// Device vendor ID (Atmel). +#define CDCMSDDDriverDescriptors_VENDORID 0x03EB + +/// Device release number. +#define CDCMSDDDriverDescriptors_RELEASE 0x0003 + +//----------------------------------------------------------------------------- +// Macros +//----------------------------------------------------------------------------- + +/// Returns the minimum between two values. +#define MIN(a, b) ((a < b) ? a : b) + +//----------------------------------------------------------------------------- +// Internal structures +//----------------------------------------------------------------------------- + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//----------------------------------------------------------------------------- +/// Configuration descriptor list for a device implementing a CDCMSD driver. +//----------------------------------------------------------------------------- +typedef struct { + + /// Standard configuration descriptor. + USBConfigurationDescriptor configuration; + + /// --- CDC 0 + /// IAD 0 + USBInterfaceAssociationDescriptor cdcIAD0; + /// Communication interface descriptor + USBInterfaceDescriptor cdcCommunication0; + /// CDC header functional descriptor. + CDCHeaderDescriptor cdcHeader0; + /// CDC call management functional descriptor. + CDCCallManagementDescriptor cdcCallManagement0; + /// CDC abstract control management functional descriptor. + CDCAbstractControlManagementDescriptor cdcAbstractControlManagement0; + /// CDC union functional descriptor (with one slave interface). + CDCUnionDescriptor cdcUnion0; + /// Notification endpoint descriptor. + USBEndpointDescriptor cdcNotification0; + /// Data interface descriptor. + USBInterfaceDescriptor cdcData0; + /// Data OUT endpoint descriptor. + USBEndpointDescriptor cdcDataOut0; + /// Data IN endpoint descriptor. + USBEndpointDescriptor cdcDataIn0; + + /// --- MSD + /// Mass storage interface descriptor. + USBInterfaceDescriptor msdInterface; + /// Bulk-out endpoint descriptor. + USBEndpointDescriptor msdBulkOut; + /// Bulk-in endpoint descriptor. + USBEndpointDescriptor msdBulkIn; + +} __attribute__ ((packed)) CDCMSDDriverConfigurationDescriptors; + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +/// Standard USB device descriptor for the CDCMSD device driver +static const USBDeviceDescriptor deviceDescriptor = { + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + 0xEF,// MI + 0x02,// + 0x01,// + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + CDCMSDDDriverDescriptors_VENDORID, + CDCMSDDDriverDescriptors_PRODUCTID, + CDCMSDDDriverDescriptors_RELEASE, + 0, // No string descriptor for manufacturer + 1, // Index of product string descriptor is #1 + 0, // No string descriptor for serial number + 1 // Device has 1 possible configuration +}; + +#if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + +/// USB device qualifier descriptor. +static const USBDeviceQualifierDescriptor qualifierDescriptor = { + + sizeof(USBDeviceQualifierDescriptor), + USBGenericDescriptor_DEVICEQUALIFIER, + USBDeviceDescriptor_USB2_00, + 0xEF,// MI + 0x02,// + 0x01,// + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + 1, // Device has one possible configuration + 0 // Reserved +}; + +/// USB configuration descriptors for the CDCMSD device driver +static const CDCMSDDriverConfigurationDescriptors configurationDescriptorsHS = +{ + + // Standard configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(CDCMSDDriverConfigurationDescriptors), + CDCMSDDDriverDescriptors_NUMINTERFACE, + 1, // This is configuration #1 + 0, // No string descriptor for this configuration + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + + // CDC + // IAD for CDC/ACM port + { + sizeof(USBInterfaceAssociationDescriptor), + USBGenericDescriptor_INTERFACEASSOCIATION, + CDCD_Descriptors_INTERFACENUM0, + 2, + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Communication class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM0, // This is interface #0 + 0, // This is alternate setting #0 for this interface + 1, // This interface uses 1 endpoint + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Class-specific header functional descriptor + { + sizeof(CDCHeaderDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_HEADER, + CDCGenericDescriptor_CDC1_10 + }, + // Class-specific call management functional descriptor + { + sizeof(CDCCallManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_CALLMANAGEMENT, + CDCCallManagementDescriptor_SELFCALLMANAGEMENT, + CDCD_Descriptors_INTERFACENUM0 + 1 // No associated data interface + }, + // Class-specific abstract control management functional descriptor + { + sizeof(CDCAbstractControlManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_ABSTRACTCONTROLMANAGEMENT, + CDCAbstractControlManagementDescriptor_LINE + }, + // Class-specific union functional descriptor with one slave interface + { + sizeof(CDCUnionDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_UNION, + CDCD_Descriptors_INTERFACENUM0, // Number of master interface is #0 + CDCD_Descriptors_INTERFACENUM0 + 1 // First slave interface is #1 + }, + // Notification endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_NOTIFICATION0), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_NOTIFICATION0), + CDCD_Descriptors_INTERRUPT_MAXPACKETSIZE), + CDCD_Descriptors_INTERRUPTIN_POLLING_HS + }, + // Data class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM0 + 1, // This is interface #1 + 0, // This is alternate setting #0 for this interface + 2, // This interface uses 2 endpoints + CDCDataInterfaceDescriptor_CLASS, + CDCDataInterfaceDescriptor_SUBCLASS, + CDCDataInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Bulk-OUT endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, + CDCD_Descriptors_DATAOUT0), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAOUT0), + CDCD_Descriptors_BULK_MAXPACKETSIZE), + 0 // Must be 0 for full-speed bulk endpoints + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_DATAIN0), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAIN0), + CDCD_Descriptors_BULK_MAXPACKETSIZE), + 0 // Must be 0 for full-speed bulk endpoints + }, + + // Mass Storage interface descriptor. + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + MSDD_Descriptors_INTERFACENUM, + 0, // This is alternate setting #0. + 2, // Interface uses two endpoints. + MSInterfaceDescriptor_CLASS, + MSInterfaceDescriptor_SCSI, + MSInterfaceDescriptor_BULKONLY, + 0 // No string descriptor for interface. + }, + // Bulk-OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + MSDD_Descriptors_BULKOUT), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(MSDD_Descriptors_BULKOUT), + USBEndpointDescriptor_MAXBULKSIZE_HS), + 0 // No string descriptor for endpoint. + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + MSDD_Descriptors_BULKIN), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(MSDD_Descriptors_BULKIN), + USBEndpointDescriptor_MAXBULKSIZE_HS), + 0 // No string descriptor for endpoint. + } + +}; + +#endif + +/// USB configuration descriptors for the CDCMSD device driver +static const CDCMSDDriverConfigurationDescriptors configurationDescriptorsFS = +{ + + // Standard configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(CDCMSDDriverConfigurationDescriptors), + CDCMSDDDriverDescriptors_NUMINTERFACE, + 1, // This is configuration #1 + 0, // No string descriptor for this configuration + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + + // CDC + // IAD for CDC/ACM port + { + sizeof(USBInterfaceAssociationDescriptor), + USBGenericDescriptor_INTERFACEASSOCIATION, + CDCD_Descriptors_INTERFACENUM0, + 2, + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Communication class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM0, // This is interface #0 + 0, // This is alternate setting #0 for this interface + 1, // This interface uses 1 endpoint + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Class-specific header functional descriptor + { + sizeof(CDCHeaderDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_HEADER, + CDCGenericDescriptor_CDC1_10 + }, + // Class-specific call management functional descriptor + { + sizeof(CDCCallManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_CALLMANAGEMENT, + CDCCallManagementDescriptor_SELFCALLMANAGEMENT, + CDCD_Descriptors_INTERFACENUM0 + 1 // No associated data interface + }, + // Class-specific abstract control management functional descriptor + { + sizeof(CDCAbstractControlManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_ABSTRACTCONTROLMANAGEMENT, + CDCAbstractControlManagementDescriptor_LINE + }, + // Class-specific union functional descriptor with one slave interface + { + sizeof(CDCUnionDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_UNION, + CDCD_Descriptors_INTERFACENUM0, // Number of master interface is #0 + CDCD_Descriptors_INTERFACENUM0 + 1 // First slave interface is #1 + }, + // Notification endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_NOTIFICATION0), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_NOTIFICATION0), + CDCD_Descriptors_INTERRUPT_MAXPACKETSIZE), + CDCD_Descriptors_INTERRUPTIN_POLLING_FS + }, + // Data class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM0 + 1, // This is interface #1 + 0, // This is alternate setting #0 for this interface + 2, // This interface uses 2 endpoints + CDCDataInterfaceDescriptor_CLASS, + CDCDataInterfaceDescriptor_SUBCLASS, + CDCDataInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Bulk-OUT endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, + CDCD_Descriptors_DATAOUT0), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAOUT0), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed bulk endpoints + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_DATAIN0), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAIN0), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed bulk endpoints + }, + + // Mass Storage interface descriptor. + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + MSDD_Descriptors_INTERFACENUM, + 0, // This is alternate setting #0. + 2, // Interface uses two endpoints. + MSInterfaceDescriptor_CLASS, + MSInterfaceDescriptor_SCSI, + MSInterfaceDescriptor_BULKONLY, + 0 // No string descriptor for interface. + }, + // Bulk-OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + MSDD_Descriptors_BULKOUT), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(MSDD_Descriptors_BULKOUT), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // No string descriptor for endpoint. + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + MSDD_Descriptors_BULKIN), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(MSDD_Descriptors_BULKIN), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // No string descriptor for endpoint. + } + +}; + +/// String descriptor with the supported languages. +static const unsigned char languageIdDescriptor[] = { + + USBStringDescriptor_LENGTH(1), + USBGenericDescriptor_STRING, + USBStringDescriptor_ENGLISH_US +}; + +/// Manufacturer name. +static const unsigned char manufacturerDescriptor[] = { + + USBStringDescriptor_LENGTH(5), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('t'), + USBStringDescriptor_UNICODE('m'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('l') +}; + +/// Product name. +static const unsigned char productDescriptor[] = { + + USBStringDescriptor_LENGTH(14), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('C'), + USBStringDescriptor_UNICODE('o'), + USBStringDescriptor_UNICODE('m'), + USBStringDescriptor_UNICODE('p'), + USBStringDescriptor_UNICODE('o'), + USBStringDescriptor_UNICODE('s'), + USBStringDescriptor_UNICODE('i'), + USBStringDescriptor_UNICODE('t'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('D'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('m'), + USBStringDescriptor_UNICODE('o') +}; + +/// Product serial number. +static const unsigned char serialNumberDescriptor[] = { + + USBStringDescriptor_LENGTH(4), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('0'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE('2'), + USBStringDescriptor_UNICODE('3') +}; + +/// Array of pointers to the four string descriptors. +static const unsigned char *stringDescriptors[] = { + + languageIdDescriptor, + manufacturerDescriptor, + productDescriptor, + serialNumberDescriptor, +}; + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +/// List of descriptors required by an USB audio speaker device driver. +const USBDDriverDescriptors cdcmsddDriverDescriptors = { + + &deviceDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptorsFS, +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + &qualifierDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptorsHS, + &deviceDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptorsHS, + &qualifierDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptorsFS, +#else + 0, 0, 0, 0, 0, 0, +#endif + stringDescriptors, + 4 // Number of string descriptors +}; diff --git a/usb/device/composite/CDCMSDDDriverDescriptors.h b/usb/device/composite/CDCMSDDDriverDescriptors.h new file mode 100644 index 0000000..5db1a0c --- /dev/null +++ b/usb/device/composite/CDCMSDDDriverDescriptors.h @@ -0,0 +1,71 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef CDCMSDDDRIVERDESCRIPTORS_H +#define CDCMSDDDRIVERDESCRIPTORS_H + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include +#include + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +/// Number of interfaces of the device +#define CDCMSDDDriverDescriptors_NUMINTERFACE 3 + +/// Number of the CDC interface. +#define CDCD_Descriptors_INTERFACENUM0 0 +/// Address of the CDC interrupt-in endpoint. +#define CDCD_Descriptors_NOTIFICATION0 3 +/// Address of the CDC bulk-in endpoint. +#define CDCD_Descriptors_DATAIN0 2 +/// Address of the CDC bulk-out endpoint. +#define CDCD_Descriptors_DATAOUT0 1 + +/// Number of the Mass Storage interface. +#define MSDD_Descriptors_INTERFACENUM 2 + +/// Address of the Mass Storage bulk-out endpoint. +#define MSDD_Descriptors_BULKOUT 4 + +/// Address of the Mass Storage bulk-in endpoint. +#define MSDD_Descriptors_BULKIN 5 + +//----------------------------------------------------------------------------- +// Exported variables +//----------------------------------------------------------------------------- + +extern const USBDDriverDescriptors cdcmsddDriverDescriptors; + +#endif //#ifndef CDCMSDDDRIVERDESCRIPTORS_H diff --git a/usb/device/composite/COMPOSITEDDriver.c b/usb/device/composite/COMPOSITEDDriver.c new file mode 100644 index 0000000..88d64b6 --- /dev/null +++ b/usb/device/composite/COMPOSITEDDriver.c @@ -0,0 +1,292 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +// GENERAL +#include +#include +#include + +// USB +#include +#include + +//- HID +#if defined(usb_CDCHID) || defined(usb_HIDAUDIO) || defined(usb_HIDMSD) + #include + #include + #include + #include + #include + + #include + #include + #include + #include + #include + #include +#endif // (HID defined) + +//- MSD +#if defined(usb_CDCMSD) || defined(usb_HIDMSD) +#endif + +//- COMPOSITE +#include "COMPOSITEDDriver.h" +#include "COMPOSITEDDriverDescriptors.h" + +//----------------------------------------------------------------------------- +// Defines +//----------------------------------------------------------------------------- + +/// Interface setting spaces (4 byte aligned) +#define NUM_INTERFACES ((COMPOSITEDDriverDescriptors_NUMINTERFACE+3)&0xFC) + +//----------------------------------------------------------------------------- +// Types +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Internal variables +//----------------------------------------------------------------------------- + +/// USBDDriver instance +static USBDDriver usbdDriver; + +// CDC +#if defined(usb_CDCAUDIO) || defined(usb_CDCHID) || defined(usb_CDCCDC) || defined(usb_CDCMSD) +/// CDCDSeriaoPort instance +static CDCDSerialPort cdcdPort; +#endif // CDC defined + +/// Array for storing the current setting of each interface +static unsigned char compositedDriverInterfaces[NUM_INTERFACES]; + +//----------------------------------------------------------------------------- +// Internal functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Optional RequestReceived() callback re-implementation +//----------------------------------------------------------------------------- +#if !defined(NOAUTOCALLBACK) + +void USBDCallbacks_RequestReceived(const USBGenericRequest *request) +{ + COMPOSITEDDriver_RequestHandler(request); +} + +#endif + +//----------------------------------------------------------------------------- +/// Invoked whenever the active setting of an interface is changed by the +/// host. Changes the status of the third LED accordingly. +/// \param interface Interface number. +/// \param setting Newly active setting. +//----------------------------------------------------------------------------- +void USBDDriverCallbacks_InterfaceSettingChanged(unsigned char interface, + unsigned char setting) +{ + // AUDIO + #if defined(usb_CDCAUDIO) || defined(usb_HIDAUDIO) + AUDDFunctionCallbacks_InterfaceSettingChanged(interface, setting); + #endif +} + +//----------------------------------------------------------------------------- +// ConfigurationChanged() callback re-implementation +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Invoked whenever the configuration value of a device is changed by the host +/// \param cfgnum Configuration number. +//----------------------------------------------------------------------------- +void USBDDriverCallbacks_ConfigurationChanged(unsigned char cfgnum) +{ + // HID + #if defined(usb_CDCHID) || defined(usb_HIDAUDIO) || defined(usb_HIDMSD) + HIDDFunctionCallbacks_ConfigurationChanged(cfgnum); + #endif +} + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Initializes the USB device composite device driver. +//----------------------------------------------------------------------------- +void COMPOSITEDDriver_Initialize() +{ + // CDC + #if defined(usb_CDCAUDIO) || defined(usb_CDCHID) || defined(usb_CDCCDC) || defined(usb_CDCMSD) + CDCDFunctionDriver_ConfigurePort(&cdcdPort, + CDCD_Descriptors_INTERFACENUM0, + CDCD_Descriptors_NOTIFICATION0, + CDCD_Descriptors_DATAIN0, + CDCD_Descriptors_DATAOUT0); + CDCDFunctionDriver_Initialize(&usbdDriver, + &cdcdPort, + 1); + #endif + + // AUDIO + #if defined(usb_CDCAUDIO) || defined(usb_HIDAUDIO) + AUDDFunctionDriver_Initialize(); + #endif + + // HID + #if defined(usb_CDCHID) || defined(usb_HIDAUDIO) || defined(usb_HIDMSD) + HIDDFunctionDriver_Initialize(&usbdDriver, + HIDD_Descriptors_INTERFACENUM, + HIDD_Descriptors_INTERRUPTIN, + HIDD_Descriptors_INTERRUPTOUT); + #endif + + // MSD + #if defined(usb_CDCMSD) || defined(usb_HIDMSD) + // Function driver initialize is put to main() for additional LUN list + #endif + + // Initialize the standard USB driver + USBDDriver_Initialize(&usbdDriver, + &compositedDriverDescriptors, + compositedDriverInterfaces); + + // Initialize the USB driver + USBD_Init(); +} + +//----------------------------------------------------------------------------- +/// Handles composite-specific USB requests sent by the host, and forwards +/// standard ones to the USB device driver. +/// \param request Pointer to a USBGenericRequest instance. +//----------------------------------------------------------------------------- +void COMPOSITEDDriver_RequestHandler(const USBGenericRequest *request) +{ + // Check if this is a class request + if (USBGenericRequest_GetType(request) == USBGenericRequest_CLASS) { + + unsigned char rc = 0; + + // AUDIO class request + #if defined(usb_CDCAUDIO) || defined(usb_HIDAUDIO) + if (rc == 0) { + + rc = AUDDFunctionDriver_RequestHandler(request); + } + #endif + + // CDC class request + #if defined(usb_CDCAUDIO) || defined(usb_CDCHID) || defined(usb_CDCMSD) || defined(usb_CDCCDC) + if (rc == 0) { + + rc = CDCDFunctionDriver_RequestHandler(request); + } + #endif + + // MSD class request + #if defined(usb_CDCMSD) || defined(usb_HIDMSD) + if (rc == 0) { + + rc = MSDDFunctionDriver_RequestHandler(request); + } + #endif + + // HID class request + #if defined(usb_CDCHID) || defined(usb_HIDAUDIO) || defined(usb_HIDMSD) + if (rc == 0) { + + rc = HIDDFunctionDriver_RequestHandler(request); + } + #endif + + if (!rc) { + + TRACE_WARNING( + "COMPOSITEDDriver_RequestHandler: Unsupported request (%d)\n\r", + USBGenericRequest_GetRequest(request)); + USBD_Stall(0); + } + + } + // Check if this is a standard request + else if (USBGenericRequest_GetType(request) == USBGenericRequest_STANDARD) { + + unsigned char rc = 0; + + #if defined(usb_CDCHID) || defined(usb_HIDAUDIO) || defined(usb_HIDMSD) + rc = HIDDFunctionDriver_RequestHandler(request); + #endif + + #if defined(usb_CDCMSD) || defined(usb_HIDMSD) + if (rc == 0) { + + rc = MSDDFunctionDriver_RequestHandler(request); + } + #endif + + // Forward request to the standard handler + if (rc == 0) { + + USBDDriver_RequestHandler(&(usbdDriver), request); + } + } + // Unsupported request type + else { + + TRACE_WARNING( + "COMPOSITEDDriver_RequestHandler: Unsupported request type (%d)\n\r", + USBGenericRequest_GetType(request)); + USBD_Stall(0); + } +} + +//----------------------------------------------------------------------------- +/// Starts a remote wake-up sequence if the host has explicitely enabled it +/// by sending the appropriate SET_FEATURE request. +//----------------------------------------------------------------------------- +void COMPOSITEDDriver_RemoteWakeUp(void) +{ + // Remote wake-up has been enabled + if (USBDDriver_IsRemoteWakeUpEnabled(&usbdDriver)) { + + USBD_RemoteWakeUp(); + } + // Remote wake-up NOT enabled + else { + + TRACE_WARNING("COMPOSITEDDriver_RemoteWakeUp: not enabled\n\r"); + } +} + + diff --git a/usb/device/composite/COMPOSITEDDriver.h b/usb/device/composite/COMPOSITEDDriver.h new file mode 100644 index 0000000..6106a9f --- /dev/null +++ b/usb/device/composite/COMPOSITEDDriver.h @@ -0,0 +1,93 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//----------------------------------------------------------------------------- +/// \unit +/// +/// !Purpose +/// +/// Definitions and methods for USB composite device implement. +/// +/// !Usage +/// +/// -# Initialize USB function specified driver ( for MSD currently ) +/// - MSDDFunctionDriver_Initialize +/// +/// -# Initialize USB composite driver and USB driver +/// - COMPOSITEDDriver_Initialize +/// +/// -# Handle and dispach USB requests +/// - COMPOSITEDDriver_RequestHandler +/// +/// -# Try starting a remote wake-up sequence +/// - COMPOSITEDDriver_RemoteWakeUp +//----------------------------------------------------------------------------- + +#ifndef COMPOSITEDDRIVER_H +#define COMPOSITEDDRIVER_H + + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include +#include + +#if defined(usb_CDCAUDIO) || defined(usb_CDCHID) || defined(usb_CDCCDC) || defined(usb_CDCMSD) + #include "CDCDFunctionDriver.h" + #include "CDCDFunctionDriverDescriptors.h" +#endif + +#if defined(usb_CDCAUDIO) || defined(usb_HIDAUDIO) + #include "AUDDFunctionDriver.h" +#endif + +#if defined(usb_CDCHID) || defined(usb_HIDAUDIO) || defined(usb_HIDMSD) + #include "HIDDFunctionDriver.h" + #include "HIDDFunctionDriverDescriptors.h" +#endif + +#if defined(usb_CDCMSD) || defined(usb_HIDMSD) + #include "MSDDFunctionDriver.h" +#endif + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +// -COMPOSITE +extern void COMPOSITEDDriver_Initialize(); + +extern void COMPOSITEDDriver_RequestHandler(const USBGenericRequest *request); + +extern void COMPOSITEDDriver_RemoteWakeUp(void); + +#endif //#ifndef COMPOSITEDDRIVER_H + diff --git a/usb/device/composite/COMPOSITEDDriverDescriptors.c b/usb/device/composite/COMPOSITEDDriverDescriptors.c new file mode 100644 index 0000000..db195af --- /dev/null +++ b/usb/device/composite/COMPOSITEDDriverDescriptors.c @@ -0,0 +1,954 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "COMPOSITEDDriver.h" +#include "COMPOSITEDDriverDescriptors.h" +#include + +//- USB Generic +#include +#include +#include +#include +#include +#include + +//- CDC +#if defined(usb_CDCAUDIO) || defined(usb_CDCHID) || defined(usb_CDCCDC) || defined(usb_CDCMSD) + #include + #include + #include + #include + #include + #include + #include + #include + #include "CDCDFunctionDriverDescriptors.h" +#endif // (CDC defined) + +//- HID +#if defined(usb_CDCHID) || defined(usb_HIDAUDIO) || defined(usb_HIDMSD) + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include "HIDDFunctionDriverDescriptors.h" +#endif // (HID defined) + +//- AUDIO +#if defined(usb_CDCAUDIO) || defined(usb_HIDAUDIO) + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include "AUDDFunctionDriverDescriptors.h" +#endif // (AUDIO defined) + +//- MSD +#if defined(usb_CDCMSD) || defined(usb_HIDMSD) + #include + #include + #include "MSDDFunctionDriverDescriptors.h" +#endif // (MSD defined) + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +/// Device product ID. +#if defined(usb_CDCHID) +#define COMPOSITEDDriverDescriptors_PRODUCTID 0x6130 +#elif defined(usb_CDCAUDIO) +#define COMPOSITEDDriverDescriptors_PRODUCTID 0x6131 +#elif defined(usb_CDCMSD) +#define COMPOSITEDDriverDescriptors_PRODUCTID 0x6132 +#elif defined(usb_CDCCDC) +#define COMPOSITEDDriverDescriptors_PRODUCTID 0x6133 +#elif defined(usb_HIDAUDIO) +#define COMPOSITEDDriverDescriptors_PRODUCTID 0x6134 +#elif defined(usb_HIDMSD) +#define COMPOSITEDDriverDescriptors_PRODUCTID 0x6135 +#else +#error COMPOSITE Device Classes not defined! +#endif + +/// Device vendor ID (Atmel). +#define COMPOSITEDDriverDescriptors_VENDORID 0x03EB + +/// Device release number. +#define COMPOSITEDDriverDescriptors_RELEASE 0x0003 + +//----------------------------------------------------------------------------- +// Macros +//----------------------------------------------------------------------------- + +/// Returns the minimum between two values. +#define MIN(a, b) ((a < b) ? a : b) + +//----------------------------------------------------------------------------- +// Internal structures +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Audio control header descriptor with one slave interface. +//----------------------------------------------------------------------------- +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//- AUDIO +#if defined(usb_CDCAUDIO) || defined(usb_HIDAUDIO) +typedef struct { + + /// Header descriptor. + AUDHeaderDescriptor header; + /// Id of the first grouped interface. + unsigned char bInterface0; + +} __attribute__ ((packed)) AUDHeaderDescriptor1; // GCC + +//----------------------------------------------------------------------------- +/// Feature unit descriptor with 3 channel controls (master, right, left). +//----------------------------------------------------------------------------- +typedef struct { + + /// Feature unit descriptor. + AUDFeatureUnitDescriptor feature; + /// Available controls for each channel. + unsigned char bmaControls[3]; + /// Index of a string descriptor for the feature unit. + unsigned char iFeature; + +} __attribute__ ((packed)) AUDFeatureUnitDescriptor3; // GCC + +//----------------------------------------------------------------------------- +/// List of descriptors for detailling the audio control interface of a +/// device using a USB audio speaker driver. +//----------------------------------------------------------------------------- +typedef struct { + + /// Header descriptor (with one slave interface). + AUDHeaderDescriptor1 header; + /// Input terminal descriptor. + AUDInputTerminalDescriptor input; + /// Output terminal descriptor. + AUDOutputTerminalDescriptor output; + /// Feature unit descriptor. + AUDFeatureUnitDescriptor3 feature; + +} __attribute__ ((packed)) AUDDSpeakerDriverAudioControlDescriptors; // GCC + +//----------------------------------------------------------------------------- +/// Format type I descriptor with one discrete sampling frequency. +//----------------------------------------------------------------------------- +typedef struct { + + /// Format type I descriptor. + AUDFormatTypeOneDescriptor formatType; + /// Sampling frequency in Hz. + unsigned char tSamFreq[3]; + +} __attribute__ ((packed)) AUDFormatTypeOneDescriptor1; // GCC +#endif // (AUDIO defined) + +//----------------------------------------------------------------------------- +/// Configuration descriptor list for a device implementing a composite driver. +//----------------------------------------------------------------------------- +typedef struct { + + /// Standard configuration descriptor. + USBConfigurationDescriptor configuration; + + #if defined(usb_CDCAUDIO) || defined(usb_CDCHID) || defined(usb_CDCCDC) || defined(usb_CDCMSD) + /// --- CDC 0 + /// IAD 0 + USBInterfaceAssociationDescriptor cdcIAD0; + /// Communication interface descriptor + USBInterfaceDescriptor cdcCommunication0; + /// CDC header functional descriptor. + CDCHeaderDescriptor cdcHeader0; + /// CDC call management functional descriptor. + CDCCallManagementDescriptor cdcCallManagement0; + /// CDC abstract control management functional descriptor. + CDCAbstractControlManagementDescriptor cdcAbstractControlManagement0; + /// CDC union functional descriptor (with one slave interface). + CDCUnionDescriptor cdcUnion0; + /// Notification endpoint descriptor. + USBEndpointDescriptor cdcNotification0; + /// Data interface descriptor. + USBInterfaceDescriptor cdcData0; + /// Data OUT endpoint descriptor. + USBEndpointDescriptor cdcDataOut0; + /// Data IN endpoint descriptor. + USBEndpointDescriptor cdcDataIn0; + #endif // (CDC defined) + + #if defined(usb_CDCHID) || defined(usb_HIDAUDIO) || defined(usb_HIDMSD) + /// --- HID + USBInterfaceDescriptor hidInterface; + HIDDescriptor hid; + USBEndpointDescriptor hidInterruptIn; + USBEndpointDescriptor hidInterruptOut; + #endif // (HID defined) + + #if defined(usb_CDCAUDIO) || defined(usb_HIDAUDIO) + /// --- AUDIO + /// IAD 1 + USBInterfaceAssociationDescriptor audIAD; + /// Audio control interface. + USBInterfaceDescriptor audInterface; + /// Descriptors for the audio control interface. + AUDDSpeakerDriverAudioControlDescriptors audControl; + /// -- AUDIO out + /// Streaming out interface descriptor (with no endpoint, required). + USBInterfaceDescriptor audStreamingOutNoIsochronous; + /// Streaming out interface descriptor. + USBInterfaceDescriptor audStreamingOut; + /// Audio class descriptor for the streaming out interface. + AUDStreamingInterfaceDescriptor audStreamingOutClass; + /// Stream format descriptor. + AUDFormatTypeOneDescriptor1 audStreamingOutFormatType; + /// Streaming out endpoint descriptor. + AUDEndpointDescriptor audStreamingOutEndpoint; + /// Audio class descriptor for the streaming out endpoint. + AUDDataEndpointDescriptor audStreamingOutDataEndpoint; + #endif // (AUDIO defined) + + #if defined(usb_CDCCDC) + /// --- CDC 1 + /// IAD 1 + USBInterfaceAssociationDescriptor cdcIAD1; + /// Communication interface descriptor + USBInterfaceDescriptor cdcCommunication1; + /// CDC header functional descriptor. + CDCHeaderDescriptor cdcHeader1; + /// CDC call management functional descriptor. + CDCCallManagementDescriptor cdcCallManagement1; + /// CDC abstract control management functional descriptor. + CDCAbstractControlManagementDescriptor cdcAbstractControlManagement1; + /// CDC union functional descriptor (with one slave interface). + CDCUnionDescriptor cdcUnion1; + /// Notification endpoint descriptor. + USBEndpointDescriptor cdcNotification1; + /// Data interface descriptor. + USBInterfaceDescriptor cdcData1; + /// Data OUT endpoint descriptor. + USBEndpointDescriptor cdcDataOut1; + /// Data IN endpoint descriptor. + USBEndpointDescriptor cdcDataIn1; + #endif // (Another CDC defined) + + #if defined(usb_CDCMSD) || defined(usb_HIDMSD) + /// --- MSD + /// Mass storage interface descriptor. + USBInterfaceDescriptor msdInterface; + /// Bulk-out endpoint descriptor. + USBEndpointDescriptor msdBulkOut; + /// Bulk-in endpoint descriptor. + USBEndpointDescriptor msdBulkIn; + #endif // (MSD defined) + +} __attribute__ ((packed)) CompositeDriverConfigurationDescriptors; + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +/// Standard USB device descriptor for the composite device driver +const USBDeviceDescriptor deviceDescriptor = { + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + #if defined(usb_HIDMSD) + 0x00, + 0x00, + 0x00, + #else + 0xEF,// MI + 0x02,// + 0x01,// + #endif + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + COMPOSITEDDriverDescriptors_VENDORID, + COMPOSITEDDriverDescriptors_PRODUCTID, + COMPOSITEDDriverDescriptors_RELEASE, + 0, // No string descriptor for manufacturer + 1, // Index of product string descriptor is #1 + 0, // No string descriptor for serial number + 1 // Device has 1 possible configuration +}; + +#if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + +/// USB device qualifier descriptor. +const USBDeviceQualifierDescriptor qualifierDescriptor = { + + sizeof(USBDeviceQualifierDescriptor), + USBGenericDescriptor_DEVICEQUALIFIER, + USBDeviceDescriptor_USB2_00, + #if defined(usb_HIDMSD) + 0x00, + 0x00, + 0x00, + #else + 0xEF,// MI + 0x02,// + 0x01,// + #endif + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + 1, // Device has one possible configuration + 0 // Reserved +}; + +#endif + +/// USB configuration descriptors for the composite device driver +const CompositeDriverConfigurationDescriptors configurationDescriptors = { + + // Standard configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(CompositeDriverConfigurationDescriptors), + COMPOSITEDDriverDescriptors_NUMINTERFACE, + 1, // This is configuration #1 + 0, // No string descriptor for this configuration + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + + #if defined(usb_CDCAUDIO) || defined(usb_CDCHID) || defined(usb_CDCCDC) || defined(usb_CDCMSD) + // CDC + // IAD for CDC/ACM port + { + sizeof(USBInterfaceAssociationDescriptor), + USBGenericDescriptor_INTERFACEASSOCIATION, + CDCD_Descriptors_INTERFACENUM0, + 2, + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Communication class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM0, // This is interface #0 + 0, // This is alternate setting #0 for this interface + 1, // This interface uses 1 endpoint + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Class-specific header functional descriptor + { + sizeof(CDCHeaderDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_HEADER, + CDCGenericDescriptor_CDC1_10 + }, + // Class-specific call management functional descriptor + { + sizeof(CDCCallManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_CALLMANAGEMENT, + CDCCallManagementDescriptor_SELFCALLMANAGEMENT, + CDCD_Descriptors_INTERFACENUM0 + 1 // No associated data interface + }, + // Class-specific abstract control management functional descriptor + { + sizeof(CDCAbstractControlManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_ABSTRACTCONTROLMANAGEMENT, + CDCAbstractControlManagementDescriptor_LINE + }, + // Class-specific union functional descriptor with one slave interface + { + sizeof(CDCUnionDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_UNION, + CDCD_Descriptors_INTERFACENUM0, // Number of master interface is #0 + CDCD_Descriptors_INTERFACENUM0 + 1 // First slave interface is #1 + }, + // Notification endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_NOTIFICATION0), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_NOTIFICATION0), + USBEndpointDescriptor_MAXINTERRUPTSIZE_FS), + 10 // Endpoint is polled every 10ms + }, + // Data class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM0 + 1, // This is interface #1 + 0, // This is alternate setting #0 for this interface + 2, // This interface uses 2 endpoints + CDCDataInterfaceDescriptor_CLASS, + CDCDataInterfaceDescriptor_SUBCLASS, + CDCDataInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Bulk-OUT endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, + CDCD_Descriptors_DATAOUT0), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAOUT0), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed bulk endpoints + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_DATAIN0), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAIN0), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed bulk endpoints + }, + #endif // (CDC defined) + + #if defined(usb_CDCHID) || defined(usb_HIDAUDIO) || defined(usb_HIDMSD) + // Interface descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + HIDD_Descriptors_INTERFACENUM, + 0, // This is alternate setting #0 + 2, // Two endpoints used + HIDInterfaceDescriptor_CLASS, + HIDInterfaceDescriptor_SUBCLASS_NONE, + HIDInterfaceDescriptor_PROTOCOL_NONE, + 0 // No associated string descriptor + }, + // HID descriptor + { + sizeof(HIDDescriptor), + HIDGenericDescriptor_HID, + HIDDescriptor_HID1_11, + 0, // Device is not localized, no country code + 1, // One HID-specific descriptor (apart from this one) + HIDGenericDescriptor_REPORT, + HIDD_Descriptors_REPORTSIZE + }, + // Interrupt IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + HIDD_Descriptors_INTERRUPTIN), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardInputReport), + HIDD_Descriptors_INTERRUPTIN_POLLING + }, + // Interrupt OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + HIDD_Descriptors_INTERRUPTOUT), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardOutputReport), + HIDD_Descriptors_INTERRUPTIN_POLLING + }, + #endif // (HID defined) + + #if defined(usb_CDCAUDIO) || defined(usb_HIDAUDIO) + // AUDIO + // IAD for AUDIO function + { + sizeof(USBInterfaceAssociationDescriptor), + USBGenericDescriptor_INTERFACEASSOCIATION, + AUDD_Descriptors_INTERFACE, + 2, + AUDControlInterfaceDescriptor_CLASS, + AUDControlInterfaceDescriptor_SUBCLASS, + AUDControlInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor for this interface + }, + // Audio control interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDD_Descriptors_CONTROL, + 0, // This is alternate setting #0 + 0, // This interface uses no endpoint + AUDControlInterfaceDescriptor_CLASS, + AUDControlInterfaceDescriptor_SUBCLASS, + AUDControlInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio control interface descriptors + { + // Header descriptor + { + { + sizeof(AUDHeaderDescriptor1), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_HEADER, + AUDHeaderDescriptor_AUD1_00, + sizeof(AUDDSpeakerDriverAudioControlDescriptors), + 1 // One streaming interface + }, + AUDD_Descriptors_STREAMING + }, + // Input terminal descriptor + { + sizeof(AUDInputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_INPUTTERMINAL, + AUDD_Descriptors_INPUTTERMINAL, + AUDInputTerminalDescriptor_USBSTREAMING, + AUDD_Descriptors_OUTPUTTERMINAL, + AUDD_NUMCHANNELS, + AUDInputTerminalDescriptor_LEFTFRONT + | AUDInputTerminalDescriptor_RIGHTFRONT, + 0, // No string descriptor for channels + 0 // No string descriptor for input terminal + }, + // Output terminal descriptor + { + sizeof(AUDOutputTerminalDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_OUTPUTTERMINAL, + AUDD_Descriptors_OUTPUTTERMINAL, + AUDOutputTerminalDescriptor_SPEAKER, + AUDD_Descriptors_INPUTTERMINAL, + AUDD_Descriptors_FEATUREUNIT, + 0 // No string descriptor + }, + // Feature unit descriptor + { + { + sizeof(AUDFeatureUnitDescriptor3), + AUDGenericDescriptor_INTERFACE, + AUDGenericDescriptor_FEATUREUNIT, + AUDD_Descriptors_FEATUREUNIT, + AUDD_Descriptors_INPUTTERMINAL, + 1, // 1 byte per channel for controls + }, + { + AUDFeatureUnitDescriptor_MUTE, // Master channel controls + 0, // Right channel controls + 0 // Left channel controls + }, + 0 // No string descriptor + } + }, + // Audio streaming interface with 0 endpoints + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDD_Descriptors_STREAMING, + 0, // This is alternate setting #0 + 0, // This interface uses no endpoints + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming interface with data endpoint + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + AUDD_Descriptors_STREAMING, + 1, // This is alternate setting #1 + 1, // This interface uses 1 endpoint + AUDStreamingInterfaceDescriptor_CLASS, + AUDStreamingInterfaceDescriptor_SUBCLASS, + AUDStreamingInterfaceDescriptor_PROTOCOL, + 0 // No string descriptor + }, + // Audio streaming class-specific descriptor + { + sizeof(AUDStreamingInterfaceDescriptor), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_GENERAL, + AUDD_Descriptors_INPUTTERMINAL, + 0, // No internal delay because of data path + AUDFormatTypeOneDescriptor_PCM + }, + // Format type I descriptor + { + { + sizeof(AUDFormatTypeOneDescriptor1), + AUDGenericDescriptor_INTERFACE, + AUDStreamingInterfaceDescriptor_FORMATTYPE, + AUDFormatTypeOneDescriptor_FORMATTYPEONE, + AUDD_NUMCHANNELS, + AUDD_BYTESPERSAMPLE, + AUDD_BYTESPERSAMPLE*8, + 1 // One discrete frequency supported + }, + { + AUDD_SAMPLERATE & 0xFF, + (AUDD_SAMPLERATE >> 8) & 0xFF, + (AUDD_SAMPLERATE >> 16) & 0xFF + } + }, + // Audio streaming endpoint standard descriptor + { + sizeof(AUDEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + AUDD_Descriptors_DATAOUT), + USBEndpointDescriptor_ISOCHRONOUS, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(AUDD_Descriptors_DATAOUT), + 1, // Polling interval = 2^(x-1) milliseconds (1 ms) + 0, // This is not a synchronization endpoint + 0 // No associated synchronization endpoint + }, + // Audio streaming endpoint class-specific descriptor + { + sizeof(AUDDataEndpointDescriptor), + AUDGenericDescriptor_ENDPOINT, + AUDDataEndpointDescriptor_SUBTYPE, + 0, // No attributes + 0, // Endpoint is not synchronized + 0 // Endpoint is not synchronized + }, + #endif // (AUDIO defined) + + #if defined(usb_CDCCDC) + // CDC 1 + // IAD for CDC/ACM port 1 + { + sizeof(USBInterfaceAssociationDescriptor), + USBGenericDescriptor_INTERFACEASSOCIATION, + CDCD_Descriptors_INTERFACENUM1, + 2, + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Communication class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM1, // This is interface #2 + 0, // This is alternate setting #0 for this interface + 1, // This interface uses 1 endpoint + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Class-specific header functional descriptor + { + sizeof(CDCHeaderDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_HEADER, + CDCGenericDescriptor_CDC1_10 + }, + // Class-specific call management functional descriptor + { + sizeof(CDCCallManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_CALLMANAGEMENT, + CDCCallManagementDescriptor_SELFCALLMANAGEMENT, + CDCD_Descriptors_INTERFACENUM1 + 1 // No associated data interface + }, + // Class-specific abstract control management functional descriptor + { + sizeof(CDCAbstractControlManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_ABSTRACTCONTROLMANAGEMENT, + CDCAbstractControlManagementDescriptor_LINE + }, + // Class-specific union functional descriptor with one slave interface + { + sizeof(CDCUnionDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_UNION, + CDCD_Descriptors_INTERFACENUM1, // Number of master interface is #2 + CDCD_Descriptors_INTERFACENUM1+1 // First slave interface is #3 + }, + // Notification endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_NOTIFICATION1), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_NOTIFICATION1), + USBEndpointDescriptor_MAXINTERRUPTSIZE_FS), + 10 // Endpoint is polled every 10ms + }, + // Data class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM1 + 1, // This is interface #3 + 0, // This is alternate setting #0 for this interface + 2, // This interface uses 2 endpoints + CDCDataInterfaceDescriptor_CLASS, + CDCDataInterfaceDescriptor_SUBCLASS, + CDCDataInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Bulk-OUT endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, + CDCD_Descriptors_DATAOUT1), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAOUT1), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed bulk endpoints + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_DATAIN1), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAIN1), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed bulk endpoints + }, + #endif // (2 CDCs defined) + + #if defined(usb_CDCMSD) || defined(usb_HIDMSD) + // Mass Storage interface descriptor. + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + MSDD_Descriptors_INTERFACENUM, + 0, // This is alternate setting #0. + 2, // Interface uses two endpoints. + MSInterfaceDescriptor_CLASS, + MSInterfaceDescriptor_SCSI, + MSInterfaceDescriptor_BULKONLY, + 0 // No string descriptor for interface. + }, + // Bulk-OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + MSDD_Descriptors_BULKOUT), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(MSDD_Descriptors_BULKOUT), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // No string descriptor for endpoint. + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + MSDD_Descriptors_BULKIN), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(MSDD_Descriptors_BULKIN), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // No string descriptor for endpoint. + }, + #endif // (MSD defined) + +}; + +/// String descriptor with the supported languages. +const unsigned char languageIdDescriptor[] = { + + USBStringDescriptor_LENGTH(1), + USBGenericDescriptor_STRING, + USBStringDescriptor_ENGLISH_US +}; + +/// Manufacturer name. +const unsigned char manufacturerDescriptor[] = { + + USBStringDescriptor_LENGTH(5), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('t'), + USBStringDescriptor_UNICODE('m'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('l') +}; + +/// Product name. +const unsigned char productDescriptor[] = { + + USBStringDescriptor_LENGTH(14), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('C'), + USBStringDescriptor_UNICODE('o'), + USBStringDescriptor_UNICODE('m'), + USBStringDescriptor_UNICODE('p'), + USBStringDescriptor_UNICODE('o'), + USBStringDescriptor_UNICODE('s'), + USBStringDescriptor_UNICODE('i'), + USBStringDescriptor_UNICODE('t'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('D'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('m'), + USBStringDescriptor_UNICODE('o') +}; + +/// Product serial number. +const unsigned char serialNumberDescriptor[] = { + + USBStringDescriptor_LENGTH(4), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('0'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE('2'), + USBStringDescriptor_UNICODE('3') +}; + +/// Array of pointers to the four string descriptors. +const unsigned char *stringDescriptors[] = { + + languageIdDescriptor, + manufacturerDescriptor, + productDescriptor, + serialNumberDescriptor, +}; + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +/// List of descriptors required by an USB audio speaker device driver. +const USBDDriverDescriptors compositedDriverDescriptors = { + + &deviceDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptors, +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + &qualifierDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptors, + &deviceDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptors, + &qualifierDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptors, +#else + 0, 0, 0, 0, 0, 0, +#endif + stringDescriptors, + 4 // Number of string descriptors +}; + +#if defined(usb_CDCHID) || defined(usb_HIDAUDIO) || defined(usb_HIDMSD) +/// Report descriptor used by the driver. +const unsigned char hiddReportDescriptor[] = { + + HIDReport_GLOBAL_USAGEPAGE + 1, HIDGenericDesktop_PAGEID, + HIDReport_LOCAL_USAGE + 1, HIDGenericDesktop_KEYBOARD, + HIDReport_COLLECTION + 1, HIDReport_COLLECTION_APPLICATION, + + // Input report: modifier keys + HIDReport_GLOBAL_REPORTSIZE + 1, 1, + HIDReport_GLOBAL_REPORTCOUNT + 1, 8, + HIDReport_GLOBAL_USAGEPAGE + 1, HIDKeypad_PAGEID, + HIDReport_LOCAL_USAGEMINIMUM + 1, + HIDD_Descriptors_FIRSTMODIFIERKEY, + HIDReport_LOCAL_USAGEMAXIMUM + 1, + HIDD_Descriptors_LASTMODIFIERKEY, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, 0, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, 1, + HIDReport_INPUT + 1, HIDReport_VARIABLE, + + // Input report: standard keys + HIDReport_GLOBAL_REPORTCOUNT + 1, 3, + HIDReport_GLOBAL_REPORTSIZE + 1, 8, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, + HIDD_Descriptors_FIRSTSTANDARDKEY, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, + HIDD_Descriptors_LASTSTANDARDKEY, + HIDReport_GLOBAL_USAGEPAGE + 1, HIDKeypad_PAGEID, + HIDReport_LOCAL_USAGEMINIMUM + 1, + HIDD_Descriptors_FIRSTSTANDARDKEY, + HIDReport_LOCAL_USAGEMAXIMUM + 1, + HIDD_Descriptors_LASTSTANDARDKEY, + HIDReport_INPUT + 1, 0 /* Data array */, + + // Output report: LEDs + HIDReport_GLOBAL_REPORTCOUNT + 1, 3, + HIDReport_GLOBAL_REPORTSIZE + 1, 1, + HIDReport_GLOBAL_USAGEPAGE + 1, HIDLeds_PAGEID, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, 0, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, 1, + HIDReport_LOCAL_USAGEMINIMUM + 1, HIDLeds_NUMLOCK, + HIDReport_LOCAL_USAGEMAXIMUM + 1, HIDLeds_SCROLLLOCK, + HIDReport_OUTPUT + 1, HIDReport_VARIABLE, + + // Output report: padding + HIDReport_GLOBAL_REPORTCOUNT + 1, 1, + HIDReport_GLOBAL_REPORTSIZE + 1, 5, + HIDReport_OUTPUT + 1, HIDReport_CONSTANT, + + HIDReport_ENDCOLLECTION +}; +#endif // (HID defined) + diff --git a/usb/device/composite/COMPOSITEDDriverDescriptors.h b/usb/device/composite/COMPOSITEDDriverDescriptors.h new file mode 100644 index 0000000..c82f9bc --- /dev/null +++ b/usb/device/composite/COMPOSITEDDriverDescriptors.h @@ -0,0 +1,61 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef COMPOSITEDDRIVERDESCRIPTORS_H +#define COMPOSITEDDRIVERDESCRIPTORS_H + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include +#include + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +/// Number of interfaces of the device +#if defined(usb_CDCAUDIO) || defined(usb_CDCCDC) + #define COMPOSITEDDriverDescriptors_NUMINTERFACE 4 +#elif defined(usb_CDCHID) || defined(usb_CDCMSD) || defined(usb_HIDAUDIO) + #define COMPOSITEDDriverDescriptors_NUMINTERFACE 3 +#elif defined(usb_HIDMSD) + #define COMPOSITEDDriverDescriptors_NUMINTERFACE 2 +#else + #error USB Composite class not defined. +#endif + +//----------------------------------------------------------------------------- +// Exported variables +//----------------------------------------------------------------------------- + +extern const USBDDriverDescriptors compositedDriverDescriptors; + +#endif //#ifndef COMPOSITEDDRIVERDESCRIPTORS_H diff --git a/usb/device/composite/DUALCDCDDriver.c b/usb/device/composite/DUALCDCDDriver.c new file mode 100644 index 0000000..cced6f3 --- /dev/null +++ b/usb/device/composite/DUALCDCDDriver.c @@ -0,0 +1,189 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +// GENERAL +#include +#include +#include + +// USB +#include +#include + +//- DUALCDC +#include "DUALCDCDDriver.h" +#include "DUALCDCDDriverDescriptors.h" + +//----------------------------------------------------------------------------- +// Defines +//----------------------------------------------------------------------------- + +/// Interface setting spaces (4 byte aligned) +#define NUM_INTERFACES ((DUALCDCDDriverDescriptors_NUMINTERFACE+3)&0xFC) + +//----------------------------------------------------------------------------- +// Types +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Internal variables +//----------------------------------------------------------------------------- + +/// USBDDriver instance +static USBDDriver usbdDriver; + +/// CDCDSeriaoPort instance for 2 CDC/CAM serial ports. +static CDCDSerialPort cdcdPorts[2]; + +/// Array for storing the current setting of each interface +static unsigned char compositedDriverInterfaces[NUM_INTERFACES]; + +//----------------------------------------------------------------------------- +// Internal functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Optional RequestReceived() callback re-implementation +//----------------------------------------------------------------------------- +#if !defined(NOAUTOCALLBACK) + +void USBDCallbacks_RequestReceived(const USBGenericRequest *request) +{ + DUALCDCDDriver_RequestHandler(request); +} + +#endif + +//----------------------------------------------------------------------------- +// ConfigurationChanged() callback re-implementation +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Initializes the USB device composite device driver. +//----------------------------------------------------------------------------- +void DUALCDCDDriver_Initialize() +{ + // CDC + CDCDFunctionDriver_ConfigurePort(&cdcdPorts[0], + CDCD_Descriptors_INTERFACENUM0, + CDCD_Descriptors_NOTIFICATION0, + CDCD_Descriptors_DATAIN0, + CDCD_Descriptors_DATAOUT0); + CDCDFunctionDriver_ConfigurePort(&cdcdPorts[1], + CDCD_Descriptors_INTERFACENUM1, + CDCD_Descriptors_NOTIFICATION1, + CDCD_Descriptors_DATAIN1, + CDCD_Descriptors_DATAOUT1); + CDCDFunctionDriver_Initialize(&usbdDriver, + cdcdPorts, + 2); + + // Initialize the standard USB driver + USBDDriver_Initialize(&usbdDriver, + &dualcdcdDriverDescriptors, + compositedDriverInterfaces); + + // Initialize the USB driver + USBD_Init(); +} + +//----------------------------------------------------------------------------- +/// Handles composite-specific USB requests sent by the host, and forwards +/// standard ones to the USB device driver. +/// \param request Pointer to a USBGenericRequest instance. +//----------------------------------------------------------------------------- +void DUALCDCDDriver_RequestHandler(const USBGenericRequest *request) +{ + // Check if this is a class request + if (USBGenericRequest_GetType(request) == USBGenericRequest_CLASS) { + + unsigned char rc = 0; + + if (rc == 0) { + + rc = CDCDFunctionDriver_RequestHandler(request); + } + + if (!rc) { + + TRACE_WARNING( + "DUALCDCDDriver_RequestHandler: Unsupported request (%d)\n\r", + USBGenericRequest_GetRequest(request)); + USBD_Stall(0); + } + + } + // Check if this is a standard request + else if (USBGenericRequest_GetType(request) == USBGenericRequest_STANDARD) { + + unsigned char rc = 0; + + // Forward request to the standard handler + if (rc == 0) { + + USBDDriver_RequestHandler(&(usbdDriver), request); + } + } + // Unsupported request type + else { + + TRACE_WARNING( + "DUALCDCDDriver_RequestHandler: Unsupported request type (%d)\n\r", + USBGenericRequest_GetType(request)); + USBD_Stall(0); + } +} + +//----------------------------------------------------------------------------- +/// Starts a remote wake-up sequence if the host has explicitely enabled it +/// by sending the appropriate SET_FEATURE request. +//----------------------------------------------------------------------------- +void DUALCDCDDriver_RemoteWakeUp(void) +{ + // Remote wake-up has been enabled + if (USBDDriver_IsRemoteWakeUpEnabled(&usbdDriver)) { + + USBD_RemoteWakeUp(); + } + // Remote wake-up NOT enabled + else { + + TRACE_WARNING("DUALCDCDDriver_RemoteWakeUp: not enabled\n\r"); + } +} + + diff --git a/usb/device/composite/DUALCDCDDriver.h b/usb/device/composite/DUALCDCDDriver.h new file mode 100644 index 0000000..8ff2c66 --- /dev/null +++ b/usb/device/composite/DUALCDCDDriver.h @@ -0,0 +1,77 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//----------------------------------------------------------------------------- +/// \unit +/// +/// !Purpose +/// +/// Definitions and methods for USB composite device implement. +/// +/// !Usage +/// +/// -# Initialize USB function specified driver ( for MSD currently ) +/// - MSDDFunctionDriver_Initialize +/// +/// -# Initialize USB composite driver and USB driver +/// - DUALCDCDDriver_Initialize +/// +/// -# Handle and dispach USB requests +/// - DUALCDCDDriver_RequestHandler +/// +/// -# Try starting a remote wake-up sequence +/// - DUALCDCDDriver_RemoteWakeUp +//----------------------------------------------------------------------------- + +#ifndef DUALCDCDDRIVER_H +#define DUALCDCDDRIVER_H + + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include +#include + +#include "CDCDFunctionDriver.h" + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +// -DUALCDC +extern void DUALCDCDDriver_Initialize(); + +extern void DUALCDCDDriver_RequestHandler(const USBGenericRequest *request); + +extern void DUALCDCDDriver_RemoteWakeUp(void); + +#endif //#ifndef DUALCDCDDRIVER_H + diff --git a/usb/device/composite/DUALCDCDDriverDescriptors.c b/usb/device/composite/DUALCDCDDriverDescriptors.c new file mode 100644 index 0000000..f39b29e --- /dev/null +++ b/usb/device/composite/DUALCDCDDriverDescriptors.c @@ -0,0 +1,702 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "DUALCDCDDriver.h" +#include "DUALCDCDDriverDescriptors.h" +#include + +//- USB Generic +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "CDCDFunctionDriverDescriptors.h" + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +/// Device product ID. +#define DUALCDCDDriverDescriptors_PRODUCTID 0x6133 + +/// Device vendor ID (Atmel). +#define DUALCDCDDriverDescriptors_VENDORID 0x03EB + +/// Device release number. +#define DUALCDCDDriverDescriptors_RELEASE 0x0003 + +//----------------------------------------------------------------------------- +// Macros +//----------------------------------------------------------------------------- + +/// Returns the minimum between two values. +#define MIN(a, b) ((a < b) ? a : b) + +//----------------------------------------------------------------------------- +// Internal structures +//----------------------------------------------------------------------------- + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//----------------------------------------------------------------------------- +/// Configuration descriptor list for a device implementing a composite driver. +//----------------------------------------------------------------------------- +typedef struct { + + /// Standard configuration descriptor. + USBConfigurationDescriptor configuration; + + /// --- CDC 0 + /// IAD 0 + USBInterfaceAssociationDescriptor cdcIAD0; + /// Communication interface descriptor + USBInterfaceDescriptor cdcCommunication0; + /// CDC header functional descriptor. + CDCHeaderDescriptor cdcHeader0; + /// CDC call management functional descriptor. + CDCCallManagementDescriptor cdcCallManagement0; + /// CDC abstract control management functional descriptor. + CDCAbstractControlManagementDescriptor cdcAbstractControlManagement0; + /// CDC union functional descriptor (with one slave interface). + CDCUnionDescriptor cdcUnion0; + /// Notification endpoint descriptor. + USBEndpointDescriptor cdcNotification0; + /// Data interface descriptor. + USBInterfaceDescriptor cdcData0; + /// Data OUT endpoint descriptor. + USBEndpointDescriptor cdcDataOut0; + /// Data IN endpoint descriptor. + USBEndpointDescriptor cdcDataIn0; + + /// --- CDC 1 + /// IAD 1 + USBInterfaceAssociationDescriptor cdcIAD1; + /// Communication interface descriptor + USBInterfaceDescriptor cdcCommunication1; + /// CDC header functional descriptor. + CDCHeaderDescriptor cdcHeader1; + /// CDC call management functional descriptor. + CDCCallManagementDescriptor cdcCallManagement1; + /// CDC abstract control management functional descriptor. + CDCAbstractControlManagementDescriptor cdcAbstractControlManagement1; + /// CDC union functional descriptor (with one slave interface). + CDCUnionDescriptor cdcUnion1; + /// Notification endpoint descriptor. + USBEndpointDescriptor cdcNotification1; + /// Data interface descriptor. + USBInterfaceDescriptor cdcData1; + /// Data OUT endpoint descriptor. + USBEndpointDescriptor cdcDataOut1; + /// Data IN endpoint descriptor. + USBEndpointDescriptor cdcDataIn1; + +} __attribute__ ((packed)) DualCdcDriverConfigurationDescriptors; + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +/// Standard USB device descriptor for the composite device driver +static const USBDeviceDescriptor deviceDescriptor = { + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + 0xEF,// MI + 0x02,// + 0x01,// + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + DUALCDCDDriverDescriptors_VENDORID, + DUALCDCDDriverDescriptors_PRODUCTID, + DUALCDCDDriverDescriptors_RELEASE, + 0, // No string descriptor for manufacturer + 1, // Index of product string descriptor is #1 + 0, // No string descriptor for serial number + 1 // Device has 1 possible configuration +}; + +#if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + +/// USB device qualifier descriptor. +static const USBDeviceQualifierDescriptor qualifierDescriptor = { + + sizeof(USBDeviceQualifierDescriptor), + USBGenericDescriptor_DEVICEQUALIFIER, + USBDeviceDescriptor_USB2_00, + 0xEF,// MI + 0x02,// + 0x01,// + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + 1, // Device has one possible configuration + 0 // Reserved +}; + +/// USB configuration descriptors for the composite device driver +static const DualCdcDriverConfigurationDescriptors configurationDescriptorsHS = +{ + + // Standard configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(DualCdcDriverConfigurationDescriptors), + DUALCDCDDriverDescriptors_NUMINTERFACE, + 1, // This is configuration #1 + 0, // No string descriptor for this configuration + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + + // CDC 0 + // IAD for CDC/ACM port + { + sizeof(USBInterfaceAssociationDescriptor), + USBGenericDescriptor_INTERFACEASSOCIATION, + CDCD_Descriptors_INTERFACENUM0, + 2, + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Communication class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM0, // This is interface #0 + 0, // This is alternate setting #0 for this interface + 1, // This interface uses 1 endpoint + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Class-specific header functional descriptor + { + sizeof(CDCHeaderDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_HEADER, + CDCGenericDescriptor_CDC1_10 + }, + // Class-specific call management functional descriptor + { + sizeof(CDCCallManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_CALLMANAGEMENT, + CDCCallManagementDescriptor_SELFCALLMANAGEMENT, + CDCD_Descriptors_INTERFACENUM0 + 1 // No associated data interface + }, + // Class-specific abstract control management functional descriptor + { + sizeof(CDCAbstractControlManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_ABSTRACTCONTROLMANAGEMENT, + CDCAbstractControlManagementDescriptor_LINE + }, + // Class-specific union functional descriptor with one slave interface + { + sizeof(CDCUnionDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_UNION, + CDCD_Descriptors_INTERFACENUM0, // Number of master interface is #0 + CDCD_Descriptors_INTERFACENUM0 + 1 // First slave interface is #1 + }, + // Notification endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_NOTIFICATION0), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_NOTIFICATION0), + CDCD_Descriptors_INTERRUPT_MAXPACKETSIZE), + CDCD_Descriptors_INTERRUPTIN_POLLING_HS + }, + // Data class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM0 + 1, // This is interface #1 + 0, // This is alternate setting #0 for this interface + 2, // This interface uses 2 endpoints + CDCDataInterfaceDescriptor_CLASS, + CDCDataInterfaceDescriptor_SUBCLASS, + CDCDataInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Bulk-OUT endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, + CDCD_Descriptors_DATAOUT0), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAOUT0), + CDCD_Descriptors_BULK_MAXPACKETSIZE), + 0 // Must be 0 for full-speed bulk endpoints + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_DATAIN0), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAIN0), + CDCD_Descriptors_BULK_MAXPACKETSIZE), + 0 // Must be 0 for full-speed bulk endpoints + }, + + // CDC 1 + // IAD for CDC/ACM port 1 + { + sizeof(USBInterfaceAssociationDescriptor), + USBGenericDescriptor_INTERFACEASSOCIATION, + CDCD_Descriptors_INTERFACENUM1, + 2, + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Communication class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM1, // This is interface #2 + 0, // This is alternate setting #0 for this interface + 1, // This interface uses 1 endpoint + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Class-specific header functional descriptor + { + sizeof(CDCHeaderDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_HEADER, + CDCGenericDescriptor_CDC1_10 + }, + // Class-specific call management functional descriptor + { + sizeof(CDCCallManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_CALLMANAGEMENT, + CDCCallManagementDescriptor_SELFCALLMANAGEMENT, + CDCD_Descriptors_INTERFACENUM1 + 1 // No associated data interface + }, + // Class-specific abstract control management functional descriptor + { + sizeof(CDCAbstractControlManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_ABSTRACTCONTROLMANAGEMENT, + CDCAbstractControlManagementDescriptor_LINE + }, + // Class-specific union functional descriptor with one slave interface + { + sizeof(CDCUnionDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_UNION, + CDCD_Descriptors_INTERFACENUM1, // Number of master interface is #2 + CDCD_Descriptors_INTERFACENUM1+1 // First slave interface is #3 + }, + // Notification endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_NOTIFICATION1), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_NOTIFICATION1), + CDCD_Descriptors_INTERRUPT_MAXPACKETSIZE), + CDCD_Descriptors_INTERRUPTIN_POLLING_HS + }, + // Data class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM1 + 1, // This is interface #3 + 0, // This is alternate setting #0 for this interface + 2, // This interface uses 2 endpoints + CDCDataInterfaceDescriptor_CLASS, + CDCDataInterfaceDescriptor_SUBCLASS, + CDCDataInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Bulk-OUT endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, + CDCD_Descriptors_DATAOUT1), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAOUT1), + CDCD_Descriptors_BULK_MAXPACKETSIZE), + 0 // Must be 0 for full-speed bulk endpoints + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_DATAIN1), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAIN1), + CDCD_Descriptors_BULK_MAXPACKETSIZE), + 0 // Must be 0 for full-speed bulk endpoints + } + +}; + +#endif + +/// USB configuration descriptors for the composite device driver +static const DualCdcDriverConfigurationDescriptors configurationDescriptorsFS = +{ + + // Standard configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(DualCdcDriverConfigurationDescriptors), + DUALCDCDDriverDescriptors_NUMINTERFACE, + 1, // This is configuration #1 + 0, // No string descriptor for this configuration + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + + // CDC 0 + // IAD for CDC/ACM port + { + sizeof(USBInterfaceAssociationDescriptor), + USBGenericDescriptor_INTERFACEASSOCIATION, + CDCD_Descriptors_INTERFACENUM0, + 2, + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Communication class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM0, // This is interface #0 + 0, // This is alternate setting #0 for this interface + 1, // This interface uses 1 endpoint + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Class-specific header functional descriptor + { + sizeof(CDCHeaderDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_HEADER, + CDCGenericDescriptor_CDC1_10 + }, + // Class-specific call management functional descriptor + { + sizeof(CDCCallManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_CALLMANAGEMENT, + CDCCallManagementDescriptor_SELFCALLMANAGEMENT, + CDCD_Descriptors_INTERFACENUM0 + 1 // No associated data interface + }, + // Class-specific abstract control management functional descriptor + { + sizeof(CDCAbstractControlManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_ABSTRACTCONTROLMANAGEMENT, + CDCAbstractControlManagementDescriptor_LINE + }, + // Class-specific union functional descriptor with one slave interface + { + sizeof(CDCUnionDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_UNION, + CDCD_Descriptors_INTERFACENUM0, // Number of master interface is #0 + CDCD_Descriptors_INTERFACENUM0 + 1 // First slave interface is #1 + }, + // Notification endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_NOTIFICATION0), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_NOTIFICATION0), + USBEndpointDescriptor_MAXINTERRUPTSIZE_FS), + CDCD_Descriptors_INTERRUPTIN_POLLING_FS + }, + // Data class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM0 + 1, // This is interface #1 + 0, // This is alternate setting #0 for this interface + 2, // This interface uses 2 endpoints + CDCDataInterfaceDescriptor_CLASS, + CDCDataInterfaceDescriptor_SUBCLASS, + CDCDataInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Bulk-OUT endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, + CDCD_Descriptors_DATAOUT0), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAOUT0), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed bulk endpoints + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_DATAIN0), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAIN0), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed bulk endpoints + }, + + // CDC 1 + // IAD for CDC/ACM port 1 + { + sizeof(USBInterfaceAssociationDescriptor), + USBGenericDescriptor_INTERFACEASSOCIATION, + CDCD_Descriptors_INTERFACENUM1, + 2, + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Communication class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM1, // This is interface #2 + 0, // This is alternate setting #0 for this interface + 1, // This interface uses 1 endpoint + CDCCommunicationInterfaceDescriptor_CLASS, + CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL, + CDCCommunicationInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Class-specific header functional descriptor + { + sizeof(CDCHeaderDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_HEADER, + CDCGenericDescriptor_CDC1_10 + }, + // Class-specific call management functional descriptor + { + sizeof(CDCCallManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_CALLMANAGEMENT, + CDCCallManagementDescriptor_SELFCALLMANAGEMENT, + CDCD_Descriptors_INTERFACENUM1 + 1 // No associated data interface + }, + // Class-specific abstract control management functional descriptor + { + sizeof(CDCAbstractControlManagementDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_ABSTRACTCONTROLMANAGEMENT, + CDCAbstractControlManagementDescriptor_LINE + }, + // Class-specific union functional descriptor with one slave interface + { + sizeof(CDCUnionDescriptor), + CDCGenericDescriptor_INTERFACE, + CDCGenericDescriptor_UNION, + CDCD_Descriptors_INTERFACENUM1, // Number of master interface is #2 + CDCD_Descriptors_INTERFACENUM1+1 // First slave interface is #3 + }, + // Notification endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_NOTIFICATION1), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_NOTIFICATION1), + USBEndpointDescriptor_MAXINTERRUPTSIZE_FS), + CDCD_Descriptors_INTERRUPTIN_POLLING_FS + }, + // Data class interface standard descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + CDCD_Descriptors_INTERFACENUM1 + 1, // This is interface #3 + 0, // This is alternate setting #0 for this interface + 2, // This interface uses 2 endpoints + CDCDataInterfaceDescriptor_CLASS, + CDCDataInterfaceDescriptor_SUBCLASS, + CDCDataInterfaceDescriptor_NOPROTOCOL, + 0 // No string descriptor for this interface + }, + // Bulk-OUT endpoint standard descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT, + CDCD_Descriptors_DATAOUT1), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAOUT1), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed bulk endpoints + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, + CDCD_Descriptors_DATAIN1), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(CDCD_Descriptors_DATAIN1), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed bulk endpoints + } + +}; + +/// String descriptor with the supported languages. +static const unsigned char languageIdDescriptor[] = { + + USBStringDescriptor_LENGTH(1), + USBGenericDescriptor_STRING, + USBStringDescriptor_ENGLISH_US +}; + +/// Manufacturer name. +static const unsigned char manufacturerDescriptor[] = { + + USBStringDescriptor_LENGTH(5), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('t'), + USBStringDescriptor_UNICODE('m'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('l') +}; + +/// Product name. +static const unsigned char productDescriptor[] = { + + USBStringDescriptor_LENGTH(14), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('C'), + USBStringDescriptor_UNICODE('o'), + USBStringDescriptor_UNICODE('m'), + USBStringDescriptor_UNICODE('p'), + USBStringDescriptor_UNICODE('o'), + USBStringDescriptor_UNICODE('s'), + USBStringDescriptor_UNICODE('i'), + USBStringDescriptor_UNICODE('t'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('D'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('m'), + USBStringDescriptor_UNICODE('o') +}; + +/// Product serial number. +static const unsigned char serialNumberDescriptor[] = { + + USBStringDescriptor_LENGTH(4), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('0'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE('2'), + USBStringDescriptor_UNICODE('3') +}; + +/// Array of pointers to the four string descriptors. +static const unsigned char *stringDescriptors[] = { + + languageIdDescriptor, + manufacturerDescriptor, + productDescriptor, + serialNumberDescriptor, +}; + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +/// List of descriptors required by an USB audio speaker device driver. +const USBDDriverDescriptors dualcdcdDriverDescriptors = { + + &deviceDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptorsFS, +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + &qualifierDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptorsHS, + &deviceDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptorsHS, + &qualifierDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptorsFS, +#else + 0, 0, 0, 0, 0, 0, +#endif + stringDescriptors, + 4 // Number of string descriptors +}; diff --git a/usb/device/composite/DUALCDCDDriverDescriptors.h b/usb/device/composite/DUALCDCDDriverDescriptors.h new file mode 100644 index 0000000..13e1f4d --- /dev/null +++ b/usb/device/composite/DUALCDCDDriverDescriptors.h @@ -0,0 +1,72 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef DUALCDCDDRIVERDESCRIPTORS_H +#define DUALCDCDDRIVERDESCRIPTORS_H + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include +#include + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +/// Number of interfaces of the device +#define DUALCDCDDriverDescriptors_NUMINTERFACE 4 + +/// Number of the CDC0 interface. +#define CDCD_Descriptors_INTERFACENUM0 0 +/// Address of the CDC0 interrupt-in endpoint. +#define CDCD_Descriptors_NOTIFICATION0 3 +/// Address of the CDC0 bulk-in endpoint. +#define CDCD_Descriptors_DATAIN0 2 +/// Address of the CDC0 bulk-out endpoint. +#define CDCD_Descriptors_DATAOUT0 1 + +/// Number of the CDC1 interface. +#define CDCD_Descriptors_INTERFACENUM1 2 +/// Address of the CDC1 interrupt-in endpoint. +#define CDCD_Descriptors_NOTIFICATION1 6 +/// Address of the CDC1 bulk-in endpoint. +#define CDCD_Descriptors_DATAIN1 5 +/// Address of the CDC1 bulk-out endpoint. +#define CDCD_Descriptors_DATAOUT1 4 + + +//----------------------------------------------------------------------------- +// Exported variables +//----------------------------------------------------------------------------- + +extern const USBDDriverDescriptors dualcdcdDriverDescriptors; + +#endif //#ifndef DUALCDCDDRIVERDESCRIPTORS_H diff --git a/usb/device/composite/HIDDFunctionDriver.c b/usb/device/composite/HIDDFunctionDriver.c new file mode 100644 index 0000000..03f8a1c --- /dev/null +++ b/usb/device/composite/HIDDFunctionDriver.c @@ -0,0 +1,477 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +// GENERAL +#include +#include +// USB +#include +#include +#include +// HID +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "HIDDFunctionDriver.h" +#include "HIDDFunctionDriverDescriptors.h" + +//----------------------------------------------------------------------------- +// Internal types +//----------------------------------------------------------------------------- + +/// Driver structure for an HID device implementing keyboard functionalities. +typedef struct { + + /// Pointer to USB device driver instance + USBDDriver * pUsbdDriver; + /// Interface Number to access this function + unsigned char interfaceNum; + /// Interrupt IN endpoint address + unsigned char interruptInEndpoint; + /// Interrupt OUT endpoint address + unsigned char interruptOutEndpoint; + /// Idle rate (in milliseconds) of the input report + unsigned char inputReportIdleRate; + /// Input report instance. + HIDDKeyboardInputReport inputReport; + /// Output report instance. + HIDDKeyboardOutputReport outputReport; + +} HIDDKeyboardDriver; + +//----------------------------------------------------------------------------- +// Internal variables +//----------------------------------------------------------------------------- + +/// Static instance of the HID keyboard device driver. +static HIDDKeyboardDriver hiddKeyboardDriver; + +//----------------------------------------------------------------------------- +// Internal functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Returns the descriptor requested by the host. +/// \param type Descriptor type. +/// \param length Maximum number of bytes to send. +/// \return 1 if the request has been handled by this function, otherwise 0. +//----------------------------------------------------------------------------- +static unsigned char HIDD_GetDescriptor(unsigned char type, + unsigned char length) +{ + const USBConfigurationDescriptor *pConfiguration; + HIDDescriptor *hidDescriptors[2]; + + switch (type) { + + case HIDGenericDescriptor_REPORT: + TRACE_INFO_WP("Report "); + + // Adjust length and send report descriptor + if (length > HIDD_Descriptors_REPORTSIZE) { + + length = HIDD_Descriptors_REPORTSIZE; + } + USBD_Write(0, &hiddReportDescriptor, length, 0, 0); + break; + + case HIDGenericDescriptor_HID: + TRACE_INFO_WP("HID "); + + // Configuration descriptor is different depending on speed + if (USBD_IsHighSpeed()) { + + pConfiguration = hiddKeyboardDriver + .pUsbdDriver->pDescriptors->pHsConfiguration; + } + else { + + pConfiguration = hiddKeyboardDriver + .pUsbdDriver->pDescriptors->pFsConfiguration; + } + + // Parse the device configuration to get the HID descriptor + USBConfigurationDescriptor_Parse(pConfiguration, + 0, + 0, + (USBGenericDescriptor **) hidDescriptors); + + // Adjust length and send HID descriptor + if (length > sizeof(HIDDescriptor)) { + + length = sizeof(HIDDescriptor); + } + USBD_Write(0, hidDescriptors[0], length, 0, 0); + break; + + default: + return 0; + } + + return 1; +} + +//----------------------------------------------------------------------------- +/// Sends the current Idle rate of the input report to the host. +//----------------------------------------------------------------------------- +static void HIDD_GetIdle() +{ + TRACE_INFO_WP("gIdle "); + + USBD_Write(0, &(hiddKeyboardDriver.inputReportIdleRate), 1, 0, 0); +} + +//----------------------------------------------------------------------------- +/// Retrieves the new idle rate of the input report from the USB host. +/// \param idleRate New input report idle rate. +//----------------------------------------------------------------------------- +static void HIDD_SetIdle(unsigned char idleRate) +{ + TRACE_INFO_WP("sIdle(%d) ", idleRate); + + hiddKeyboardDriver.inputReportIdleRate = idleRate; + USBD_Write(0, 0, 0, 0, 0); +} + +//----------------------------------------------------------------------------- +/// Sends the requested report to the host. +/// \param type Report type. +/// \param length Maximum number of bytes to send. +//----------------------------------------------------------------------------- +static void HIDD_GetReport(unsigned char type, + unsigned short length) +{ + TRACE_INFO_WP("gReport "); + + // Check report type + switch (type) { + + case HIDReportRequest_INPUT: + TRACE_INFO_WP("In "); + + // Adjust size and send report + if (length > sizeof(HIDDKeyboardInputReport)) { + + length = sizeof(HIDDKeyboardInputReport); + } + USBD_Write(0, // Endpoint #0 + &(hiddKeyboardDriver.inputReport), + length, + 0, // No callback + 0); + break; + + case HIDReportRequest_OUTPUT: + TRACE_INFO_WP("Out "); + + // Adjust size and send report + if (length > sizeof(HIDDKeyboardOutputReport)) { + + length = sizeof(HIDDKeyboardOutputReport); + } + USBD_Write(0, // Endpoint #0 + &(hiddKeyboardDriver.outputReport), + length, + 0, // No callback + 0); + break; + + default: + USBD_Stall(0); + } +} + +//----------------------------------------------------------------------------- +/// Callback invoked when an output report has been received from the host. +/// Forward the new status of the LEDs to the user program via the +//----------------------------------------------------------------------------- +static void HIDD_ReportReceived() +{ + TRACE_INFO_WP("oReport "); + + // Trigger callback + HIDDKeyboardCallbacks_LedsChanged( + HIDDKeyboardOutputReport_GetNumLockStatus( + &(hiddKeyboardDriver.outputReport)), + HIDDKeyboardOutputReport_GetCapsLockStatus( + &(hiddKeyboardDriver.outputReport)), + HIDDKeyboardOutputReport_GetScrollLockStatus( + &(hiddKeyboardDriver.outputReport))); + + // Restart transfer + USBD_Read(hiddKeyboardDriver.interruptOutEndpoint, + &(hiddKeyboardDriver.outputReport), + sizeof(HIDDKeyboardOutputReport), + (TransferCallback) HIDD_ReportReceived, + 0); // No argument for callback function +} + +//----------------------------------------------------------------------------- +/// Retrieves the new value of a report from the host and saves it. +/// \param type Report type. +/// \param length Report length. +//----------------------------------------------------------------------------- +static void HIDD_SetReport(unsigned char type, + unsigned short length) +{ + TRACE_INFO_WP("sReport "); + + // Check report type + switch (type) { + + case HIDReportRequest_INPUT: + // SET_REPORT requests on input reports are ignored + USBD_Stall(0); + break; + + case HIDReportRequest_OUTPUT: + // Check report length + if (length != sizeof(HIDDKeyboardOutputReport)) { + + USBD_Stall(0); + } + else { + + USBD_Read(0, // Endpoint #0 + &(hiddKeyboardDriver.outputReport), + length, + (TransferCallback) HIDD_ReportReceived, + 0); // No argument to the callback function + } + break; + + default: + USBD_Stall(0); + } +} + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Initializes an USB HID keyboard function driver. +/// \param pUsbdDriver Pointer to the USB driver instance. +/// \param interfaceNum Interface number to access the MSD function +/// \param interruptInEndpoint Interrupt IN endpoint address +/// \param interruptOutEndpoint Interrupt OUT endpoint address +//----------------------------------------------------------------------------- +void HIDDFunctionDriver_Initialize(USBDDriver * pUsbdDriver, + unsigned char interfaceNum, + unsigned char interruptInEndpoint, + unsigned char interruptOutEndpoint) +{ + hiddKeyboardDriver.inputReportIdleRate = 0; + HIDDKeyboardInputReport_Initialize(&(hiddKeyboardDriver.inputReport)); + HIDDKeyboardOutputReport_Initialize(&(hiddKeyboardDriver.outputReport)); + + hiddKeyboardDriver.pUsbdDriver = pUsbdDriver; + hiddKeyboardDriver.interfaceNum = interfaceNum; + hiddKeyboardDriver.interruptInEndpoint = interruptInEndpoint; + hiddKeyboardDriver.interruptOutEndpoint = interruptOutEndpoint; +} + +//----------------------------------------------------------------------------- +/// Handles HID-specific SETUP request sent by the host. +/// \param request Pointer to a USBGenericRequest instance. +/// \return 0 if the request is Unsupported, 1 if the request handled. +//----------------------------------------------------------------------------- +unsigned char HIDDFunctionDriver_RequestHandler( + const USBGenericRequest *request) +{ + TRACE_INFO_WP("NewReq "); + + // Check if this is a standard request + if (USBGenericRequest_GetType(request) == USBGenericRequest_STANDARD) { + + // This is a standard request + switch (USBGenericRequest_GetRequest(request)) { + + case USBGenericRequest_GETDESCRIPTOR: + // Check if this is a HID descriptor, otherwise forward it to + // the standard driver + if (!HIDD_GetDescriptor( + USBGetDescriptorRequest_GetDescriptorType(request), + USBGenericRequest_GetLength(request))) { + + USBDDriver_RequestHandler(hiddKeyboardDriver.pUsbdDriver, + request); + } + break; + + default: + return 0; + } + } + // Check if this is a class request + else if (USBGenericRequest_GetType(request) == USBGenericRequest_CLASS) { + + // This is a class-specific request + switch (USBGenericRequest_GetRequest(request)) { + + case HIDGenericRequest_GETIDLE: + HIDD_GetIdle(); + break; + + case HIDGenericRequest_SETIDLE: + HIDD_SetIdle(HIDIdleRequest_GetIdleRate(request)); + break; + + case HIDGenericRequest_GETREPORT: + HIDD_GetReport( + HIDReportRequest_GetReportType(request), + USBGenericRequest_GetLength(request)); + break; + + case HIDGenericRequest_SETREPORT: + HIDD_SetReport( + HIDReportRequest_GetReportType(request), + USBGenericRequest_GetLength(request)); + break; + + default: + return 0; + } + } + return 1; +} + +//----------------------------------------------------------------------------- +/// Invoked whenever the configuration of the device is changed by the host. +/// \param cfgnum Newly configuration number. +//----------------------------------------------------------------------------- +void HIDDFunctionCallbacks_ConfigurationChanged(unsigned char cfgnum) +{ + if (cfgnum > 0) { + + // Start receiving output reports + USBD_Read(hiddKeyboardDriver.interruptOutEndpoint, + &(hiddKeyboardDriver.outputReport), + sizeof(HIDDKeyboardOutputReport), + (TransferCallback) HIDD_ReportReceived, + 0); // No argument for callback function + } +} + +//----------------------------------------------------------------------------- +/// Reports a change in which keys are currently pressed or release to the +/// host. +/// \param pressedKeys Pointer to an array of key codes indicating keys that +/// have been pressed since the last call to +/// . +/// \param pressedKeysSize Number of key codes in the pressedKeys array. +/// \param releasedKeys Pointer to an array of key codes indicates keys that +/// have been released since the last call to +/// . +/// \param releasedKeysSize Number of key codes in the releasedKeys array. +/// \return if the report has been sent to the host; +/// otherwise an error code. +//----------------------------------------------------------------------------- +unsigned char HIDDKeyboardDriver_ChangeKeys(unsigned char *pressedKeys, + unsigned char pressedKeysSize, + unsigned char *releasedKeys, + unsigned char releasedKeysSize) +{ + // Press keys + while (pressedKeysSize > 0) { + + // Check if this is a standard or modifier key + if (HIDKeypad_IsModifierKey(*pressedKeys)) { + + // Set the corresponding bit in the input report + HIDDKeyboardInputReport_PressModifierKey( + &(hiddKeyboardDriver.inputReport), + *pressedKeys); + } + else { + + HIDDKeyboardInputReport_PressStandardKey( + &(hiddKeyboardDriver.inputReport), + *pressedKeys); + } + + pressedKeysSize--; + pressedKeys++; + } + + // Release keys + while (releasedKeysSize > 0) { + + // Check if this is a standard or modifier key + if (HIDKeypad_IsModifierKey(*releasedKeys)) { + + // Set the corresponding bit in the input report + HIDDKeyboardInputReport_ReleaseModifierKey( + &(hiddKeyboardDriver.inputReport), + *releasedKeys); + } + else { + + HIDDKeyboardInputReport_ReleaseStandardKey( + &(hiddKeyboardDriver.inputReport), + *releasedKeys); + } + + releasedKeysSize--; + releasedKeys++; + } + + // Send input report through the interrupt IN endpoint + return USBD_Write(hiddKeyboardDriver.interruptInEndpoint, + &(hiddKeyboardDriver.inputReport), + sizeof(HIDDKeyboardInputReport), + 0, + 0); +} + +//----------------------------------------------------------------------------- +/// Starts a remote wake-up sequence if the host has explicitely enabled it +/// by sending the appropriate SET_FEATURE request. +//----------------------------------------------------------------------------- +void HIDDKeyboardDriver_RemoteWakeUp(void) +{ + // Remote wake-up has been enabled + if (USBDDriver_IsRemoteWakeUpEnabled(hiddKeyboardDriver.pUsbdDriver)) { + + USBD_RemoteWakeUp(); + } +} diff --git a/usb/device/composite/HIDDFunctionDriver.h b/usb/device/composite/HIDDFunctionDriver.h new file mode 100644 index 0000000..a788d57 --- /dev/null +++ b/usb/device/composite/HIDDFunctionDriver.h @@ -0,0 +1,64 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef HIDDFUNCTIONDRIVER_H +#define HIDDFUNCTIONDRIVER_H + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include +#include + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +//- Function API for composite device +extern void HIDDFunctionDriver_Initialize(USBDDriver * pUsbdDriver, + unsigned char interfaceNum, + unsigned char interruptInEndpoint, + unsigned char interruptOutEndpoint); + +extern unsigned char HIDDFunctionDriver_RequestHandler( + const USBGenericRequest *request); + +extern void HIDDFunctionCallbacks_ConfigurationChanged(unsigned char cfgnum); + +//- HID Keyboard API +extern unsigned char HIDDKeyboardDriver_ChangeKeys( + unsigned char *pressedKeys, + unsigned char pressedKeysSize, + unsigned char *releasedKeys, + unsigned char releasedKeysSize); + +extern void HIDDKeyboardDriver_RemoteWakeUp(void); + +#endif // #define HIDDFUNCTIONDRIVER_H diff --git a/usb/device/composite/HIDDFunctionDriverDescriptors.c b/usb/device/composite/HIDDFunctionDriverDescriptors.c new file mode 100644 index 0000000..747a5fb --- /dev/null +++ b/usb/device/composite/HIDDFunctionDriverDescriptors.c @@ -0,0 +1,118 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include + +//- HID +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "HIDDFunctionDriverDescriptors.h" + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Macros +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Internal structures +//----------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +/// Report descriptor used by the HID function driver. +const unsigned char hiddReportDescriptor[] = { + + HIDReport_GLOBAL_USAGEPAGE + 1, HIDGenericDesktop_PAGEID, + HIDReport_LOCAL_USAGE + 1, HIDGenericDesktop_KEYBOARD, + HIDReport_COLLECTION + 1, HIDReport_COLLECTION_APPLICATION, + + // Input report: modifier keys + HIDReport_GLOBAL_REPORTSIZE + 1, 1, + HIDReport_GLOBAL_REPORTCOUNT + 1, 8, + HIDReport_GLOBAL_USAGEPAGE + 1, HIDKeypad_PAGEID, + HIDReport_LOCAL_USAGEMINIMUM + 1, + HIDD_Descriptors_FIRSTMODIFIERKEY, + HIDReport_LOCAL_USAGEMAXIMUM + 1, + HIDD_Descriptors_LASTMODIFIERKEY, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, 0, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, 1, + HIDReport_INPUT + 1, HIDReport_VARIABLE, + + // Input report: standard keys + HIDReport_GLOBAL_REPORTCOUNT + 1, 3, + HIDReport_GLOBAL_REPORTSIZE + 1, 8, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, + HIDD_Descriptors_FIRSTSTANDARDKEY, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, + HIDD_Descriptors_LASTSTANDARDKEY, + HIDReport_GLOBAL_USAGEPAGE + 1, HIDKeypad_PAGEID, + HIDReport_LOCAL_USAGEMINIMUM + 1, + HIDD_Descriptors_FIRSTSTANDARDKEY, + HIDReport_LOCAL_USAGEMAXIMUM + 1, + HIDD_Descriptors_LASTSTANDARDKEY, + HIDReport_INPUT + 1, 0 /* Data array */, + + // Output report: LEDs + HIDReport_GLOBAL_REPORTCOUNT + 1, 3, + HIDReport_GLOBAL_REPORTSIZE + 1, 1, + HIDReport_GLOBAL_USAGEPAGE + 1, HIDLeds_PAGEID, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, 0, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, 1, + HIDReport_LOCAL_USAGEMINIMUM + 1, HIDLeds_NUMLOCK, + HIDReport_LOCAL_USAGEMAXIMUM + 1, HIDLeds_SCROLLLOCK, + HIDReport_OUTPUT + 1, HIDReport_VARIABLE, + + // Output report: padding + HIDReport_GLOBAL_REPORTCOUNT + 1, 1, + HIDReport_GLOBAL_REPORTSIZE + 1, 5, + HIDReport_OUTPUT + 1, HIDReport_CONSTANT, + + HIDReport_ENDCOLLECTION +}; diff --git a/usb/device/composite/HIDDFunctionDriverDescriptors.h b/usb/device/composite/HIDDFunctionDriverDescriptors.h new file mode 100644 index 0000000..7f64321 --- /dev/null +++ b/usb/device/composite/HIDDFunctionDriverDescriptors.h @@ -0,0 +1,86 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef HIDDFUNCTIONDRIVERDESCRIPTORS_H +#define HIDDFUNCTIONDRIVERDESCRIPTORS_H + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include +#include + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +//- Interface & Endpoints +/// Interface Number. +/// Interrupt IN endpoint number. +/// Interrupt OUT endpoint number. +/// Interrupt IN endpoint polling rate (in milliseconds). +/// Interrupt OUT endpoint polling rate (in milliseconds). +#if defined(usb_HIDAUDIO) +#define HIDD_Descriptors_INTERFACENUM 0 +#define HIDD_Descriptors_INTERRUPTIN 1 +#define HIDD_Descriptors_INTERRUPTOUT 2 +#define HIDD_Descriptors_INTERRUPTIN_POLLING 10 +#endif + +/// Default HID interrupt IN endpoint polling rate (16ms). +#define HIDD_Descriptors_INTERRUPTIN_POLLING_FS 16 +#define HIDD_Descriptors_INTERRUPTIN_POLLING_HS 8 +/// Default interrupt OUT endpoint polling rate (16ms). +#define HIDD_Descriptors_INTERRUPTOUT_POLLING_FS 16 +#define HIDD_Descriptors_INTERRUPTOUT_POLLING_HS 8 + +//- Keypad keys +/// Key code of the first accepted modifier key. +#define HIDD_Descriptors_FIRSTMODIFIERKEY HIDKeypad_LEFTCONTROL +/// Key code of the last accepted modifier key. +#define HIDD_Descriptors_LASTMODIFIERKEY HIDKeypad_RIGHTGUI +/// Key code of the first accepted standard key. +#define HIDD_Descriptors_FIRSTSTANDARDKEY 0 +/// Key code of the last accepted standard key. +#define HIDD_Descriptors_LASTSTANDARDKEY HIDKeypad_NUMLOCK + +//- Report descriptor +/// Size of the report descriptor in bytes. +#define HIDD_Descriptors_REPORTSIZE 61 + +//----------------------------------------------------------------------------- +// Exported variables +//----------------------------------------------------------------------------- + +/// Report descriptor used by the driver. +extern const unsigned char hiddReportDescriptor[]; + +#endif // #define HIDDFUNCTIONDRIVERDESCRIPTORS_H + diff --git a/usb/device/composite/HIDMSDDDriver.c b/usb/device/composite/HIDMSDDDriver.c new file mode 100644 index 0000000..2ef2ea7 --- /dev/null +++ b/usb/device/composite/HIDMSDDDriver.c @@ -0,0 +1,227 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +// GENERAL +#include +#include +#include + +// USB +#include +#include + +//- HID +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +//- MSD + +//- HIDMSD +#include "HIDMSDDDriver.h" +#include "HIDMSDDDriverDescriptors.h" + +//----------------------------------------------------------------------------- +// Defines +//----------------------------------------------------------------------------- + +/// Interface setting spaces (4 byte aligned) +#define NUM_INTERFACES ((HIDMSDDDriverDescriptors_NUMINTERFACE+3)&0xFC) + +//----------------------------------------------------------------------------- +// Types +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Internal variables +//----------------------------------------------------------------------------- + +/// USBDDriver instance +static USBDDriver usbdDriver; + +/// Array for storing the current setting of each interface +static unsigned char hidmsddDriverInterfaces[NUM_INTERFACES]; + +//----------------------------------------------------------------------------- +// Internal functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Optional RequestReceived() callback re-implementation +//----------------------------------------------------------------------------- +#if !defined(NOAUTOCALLBACK) + +void USBDCallbacks_RequestReceived(const USBGenericRequest *request) +{ + HIDMSDDDriver_RequestHandler(request); +} + +#endif + +//----------------------------------------------------------------------------- +// ConfigurationChanged() callback re-implementation +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Invoked whenever the configuration value of a device is changed by the host +/// \param cfgnum Configuration number. +//----------------------------------------------------------------------------- +void USBDDriverCallbacks_ConfigurationChanged(unsigned char cfgnum) +{ + // HID + HIDDFunctionCallbacks_ConfigurationChanged(cfgnum); + + // MSD + MSDDFunctionCallbacks_ConfigurationChanged(cfgnum); +} + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Initializes the USB device HIDMSD device driver. +//----------------------------------------------------------------------------- +void HIDMSDDDriver_Initialize(MSDLun *pLuns, unsigned char numLuns) +{ + // HID + HIDDFunctionDriver_Initialize(&usbdDriver, + HIDD_Descriptors_INTERFACENUM, + HIDD_Descriptors_INTERRUPTIN, + HIDD_Descriptors_INTERRUPTOUT); + + // MSD + MSDDFunctionDriver_Initialize(&usbdDriver, + pLuns, numLuns, + MSDD_Descriptors_INTERFACENUM, + MSDD_Descriptors_BULKIN, + MSDD_Descriptors_BULKOUT); + + // Initialize the standard USB driver + USBDDriver_Initialize(&usbdDriver, + &hidmsddDriverDescriptors, + hidmsddDriverInterfaces); + + // Initialize the USB driver + USBD_Init(); +} + +//----------------------------------------------------------------------------- +/// Handles HIDMSD-specific USB requests sent by the host, and forwards +/// standard ones to the USB device driver. +/// \param request Pointer to a USBGenericRequest instance. +//----------------------------------------------------------------------------- +void HIDMSDDDriver_RequestHandler(const USBGenericRequest *request) +{ + // Check if this is a class request + if (USBGenericRequest_GetType(request) == USBGenericRequest_CLASS) { + + unsigned char rc = 0; + + // MSD class request + if (rc == 0) { + + rc = MSDDFunctionDriver_RequestHandler(request); + } + + // HID class request + if (rc == 0) { + + rc = HIDDFunctionDriver_RequestHandler(request); + } + + if (!rc) { + + TRACE_WARNING( + "HIDMSDDDriver_RequestHandler: Unsupported request (%d)\n\r", + USBGenericRequest_GetRequest(request)); + USBD_Stall(0); + } + + } + // Check if this is a standard request + else if (USBGenericRequest_GetType(request) == USBGenericRequest_STANDARD) { + + unsigned char rc = 0; + + rc = HIDDFunctionDriver_RequestHandler(request); + + if (rc == 0) { + + rc = MSDDFunctionDriver_RequestHandler(request); + } + + // Forward request to the standard handler + if (rc == 0) { + + USBDDriver_RequestHandler(&(usbdDriver), request); + } + } + // Unsupported request type + else { + + TRACE_WARNING( + "HIDMSDDDriver_RequestHandler: Unsupported request type (%d)\n\r", + USBGenericRequest_GetType(request)); + USBD_Stall(0); + } +} + +//----------------------------------------------------------------------------- +/// Starts a remote wake-up sequence if the host has explicitely enabled it +/// by sending the appropriate SET_FEATURE request. +//----------------------------------------------------------------------------- +void HIDMSDDDriver_RemoteWakeUp(void) +{ + // Remote wake-up has been enabled + if (USBDDriver_IsRemoteWakeUpEnabled(&usbdDriver)) { + + USBD_RemoteWakeUp(); + } + // Remote wake-up NOT enabled + else { + + TRACE_WARNING("HIDMSDDDriver_RemoteWakeUp: not enabled\n\r"); + } +} + + diff --git a/usb/device/composite/HIDMSDDDriver.h b/usb/device/composite/HIDMSDDDriver.h new file mode 100644 index 0000000..ba37205 --- /dev/null +++ b/usb/device/composite/HIDMSDDDriver.h @@ -0,0 +1,79 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//----------------------------------------------------------------------------- +/// \unit +/// +/// !Purpose +/// +/// Definitions and methods for USB HID + MSD HIDMSD device implement. +/// +/// !Usage +/// +/// -# Initialize USB function specified driver ( for MSD currently ) +/// - MSDDFunctionDriver_Initialize +/// +/// -# Initialize USB HIDMSD driver and USB driver +/// - HIDMSDDDriver_Initialize +/// +/// -# Handle and dispach USB requests +/// - HIDMSDDDriver_RequestHandler +/// +/// -# Try starting a remote wake-up sequence +/// - HIDMSDDDriver_RemoteWakeUp +//----------------------------------------------------------------------------- + +#ifndef HIDMSDDDRIVER_H +#define HIDMSDDDRIVER_H + + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include +#include + +#include "HIDDFunctionDriver.h" +#include "MSDDFunctionDriver.h" + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +// -HIDMSD Composite device +extern void HIDMSDDDriver_Initialize(MSDLun *pLuns, + unsigned char numLuns); + +extern void HIDMSDDDriver_RequestHandler(const USBGenericRequest *request); + +extern void HIDMSDDDriver_RemoteWakeUp(void); + +#endif //#ifndef HIDMSDDDRIVER_H + diff --git a/usb/device/composite/HIDMSDDDriverDescriptors.c b/usb/device/composite/HIDMSDDDriverDescriptors.c new file mode 100644 index 0000000..aecfd61 --- /dev/null +++ b/usb/device/composite/HIDMSDDDriverDescriptors.c @@ -0,0 +1,449 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "HIDMSDDDriver.h" +#include "HIDMSDDDriverDescriptors.h" +#include + +//- USB Generic +#include +#include +#include +#include +#include +#include + +//- HID +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "HIDDFunctionDriverDescriptors.h" + +//- MSD +#include +#include +#include "MSDDFunctionDriverDescriptors.h" + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +/// Device product ID. +#define HIDMSDDDriverDescriptors_PRODUCTID 0x6135 + +/// Device vendor ID (Atmel). +#define HIDMSDDDriverDescriptors_VENDORID 0x03EB + +/// Device release number. +#define HIDMSDDDriverDescriptors_RELEASE 0x0003 + +//----------------------------------------------------------------------------- +// Macros +//----------------------------------------------------------------------------- + +/// Returns the minimum between two values. +#define MIN(a, b) ((a < b) ? a : b) + +//----------------------------------------------------------------------------- +// Internal structures +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Audio control header descriptor with one slave interface. +//----------------------------------------------------------------------------- +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//----------------------------------------------------------------------------- +/// Configuration descriptor list for a device implementing a composite driver. +//----------------------------------------------------------------------------- +typedef struct { + + /// Standard configuration descriptor. + USBConfigurationDescriptor configuration; + + /// --- HID + USBInterfaceDescriptor hidInterface; + HIDDescriptor hid; + USBEndpointDescriptor hidInterruptIn; + USBEndpointDescriptor hidInterruptOut; + + /// --- MSD + /// Mass storage interface descriptor. + USBInterfaceDescriptor msdInterface; + /// Bulk-out endpoint descriptor. + USBEndpointDescriptor msdBulkOut; + /// Bulk-in endpoint descriptor. + USBEndpointDescriptor msdBulkIn; + +} __attribute__ ((packed)) HidMsdDriverConfigurationDescriptors; + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +/// Standard USB device descriptor for the composite device driver +static const USBDeviceDescriptor deviceDescriptor = +{ + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + 0x00, + 0x00, + 0x00, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + HIDMSDDDriverDescriptors_VENDORID, + HIDMSDDDriverDescriptors_PRODUCTID, + HIDMSDDDriverDescriptors_RELEASE, + 0, // No string descriptor for manufacturer + 1, // Index of product string descriptor is #1 + 0, // No string descriptor for serial number + 1 // Device has 1 possible configuration +}; + +#if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + +/// USB device qualifier descriptor. +static const USBDeviceQualifierDescriptor qualifierDescriptor = +{ + + sizeof(USBDeviceQualifierDescriptor), + USBGenericDescriptor_DEVICEQUALIFIER, + USBDeviceDescriptor_USB2_00, + 0x00, + 0x00, + 0x00, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + 1, // Device has one possible configuration + 0 // Reserved +}; + +/// USB configuration descriptors for the composite device driver +static const HidMsdDriverConfigurationDescriptors configurationDescriptorsHS = +{ + + // Standard configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(HidMsdDriverConfigurationDescriptors), + HIDMSDDDriverDescriptors_NUMINTERFACE, + 1, // This is configuration #1 + 0, // No string descriptor for this configuration + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + + // Interface descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + HIDD_Descriptors_INTERFACENUM, + 0, // This is alternate setting #0 + 2, // Two endpoints used + HIDInterfaceDescriptor_CLASS, + HIDInterfaceDescriptor_SUBCLASS_NONE, + HIDInterfaceDescriptor_PROTOCOL_NONE, + 0 // No associated string descriptor + }, + // HID descriptor + { + sizeof(HIDDescriptor), + HIDGenericDescriptor_HID, + HIDDescriptor_HID1_11, + 0, // Device is not localized, no country code + 1, // One HID-specific descriptor (apart from this one) + HIDGenericDescriptor_REPORT, + HIDD_Descriptors_REPORTSIZE + }, + // Interrupt IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + HIDD_Descriptors_INTERRUPTIN), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardInputReport), + HIDD_Descriptors_INTERRUPTIN_POLLING_HS + }, + // Interrupt OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + HIDD_Descriptors_INTERRUPTOUT), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardOutputReport), + HIDD_Descriptors_INTERRUPTIN_POLLING_HS + }, + + // Mass Storage interface descriptor. + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + MSDD_Descriptors_INTERFACENUM, + 0, // This is alternate setting #0. + 2, // Interface uses two endpoints. + MSInterfaceDescriptor_CLASS, + MSInterfaceDescriptor_SCSI, + MSInterfaceDescriptor_BULKONLY, + 0 // No string descriptor for interface. + }, + // Bulk-OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + MSDD_Descriptors_BULKOUT), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(MSDD_Descriptors_BULKOUT), + USBEndpointDescriptor_MAXBULKSIZE_HS), + 0 // No string descriptor for endpoint. + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + MSDD_Descriptors_BULKIN), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(MSDD_Descriptors_BULKIN), + USBEndpointDescriptor_MAXBULKSIZE_HS), + 0 // No string descriptor for endpoint. + } + +}; + +#endif + +/// USB FS configuration descriptors for the composite device driver +static const HidMsdDriverConfigurationDescriptors configurationDescriptorsFS = +{ + + // Standard configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(HidMsdDriverConfigurationDescriptors), + HIDMSDDDriverDescriptors_NUMINTERFACE, + 1, // This is configuration #1 + 0, // No string descriptor for this configuration + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + + // Interface descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + HIDD_Descriptors_INTERFACENUM, + 0, // This is alternate setting #0 + 2, // Two endpoints used + HIDInterfaceDescriptor_CLASS, + HIDInterfaceDescriptor_SUBCLASS_NONE, + HIDInterfaceDescriptor_PROTOCOL_NONE, + 0 // No associated string descriptor + }, + // HID descriptor + { + sizeof(HIDDescriptor), + HIDGenericDescriptor_HID, + HIDDescriptor_HID1_11, + 0, // Device is not localized, no country code + 1, // One HID-specific descriptor (apart from this one) + HIDGenericDescriptor_REPORT, + HIDD_Descriptors_REPORTSIZE + }, + // Interrupt IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + HIDD_Descriptors_INTERRUPTIN), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardInputReport), + HIDD_Descriptors_INTERRUPTIN_POLLING_FS + }, + // Interrupt OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + HIDD_Descriptors_INTERRUPTOUT), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardOutputReport), + HIDD_Descriptors_INTERRUPTIN_POLLING_FS + }, + + // Mass Storage interface descriptor. + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + MSDD_Descriptors_INTERFACENUM, + 0, // This is alternate setting #0. + 2, // Interface uses two endpoints. + MSInterfaceDescriptor_CLASS, + MSInterfaceDescriptor_SCSI, + MSInterfaceDescriptor_BULKONLY, + 0 // No string descriptor for interface. + }, + // Bulk-OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + MSDD_Descriptors_BULKOUT), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(MSDD_Descriptors_BULKOUT), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // No string descriptor for endpoint. + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + MSDD_Descriptors_BULKIN), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(MSDD_Descriptors_BULKIN), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // No string descriptor for endpoint. + } + +}; + +/// String descriptor with the supported languages. +static const unsigned char languageIdDescriptor[] = { + + USBStringDescriptor_LENGTH(1), + USBGenericDescriptor_STRING, + USBStringDescriptor_ENGLISH_US +}; + +/// Manufacturer name. +static const unsigned char manufacturerDescriptor[] = { + + USBStringDescriptor_LENGTH(5), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('t'), + USBStringDescriptor_UNICODE('m'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('l') +}; + +/// Product name. +static const unsigned char productDescriptor[] = { + + USBStringDescriptor_LENGTH(14), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('C'), + USBStringDescriptor_UNICODE('o'), + USBStringDescriptor_UNICODE('m'), + USBStringDescriptor_UNICODE('p'), + USBStringDescriptor_UNICODE('o'), + USBStringDescriptor_UNICODE('s'), + USBStringDescriptor_UNICODE('i'), + USBStringDescriptor_UNICODE('t'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('D'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('m'), + USBStringDescriptor_UNICODE('o') +}; + +/// Product serial number. +static const unsigned char serialNumberDescriptor[] = { + + USBStringDescriptor_LENGTH(4), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('0'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE('2'), + USBStringDescriptor_UNICODE('3') +}; + +/// Array of pointers to the four string descriptors. +static const unsigned char *stringDescriptors[] = { + + languageIdDescriptor, + manufacturerDescriptor, + productDescriptor, + serialNumberDescriptor, +}; + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +/// List of descriptors required by an USB audio speaker device driver. +const USBDDriverDescriptors hidmsddDriverDescriptors = { + + &deviceDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptorsFS, +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + &qualifierDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptorsHS, + &deviceDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptorsHS, + &qualifierDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptorsFS, +#else + 0, 0, 0, 0, 0, 0, +#endif + stringDescriptors, + 4 // Number of string descriptors +}; diff --git a/usb/device/composite/HIDMSDDDriverDescriptors.h b/usb/device/composite/HIDMSDDDriverDescriptors.h new file mode 100644 index 0000000..85739be --- /dev/null +++ b/usb/device/composite/HIDMSDDDriverDescriptors.h @@ -0,0 +1,66 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef HIDMSDDDRIVERDESCRIPTORS_H +#define HIDMSDDDRIVERDESCRIPTORS_H + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include +#include + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +/// Number of interfaces of the device +#define HIDMSDDDriverDescriptors_NUMINTERFACE 2 + +#define HIDD_Descriptors_INTERFACENUM 0 +/// Address of the HID interrupt IN endpoint. +#define HIDD_Descriptors_INTERRUPTIN 1 +/// Address of the HID interrupt OUT endpoint. +#define HIDD_Descriptors_INTERRUPTOUT 2 + +#define MSDD_Descriptors_INTERFACENUM 1 +/// Address of the Mass Storage bulk-out endpoint. +#define MSDD_Descriptors_BULKOUT 4 +/// Address of the Mass Storage bulk-in endpoint. +#define MSDD_Descriptors_BULKIN 5 + + +//----------------------------------------------------------------------------- +// Exported variables +//----------------------------------------------------------------------------- + +extern const USBDDriverDescriptors hidmsddDriverDescriptors; + +#endif //#ifndef HIDMSDDDRIVERDESCRIPTORS_H diff --git a/usb/device/composite/MSDDFunctionDriver.c b/usb/device/composite/MSDDFunctionDriver.c new file mode 100644 index 0000000..840294e --- /dev/null +++ b/usb/device/composite/MSDDFunctionDriver.c @@ -0,0 +1,327 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//----------------------------------------------------------------------------- +// Includes +//----------------------------------------------------------------------------- + +// GENERAL +#include +#include +// USB +#include +#include +#include +#include +// MSD +#include +#include +#include "MSDDFunctionDriverDescriptors.h" + +//----------------------------------------------------------------------------- +// Internal types +//----------------------------------------------------------------------------- + +/// Driver structure for an HID device implementing keyboard functionalities. +typedef struct { + + /// Pointer to USB device driver instance + USBDDriver * pUsbdDriver; + /// Pointer to MSD driver instance + MSDDriver * pMsdDriver; + /// Interface Number of MS Function + unsigned char interfaceNum; + /// Interrupt IN endpoint address + unsigned char bulkInEndpoint; + /// Interrupt OUT endpoint address + unsigned char bulkOutEndpoint; + +} MSDFunctionDriver; + +//----------------------------------------------------------------------------- +// Internal variables +//----------------------------------------------------------------------------- + +/// Mass storage general driver instance. +static MSDDriver msdDriver; + +/// Mass storage function driver instance. +static MSDFunctionDriver msdFunDriver; + +//----------------------------------------------------------------------------- +// Internal functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Resets the state of the MSD driver +//----------------------------------------------------------------------------- +static void MSDD_Reset() +{ + TRACE_INFO_WP("MSDReset "); + + msdDriver.state = MSDD_STATE_READ_CBW; + msdDriver.waitResetRecovery = 0; + msdDriver.commandState.state = 0; +} + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Initializes a MSD driver +/// \param luns Pointer to a list of LUNs +/// \param numLuns Number of LUN in list +/// \param interfaceNum Interface number to access the MSD function +/// \param bulkInEndpoint Bulk IN endpoint address +/// \param bulkOutEndpoint Bulk OUT endpoint address +//----------------------------------------------------------------------------- +void MSDDFunctionDriver_Initialize(USBDDriver * pUsbdDriver, + MSDLun *luns, unsigned char numLuns, + unsigned char interfaceNum, + unsigned char bulkInEndpoint, + unsigned char bulkOutEndpoint) +{ + TRACE_INFO("MSD init\n\r"); + + msdFunDriver.pUsbdDriver = pUsbdDriver; + msdFunDriver.pMsdDriver = &msdDriver; + msdFunDriver.interfaceNum = interfaceNum; + msdFunDriver.bulkInEndpoint = bulkInEndpoint; + msdFunDriver.bulkOutEndpoint = bulkOutEndpoint; + + // Command state initialization + msdDriver.commandState.state = 0; + msdDriver.commandState.postprocess = 0; + msdDriver.commandState.length = 0; + msdDriver.commandState.transfer.semaphore = 0; + + // LUNs + msdDriver.luns = luns; + msdDriver.maxLun = (unsigned char) (numLuns - 1); + + // Reset BOT driver + MSDD_Reset(); +} + +//----------------------------------------------------------------------------- +/// Invoked when a new SETUP request is received from the host. Forwards the +/// request to the Mass Storage device driver handler function. +/// \param request Pointer to a USBGenericRequest instance. +/// \return 0 if the request is Unsupported, 1 if the request handled. +//----------------------------------------------------------------------------- +unsigned char MSDDFunctionDriver_RequestHandler( + const USBGenericRequest *request) +{ + // Handle requests + switch (USBGenericRequest_GetRequest(request)) { + //--------------------- + case USBGenericRequest_CLEARFEATURE: + //--------------------- + TRACE_INFO_WP("ClrFeat "); + + switch (USBFeatureRequest_GetFeatureSelector(request)) { + + //--------------------- + case USBFeatureRequest_ENDPOINTHALT: + //--------------------- + TRACE_INFO_WP("Hlt "); + + // Do not clear the endpoint halt status if the device is waiting + // for a reset recovery sequence + if (!msdDriver.waitResetRecovery) { + + // Forward the request to the standard handler + return 0; + } + else { + + TRACE_INFO_WP("No "); + } + + USBD_Write(0, 0, 0, 0, 0); + break; + + //------ + default: + //------ + // Forward the request to the standard handler + return 0; + } + break; + + //------------------- + case MSD_GET_MAX_LUN: + //------------------- + TRACE_INFO_WP("gMaxLun "); + + // Check request parameters + if ((request->wValue == 0) + && (request->wIndex == msdFunDriver.interfaceNum) + && (request->wLength == 1)) { + + USBD_Write(0, &(msdDriver.maxLun), 1, 0, 0); + + } + else { + + TRACE_WARNING( + "MSDDriver_RequestHandler: GetMaxLUN(%d,%d,%d)\n\r", + request->wValue, request->wIndex, request->wLength); + USBD_Stall(0); + } + break; + + //----------------------- + case MSD_BULK_ONLY_RESET: + //----------------------- + TRACE_INFO_WP("Rst "); + + // Check parameters + if ((request->wValue == 0) + && (request->wIndex == msdFunDriver.interfaceNum) + && (request->wLength == 0)) { + + // Reset the MSD driver + MSDD_Reset(); + USBD_Write(0, 0, 0, 0, 0); + } + else { + + TRACE_WARNING( + "MSDDriver_RequestHandler: Reset(%d,%d,%d)\n\r", + request->wValue, request->wIndex, request->wLength); + USBD_Stall(0); + } + break; + + //------ + default: + //------ + // Forward request to standard handler + return 0; + } + + return 1; +} + +//----------------------------------------------------------------------------- +/// Invoked whenever the configuration of the device is changed by the host. +/// \param cfgnum Newly configuration number. +//----------------------------------------------------------------------------- +void MSDDFunctionCallbacks_ConfigurationChanged(unsigned char cfgnum) +{ + if (cfgnum > 0) { + + MSDD_Reset(); + } +} + +//----------------------------------------------------------------------------- +/// Reads from host through MSD defined pipe. Act as USBD_Read. +/// \param data Pointer to the data buffer that contains data read from host. +/// \param size The number of bytes should be read (buffer size). +/// \param callback Pointer to the function invoked on end of reading. +/// \param argument Pointer to additional argument data struct. +//----------------------------------------------------------------------------- +char MSDD_Read(void *data, + unsigned int size, + TransferCallback callback, + void *argument) + +{ + return USBD_Read(msdFunDriver.bulkOutEndpoint, + data, + size, + callback, + argument); +} + +//----------------------------------------------------------------------------- +/// Writes to host through MSD defined pipe. Act as USBD_Write. +/// \param data Pointer to the data that writes to the host. +/// \param size The number of bytes should be write. +/// \param callback Pointer to the function invoked on end of writing. +/// \param argument Pointer to additional argument data struct. +//----------------------------------------------------------------------------- +char MSDD_Write(void *data, + unsigned int size, + TransferCallback callback, + void *argument) +{ + return USBD_Write(msdFunDriver.bulkInEndpoint, + data, + size, + callback, + argument); +} + +//----------------------------------------------------------------------------- +/// HALT Specified USB pipe. +/// \param stallCASE Case of the stall condition (Bulk In/Out/Both). +//----------------------------------------------------------------------------- +void MSDD_Halt(unsigned int stallCASE) +{ + if (stallCASE & MSDD_CASE_STALL_OUT) { + + USBD_Halt(msdFunDriver.bulkOutEndpoint); + } + + if (stallCASE & MSDD_CASE_STALL_IN) { + + USBD_Halt(msdFunDriver.bulkInEndpoint); + } +} + +//----------------------------------------------------------------------------- +/// Return halted status +/// \return stallCASE bitmap, case of the stall condition +/// (bit: MSDD_CASE_STALL_OUT or MSDD_CASE_STALL_IN) +//----------------------------------------------------------------------------- +unsigned int MSDD_IsHalted(void) +{ + unsigned int stallCASE = 0; + if (USBD_IsHalted(msdFunDriver.bulkOutEndpoint)) { + + stallCASE |= MSDD_CASE_STALL_OUT; + } + if (USBD_IsHalted(msdFunDriver.bulkInEndpoint)) { + + stallCASE |= MSDD_CASE_STALL_IN; + } + return stallCASE; +} + +//----------------------------------------------------------------------------- +/// State machine for the MSD driver +//----------------------------------------------------------------------------- +void MSDDriver_StateMachine(void) +{ + MSDD_StateMachine(&msdDriver); +} diff --git a/usb/device/composite/MSDDFunctionDriver.h b/usb/device/composite/MSDDFunctionDriver.h new file mode 100644 index 0000000..c96fbfd --- /dev/null +++ b/usb/device/composite/MSDDFunctionDriver.h @@ -0,0 +1,72 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//----------------------------------------------------------------------------- +/// \unit +/// !Purpose +/// +/// Mass storage function driver implementation. +/// +/// !Usage +/// TODO +//----------------------------------------------------------------------------- + +#ifndef MSDDFUNCTIONDRIVER_H +#define MSDDFUNCTIONDRIVER_H + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include +#include +#include +#include + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +//- Function API for composite device +extern void MSDDFunctionDriver_Initialize(USBDDriver * pUsbdDriver, + MSDLun *luns, unsigned char numLuns, + unsigned char interfaceNum, + unsigned char bulkInEndpoint, + unsigned char bulkOutEndpoint); + +extern unsigned char MSDDFunctionDriver_RequestHandler( + const USBGenericRequest *request); + +extern void MSDDFunctionCallbacks_ConfigurationChanged(unsigned char cfgnum); + +//- MSD APIs +extern void MSDDriver_StateMachine(void); + +#endif // #define MSDDFUNCTIONDRIVER_H + diff --git a/usb/device/composite/MSDDFunctionDriverDescriptors.h b/usb/device/composite/MSDDFunctionDriverDescriptors.h new file mode 100644 index 0000000..6da6214 --- /dev/null +++ b/usb/device/composite/MSDDFunctionDriverDescriptors.h @@ -0,0 +1,69 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef MSDDFUNCTIONDRIVERDESCRIPTORS_H +#define MSDDFUNCTIONDRIVERDESCRIPTORS_H + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// \page "MS interface & endpoint descriptor settings" +/// This page lists the definition used by the Mass Storage driver. +/// +/// !Settings +/// +/// - MSDD_Descriptors_INTERFACENUM +/// - MSDD_Descriptors_BULKOUT +/// - MSDD_Descriptors_BULKIN + +/// Number of the Mass Storage interface. +#if defined(usb_CDCMSD) +#define MSDD_Descriptors_INTERFACENUM 2 +#elif defined(usb_HIDMSD) +#define MSDD_Descriptors_INTERFACENUM 1 +#endif + +/// Address of the Mass Storage bulk-out endpoint. +#define MSDD_Descriptors_BULKOUT 4 + +/// Address of the Mass Storage bulk-in endpoint. +#define MSDD_Descriptors_BULKIN 5 +//----------------------------------------------------------------------------- + + +#endif // #define MSDDFUNCTIONDRIVERDESCRIPTORS_H + diff --git a/usb/device/composite/drv/CompositeCDCSerial.inf b/usb/device/composite/drv/CompositeCDCSerial.inf new file mode 100644 index 0000000..973a14b --- /dev/null +++ b/usb/device/composite/drv/CompositeCDCSerial.inf @@ -0,0 +1,57 @@ +; $Id: 6119.inf,v 1.1.2.1 2006/12/05 08:33:25 danielru Exp $ + +[Version] ; Version section +Signature="$Chicago$" ; All Windows versions +Class=Ports ; This is a serial port driver +ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} ; Associated GUID +Provider=%ATMEL% ; Driver is provided by ATMEL +DriverVer=09/12/2006,1.1.1.5 ; Driver version 1.1.1.5 published on 23 February 2007 + +[DestinationDirs] ; DestinationDirs section +DefaultDestDir=12 ; Default install directory is \drivers or \IOSubSys + +[Manufacturer] ; Manufacturer section +%ATMEL%=AtmelMfg ; Only one manufacturer (ATMEL), models section is named + ; AtmelMfg + +[AtmelMfg] ; Models section corresponding to ATMEL +%USBtoSerialConverter%=USBtoSer.Install,USB\VID_03EB&PID_6130&MI_00 ; Identifies a device with ATMEL Vendor ID (03EBh) and + ; Product ID equal to 6130h. Corresponding Install section + ; is named USBtoSer.Install ( CDCHID ) +%USBtoSerialConverter%=USBtoSer.Install,USB\VID_03EB&PID_6131&MI_00 ; Identifies a device with ATMEL Vendor ID (03EBh) and + ; Product ID equal to 6131h. Corresponding Install section + ; is named USBtoSer.Install ( CDCAUDIO ) +%USBtoSerialConverter%=USBtoSer.Install,USB\VID_03EB&PID_6132&MI_00 ; Identifies a device with ATMEL Vendor ID (03EBh) and + ; Product ID equal to 6132h. Corresponding Install section + ; is named USBtoSer.Install ( CDCMSD ) +%USBtoSerialConverter%=USBtoSer.Install,USB\VID_03EB&PID_6133&MI_00 ; Identifies a device with ATMEL Vendor ID (03EBh) and + ; Product ID equal to 6133h. Corresponding Install section + ; is named USBtoSer.Install ( CDCCDC ) +%USBtoSerialConverter%=USBtoSer.Install,USB\VID_03EB&PID_6133&MI_02 ; Identifies a device with ATMEL Vendor ID (03EBh) and + ; Product ID equal to 6133h. Corresponding Install section + ; is named USBtoSer.Install ( CDCCDC ) + +[USBtoSer.Install] ; Install section +include=mdmcpq.inf +CopyFiles=FakeModemCopyFileSection +AddReg=USBtoSer.AddReg ; Registry keys to add are listed in USBtoSer.AddReg + +[USBtoSer.AddReg] ; AddReg section +HKR,,DevLoader,,*ntkern ; +HKR,,NTMPDriver,,usbser.sys +HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" + +[USBtoSer.Install.Services] ; Services section +AddService=usbser,0x00000002,USBtoSer.AddService ; Assign usbser as the PnP driver for the device + +[USBtoSer.AddService] ; Service install section +DisplayName=%USBSer% ; Name of the serial driver +ServiceType=1 ; Service kernel driver +StartType=3 ; Driver is started by the PnP manager +ErrorControl=1 ; Warn about errors +ServiceBinary=%12%\usbser.sys ; Driver filename + +[Strings] ; Strings section +ATMEL="ATMEL Corp." ; String value for the ATMEL symbol +USBtoSerialConverter="AT91 USB to Serial Converter" ; String value for the USBtoSerialConverter symbol +USBSer="USB Composite Serial Driver" ; String value for the USBSer symbol \ No newline at end of file diff --git a/usb/device/composite/drv/drv.dir b/usb/device/composite/drv/drv.dir new file mode 100644 index 0000000..1f2d5d6 --- /dev/null +++ b/usb/device/composite/drv/drv.dir @@ -0,0 +1,45 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// +/// !!!Purpose +/// +/// This directory provides install file for +/// - CDC HID +/// - CDC AUDIO +/// - CDC MSD +/// - CDC CDC +/// +/// !!!Contents +/// +/// CompositeCDCSerial.inf +/// +//------------------------------------------------------------------------------ diff --git a/usb/device/core/USBD.h b/usb/device/core/USBD.h new file mode 100644 index 0000000..e6c2e9b --- /dev/null +++ b/usb/device/core/USBD.h @@ -0,0 +1,276 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !!!Purpose +/// +/// Collection of methods for using the USB device controller on AT91 +/// microcontrollers. +/// +/// !!!Usage +/// +/// Please refer to the corresponding application note. +/// - "AT91 USB device framework" +/// - "USBD API" . "USBD API Methods" +//------------------------------------------------------------------------------ + +#ifndef USBD_H +#define USBD_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Compile Options +//------------------------------------------------------------------------------ + +/// Compile option for HS or OTG, use DMA. Remove this define for not use DMA. +#if defined(CHIP_USB_OTGHS) || defined(CHIP_USB_UDPHS) +#define DMA +#endif + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB device API return values" +/// +/// This page lists the return values of the USB %device driver API +/// +/// !Return codes +/// - USBD_STATUS_SUCCESS +/// - USBD_STATUS_LOCKED +/// - USBD_STATUS_ABORTED +/// - USBD_STATUS_RESET + +/// Indicates the operation was successful. +#define USBD_STATUS_SUCCESS 0 +/// Endpoint/device is already busy. +#define USBD_STATUS_LOCKED 1 +/// Operation has been aborted. +#define USBD_STATUS_ABORTED 2 +/// Operation has been aborted because the device has been reset. +#define USBD_STATUS_RESET 3 +/// Part ot operation successfully done. +#define USBD_STATUS_PARTIAL_DONE 4 +/// Operation failed because parameter error +#define USBD_STATUS_INVALID_PARAMETER 5 +/// Operation failed because in unexpected state +#define USBD_STATUS_WRONG_STATE 6 +/// Operation failed because HW not supported +#define USBD_STATUS_HW_NOT_SUPPORTED 0xFE +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB device states" +/// +/// This page lists the %device states of the USB %device driver. +/// +/// !States +/// - USBD_STATE_SUSPENDED +/// - USBD_STATE_ATTACHED +/// - USBD_STATE_POWERED +/// - USBD_STATE_DEFAULT +/// - USBD_STATE_ADDRESS +/// - USBD_STATE_CONFIGURED + +/// The device is currently suspended. +#define USBD_STATE_SUSPENDED 0 +/// USB cable is plugged into the device. +#define USBD_STATE_ATTACHED 1 +/// Host is providing +5V through the USB cable. +#define USBD_STATE_POWERED 2 +/// Device has been reset. +#define USBD_STATE_DEFAULT 3 +/// The device has been given an address on the bus. +#define USBD_STATE_ADDRESS 4 +/// A valid configuration has been selected. +#define USBD_STATE_CONFIGURED 5 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "USB device LEDs" +/// +/// This page lists the LEDs used in the USB %device driver. +/// +/// !LEDs +/// - USBD_LEDPOWER +/// - USBD_LEDUSB +/// - USBD_LEDOTHER + +/// LED for indicating that the device is powered. +#define USBD_LEDPOWER 0 +/// LED for indicating USB activity. +#define USBD_LEDUSB 1 +/// LED for custom usage. +#define USBD_LEDOTHER 2 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Buffer struct used for multi-buffer-listed transfer. +/// The driver can process 255 bytes of buffers or buffer list window. +//------------------------------------------------------------------------------ +typedef struct _USBDTransferBuffer { + /// Pointer to frame buffer + unsigned char * pBuffer; + /// Size of the frame (up to 64K-1) + unsigned short size; + /// Bytes transferred + unsigned short transferred; + /// Bytes in FIFO + unsigned short buffered; + /// Bytes remaining + unsigned short remaining; +} USBDTransferBuffer; + +#ifdef __ICCARM__ // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// Struct used for USBD DMA Link List Transfer Descriptor, must be 16-bytes +/// aligned. +/// (For USB, DMA transfer is linked to EPs and FIFO address is EP defined) +//------------------------------------------------------------------------------ +typedef struct _USBDDmaDescriptor { + /// Pointer to Next Descriptor + void* pNxtDesc; + /// Pointer to data buffer address + void* pDataAddr; + /// DMA Control setting register value + unsigned int ctrlSettings:8, /// Control settings + reserved:8, /// Not used + bufferLength:16; /// Length of buffer + /// Loaded to DMA register, OK to modify + unsigned int used; +} __attribute__((aligned(16))) USBDDmaDescriptor; + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// Callback used by transfer functions (USBD_Read & USBD_Write) to notify +/// that a transaction is complete. +//------------------------------------------------------------------------------ +typedef void (*TransferCallback)(void *pArg, + unsigned char status, + unsigned int transferred, + unsigned int remaining); + +//------------------------------------------------------------------------------ +/// Callback used by MBL transfer functions (USBD_Read & USBD_Write) to notify +/// that a transaction is complete. +/// \param pArg Pointer to callback arguments. +/// \param status USBD status. +/// \param nbFreed Number of buffers that is freed since last callback. +//------------------------------------------------------------------------------ +typedef void (*MblTransferCallback)(void *pArg, + unsigned char status, + unsigned int nbFreed); + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern void USBD_IrqHandler(void); + +extern void USBD_Init(void); + +extern void USBD_ConfigureSpeed(unsigned char forceFS); + +extern void USBD_Connect(void); + +extern void USBD_Disconnect(void); + +extern char USBD_Write( + unsigned char bEndpoint, + const void *pData, + unsigned int size, + TransferCallback callback, + void *pArg); + +extern char USBD_MblWrite( + unsigned char bEndpoint, + void * pMbl, + unsigned short wListSize, + unsigned char bCircList, + unsigned short wStartNdx, + MblTransferCallback fCallback, + void * pArgument); + +extern char USBD_MblReuse( + unsigned char bEndpoint, + unsigned char * pNewBuffer, + unsigned short wNewSize); + +extern char USBD_Read( + unsigned char bEndpoint, + void *pData, + unsigned int dLength, + TransferCallback fCallback, + void *pArg); + +extern unsigned char USBD_Stall(unsigned char bEndpoint); + +extern void USBD_Halt(unsigned char bEndpoint); + +extern void USBD_Unhalt(unsigned char bEndpoint); + +extern void USBD_ConfigureEndpoint(const USBEndpointDescriptor *pDescriptor); + +extern unsigned char USBD_IsHalted(unsigned char bEndpoint); + +extern void USBD_RemoteWakeUp(void); + +extern void USBD_SetAddress(unsigned char address); + +extern void USBD_SetConfiguration(unsigned char cfgnum); + +extern unsigned char USBD_GetState(void); + +extern unsigned char USBD_IsHighSpeed(void); + +extern void USBD_Test(unsigned char bIndex); + +#endif //#ifndef USBD_H + diff --git a/usb/device/core/USBDCallbacks.h b/usb/device/core/USBDCallbacks.h new file mode 100644 index 0000000..d4d5c7e --- /dev/null +++ b/usb/device/core/USBDCallbacks.h @@ -0,0 +1,65 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definitions of callbacks used by the USBD API to notify the user + application of incoming events. These functions are declared as 'weak', + so they can be re-implemented elsewhere in the application in a + transparent way. +*/ + +#ifndef USBDCALLBACKS_H +#define USBDCALLBACKS_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern void USBDCallbacks_Initialized(void); + +extern void USBDCallbacks_Reset(void); + +extern void USBDCallbacks_Suspended(void); + +extern void USBDCallbacks_Resumed(void); + +extern void USBDCallbacks_RequestReceived(const USBGenericRequest *request); + +#endif //#ifndef USBDCALLBACKS_H + diff --git a/usb/device/core/USBDCallbacks_Initialized.c b/usb/device/core/USBDCallbacks_Initialized.c new file mode 100644 index 0000000..0ac4ffe --- /dev/null +++ b/usb/device/core/USBDCallbacks_Initialized.c @@ -0,0 +1,67 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBDCallbacks.h" +#include "USBD.h" +#include +#include + +//------------------------------------------------------------------------------ +// Exported function +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Invoked after the USB driver has been initialized. By default, configures +/// the UDP/UDPHS interrupt. +//------------------------------------------------------------------------------ +void USBDCallbacks_Initialized(void) +{ +#if defined(CHIP_USB_UDP) + // Configure and enable the UDP interrupt + IRQ_ConfigureIT(AT91C_ID_UDP, 0, USBD_IrqHandler); + IRQ_EnableIT(AT91C_ID_UDP); + +#elif defined(CHIP_USB_UDPHS) + // Configure and enable the UDPHS interrupt + IRQ_ConfigureIT(AT91C_ID_UDPHS, 0, USBD_IrqHandler); + IRQ_EnableIT(AT91C_ID_UDPHS); + +#elif defined(CHIP_USB_OTGHS) + IRQ_ConfigureIT(AT91C_ID_OTGHS, 1, (void*) 0); + IRQ_EnableIT(AT91C_ID_OTGHS); + +#else + #error Unsupported controller. +#endif +} + diff --git a/usb/device/core/USBDCallbacks_RequestReceived.c b/usb/device/core/USBDCallbacks_RequestReceived.c new file mode 100644 index 0000000..29468ff --- /dev/null +++ b/usb/device/core/USBDCallbacks_RequestReceived.c @@ -0,0 +1,49 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBDCallbacks.h" + +//------------------------------------------------------------------------------ +// Exported function +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// USBDCallbacks_RequestReceived - Invoked when a new SETUP request is +/// received. Does nothing by default. +/// \param pRequest Pointer to the request to handle. +//------------------------------------------------------------------------------ +void USBDCallbacks_RequestReceived(const USBGenericRequest *pRequest) +{ + // Does nothing +} + diff --git a/usb/device/core/USBDCallbacks_Reset.c b/usb/device/core/USBDCallbacks_Reset.c new file mode 100644 index 0000000..64d9aaa --- /dev/null +++ b/usb/device/core/USBDCallbacks_Reset.c @@ -0,0 +1,47 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBDCallbacks.h" + +//------------------------------------------------------------------------------ +// Exported function +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Invoked when the USB driver is reset. Does nothing by default. +//------------------------------------------------------------------------------ +void USBDCallbacks_Reset(void) +{ + // Does nothing +} + diff --git a/usb/device/core/USBDCallbacks_Resumed.c b/usb/device/core/USBDCallbacks_Resumed.c new file mode 100644 index 0000000..3d58646 --- /dev/null +++ b/usb/device/core/USBDCallbacks_Resumed.c @@ -0,0 +1,54 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBDCallbacks.h" +#include "USBD.h" +#include + +//------------------------------------------------------------------------------ +// Exported function +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Invoked when the USB device leaves the Suspended state. By default, +/// configures the LEDs. +//------------------------------------------------------------------------------ +void USBDCallbacks_Resumed(void) +{ + // Initialize LEDs + LED_Configure(USBD_LEDPOWER); + LED_Set(USBD_LEDPOWER); + LED_Configure(USBD_LEDUSB); + LED_Clear(USBD_LEDUSB); +} + diff --git a/usb/device/core/USBDCallbacks_Suspended.c b/usb/device/core/USBDCallbacks_Suspended.c new file mode 100644 index 0000000..dbc10b9 --- /dev/null +++ b/usb/device/core/USBDCallbacks_Suspended.c @@ -0,0 +1,51 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBDCallbacks.h" +#include "USBD.h" +#include + +//------------------------------------------------------------------------------ +// Exported function +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Invoked when the USB device gets suspended. By default, turns off all LEDs. +//------------------------------------------------------------------------------ +void USBDCallbacks_Suspended(void) +{ + // Turn off LEDs + LED_Clear(USBD_LEDPOWER); + LED_Clear(USBD_LEDUSB); +} + diff --git a/usb/device/core/USBDDriver.c b/usb/device/core/USBDDriver.c new file mode 100644 index 0000000..6a7c000 --- /dev/null +++ b/usb/device/core/USBDDriver.c @@ -0,0 +1,753 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBDDriver.h" +#include "USBDDriverCallbacks.h" +#include "USBD.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//------------------------------------------------------------------------------ +// Local functions +//------------------------------------------------------------------------------ +#if defined(CHIP_USB_OTGHS) +static unsigned char otg_features_supported = 0; +#endif + +//------------------------------------------------------------------------------ +/// Send a NULL packet +//------------------------------------------------------------------------------ +static void TerminateCtrlInWithNull(void *pArg, + unsigned char status, + unsigned int transferred, + unsigned int remaining) +{ + USBD_Write(0, // Endpoint #0 + 0, // No data buffer + 0, // No data buffer + (TransferCallback) 0, + (void *) 0); +} + +//------------------------------------------------------------------------------ +/// Configures the device by setting it into the Configured state and +/// initializing all endpoints. +/// \param pDriver Pointer to a USBDDriver instance. +/// \param cfgnum Configuration number to set. +//------------------------------------------------------------------------------ +static void SetConfiguration(USBDDriver *pDriver, unsigned char cfgnum) +{ + USBEndpointDescriptor *pEndpoints[CHIP_USB_NUMENDPOINTS+1]; + const USBConfigurationDescriptor *pConfiguration; + + // Use different descriptor depending on device speed + if (USBD_IsHighSpeed()) { + + pConfiguration = pDriver->pDescriptors->pHsConfiguration; + } + else { + + pConfiguration = pDriver->pDescriptors->pFsConfiguration; + } + + // Set & save the desired configuration + USBD_SetConfiguration(cfgnum); + pDriver->cfgnum = cfgnum; + + // If the configuration is not 0, configure endpoints + if (cfgnum != 0) { + + // Parse configuration to get endpoint descriptors + USBConfigurationDescriptor_Parse(pConfiguration, 0, pEndpoints, 0); + + // Configure endpoints + int i = 0; + while (pEndpoints[i] != 0) { + + USBD_ConfigureEndpoint(pEndpoints[i]); + i++; + } + } + // Should be done before send the ZLP + USBDDriverCallbacks_ConfigurationChanged(cfgnum); + + // Acknowledge the request + USBD_Write(0, // Endpoint #0 + 0, // No data buffer + 0, // No data buffer + (TransferCallback) 0, + (void *) 0); +} + +//------------------------------------------------------------------------------ +/// Sends the current configuration number to the host. +/// \param pDriver Pointer to a USBDDriver instance. +//------------------------------------------------------------------------------ +static void GetConfiguration(const USBDDriver *pDriver) +{ + USBD_Write(0, &(pDriver->cfgnum), 1, 0, 0); +} + +//------------------------------------------------------------------------------ +/// Sends the current status of the device to the host. +/// \param pDriver Pointer to a USBDDriver instance. +//------------------------------------------------------------------------------ +static void GetDeviceStatus(const USBDDriver *pDriver) +{ + static unsigned short data; + const USBConfigurationDescriptor *pConfiguration; + + data = 0; + // Use different configuration depending on device speed + if (USBD_IsHighSpeed()) { + + pConfiguration = pDriver->pDescriptors->pHsConfiguration; + } + else { + + pConfiguration = pDriver->pDescriptors->pFsConfiguration; + } + + // Check current configuration for power mode (if device is configured) + if (pDriver->cfgnum != 0) { + + if (USBConfigurationDescriptor_IsSelfPowered(pConfiguration)) { + + data |= 1; + } + } + + // Check if remote wake-up is enabled + if (pDriver->isRemoteWakeUpEnabled) { + + data |= 2; + } + + // Send the device status + USBD_Write(0, &data, 2, 0, 0); +} + +//------------------------------------------------------------------------------ +/// Sends the current status of an endpoints to the USB host. +/// \param bEndpoint Endpoint number. +//------------------------------------------------------------------------------ +static void GetEndpointStatus(unsigned char bEndpoint) +{ + static unsigned short data; + + data = 0; + // Check if the endpoint exists + if (bEndpoint > CHIP_USB_NUMENDPOINTS) { + + USBD_Stall(0); + } + else { + + // Check if the endpoint if currently halted + if (USBD_IsHalted(bEndpoint)) { + + data = 1; + } + + // Send the endpoint status + USBD_Write(0, &data, 2, 0, 0); + } +} + +//------------------------------------------------------------------------------ +/// Sends the requested USB descriptor to the host if available, or STALLs the +/// request. +/// \param pDriver Pointer to a USBDDriver instance. +/// \param type Type of the requested descriptor +/// \param index Index of the requested descriptor. +/// \param length Maximum number of bytes to return. +//------------------------------------------------------------------------------ +static void GetDescriptor( + const USBDDriver *pDriver, + unsigned char type, + unsigned char indexRDesc, + unsigned int length) +{ + const USBDeviceDescriptor *pDevice; + const USBConfigurationDescriptor *pConfiguration; + const USBDeviceQualifierDescriptor *pQualifier; + const USBConfigurationDescriptor *pOtherSpeed; + const USBGenericDescriptor **pStrings = + (const USBGenericDescriptor **) pDriver->pDescriptors->pStrings; + const USBGenericDescriptor *pString; + unsigned char numStrings = pDriver->pDescriptors->numStrings; + unsigned char terminateWithNull = 0; + + // Use different set of descriptors depending on device speed + if (USBD_IsHighSpeed()) { + + TRACE_DEBUG("HS "); + pDevice = pDriver->pDescriptors->pHsDevice; + pConfiguration = pDriver->pDescriptors->pHsConfiguration; + pQualifier = pDriver->pDescriptors->pHsQualifier; + pOtherSpeed = pDriver->pDescriptors->pHsOtherSpeed; + } + else { + + TRACE_DEBUG("FS "); + pDevice = pDriver->pDescriptors->pFsDevice; + pConfiguration = pDriver->pDescriptors->pFsConfiguration; + pQualifier = pDriver->pDescriptors->pFsQualifier; + pOtherSpeed = pDriver->pDescriptors->pFsOtherSpeed; + } + + // Check the descriptor type + switch (type) { + + case USBGenericDescriptor_DEVICE: + TRACE_INFO_WP("Dev "); + + // Adjust length and send descriptor + if (length > USBGenericDescriptor_GetLength((USBGenericDescriptor *) pDevice)) { + + length = USBGenericDescriptor_GetLength((USBGenericDescriptor *) pDevice); + } + USBD_Write(0, pDevice, length, 0, 0); + break; + + case USBGenericDescriptor_CONFIGURATION: + TRACE_INFO_WP("Cfg "); + + // Adjust length and send descriptor + if (length > USBConfigurationDescriptor_GetTotalLength(pConfiguration)) { + + length = USBConfigurationDescriptor_GetTotalLength(pConfiguration); + terminateWithNull = ((length % pDevice->bMaxPacketSize0) == 0); + } + USBD_Write(0, + pConfiguration, + length, + terminateWithNull ? TerminateCtrlInWithNull : 0, + 0); + break; + + case USBGenericDescriptor_DEVICEQUALIFIER: + TRACE_INFO_WP("Qua "); + + // Check if descriptor exists + if (!pQualifier) { + + USBD_Stall(0); + } + else { + + // Adjust length and send descriptor + if (length > USBGenericDescriptor_GetLength((USBGenericDescriptor *) pQualifier)) { + + length = USBGenericDescriptor_GetLength((USBGenericDescriptor *) pQualifier); + } + USBD_Write(0, pQualifier, length, 0, 0); + } + break; + + case USBGenericDescriptor_OTHERSPEEDCONFIGURATION: + TRACE_INFO_WP("OSC "); + + // Check if descriptor exists + if (!pOtherSpeed) { + + USBD_Stall(0); + } + else { + + // Adjust length and send descriptor + if (length > USBConfigurationDescriptor_GetTotalLength(pOtherSpeed)) { + + length = USBConfigurationDescriptor_GetTotalLength(pOtherSpeed); + terminateWithNull = ((length % pDevice->bMaxPacketSize0) == 0); + } + USBD_Write(0, + pOtherSpeed, + length, + terminateWithNull ? TerminateCtrlInWithNull : 0, + 0); + } + break; + + case USBGenericDescriptor_STRING: + TRACE_INFO_WP("Str%d ", indexRDesc); + + // Check if descriptor exists + if (indexRDesc >= numStrings) { + + USBD_Stall(0); + } + else { + + pString = pStrings[indexRDesc]; + + // Adjust length and send descriptor + if (length > USBGenericDescriptor_GetLength(pString)) { + + length = USBGenericDescriptor_GetLength(pString); + terminateWithNull = ((length % pDevice->bMaxPacketSize0) == 0); + } + USBD_Write(0, + pString, + length, + terminateWithNull ? TerminateCtrlInWithNull : 0, + 0); + } + break; + + default: + TRACE_WARNING( + "USBDDriver_GetDescriptor: Unknown descriptor type (%d)\n\r", + type); + USBD_Stall(0); + } +} + +//------------------------------------------------------------------------------ +/// Sets the active setting of the given interface if the configuration supports +/// it; otherwise, the control pipe is STALLed. If the setting of an interface +/// changes. +/// \parma pDriver Pointer to a USBDDriver instance. +/// \parma infnum Interface number. +/// \parma setting New active setting for the interface. +//------------------------------------------------------------------------------ +static void SetInterface( + USBDDriver *pDriver, + unsigned char infnum, + unsigned char setting) +{ + // Make sure alternate settings are supported + if (!pDriver->pInterfaces) { + + USBD_Stall(0); + } + else { + + // Change the current setting of the interface and trigger the callback + // if necessary + if (pDriver->pInterfaces[infnum] != setting) { + + pDriver->pInterfaces[infnum] = setting; + USBDDriverCallbacks_InterfaceSettingChanged(infnum, setting); + } + + // Acknowledge the request + USBD_Write(0, 0, 0, 0, 0); + } +} + +//------------------------------------------------------------------------------ +/// Sends the currently active setting of the given interface to the USB +/// host. If alternate settings are not supported, this function STALLs the +/// control pipe. +/// \param pDriver Pointer to a USBDDriver instance. +/// \param infnum Interface number. +//------------------------------------------------------------------------------ +static void GetInterface( + const USBDDriver *pDriver, + unsigned char infnum) +{ + // Make sure alternate settings are supported, or STALL the control pipe + if (!pDriver->pInterfaces) { + + USBD_Stall(0); + } + else { + + // Sends the current interface setting to the host + USBD_Write(0, &(pDriver->pInterfaces[infnum]), 1, 0, 0); + } +} + +#if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) +//------------------------------------------------------------------------------ +// Performs the selected test on the USB device (high-speed only). +// \param test Test selector value. +//------------------------------------------------------------------------------ +static void USBDDriver_Test(unsigned char test) +{ + TRACE_DEBUG("UDPHS_Test\n\r"); + + // the lower byte of wIndex must be zero + // the most significant byte of wIndex is used to specify the specific test mode + switch (test) { + case USBFeatureRequest_TESTPACKET: + //Test mode Test_Packet: + //Upon command, a port must repetitively transmit the following test packet until + //the exit action is taken. This enables the testing of rise and fall times, eye + //patterns, jitter, and any other dynamic waveform specifications. + //The test packet is made up by concatenating the following strings. + //(Note: For J/K NRZI data, and for NRZ data, the bit on the left is the first one + //transmitted. “S” indicates that a bit stuff occurs, which inserts an “extra” NRZI data bit. + //“* N” is used to indicate N occurrences of a string of bits or symbols.) + //A port in Test_Packet mode must send this packet repetitively. The inter-packet timing + //must be no less than the minimum allowable inter-packet gap as defined in Section 7.1.18 and + //no greater than 125 us. + // Send ZLP + USBD_Test(USBFeatureRequest_TESTSENDZLP); + // Tst PACKET + USBD_Test(USBFeatureRequest_TESTPACKET); + while (1); + //break; not reached + + case USBFeatureRequest_TESTJ: + //Test mode Test_J: + //Upon command, a port’s transceiver must enter the high-speed J state and remain in that + //state until the exit action is taken. This enables the testing of the high output drive + //level on the D+ line. + // Send ZLP + USBD_Test(USBFeatureRequest_TESTSENDZLP); + // Tst J + USBD_Test(USBFeatureRequest_TESTJ); + while (1); + //break; not reached + + case USBFeatureRequest_TESTK: + //Test mode Test_K: + //Upon command, a port’s transceiver must enter the high-speed K state and remain in + //that state until the exit action is taken. This enables the testing of the high output drive + //level on the D- line. + // Send a ZLP + USBD_Test(USBFeatureRequest_TESTSENDZLP); + USBD_Test(USBFeatureRequest_TESTK); + while (1); + //break; not reached + + case USBFeatureRequest_TESTSE0NAK: + //Test mode Test_SE0_NAK: + //Upon command, a port’s transceiver must enter the high-speed receive mode + //and remain in that mode until the exit action is taken. This enables the testing + //of output impedance, low level output voltage, and loading characteristics. + //In addition, while in this mode, upstream facing ports (and only upstream facing ports) + //must respond to any IN token packet with a NAK handshake (only if the packet CRC is + //determined to be correct) within the normal allowed device response time. This enables testing of + //the device squelch level circuitry and, additionally, provides a general purpose stimulus/response + //test for basic functional testing. + // Send a ZLP + USBD_Test(USBFeatureRequest_TESTSENDZLP); + // Test SE0_NAK + USBD_Test(USBFeatureRequest_TESTSE0NAK); + while (1); + //break; not reached + + default: + USBD_Stall(0); + break; + + } + // The exit action is to power cycle the device. + // The device must be disconnected from the host +} +#endif + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes a USBDDriver instance with a list of descriptors. If +/// interfaces can have multiple alternate settings, an array to store the +/// current setting for each interface must be provided. +/// \param pDriver Pointer to a USBDDriver instance. +/// \param pDescriptors Pointer to a USBDDriverDescriptors instance. +/// \param pInterfaces Pointer to an array for storing the current alternate +/// setting of each interface (optional). +//------------------------------------------------------------------------------ +void USBDDriver_Initialize( + USBDDriver *pDriver, + const USBDDriverDescriptors *pDescriptors, + unsigned char *pInterfaces) +{ + + pDriver->cfgnum = 0; +#if (BOARD_USB_BMATTRIBUTES == USBConfigurationDescriptor_SELFPOWERED_RWAKEUP) \ + || (BOARD_USB_BMATTRIBUTES == USBConfigurationDescriptor_BUSPOWERED_RWAKEUP) + pDriver->isRemoteWakeUpEnabled = 1; +#else + pDriver->isRemoteWakeUpEnabled = 0; +#endif + + pDriver->pDescriptors = pDescriptors; + pDriver->pInterfaces = pInterfaces; + + // Initialize interfaces array if not null + if (pInterfaces != 0) { + + memset(pInterfaces, sizeof(pInterfaces), 0); + } +} + +//------------------------------------------------------------------------------ +/// Handles the given request if it is standard, otherwise STALLs it. +/// \param pDriver Pointer to a USBDDriver instance. +/// \param pRequest Pointer to a USBGenericRequest instance. +//------------------------------------------------------------------------------ +void USBDDriver_RequestHandler( + USBDDriver *pDriver, + const USBGenericRequest *pRequest) +{ + unsigned char cfgnum; + unsigned char infnum; + unsigned char eptnum; + unsigned char setting; + unsigned char type; + unsigned char indexDesc; + unsigned int length; + unsigned int address; + + TRACE_INFO_WP("Std "); + + // Check request code + switch (USBGenericRequest_GetRequest(pRequest)) { + + case USBGenericRequest_GETDESCRIPTOR: + TRACE_INFO_WP("gDesc "); + + // Send the requested descriptor + type = USBGetDescriptorRequest_GetDescriptorType(pRequest); + indexDesc = USBGetDescriptorRequest_GetDescriptorIndex(pRequest); + length = USBGenericRequest_GetLength(pRequest); + GetDescriptor(pDriver, type, indexDesc, length); + break; + + case USBGenericRequest_SETADDRESS: + TRACE_INFO_WP("sAddr "); + + // Sends a zero-length packet and then set the device address + address = USBSetAddressRequest_GetAddress(pRequest); + USBD_Write(0, 0, 0, (TransferCallback) USBD_SetAddress, (void *) address); + break; + + case USBGenericRequest_SETCONFIGURATION: + TRACE_INFO_WP("sCfg "); + + // Set the requested configuration + cfgnum = USBSetConfigurationRequest_GetConfiguration(pRequest); + SetConfiguration(pDriver, cfgnum); + break; + + case USBGenericRequest_GETCONFIGURATION: + TRACE_INFO_WP("gCfg "); + + // Send the current configuration number + GetConfiguration(pDriver); + break; + + case USBGenericRequest_GETSTATUS: + TRACE_INFO_WP("gSta "); + + // Check who is the recipient + switch (USBGenericRequest_GetRecipient(pRequest)) { + + case USBGenericRequest_DEVICE: + TRACE_INFO_WP("Dev "); + + // Send the device status + GetDeviceStatus(pDriver); + break; + + case USBGenericRequest_ENDPOINT: + TRACE_INFO_WP("Ept "); + + // Send the endpoint status + eptnum = USBGenericRequest_GetEndpointNumber(pRequest); + GetEndpointStatus(eptnum); + break; + + default: + TRACE_WARNING( + "USBDDriver_RequestHandler: Unknown recipient (%d)\n\r", + USBGenericRequest_GetRecipient(pRequest)); + USBD_Stall(0); + } + break; + + case USBGenericRequest_CLEARFEATURE: + TRACE_INFO_WP("cFeat "); + + // Check which is the requested feature + switch (USBFeatureRequest_GetFeatureSelector(pRequest)) { + + case USBFeatureRequest_ENDPOINTHALT: + TRACE_INFO_WP("Hlt "); + + // Unhalt endpoint and send a zero-length packet + USBD_Unhalt(USBGenericRequest_GetEndpointNumber(pRequest)); + USBD_Write(0, 0, 0, 0, 0); + break; + + case USBFeatureRequest_DEVICEREMOTEWAKEUP: + TRACE_INFO_WP("RmWU "); + + // Disable remote wake-up and send a zero-length packet + pDriver->isRemoteWakeUpEnabled = 0; + USBD_Write(0, 0, 0, 0, 0); + break; + + default: + TRACE_WARNING( + "USBDDriver_RequestHandler: Unknown feature selector (%d)\n\r", + USBFeatureRequest_GetFeatureSelector(pRequest)); + USBD_Stall(0); + } + break; + + case USBGenericRequest_SETFEATURE: + TRACE_INFO_WP("sFeat "); + + // Check which is the selected feature + switch (USBFeatureRequest_GetFeatureSelector(pRequest)) { + + case USBFeatureRequest_DEVICEREMOTEWAKEUP: + TRACE_INFO_WP("RmWU "); + + // Enable remote wake-up and send a ZLP + pDriver->isRemoteWakeUpEnabled = 1; + USBD_Write(0, 0, 0, 0, 0); + break; + + case USBFeatureRequest_ENDPOINTHALT: + TRACE_INFO_WP("Halt "); + // Halt endpoint + USBD_Halt(USBGenericRequest_GetEndpointNumber(pRequest)); + USBD_Write(0, 0, 0, 0, 0); + break; + +#if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + + case USBFeatureRequest_TESTMODE: + // 7.1.20 Test Mode Support, 9.4.9 SetFeature + if ((USBGenericRequest_GetRecipient(pRequest) == USBGenericRequest_DEVICE) + && ((USBGenericRequest_GetIndex(pRequest) & 0x000F) == 0)) { + + // Handle test request + USBDDriver_Test(USBFeatureRequest_GetTestSelector(pRequest)); + } + else { + + USBD_Stall(0); + } + break; +#endif +#if defined(CHIP_USB_OTGHS) + case USBFeatureRequest_OTG_B_HNP_ENABLE: + TRACE_INFO_WP("OTG_B_HNP_ENABLE "); + otg_features_supported |= 1<isRemoteWakeUpEnabled; +} + +#if defined(CHIP_USB_OTGHS) +//------------------------------------------------------------------------------ +/// Return OTG features supported +/// \return the OTG features +//------------------------------------------------------------------------------ +unsigned char USBDDriver_returnOTGFeatures(void) +{ + return otg_features_supported; +} + +//------------------------------------------------------------------------------ +/// Clear OTG features supported +/// \return none +//------------------------------------------------------------------------------ +void USBDDriver_clearOTGFeatures(void) +{ + otg_features_supported = 0; +} +#endif + diff --git a/usb/device/core/USBDDriver.h b/usb/device/core/USBDDriver.h new file mode 100644 index 0000000..40ca6d7 --- /dev/null +++ b/usb/device/core/USBDDriver.h @@ -0,0 +1,101 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + USB Device Driver class definition. + + !!!Usage + + -# Instanciate a USBDDriver object and initialize it using + USBDDriver_Initialize. + -# When a USB SETUP request is received, forward it to the standard + driver using USBDDriver_RequestHandler. + -# Check the Remote Wakeup setting via USBDDriver_IsRemoteWakeUpEnabled. +*/ + +#ifndef USBDDRIVER_H +#define USBDDRIVER_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBDDriverDescriptors.h" +#include + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// USB device driver structure, holding a list of descriptors identifying +/// the device as well as the driver current state. +//------------------------------------------------------------------------------ +typedef struct { + + /// List of descriptors used by the device. + const USBDDriverDescriptors *pDescriptors; + /// Current setting for each interface. + unsigned char *pInterfaces; + /// Current configuration number (0 -> device is not configured). + unsigned char cfgnum; + /// Indicates if remote wake up has been enabled by the host. + unsigned char isRemoteWakeUpEnabled; +#if defined(CHIP_USB_OTGHS) + /// Features supported by OTG + unsigned char otg_features_supported; +#endif +} USBDDriver; + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern void USBDDriver_Initialize( + USBDDriver *pDriver, + const USBDDriverDescriptors *pDescriptors, + unsigned char *pInterfaces); + +extern void USBDDriver_RequestHandler( + USBDDriver *pDriver, + const USBGenericRequest *pRequest); + +extern unsigned char USBDDriver_IsRemoteWakeUpEnabled(const USBDDriver *pDriver); + +#if defined(CHIP_USB_OTGHS) +extern unsigned char USBDDriver_returnOTGFeatures(void); +extern void USBDDriver_clearOTGFeatures(void); +#endif + +#endif //#ifndef USBDDRIVER_H + diff --git a/usb/device/core/USBDDriverCallbacks.h b/usb/device/core/USBDDriverCallbacks.h new file mode 100644 index 0000000..053e8ac --- /dev/null +++ b/usb/device/core/USBDDriverCallbacks.h @@ -0,0 +1,61 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of several callbacks which are triggered by the USB software + driver after receiving specific requests. + + !!!Usage + + -# Re-implement the USBDDriverCallbacks_ConfigurationChanged + callback to know when the hosts changes the active configuration of + the device. + -# Re-implement the USBDDriverCallbacks_InterfaceSettingChanged + callback to get notified whenever the active setting of an interface + is changed by the host. +*/ + +#ifndef USBDDRIVERCALLBACKS_H +#define USBDDRIVERCALLBACKS_H + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern void USBDDriverCallbacks_ConfigurationChanged(unsigned char cfgnum); + +extern void USBDDriverCallbacks_InterfaceSettingChanged(unsigned char interface, + unsigned char setting); + +#endif //#ifndef USBDDRIVERCALLBACKS_H + diff --git a/usb/device/core/USBDDriverCb_CfgChanged.c b/usb/device/core/USBDDriverCb_CfgChanged.c new file mode 100644 index 0000000..08e2b2f --- /dev/null +++ b/usb/device/core/USBDDriverCb_CfgChanged.c @@ -0,0 +1,49 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBDDriverCallbacks.h" +#include + +//------------------------------------------------------------------------------ +// Global functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Indicates that the current configuration of the device has changed. +/// \param cfgnum New device configuration index. +//------------------------------------------------------------------------------ +void USBDDriverCallbacks_ConfigurationChanged(unsigned char cfgnum) +{ + TRACE_INFO_WP("ConfigurationChanged "); +} + diff --git a/usb/device/core/USBDDriverCb_IfSettingChanged.c b/usb/device/core/USBDDriverCb_IfSettingChanged.c new file mode 100644 index 0000000..c9049e6 --- /dev/null +++ b/usb/device/core/USBDDriverCb_IfSettingChanged.c @@ -0,0 +1,52 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBDDriverCallbacks.h" +#include + +//------------------------------------------------------------------------------ +// Global functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Notifies of a change in the currently active setting of an interface. +/// \param interface Number of the interface whose setting has changed. +/// \param setting New interface setting. +//------------------------------------------------------------------------------ +void USBDDriverCallbacks_InterfaceSettingChanged( + unsigned char interface, + unsigned char setting) +{ + TRACE_INFO_WP("InterfaceSettingChanged "); +} + diff --git a/usb/device/core/USBDDriverDescriptors.h b/usb/device/core/USBDDriverDescriptors.h new file mode 100644 index 0000000..f1064e4 --- /dev/null +++ b/usb/device/core/USBDDriverDescriptors.h @@ -0,0 +1,86 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of a class for declaring USB descriptors required by the + device driver. +*/ + +#ifndef USBDDRIVERDESCRIPTORS_H +#define USBDDRIVERDESCRIPTORS_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include +#include + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// List of all descriptors used by a USB device driver. Each descriptor can +/// be provided in two versions: full-speed and high-speed. Devices which are +/// not high-speed capable do not need to provided high-speed descriptors and +/// the full-speed qualifier & other speed descriptors. +//------------------------------------------------------------------------------ +typedef struct { + + /// Pointer to the full-speed device descriptor. + const USBDeviceDescriptor *pFsDevice; + /// Pointer to the full-speed configuration descriptor. + const USBConfigurationDescriptor *pFsConfiguration; + /// Pointer to the full-speed qualifier descriptor. + const USBDeviceQualifierDescriptor *pFsQualifier; + /// Pointer to the full-speed other speed configuration descriptor. + const USBConfigurationDescriptor *pFsOtherSpeed; + /// Pointer to the high-speed device descriptor. + const USBDeviceDescriptor *pHsDevice; + /// Pointer to the high-speed configuration descriptor. + const USBConfigurationDescriptor *pHsConfiguration; + /// Pointer to the high-speed qualifier descriptor. + const USBDeviceQualifierDescriptor *pHsQualifier; + /// Pointer to the high-speed other speed configuration descriptor. + const USBConfigurationDescriptor *pHsOtherSpeed; + /// Pointer to the list of string descriptors. + const unsigned char **pStrings; + /// Number of string descriptors in list. + unsigned char numStrings; + +} USBDDriverDescriptors; + +#endif //#ifndef USBDDRIVERDESCRIPTORS_H + diff --git a/usb/device/core/USBD_OTGHS.c b/usb/device/core/USBD_OTGHS.c new file mode 100644 index 0000000..1795aaf --- /dev/null +++ b/usb/device/core/USBD_OTGHS.c @@ -0,0 +1,1697 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBD.h" +#include "USBDCallbacks.h" +#include "USBDDriver.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +/// Maximum number of endpoints interrupts. +#define NUM_IT_MAX \ + (AT91C_BASE_OTGHS->OTGHS_IPFEATURES & AT91C_OTGHS_EPT_NBR_MAX) +/// Maximum number of endpoint DMA interrupts +#define NUM_IT_MAX_DMA \ + ((AT91C_BASE_OTGHS->OTGHS_IPFEATURES & AT91C_OTGHS_DMA_CHANNEL_NBR)>>4) +/// Bits that should be shifted to access DMA control bits. +#define SHIFT_DMA 24 +/// Bits that should be shifted to access interrupt bits. +#define SHIFT_INTERUPT 12 + +/// Max size of the FMA FIFO +#define DMA_MAX_FIFO_SIZE 32768 + +#define EPT_VIRTUAL_SIZE 8192 + +//------------------------------------------------------------------------------ +/// \page "Endpoint states" +/// This page lists the endpoint states. +/// !States +// - UDP_ENDPOINT_DISABLED +// - UDP_ENDPOINT_HALTED +// - UDP_ENDPOINT_IDLE +// - UDP_ENDPOINT_SENDING +// - UDP_ENDPOINT_RECEIVING + +/// Endpoint states: Endpoint is disabled +#define UDP_ENDPOINT_DISABLED 0 +/// Endpoint states: Endpoint is halted (i.e. STALLs every request) +#define UDP_ENDPOINT_HALTED 1 +/// Endpoint states: Endpoint is idle (i.e. ready for transmission) +#define UDP_ENDPOINT_IDLE 2 +/// Endpoint states: Endpoint is sending data +#define UDP_ENDPOINT_SENDING 3 +/// Endpoint states: Endpoint is receiving data +#define UDP_ENDPOINT_RECEIVING 4 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Structures +//------------------------------------------------------------------------------ + +/// Describes an ongoing transfer on a UDP endpoint. +typedef struct +{ + /// Pointer to a data buffer used for emission/reception. + char *pData; + /// Number of bytes which have been written into the UDP internal FIFO + /// buffers. + volatile int buffered; + /// Number of bytes which have been sent/received. + volatile int transferred; + /// Number of bytes which have not been buffered/transferred yet. + volatile int remaining; + /// Optional callback to invoke when the transfer completes. + volatile TransferCallback fCallback; + /// Optional argument to the callback function. + void *pArgument; +} Transfer; + +//------------------------------------------------------------------------------ +/// Describes the state of an endpoint of the UDP controller. +//------------------------------------------------------------------------------ +typedef struct +{ + /// Current endpoint state. + volatile unsigned char state; + /// Current reception bank (0 or 1). + unsigned char bank; + /// Maximum packet size for the endpoint. + unsigned short size; + /// Describes an ongoing transfer (if current state is either + /// or ) + Transfer transfer; + /// Special case for send a ZLP + unsigned char sendZLP; +} Endpoint; + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +/// Holds the internal state for each endpoint of the UDP. +static Endpoint endpoints[CHIP_USB_NUMENDPOINTS]; +/// Device current state. +static unsigned char deviceState; +/// Indicates the previous device state +static unsigned char previousDeviceState; + +/// 7.1.20 Test Mode Support +/// Test codes for the USB HS test mode. +static const char test_packet_buffer[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // JKJKJKJK * 9 + 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA, // JJKKJJKK * 8 + 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE, // JJJJKKKK * 8 + 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // JJJJJJJKKKKKKK * 8 + 0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD, // JJJJJJJK * 8 + 0xFC,0x7E,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD,0x7E // {JKKKKKKK * 10}, JK +}; + +//------------------------------------------------------------------------------ +// Internal Functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Enable UDPHS clock +//------------------------------------------------------------------------------ +static inline void OTGHS_EnableUsbClock( void ) +{ + +} + +//------------------------------------------------------------------------------ +/// Disable UDPHS clock +//------------------------------------------------------------------------------ +static inline void OTGHS_DisableUsbClock( void ) +{ + +} + +//------------------------------------------------------------------------------ +/// Enables the transceiver of the USB controller +//------------------------------------------------------------------------------ +static void OTGHS_EnableTransceiver(void) +{ + AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_OTGPADE; +} + +//------------------------------------------------------------------------------ +/// Disables the transceiver of the USB controller associated with the specified +/// USB driver +//------------------------------------------------------------------------------ +static void OTGHS_DisableTransceiver(void) +{ + AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_OTGPADE; +} + +//------------------------------------------------------------------------------ +/// Handles a completed transfer on the given endpoint, invoking the +/// configured callback if any. +/// \param bEndpoint Number of the endpoint for which the transfer has completed. +/// \param bStatus Status code returned by the transfer operation +//------------------------------------------------------------------------------ +static void OTGHS_EndOfTransfer( unsigned char bEndpoint, char bStatus ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = &(pEndpoint->transfer); + + // Check that endpoint was sending or receiving data + if( (pEndpoint->state == UDP_ENDPOINT_RECEIVING) + || (pEndpoint->state == UDP_ENDPOINT_SENDING) ) { + + TRACE_DEBUG_WP("Eo"); + if(pEndpoint->state == UDP_ENDPOINT_SENDING) { + pEndpoint->sendZLP = 0; + } + // Endpoint returns in Idle state + pEndpoint->state = UDP_ENDPOINT_IDLE; + + // Invoke callback is present + if (pTransfer->fCallback != 0) { + + ((TransferCallback) pTransfer->fCallback) + (pTransfer->pArgument, + bStatus, + pTransfer->transferred, + pTransfer->remaining + pTransfer->buffered); + } + else { + TRACE_DEBUG_WP("No callBack\n\r"); + } + } +} + +//------------------------------------------------------------------------------ +/// Transfers a data payload from the current tranfer buffer to the endpoint +/// FIFO +/// \param bEndpoint Number of the endpoint which is sending data. +//------------------------------------------------------------------------------ +static void OTGHS_WritePayload( unsigned char bEndpoint ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = &(pEndpoint->transfer); + char *pFifo; + signed int size; + unsigned int dCtr; + + pFifo = (char*)((unsigned int *)AT91C_BASE_OTGHS_EPTFIFO + (EPT_VIRTUAL_SIZE * bEndpoint)); + + // Get the number of bytes to send + size = pEndpoint->size; + if (size > pTransfer->remaining) { + + size = pTransfer->remaining; + } + + // Update transfer descriptor information + pTransfer->buffered += size; + pTransfer->remaining -= size; + + // Write packet in the FIFO buffer + dCtr = 0; + while (size > 0) { + + pFifo[dCtr] = *(pTransfer->pData); + pTransfer->pData++; + size--; + dCtr++; + } +} + +//------------------------------------------------------------------------------ +/// Transfers a data payload from an endpoint FIFO to the current transfer buffer +/// \param bEndpoint Endpoint number. +/// \param wPacketSize Size of received data packet +//------------------------------------------------------------------------------ +static void OTGHS_ReadPayload( unsigned char bEndpoint, int wPacketSize ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = &(pEndpoint->transfer); + char *pFifo; + unsigned char dBytes=0; + + pFifo = (char*)((unsigned int *)AT91C_BASE_OTGHS_EPTFIFO + (EPT_VIRTUAL_SIZE * bEndpoint)); + + // Check that the requested size is not bigger than the remaining transfer + if (wPacketSize > pTransfer->remaining) { + + pTransfer->buffered += wPacketSize - pTransfer->remaining; + wPacketSize = pTransfer->remaining; + } + + // Update transfer descriptor information + pTransfer->remaining -= wPacketSize; + pTransfer->transferred += wPacketSize; + + // Retrieve packet + while (wPacketSize > 0) { + + *(pTransfer->pData) = pFifo[dBytes]; + pTransfer->pData++; + wPacketSize--; + dBytes++; + } +} + +//------------------------------------------------------------------------------ +/// Received SETUP packet from endpoint 0 FIFO +/// \param pRequest Generic USB SETUP request sent over Control endpoints +//------------------------------------------------------------------------------ +static void OTGHS_ReadRequest( USBGenericRequest *pRequest ) +{ + unsigned int *pData = (unsigned int *)pRequest; + unsigned int fifo; + + fifo = (AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0[0]); + *pData = fifo; + fifo = (AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0[0]); + pData++; + *pData = fifo; + //TRACE_ERROR("SETUP: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n\r", pData[0],pData[1],pData[2],pData[3],pData[4],pData[5],pData[6],pData[7]); +} + +//------------------------------------------------------------------------------ +/// Reset all endpoint transfer descriptors +//------------------------------------------------------------------------------ +static void OTGHS_ResetEndpoints( void ) +{ + Endpoint *pEndpoint; + Transfer *pTransfer; + + unsigned char bEndpoint; + + // Reset the transfer descriptor of every endpoint + for( bEndpoint = 0; bEndpoint < CHIP_USB_NUMENDPOINTS; bEndpoint++ ) { + + pEndpoint = &(endpoints[bEndpoint]); + pTransfer = &(pEndpoint->transfer); + + // Reset endpoint transfer descriptor + pTransfer->pData = 0; + pTransfer->transferred = -1; + pTransfer->buffered = -1; + pTransfer->remaining = -1; + pTransfer->fCallback = 0; + pTransfer->pArgument = 0; + + // Reset endpoint state + pEndpoint->bank = 0; + pEndpoint->state = UDP_ENDPOINT_DISABLED; + // Reset ZLP + pEndpoint->sendZLP = 0; + } +} + + +//------------------------------------------------------------------------------ +/// Disable all endpoints (except control endpoint 0), aborting current +/// transfers if necessary +//------------------------------------------------------------------------------ +static void OTGHS_DisableEndpoints( void ) +{ + unsigned char bEndpoint; + + // Disable each endpoint, terminating any pending transfer + + + // Control endpoint 0 is not disabled + for( bEndpoint = 1; bEndpoint < CHIP_USB_NUMENDPOINTS; bEndpoint++ ) { + + OTGHS_EndOfTransfer( bEndpoint, USBD_STATUS_ABORTED ); + endpoints[bEndpoint].state = UDP_ENDPOINT_DISABLED; + } +} + + +//------------------------------------------------------------------------------ +/// Endpoint interrupt handler. +/// Handle IN/OUT transfers, received SETUP packets and STALLing +/// \param bEndpoint Index of endpoint +//------------------------------------------------------------------------------ +static void OTGHS_EndpointHandler( unsigned char bEndpoint ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = &(pEndpoint->transfer); + unsigned int status = AT91C_BASE_OTGHS->OTGHS_DEVEPTISR[bEndpoint]; + unsigned short wPacketSize; + USBGenericRequest request; + + TRACE_DEBUG_WP("E%d ", bEndpoint); + TRACE_DEBUG_WP("st:0x%X ", status); + + // Handle interrupts + // IN packet sent + if((AT91C_BASE_OTGHS->OTGHS_DEVEPTIMR[bEndpoint] & AT91C_OTGHS_TXINI) + && (status & AT91C_OTGHS_TXINI )) { + + TRACE_DEBUG_WP("Wr "); + + // Check that endpoint was in Sending state + if( pEndpoint->state == UDP_ENDPOINT_SENDING ) { + + if (pTransfer->buffered > 0) { + pTransfer->transferred += pTransfer->buffered; + pTransfer->buffered = 0; + } + + if( ((pTransfer->buffered)==0) + &&((pTransfer->transferred)==0) + &&((pTransfer->remaining)==0) + &&(pEndpoint->sendZLP == 0)) { + pEndpoint->sendZLP = 1; + } + + // End of transfer ? + if( (pTransfer->remaining > 0) + ||(pEndpoint->sendZLP == 1)) { + + pEndpoint->sendZLP = 2; + // Transfer remaining data + TRACE_DEBUG_WP(" %d ", pEndpoint->size); + // Send next packet + OTGHS_WritePayload(bEndpoint); + + // Send Token IN + AT91C_BASE_OTGHS->OTGHS_DEVEPTICR[bEndpoint] = AT91C_OTGHS_TXINI; + // For a non-control endpoint, the FIFOCON bit must be cleared + // to start the transfer + if ((AT91C_OTGHS_EPT_TYPE & AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint]) + != AT91C_OTGHS_EPT_TYPE_CTL_EPT) { + // Send IN + AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_FIFOCON; + } + } + else { + + TRACE_DEBUG_WP("\n\r0pTransfer->buffered %d \n\r", pTransfer->buffered); + TRACE_DEBUG_WP("0pTransfer->transferred %d \n\r", pTransfer->transferred); + TRACE_DEBUG_WP("0pTransfer->remaining %d \n\r", pTransfer->remaining); + + TRACE_DEBUG_WP(" %d ", pTransfer->transferred); + + // Disable interrupt if this is not a control endpoint + if ((AT91C_OTGHS_EPT_TYPE & AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint]) + != AT91C_OTGHS_EPT_TYPE_CTL_EPT) { + + AT91C_BASE_OTGHS->OTGHS_DEVIDR = 1<OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_TXINI; + OTGHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + pEndpoint->sendZLP = 0; + } + } + else { + TRACE_DEBUG("Error Wr %d", pEndpoint->sendZLP); + } + } + + // OUT packet received + if( AT91C_OTGHS_RXOUT == (status & AT91C_OTGHS_RXOUT) ) { + + // Check that the endpoint is in Receiving state + if (pEndpoint->state != UDP_ENDPOINT_RECEIVING) { + + // Check if an ACK has been received on a Control endpoint + if( ((AT91C_OTGHS_EPT_TYPE & AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint]) + == AT91C_OTGHS_EPT_TYPE_CTL_EPT) + && (0 == (status & AT91C_OTGHS_BYCT)) ) { + + // Control endpoint, 0 bytes received + // Acknowledge the data and finish the current transfer + TRACE_DEBUG_WP("Ack "); + AT91C_BASE_OTGHS->OTGHS_DEVEPTICR[bEndpoint] = AT91C_OTGHS_RXOUT; + AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_RXOUT; + //OTGHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + } + // Check if the data has been STALLed + else if( AT91C_OTGHS_STALL == (status & AT91C_OTGHS_STALL)) { + + // Discard STALLed data + TRACE_DEBUG_WP("Discard "); + AT91C_BASE_OTGHS->OTGHS_DEVEPTICR[bEndpoint] = AT91C_OTGHS_RXOUT; + } + else { + // NAK the data + TRACE_DEBUG_WP("Nak "); + AT91C_BASE_OTGHS->OTGHS_DEVIDR = 1<> 20) & 0x7FF); + + //TRACE_ERROR_WP("out:%d ", wPacketSize); + OTGHS_ReadPayload(bEndpoint, wPacketSize); + AT91C_BASE_OTGHS->OTGHS_DEVEPTICR[bEndpoint] = AT91C_OTGHS_RXOUT; + if((AT91C_OTGHS_EPT_TYPE & AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint]) + != AT91C_OTGHS_EPT_TYPE_CTL_EPT) { + AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_FIFOCON; + } + + // Check if the transfer is finished + if ((pTransfer->remaining == 0) || (wPacketSize < pEndpoint->size)) { + + AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_RXOUT; + + // Disable interrupt if this is not a control endpoint + if ((AT91C_OTGHS_EPT_TYPE & AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint]) + != AT91C_OTGHS_EPT_TYPE_CTL_EPT) { + + AT91C_BASE_OTGHS->OTGHS_DEVIDR = 1<OTGHS_DEVEPTICR[bEndpoint] = AT91C_OTGHS_STALL; + + // If the endpoint is not halted, clear the STALL condition + if (pEndpoint->state != UDP_ENDPOINT_HALTED) { + + TRACE_WARNING("_ " ); + AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_STALLRQ; + } + } + + // SETUP packet received + if( AT91C_OTGHS_RXSTP == (status & AT91C_OTGHS_RXSTP) ) { + + TRACE_DEBUG_WP("Stp "); + + // If a transfer was pending, complete it + // Handles the case where during the status phase of a control write + // transfer, the host receives the device ZLP and ack it, but the ack + // is not received by the device + if ((pEndpoint->state == UDP_ENDPOINT_RECEIVING) + || (pEndpoint->state == UDP_ENDPOINT_SENDING)) { + + OTGHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + } + + // Copy the setup packet + OTGHS_ReadRequest(&request); + + // Acknowledge setup packet + AT91C_BASE_OTGHS->OTGHS_DEVEPTICR[bEndpoint] = AT91C_OTGHS_RXSTP; + + // Forward the request to the upper layer + USBDCallbacks_RequestReceived(&request); + } +} + +//------------------------------------------------------------------------------ +// Interrupt service routine +//------------------------------------------------------------------------------ +#ifdef DMA +//---------------------------------------------------------------------------- +/// Endpoint DMA interrupt handler. +/// This function (ISR) handles dma interrupts +/// \param bEndpoint Index of endpoint +//---------------------------------------------------------------------------- +static void OTGHS_DmaHandler( unsigned char bEndpoint ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = &(pEndpoint->transfer); + int justTransferred; + unsigned int status; + unsigned char result = USBD_STATUS_SUCCESS; + + status = AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMASTATUS; + TRACE_DEBUG_WP("Dma Ept%d ", bEndpoint); + + // Disable DMA interrupt to avoid receiving 2 interrupts (B_EN and TR_EN) + AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMACONTROL &= + ~(unsigned int)(AT91C_OTGHS_END_TR_EN | AT91C_OTGHS_END_B_EN); + + AT91C_BASE_OTGHS->OTGHS_DEVIDR = (1<buffered + - ((status & (unsigned int)AT91C_OTGHS_BUFF_COUNT) >> 16); + pTransfer->transferred += justTransferred; + + pTransfer->buffered = ((status & (unsigned int)AT91C_OTGHS_BUFF_COUNT) >> 16); + + pTransfer->remaining -= justTransferred; + + TRACE_DEBUG_WP("\n\r1pTransfer->buffered %d \n\r", pTransfer->buffered); + TRACE_DEBUG_WP("1pTransfer->transferred %d \n\r", pTransfer->transferred); + TRACE_DEBUG_WP("1pTransfer->remaining %d \n\r", pTransfer->remaining); + + if( (pTransfer->remaining + pTransfer->buffered) > 0 ) { + + // Prepare an other transfer + if( pTransfer->remaining > DMA_MAX_FIFO_SIZE ) { + + pTransfer->buffered = DMA_MAX_FIFO_SIZE; + } + else { + pTransfer->buffered = pTransfer->remaining; + } + + AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMAADDRESS = + (unsigned int)((pTransfer->pData) + (pTransfer->transferred)); + + // Clear unwanted interrupts + AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMASTATUS; + + // Enable DMA endpoint interrupt + AT91C_BASE_OTGHS->OTGHS_DEVIER = (1 << SHIFT_DMA << bEndpoint); + // DMA config for receive the good size of buffer, or an error buffer + + AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMACONTROL = 0; // raz + AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMACONTROL = + ( ((pTransfer->buffered << 16) & AT91C_OTGHS_BUFF_COUNT) + | AT91C_OTGHS_END_TR_EN + | AT91C_OTGHS_END_TR_IT + | AT91C_OTGHS_END_B_EN + | AT91C_OTGHS_END_BUFFIT + | AT91C_OTGHS_CHANN_ENB ); + } + } + else if( AT91C_OTGHS_END_TR_ST == (status & AT91C_OTGHS_END_TR_ST) ) { + + TRACE_DEBUG_WP("EndTransf "); + + pTransfer->transferred = pTransfer->buffered + - ((status & (unsigned int)AT91C_OTGHS_BUFF_COUNT) >> 16); + pTransfer->remaining = 0; + TRACE_DEBUG_WP("\n\r0pTransfer->buffered %d \n\r", pTransfer->buffered); + TRACE_DEBUG_WP("0pTransfer->transferred %d \n\r", pTransfer->transferred); + TRACE_DEBUG_WP("0pTransfer->remaining %d \n\r", pTransfer->remaining); + } + else { + + TRACE_ERROR("OTGHS_DmaHandler: Error (0x%08X)\n\r", status); + result = USBD_STATUS_ABORTED; + } + + // Invoke callback + if( pTransfer->remaining == 0 ) { + + TRACE_DEBUG_WP("EOT "); + OTGHS_EndOfTransfer(bEndpoint, result); + } +} +#endif + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// USB device interrupt handler +/// Manages device resume, suspend, end of bus reset. +/// Forwards endpoint interrupts to the appropriate handler. +//------------------------------------------------------------------------------ +void USBD_IrqHandler(void) +{ + unsigned int status; + unsigned char numIT; + + if (deviceState >= USBD_STATE_POWERED) { + + LED_Set(USBD_LEDUSB); + } + +#ifndef OTG_PROJECT + // Get interrupts status + status = AT91C_BASE_OTGHS->OTGHS_SR & AT91C_BASE_OTGHS->OTGHS_CTRL & 0xFF; + while (status != 0) { + //TRACE_ERROR_WP("~"); + if((status&AT91C_OTGHS_VBUSTI)==AT91C_OTGHS_VBUSTI) { + TRACE_DEBUG_WP("__VBus\n\r"); + + USBD_Connect(); + + // Acknowledge the interrupt + AT91C_BASE_OTGHS->OTGHS_SCR = AT91C_OTGHS_VBUSTI; + } + + // Don't treat others interrupt for this time + AT91C_BASE_OTGHS->OTGHS_SCR = AT91C_OTGHS_IDT | AT91C_OTGHS_SRP + | AT91C_OTGHS_VBERR | AT91C_OTGHS_BCERR + | AT91C_OTGHS_ROLEEX | AT91C_OTGHS_HNPERR + | AT91C_OTGHS_STO; + + AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_IDT; + + status = AT91C_BASE_OTGHS->OTGHS_SR & AT91C_BASE_OTGHS->OTGHS_CTRL & 0xFF; + } +#endif + + // Get OTG Device interrupts status + status = AT91C_BASE_OTGHS->OTGHS_DEVISR & AT91C_BASE_OTGHS->OTGHS_DEVIMR; + //TRACE_ERROR_WP("S=0x%X\n\r", AT91C_BASE_OTGHS->OTGHS_DEVISR ); + //TRACE_ERROR_WP("M=0x%X\n\r", AT91C_BASE_OTGHS->OTGHS_DEVIMR ); + while (status != 0) { + //TRACE_ERROR_WP("="); + // Start Of Frame (SOF) + if((status&AT91C_OTGHS_SOF)==AT91C_OTGHS_SOF) { + TRACE_DEBUG_WP("SOF "); + + // Invoke the SOF callback + //USB_StartOfFrameCallback(); + + // Acknowledge interrupt + AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_SOF; + status &= ~(unsigned int)AT91C_OTGHS_SOF; + } + + // Suspend + // This interrupt is always treated last (hence the '==') + else if (status == AT91C_OTGHS_SUSP) { + + TRACE_DEBUG_WP("S"); + + // The device enters the Suspended state + // MCK + UDPCK must be off + // Pull-Up must be connected + // Transceiver must be disabled + + LED_Clear(USBD_LEDUSB); + + // Enable wakeup + AT91C_BASE_OTGHS->OTGHS_DEVIER = AT91C_OTGHS_EORST | AT91C_OTGHS_WAKEUP | AT91C_OTGHS_EORSM; + + // Acknowledge interrupt + AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_SUSP; + previousDeviceState = deviceState; + deviceState = USBD_STATE_SUSPENDED; + OTGHS_DisableTransceiver(); + OTGHS_DisableUsbClock(); + // Invoke the Suspend callback + USBDCallbacks_Suspended(); + } + + // Resume + else if( ((status & AT91C_OTGHS_WAKEUP) != 0) // line activity + || ((status & AT91C_OTGHS_EORSM) != 0)) { // pc wakeup + + // Invoke the Resume callback + USBDCallbacks_Resumed(); + + TRACE_DEBUG_WP("R"); + + OTGHS_EnableUsbClock(); + OTGHS_EnableTransceiver(); + + // The device enters Configured state + // MCK + UDPCK must be on + // Pull-Up must be connected + // Transceiver must be enabled + + deviceState = previousDeviceState; + + AT91C_BASE_OTGHS->OTGHS_DEVICR = + (AT91C_OTGHS_WAKEUP | AT91C_OTGHS_EORSM | AT91C_OTGHS_SUSP); + AT91C_BASE_OTGHS->OTGHS_DEVIER = (AT91C_OTGHS_EORST | AT91C_OTGHS_SUSP); + AT91C_BASE_OTGHS->OTGHS_DEVICR = (AT91C_OTGHS_WAKEUP | AT91C_OTGHS_EORSM); + AT91C_BASE_OTGHS->OTGHS_DEVIDR = AT91C_OTGHS_WAKEUP; + + } + + // End of bus reset + else if ((status & AT91C_OTGHS_EORST) == AT91C_OTGHS_EORST) { + + TRACE_DEBUG_WP("EoB "); + + // The device enters the Default state + deviceState = USBD_STATE_DEFAULT; + // MCK + UDPCK are already enabled + // Pull-Up is already connected + // Transceiver must be enabled + // Endpoint 0 must be enabled + + OTGHS_EnableTransceiver(); + USBDDriver_clearOTGFeatures(); + + // The device leaves the Address & Configured states + OTGHS_ResetEndpoints(); + OTGHS_DisableEndpoints(); + USBD_ConfigureEndpoint(0); + + // Flush and enable the Suspend interrupt + AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_WAKEUP | AT91C_OTGHS_SUSP; + + //// Enable the Start Of Frame (SOF) interrupt if needed + //if (pCallbacks->startOfFrame != 0) + //{ + // AT91C_BASE_OTGHS->OTGHS_DEVIER |= AT91C_OTGHS_SOF; + //} + + // Invoke the Reset callback + USBDCallbacks_Reset(); + + // Acknowledge end of bus reset interrupt + AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_EORST; + } + + // Handle upstream resume interrupt + else if (status & AT91C_OTGHS_UPRSM) { + + TRACE_DEBUG_WP("ExtRes "); + + // - Acknowledge the IT + AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_UPRSM; + } + + // Endpoint interrupts + else { +#ifndef DMA + + // Handle endpoint interrupts + for (numIT = 0; numIT < NUM_IT_MAX; numIT++) { + + if ((status & (1 << SHIFT_INTERUPT << numIT)) != 0) { + + OTGHS_EndpointHandler(numIT); + } + } +#else + // Handle endpoint control interrupt + if ((status & (1 << SHIFT_INTERUPT << 0)) != 0) { + + OTGHS_EndpointHandler( 0 ); + } + else { + + numIT = 1; + while((status&(0x7E<OTGHS_DEVISR & AT91C_BASE_OTGHS->OTGHS_DEVIMR; + + TRACE_DEBUG_WP("\n\r"); + + if (status != 0) { + + TRACE_DEBUG_WP(" - "); + } + } + + if (deviceState >= USBD_STATE_POWERED) { + + LED_Clear(USBD_LEDUSB); + } +} + +//------------------------------------------------------------------------------ +/// Configure an endpoint with the provided endpoint descriptor +/// \param pDdescriptor Pointer to the endpoint descriptor +//------------------------------------------------------------------------------ +void USBD_ConfigureEndpoint(const USBEndpointDescriptor *pDescriptor) + +{ + Endpoint *pEndpoint; + unsigned char bEndpoint; + unsigned char bType; + unsigned char bEndpointDir; + unsigned char bSizeEpt = 0; + + // NULL descriptor -> Control endpoint 0 + if (pDescriptor == 0) { + + bEndpoint = 0; + pEndpoint = &(endpoints[bEndpoint]); + bType = USBEndpointDescriptor_CONTROL; + bEndpointDir = 0; + pEndpoint->size = CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0); + pEndpoint->bank = CHIP_USB_ENDPOINTS_BANKS(0); + } + else { + + // The endpoint number + bEndpoint = USBEndpointDescriptor_GetNumber(pDescriptor); + pEndpoint = &(endpoints[bEndpoint]); + // Transfer type: Control, Isochronous, Bulk, Interrupt + bType = USBEndpointDescriptor_GetType(pDescriptor); + // Direction, ignored for control endpoints + bEndpointDir = USBEndpointDescriptor_GetDirection(pDescriptor); + pEndpoint->size = USBEndpointDescriptor_GetMaxPacketSize(pDescriptor); + pEndpoint->bank = CHIP_USB_ENDPOINTS_BANKS(bEndpoint); + } + + // Abort the current transfer is the endpoint was configured and in + // Write or Read state + if( (pEndpoint->state == UDP_ENDPOINT_RECEIVING) + || (pEndpoint->state == UDP_ENDPOINT_SENDING) ) { + + OTGHS_EndOfTransfer(bEndpoint, USBD_STATUS_RESET); + } + pEndpoint->state = UDP_ENDPOINT_IDLE; + + // Disable endpoint + AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_TXINI + | AT91C_OTGHS_RXOUT + | AT91C_OTGHS_RXSTP + | AT91C_OTGHS_NAKOUT + | AT91C_OTGHS_NAKIN + | AT91C_OTGHS_OVERFL + | AT91C_OTGHS_STALL + | AT91C_OTGHS_SHRTPACK + | AT91C_OTGHS_MADATA + | AT91C_OTGHS_DATAX + | AT91C_OTGHS_ERRTRANS + | AT91C_OTGHS_NBUSYBK + | AT91C_OTGHS_FIFOCON + | AT91C_OTGHS_EPDISHDMA + | AT91C_OTGHS_NYETDIS + | AT91C_OTGHS_STALLRQ; + + // Reset Endpoint Fifos + AT91C_BASE_OTGHS->OTGHS_DEVEPT |= (1<OTGHS_DEVEPT &= ~(1<size <= 8 ) { + bSizeEpt = 0; + } + else if ( pEndpoint->size <= 16 ) { + bSizeEpt = 1; + } + else if ( pEndpoint->size <= 32 ) { + bSizeEpt = 2; + } + else if ( pEndpoint->size <= 64 ) { + bSizeEpt = 3; + } + else if ( pEndpoint->size <= 128 ) { + bSizeEpt = 4; + } + else if ( pEndpoint->size <= 256 ) { + bSizeEpt = 5; + } + else if ( pEndpoint->size <= 512 ) { + bSizeEpt = 6; + } + else if ( pEndpoint->size <= 1024 ) { + bSizeEpt = 7; + } //else { + // sizeEpt = 0; // control endpoint + //} + + // Enable endpoint + AT91C_BASE_OTGHS->OTGHS_DEVEPT |= (1<OTGHS_DEVIER = 1<OTGHS_DEVEPTCFG[bEndpoint] = (bSizeEpt << 4) + | (bEndpointDir << 8) + | (bType << 11) + | (((pEndpoint->bank)-1) << 2); + + if (bType == USBEndpointDescriptor_CONTROL) { + + AT91C_BASE_OTGHS->OTGHS_DEVEPTIER[bEndpoint] = AT91C_OTGHS_RXSTP; + } +#ifdef DMA + else { + AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint] |= AT91C_OTGHS_AUTOSW; + } +#endif + + AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_NYETDIS;// with nyet + //AT91C_BASE_OTGHS->OTGHS_DEVEPTIER[bEndpoint] = AT91C_OTGHS_NYETDIS; // without nyet + + // Check if the configuration is ok + AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint] |= AT91C_OTGHS_ALLOC; + if((AT91C_BASE_OTGHS->OTGHS_DEVEPTISR[bEndpoint]&AT91C_OTGHS_CFGOK)==0) { + + TRACE_ERROR("PB bEndpoint: 0x%X\n\r", bEndpoint); + TRACE_ERROR("PB bSizeEpt: 0x%X\n\r", bSizeEpt); + TRACE_ERROR("PB bEndpointDir: 0x%X\n\r", bEndpointDir); + TRACE_ERROR("PB bType: 0x%X\n\r", bType); + TRACE_ERROR("PB pEndpoint->bank: 0x%X\n\r", pEndpoint->bank); + TRACE_ERROR("PB OTGHS_EPTCFG: 0x%X\n\r", AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint]); + for(;;); + } +} + +//------------------------------------------------------------------------------ +/// Sends data through an USB endpoint (IN) +/// Sets up the transfer descriptor, write one or two data payloads +/// (depending on the number of FIFO banks for the endpoint) and then +/// starts the actual transfer. The operation is complete when all +/// the data has been sent. +/// \param bEndpoint Index of endpoint +/// \param *pData Data to be written +/// \param dLength Data length to be send +/// \param fCallback Callback to be call after the success command +/// \param *pArgument Callback argument +/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS +//------------------------------------------------------------------------------ +char USBD_Write( unsigned char bEndpoint, + const void *pData, + unsigned int dLength, + TransferCallback fCallback, + void *pArgument ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = &(pEndpoint->transfer); +//unsigned char i; +//unsigned char * data; + + // Return if the endpoint is not in IDLE state + if (pEndpoint->state != UDP_ENDPOINT_IDLE) { + + return USBD_STATUS_LOCKED; + } + + TRACE_DEBUG_WP("Write%d(%d) ", bEndpoint, dLength); + pEndpoint->sendZLP = 0; + // Setup the transfer descriptor + pTransfer->pData = (void *) pData; + pTransfer->remaining = dLength; + pTransfer->buffered = 0; + pTransfer->transferred = 0; + pTransfer->fCallback = fCallback; + pTransfer->pArgument = pArgument; + + // Send one packet + pEndpoint->state = UDP_ENDPOINT_SENDING; + +#ifdef DMA + // Test if endpoint type control + if (AT91C_OTGHS_EPT_TYPE_CTL_EPT == (AT91C_OTGHS_EPT_TYPE & AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint])) { +#endif + // Enable endpoint IT + AT91C_BASE_OTGHS->OTGHS_DEVIER = (1<OTGHS_DEVEPTIER[bEndpoint] = AT91C_OTGHS_TXINI; + +#ifdef DMA + } + else { + if( CHIP_USB_ENDPOINTS_DMA(bEndpoint) == 0 ) { + TRACE_FATAL("Endpoint has no DMA\n\r"); + } + if( pTransfer->remaining == 0 ) { + + // DMA not handle ZLP + AT91C_BASE_OTGHS->OTGHS_DEVEPTICR[bEndpoint] = AT91C_OTGHS_TXINI; + // For a non-control endpoint, the FIFOCON bit must be cleared + // to start the transfer + if ((AT91C_OTGHS_EPT_TYPE & AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint]) + != AT91C_OTGHS_EPT_TYPE_CTL_EPT) { + + AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_FIFOCON; + } + AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_TXINI; + + // Enable endpoint IT + AT91C_BASE_OTGHS->OTGHS_DEVIER = (1<remaining > DMA_MAX_FIFO_SIZE ) { + + // Transfer the max + pTransfer->buffered = DMA_MAX_FIFO_SIZE; + } + else { + // Transfer the good size + pTransfer->buffered = pTransfer->remaining; + } + + TRACE_DEBUG_WP("\n\r_WR:%d ", pTransfer->remaining ); + TRACE_DEBUG_WP("B:%d ", pTransfer->buffered ); + TRACE_DEBUG_WP("T:%d ", pTransfer->transferred ); + + AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMAADDRESS = (unsigned int)(pTransfer->pData); + + // Clear unwanted interrupts + AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMASTATUS; + + // Enable DMA endpoint interrupt + AT91C_BASE_OTGHS->OTGHS_DEVIER = (1<OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMACONTROL = 0; // raz + AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMACONTROL = + (((pTransfer->buffered<<16)&AT91C_OTGHS_BUFF_LENGTH) + | AT91C_OTGHS_END_B_EN + | AT91C_OTGHS_END_BUFFIT + | AT91C_OTGHS_CHANN_ENB); + } + } +#endif + + return USBD_STATUS_SUCCESS; +} + +//------------------------------------------------------------------------------ +/// Reads incoming data on an USB endpoint (OUT) +/// \param bEndpoint Index of endpoint +/// \param *pData Data to be readen +/// \param dLength Data length to be receive +/// \param fCallback Callback to be call after the success command +/// \param *pArgument Callback argument +/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS +//------------------------------------------------------------------------------ +char USBD_Read( unsigned char bEndpoint, + void *pData, + unsigned int dLength, + TransferCallback fCallback, + void *pArgument ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = &(pEndpoint->transfer); + + // Return if the endpoint is not in IDLE state + if (pEndpoint->state != UDP_ENDPOINT_IDLE) { + + return USBD_STATUS_LOCKED; + } + + TRACE_DEBUG_WP("Read%d(%d) ", bEndpoint, dLength); + //TRACE_ERROR_WP("Read%d(%d) ", bEndpoint, dLength); + + // Endpoint enters Receiving state + pEndpoint->state = UDP_ENDPOINT_RECEIVING; + + // Set the transfer descriptor + pTransfer->pData = pData; + pTransfer->remaining = dLength; + pTransfer->buffered = 0; + pTransfer->transferred = 0; + pTransfer->fCallback = fCallback; + pTransfer->pArgument = pArgument; + +#ifdef DMA + // Test if endpoint type control + if (AT91C_OTGHS_EPT_TYPE_CTL_EPT == (AT91C_OTGHS_EPT_TYPE & AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint])) { +#endif + // Control endpoint + // Enable endpoint IT + AT91C_BASE_OTGHS->OTGHS_DEVIER = (1<OTGHS_DEVEPTIER[bEndpoint] = AT91C_OTGHS_RXOUT; +#ifdef DMA + } + else { + if( CHIP_USB_ENDPOINTS_DMA(bEndpoint) == 0 ) { + TRACE_FATAL("Endpoint has no DMA\n\r"); + } + TRACE_DEBUG_WP("Read%d(%d) ", bEndpoint, dLength); + + // Others endpoints (not control) + if( pTransfer->remaining > DMA_MAX_FIFO_SIZE ) { + + // Transfer the max + pTransfer->buffered = DMA_MAX_FIFO_SIZE; + } + else { + // Transfer the good size + pTransfer->buffered = pTransfer->remaining; + } + + AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMAADDRESS = (unsigned int)(pTransfer->pData); + + // Clear unwanted interrupts + AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMASTATUS; + + // Enable DMA endpoint interrupt + AT91C_BASE_OTGHS->OTGHS_DEVIER = (1<remaining ); + TRACE_DEBUG_WP("B:%d ", pTransfer->buffered ); + TRACE_DEBUG_WP("T:%d ", pTransfer->transferred ); + + // DMA config + AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMACONTROL = 0; // raz + AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMACONTROL = + (((pTransfer->buffered<<16)&AT91C_OTGHS_BUFF_LENGTH) + | AT91C_OTGHS_END_TR_EN + | AT91C_OTGHS_END_TR_IT + | AT91C_OTGHS_END_B_EN + | AT91C_OTGHS_END_BUFFIT + | AT91C_OTGHS_CHANN_ENB); + } +#endif + + return USBD_STATUS_SUCCESS; +} + +//------------------------------------------------------------------------------ +/// Put endpoint into Halt state +/// \param bEndpoint Index of endpoint +//------------------------------------------------------------------------------ +void USBD_Halt( unsigned char bEndpoint ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + + TRACE_INFO("usbd_Halt%d ", bEndpoint); + //TRACE_ERROR("usbd_Halt%d ", bEndpoint); + + // Check that endpoint is enabled and not already in Halt state + if( (pEndpoint->state != UDP_ENDPOINT_DISABLED) + && (pEndpoint->state != UDP_ENDPOINT_HALTED) ) { + + TRACE_INFO("Halt%d ", bEndpoint); + + // Abort the current transfer if necessary + OTGHS_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED); + + pEndpoint->state = UDP_ENDPOINT_HALTED; + // Put endpoint into Halt state + AT91C_BASE_OTGHS->OTGHS_DEVEPTIER[bEndpoint] = AT91C_OTGHS_STALLRQ; + AT91C_BASE_OTGHS->OTGHS_DEVEPTIER[bEndpoint] = AT91C_OTGHS_STALL; + } +} + +//------------------------------------------------------------------------------ +/// Clears the Halt feature on the given endpoint. +/// \param bEndpoint Index of endpoint +//------------------------------------------------------------------------------ +void USBD_Unhalt( unsigned char bEndpoint ) +{ + unsigned int cfgSav; + + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + + // Check if the endpoint is enabled + //if (pEndpoint->state != UDP_ENDPOINT_DISABLED) { + if (pEndpoint->state == UDP_ENDPOINT_HALTED) { + + TRACE_DEBUG_WP("Unhalt%d ", bEndpoint); + //TRACE_ERROR("Unhalt%d ", bEndpoint); + + // Return endpoint to Idle state + pEndpoint->state = UDP_ENDPOINT_IDLE; + + cfgSav = AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint]; + + // Reset Endpoint Fifos + AT91C_BASE_OTGHS->OTGHS_DEVEPT |= (1<OTGHS_DEVEPT &= ~(1<OTGHS_DEVEPTCFG[bEndpoint] = cfgSav; + + if((AT91C_BASE_OTGHS->OTGHS_DEVEPTISR[bEndpoint]&AT91C_OTGHS_CFGOK)==0) { + + TRACE_ERROR("PB bEndpoint: 0x%X\n\r", bEndpoint); + for(;;); + } + + // Reset data-toggle + AT91C_BASE_OTGHS->OTGHS_DEVEPTIER[bEndpoint] = AT91C_OTGHS_RSTDT; + + // Clear FORCESTALL flag + // Disable stall on endpoint + AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_STALLRQ; + AT91C_BASE_OTGHS->OTGHS_DEVEPTICR[bEndpoint] = AT91C_OTGHS_STALL; + } +} + +//------------------------------------------------------------------------------ +/// Returns the current Halt status of an endpoint. +/// \param bEndpoint Index of endpoint +/// \return 1 if the endpoint is currently halted; otherwise 0 +//------------------------------------------------------------------------------ +unsigned char USBD_IsHalted( unsigned char bEndpoint ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + unsigned char status = 0; + + if (pEndpoint->state == UDP_ENDPOINT_HALTED) { + status = 1; + } + return( status ); +} + +//------------------------------------------------------------------------------ +/// IS High Speed device working in High Speed ? +/// \return 1 if the device is in High Speed; otherwise 0 (Full Speed) +//------------------------------------------------------------------------------ +unsigned char USBD_IsHighSpeed( void ) +{ + unsigned char status = 0; + + if(AT91C_OTGHS_SPEED_SR_HS == (AT91C_BASE_OTGHS->OTGHS_SR & (0x03<<12))) { + // High Speed + TRACE_DEBUG_WP("High Speed\n\r"); + status = 1; + } + else { + TRACE_DEBUG_WP("Full Speed\n\r"); + } + return( status ); +} + +//------------------------------------------------------------------------------ +/// Causes the endpoint to acknowledge the next received packet with a STALL +/// handshake. +/// Further packets are then handled normally. +/// \param bEndpoint Index of endpoint +/// \return Operation result code: USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS +//------------------------------------------------------------------------------ +unsigned char USBD_Stall( unsigned char bEndpoint ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + + // Check that endpoint is in Idle state + if (pEndpoint->state != UDP_ENDPOINT_IDLE) { + + TRACE_WARNING("UDP_Stall: Endpoint%d locked\n\r", bEndpoint); + return USBD_STATUS_LOCKED; + } + + TRACE_DEBUG_WP("Stall%d ", bEndpoint); + + // Sends a STALL handshake for the next host request. + // A STALL handshake will be sent for each following request until a SETUP + // or a Clear Halt Feature occurs for this endpoint. + AT91C_BASE_OTGHS->OTGHS_DEVEPTIER[bEndpoint] = AT91C_OTGHS_STALLRQ|AT91C_OTGHS_RXSTP; + + return USBD_STATUS_SUCCESS; +} + +//------------------------------------------------------------------------------ +/// Activates a remote wakeup procedure +//------------------------------------------------------------------------------ +void USBD_RemoteWakeUp(void) +{ + TRACE_DEBUG_WP("Remote WakeUp\n\r"); + + // Device is currently suspended + if (deviceState == USBD_STATE_SUSPENDED) { + + TRACE_DEBUG_WP("RW\n\r"); + OTGHS_EnableUsbClock(); + OTGHS_EnableTransceiver(); + + // Activates a remote wakeup + AT91C_BASE_OTGHS->OTGHS_DEVCTRL |= AT91C_OTGHS_RMWKUP; + } + // Device is NOT suspended + else { + + TRACE_WARNING("USBD_RemoteWakeUp: Device is not suspended\n\r"); + } +} + +//------------------------------------------------------------------------------ +/// Sets the device address +/// \param address Adress to be set +//------------------------------------------------------------------------------ +void USBD_SetAddress( unsigned char address ) +{ + TRACE_DEBUG_WP("SetAddr(%d) ", address); + + // Set address + AT91C_BASE_OTGHS->OTGHS_DEVCTRL &= ~(unsigned int)AT91C_OTGHS_UADD; + AT91C_BASE_OTGHS->OTGHS_DEVCTRL |= address & AT91C_OTGHS_UADD; + AT91C_BASE_OTGHS->OTGHS_DEVCTRL |= AT91C_OTGHS_ADDEN; + + // If the address is 0, the device returns to the Default state + if (address == 0) { + deviceState = USBD_STATE_DEFAULT; + } + // If the address is non-zero, the device enters the Address state + else { + deviceState = USBD_STATE_ADDRESS; + } +} + +//------------------------------------------------------------------------------ +/// Changes the device state from Address to Configured, or from Configured +/// to Address. +/// This method directly access the last received SETUP packet to decide on +/// what to do. +/// \param cfgnum configuration number +//------------------------------------------------------------------------------ +void USBD_SetConfiguration( unsigned char cfgnum ) +{ + TRACE_DEBUG_WP("SetCfg(%d) ", cfgnum); + + // Check the request + if( cfgnum != 0 ) { + + // Enter Configured state + deviceState = USBD_STATE_CONFIGURED; + } + // If the configuration number is zero, the device goes back to the Address + // state + else { + + // Go back to Address state + deviceState = USBD_STATE_ADDRESS; + + // Abort all transfers + OTGHS_DisableEndpoints(); + } +} + + +//------------------------------------------------------------------------------ +/// Enables the pull-up on the D+ line to connect the device to the USB. +//------------------------------------------------------------------------------ +void USBD_Connect( void ) +{ + TRACE_DEBUG_WP("Conn "); +#if defined(CHIP_USB_PULLUP_INTERNAL) + AT91C_BASE_OTGHS->OTGHS_DEVCTRL &= ~(unsigned int)AT91C_OTGHS_DETACH; +#else + #error "not defined" +#endif +} + +//------------------------------------------------------------------------------ +/// Disables the pull-up on the D+ line to disconnect the device from the bus. +//------------------------------------------------------------------------------ +void USBD_Disconnect( void ) +{ + TRACE_DEBUG_WP("Disc "); +#if defined(CHIP_USB_PULLUP_INTERNAL) + AT91C_BASE_OTGHS->OTGHS_DEVCTRL |= AT91C_OTGHS_DETACH; + +#else + #error "not defined" +#endif + // Device returns to the Powered state + if (deviceState > USBD_STATE_POWERED) { + + deviceState = USBD_STATE_POWERED; + } +} + +//------------------------------------------------------------------------------ +/// Certification test for High Speed device. +/// \param bIndex Test to be done +//------------------------------------------------------------------------------ +void USBD_Test( unsigned char bIndex ) +{ + char *pFifo; + unsigned char i; + + AT91C_BASE_OTGHS->OTGHS_DEVIDR &= ~(unsigned int)AT91C_OTGHS_SUSP; + AT91C_BASE_OTGHS->OTGHS_DEVCTRL |= AT91C_OTGHS_SPDCONF_HS; // remove suspend ? + + switch( bIndex ) { + case USBFeatureRequest_TESTPACKET: + TRACE_DEBUG_WP("TEST_PACKET "); + + AT91C_BASE_OTGHS->OTGHS_DEVDMA[1].OTGHS_DEVDMACONTROL = 0; // raz + AT91C_BASE_OTGHS->OTGHS_DEVDMA[2].OTGHS_DEVDMACONTROL = 0; // raz + + // Configure endpoint 2, 64 bytes, direction IN, type BULK, 1 bank + AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[2] = AT91C_OTGHS_EPT_SIZE_64 + | AT91C_OTGHS_EPT_DIR_IN + | AT91C_OTGHS_EPT_TYPE_BUL_EPT + | AT91C_OTGHS_BK_NUMBER_1; + // Check if the configuration is ok + AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[2] |= AT91C_OTGHS_ALLOC; + while((AT91C_BASE_OTGHS->OTGHS_DEVEPTISR[2]&AT91C_OTGHS_CFGOK)==0) { + } + + AT91C_BASE_OTGHS->OTGHS_DEVEPT |= AT91C_OTGHS_EPEN2; + + // Write FIFO + pFifo = (char*)((unsigned int *)AT91C_BASE_OTGHS_EPTFIFO + (EPT_VIRTUAL_SIZE * 2)); + for( i=0; iOTGHS_DEVCTRL |= AT91C_OTGHS_TSTPCKT; + // Send packet + AT91C_BASE_OTGHS->OTGHS_DEVEPTICR[2] = AT91C_OTGHS_TXINI; + AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[2] = AT91C_OTGHS_FIFOCON; + break; + + case USBFeatureRequest_TESTJ: + TRACE_DEBUG_WP("TEST_J "); + AT91C_BASE_OTGHS->OTGHS_DEVCTRL |= AT91C_OTGHS_TSTJ; + break; + + case USBFeatureRequest_TESTK: + TRACE_DEBUG_WP("TEST_K "); + AT91C_BASE_OTGHS->OTGHS_DEVCTRL |= AT91C_OTGHS_TSTK; + break; + + case USBFeatureRequest_TESTSE0NAK: + TRACE_DEBUG_WP("TEST_SEO_NAK "); + AT91C_BASE_OTGHS->OTGHS_DEVIDR = 0xFFFFFFFF; + break; + + case USBFeatureRequest_TESTSENDZLP: + //while( 0 != (AT91C_BASE_UDPHS->UDPHS_EPT[0].UDPHS_EPTSTA & AT91C_UDPHS_TX_PK_RDY ) ) {} + AT91C_BASE_OTGHS->OTGHS_DEVEPTICR[0] = AT91C_OTGHS_TXINI; + //while( 0 != (AT91C_BASE_UDPHS->UDPHS_EPT[0].UDPHS_EPTSTA & AT91C_UDPHS_TX_PK_RDY ) ) {} + TRACE_DEBUG_WP("SEND_ZLP "); + break; + } + TRACE_DEBUG_WP("\n\r"); +} + +//------------------------------------------------------------------------------ +/// Initializes the specified USB driver +/// This function initializes the current FIFO bank of endpoints, +/// configures the pull-up and VBus lines, disconnects the pull-up and +/// then trigger the Init callback. +//------------------------------------------------------------------------------ +void USBD_Init(void) +{ + // forceFS must not be used ! + unsigned int i; + + TRACE_DEBUG_WP("USBD Init()\n\r"); + + // Enable USB macro + *AT91C_OTGHS_CTRL |= AT91C_OTGHS_USBECTRL; + + // Automatic mode speed for device + *AT91C_OTGHS_DEVCTRL &= ~(unsigned int)AT91C_OTGHS_SPDCONF_FS; // Normal mode + + *AT91C_OTGHS_DEVCTRL &= ~(unsigned int)( AT91C_OTGHS_LS | AT91C_OTGHS_TSTJ + | AT91C_OTGHS_TSTK | AT91C_OTGHS_TSTPCKT + | AT91C_OTGHS_OPMODE2 ); // Normal mode + + AT91C_BASE_OTGHS->OTGHS_DEVCTRL = 0; + AT91C_BASE_OTGHS->OTGHS_HSTCTRL = 0; + + // Enable OTG pad + *AT91C_OTGHS_CTRL |= AT91C_OTGHS_OTGPADE; + + // Enable clock OTG pad + *AT91C_OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_FRZCLKCTRL; + + //Usb_disable(); + AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_USBECTRL; + AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_OTGPADE; + AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_FRZCLKCTRL; + //Usb_enable(); + AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_USBECTRL; + AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_OTGPADE; + AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_FRZCLKCTRL; + //Usb_select_device(); + AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_UIDE; + AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_UIMOD; + + // Device is in the Attached state + deviceState = USBD_STATE_SUSPENDED; + previousDeviceState = USBD_STATE_POWERED; + + + PMC_EnablePeripheral(AT91C_ID_OTGHS); + + // Reset endpoint structures + OTGHS_ResetEndpoints(); + + // Enables the USB Clock + OTGHS_EnableUsbClock(); + + //926C + // Enable USB macro and clear all other bit + AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_USBECTRL; + AT91C_BASE_OTGHS->OTGHS_CTRL = AT91C_OTGHS_USBECTRL; + + // Configure the pull-up on D+ and disconnect it + USBD_Disconnect(); + + // Enable clock OTG pad + AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_FRZCLKCTRL; + TRACE_DEBUG("AT91C_OTGHS_CTRL: 0x%X\n\r", AT91C_BASE_OTGHS->OTGHS_CTRL ); + + // Clear General IT + AT91C_BASE_OTGHS->OTGHS_SCR = 0x01FF; + + // Clear OTG Device IT + AT91C_BASE_OTGHS->OTGHS_DEVICR = 0xFF; + + // Clear OTG Host IT + AT91C_BASE_OTGHS->OTGHS_HSTICR = 0x7F; + + // Reset all Endpoints Fifos + AT91C_BASE_OTGHS->OTGHS_DEVEPT |= (0x7F<<16); + AT91C_BASE_OTGHS->OTGHS_DEVEPT &= ~(unsigned int)(0x7F<<16); + + // Disable all endpoints + AT91C_BASE_OTGHS->OTGHS_DEVEPT &= ~(unsigned int)0x7F; + + AT91C_BASE_OTGHS->OTGHS_TSTA2 = 0; + + // Device is in the Attached state + deviceState = USBD_STATE_SUSPENDED; + previousDeviceState = USBD_STATE_POWERED; + + // Automatic mode speed for device + AT91C_BASE_OTGHS->OTGHS_DEVCTRL &= ~(unsigned int)AT91C_OTGHS_SPDCONF_FS; + // Force Full Speed mode for device + //*AT91C_OTGHS_DEVCTRL = AT91C_OTGHS_SPDCONF_FS; + // Force High Speed mode for device + //*AT91C_OTGHS_DEVCTRL = AT91C_OTGHS_SPDCONF_HS; + + AT91C_BASE_OTGHS->OTGHS_DEVCTRL &= ~(unsigned int)( AT91C_OTGHS_LS + | AT91C_OTGHS_TSTJ + | AT91C_OTGHS_TSTK + | AT91C_OTGHS_TSTPCKT + | AT91C_OTGHS_OPMODE2 ); + + + // Automatic mode speed for host + AT91C_BASE_OTGHS->OTGHS_HSTCTRL &= ~(unsigned int)AT91C_OTGHS_SPDCONF_HST_FS; + // Force Full Speed mode for host + //AT91C_BASE_OTGHS->OTGHS_HSTCTRL = AT91C_OTGHS_SPDCONF_HST_FS; + // Force High Speed mode for host + //*AT91C_BASE_OTGHS->OTGHS_HSTCTRL = AT91C_OTGHS_SPDCONF_HST_HS; + + // Enable USB macro + AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_USBECTRL; + + // Enable the UID pin select + AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_UIDE; + + // Enable OTG pad + AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_OTGPADE; + + // Enable clock OTG pad + AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_FRZCLKCTRL; + + + // With OR without DMA !!! + // Initialization of DMA + for( i=1; i<=(unsigned int)((AT91C_BASE_OTGHS->OTGHS_IPFEATURES & AT91C_OTGHS_DMA_CHANNEL_NBR)>>4); i++ ) { + + // RESET endpoint canal DMA: + // DMA stop channel command + AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMACONTROL = 0; // STOP command + + // Disable endpoint + AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[i] = 0XFFFFFFFF; + + // Reset endpoint config + AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[i] = 0; + + // Reset DMA channel (Buff count and Control field) + AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMACONTROL = 0x02; // NON STOP command + + // Reset DMA channel 0 (STOP) + AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMACONTROL = 0; // STOP command + + // Clear DMA channel status (read the register for clear it) + AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMASTATUS = AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMASTATUS; + + } + + + // Configure interrupts + USBDCallbacks_Initialized(); + + AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_VBUSTI; + + TRACE_DEBUG("AT91C_OTGHS_CTRL: 0x%X\n\r", AT91C_BASE_OTGHS->OTGHS_CTRL ); + TRACE_DEBUG("AT91C_OTGHS_SR: 0x%X\n\r", AT91C_BASE_OTGHS->OTGHS_SR ); + + AT91C_BASE_OTGHS->OTGHS_DEVIER = AT91C_OTGHS_WAKEUP; + + TRACE_DEBUG("NUM_IT_MAX_DMA: 0x%X\n\r", NUM_IT_MAX_DMA ); + TRACE_DEBUG("NUM_IT_MAX: 0x%X\n\r", NUM_IT_MAX ); + +} + + +//------------------------------------------------------------------------------ +/// Returns the current state of the USB device. +/// \return Device current state. +//------------------------------------------------------------------------------ +unsigned char USBD_GetState( void ) +{ + return deviceState; +} + diff --git a/usb/device/core/USBD_UDP.c b/usb/device/core/USBD_UDP.c new file mode 100644 index 0000000..437d185 --- /dev/null +++ b/usb/device/core/USBD_UDP.c @@ -0,0 +1,1692 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Implementation of USB device functions on a UDP controller. + + See "USBD API Methods". +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBD.h" +#include "USBDCallbacks.h" +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "UDP register field values" +/// +/// This page lists the initialize values of UDP registers. +/// +/// !Values +/// - UDP_RXDATA + +/// Bit mask for both banks of the UDP_CSR register. +#define UDP_RXDATA (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1) +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "Endpoint states" +/// +/// This page lists the endpoint states. +/// +/// !States +// - UDP_ENDPOINT_DISABLED +// - UDP_ENDPOINT_HALTED +// - UDP_ENDPOINT_IDLE +// - UDP_ENDPOINT_SENDING +// - UDP_ENDPOINT_RECEIVING +// - UDP_ENDPOINT_SENDINGM +// - UDP_ENDPOINT_RECEIVINGM + +/// Endpoint states: Endpoint is disabled +#define UDP_ENDPOINT_DISABLED 0 +/// Endpoint states: Endpoint is halted (i.e. STALLs every request) +#define UDP_ENDPOINT_HALTED 1 +/// Endpoint states: Endpoint is idle (i.e. ready for transmission) +#define UDP_ENDPOINT_IDLE 2 +/// Endpoint states: Endpoint is sending data +#define UDP_ENDPOINT_SENDING 3 +/// Endpoint states: Endpoint is receiving data +#define UDP_ENDPOINT_RECEIVING 4 +/// Endpoint states: Endpoint is sending MBL +#define UDP_ENDPOINT_SENDINGM 5 +/// Endpoint states: Endpoint is receiving MBL +#define UDP_ENDPOINT_RECEIVINGM 6 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "UDP_CSR register access" +/// +/// This page lists the macroes to access UDP CSR register. +/// +/// !Macros +/// - CLEAR_CSR +/// - SET_CSR + +/// Bitmap for all status bits in CSR. +#define REG_NO_EFFECT_1_ALL AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 \ + |AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP \ + |AT91C_UDP_TXCOMP + +/// Clears the specified bit(s) in the UDP_CSR register. +/// \param endpoint The endpoint number of the CSR to process. +/// \param flags The bitmap to set to 1. +#define SET_CSR(endpoint, flags) \ + { \ + volatile unsigned int reg; \ + int timeOut = 200; \ + reg = AT91C_BASE_UDP->UDP_CSR[endpoint] ; \ + reg |= REG_NO_EFFECT_1_ALL; \ + reg |= (flags); \ + AT91C_BASE_UDP->UDP_CSR[endpoint] = reg; \ + while ( (AT91C_BASE_UDP->UDP_CSR[endpoint] & (flags)) != (flags)) \ + { \ + if (-- timeOut <= 0) break; \ + } \ + } + +/// Sets the specified bit(s) in the UDP_CSR register. +/// \param endpoint The endpoint number of the CSR to process. +/// \param flags The bitmap to clear to 0. +#define CLEAR_CSR(endpoint, flags) \ + { \ + volatile unsigned int reg; \ + reg = AT91C_BASE_UDP->UDP_CSR[endpoint]; \ + reg |= REG_NO_EFFECT_1_ALL; \ + reg &= ~(flags); \ + AT91C_BASE_UDP->UDP_CSR[endpoint] = reg; \ + while ( (AT91C_BASE_UDP->UDP_CSR[endpoint] & (flags)) == (flags)); \ + } +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +/// Describes an ongoing transfer on a UDP endpoint. +typedef struct { + + /// Pointer to a data buffer used for emission/reception. + char *pData; + /// Number of bytes which have been written into the UDP internal FIFO + /// buffers. + volatile int buffered; + /// Number of bytes which have been sent/received. + volatile int transferred; + /// Number of bytes which have not been buffered/transferred yet. + volatile int remaining; + /// Optional callback to invoke when the transfer completes. + volatile TransferCallback fCallback; + /// Optional argument to the callback function. + void *pArgument; +} Transfer; + +/// Describes Multi Buffer List transfer on a UDP endpoint. +typedef struct { + /// Pointer to frame list + USBDTransferBuffer *pMbl; + /// Pointer to last loaded buffer + USBDTransferBuffer *pLastLoaded; + /// List size + unsigned short listSize; + /// Current processing frame + unsigned short currBuffer; + /// First freed frame to re-use + unsigned short freedBuffer; + /// Frame setting, circle frame list + unsigned char circList; + /// All buffer listed is used + unsigned char allUsed; + /// Optional callback to invoke when the transfer completes. + MblTransferCallback fCallback; + /// Optional argument to the callback function. + void *pArgument; +} MblTransfer; + +//------------------------------------------------------------------------------ +/// Describes the state of an endpoint of the UDP controller. +//------------------------------------------------------------------------------ +typedef struct { + + /// Current endpoint state. + volatile unsigned char state; + /// Current reception bank (0 or 1). + volatile unsigned char bank; + /// Maximum packet size for the endpoint. + volatile unsigned short size; + /// Describes an ongoing transfer (if current state is either + /// or ) + union { + Transfer singleTransfer; + MblTransfer mblTransfer; + } transfer; +} Endpoint; + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +/// Holds the internal state for each endpoint of the UDP. +static Endpoint endpoints[CHIP_USB_NUMENDPOINTS]; + +/// Device current state. +static unsigned char deviceState; +/// Indicates the previous device state +static unsigned char previousDeviceState; + +//------------------------------------------------------------------------------ +// Internal Functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Enables the clock of the UDP peripheral. +//------------------------------------------------------------------------------ +static inline void UDP_EnablePeripheralClock(void) +{ + AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_UDP; +} + +//------------------------------------------------------------------------------ +/// Disables the UDP peripheral clock. +//------------------------------------------------------------------------------ +static inline void UDP_DisablePeripheralClock(void) +{ + AT91C_BASE_PMC->PMC_PCDR = 1 << AT91C_ID_UDP; +} + +//------------------------------------------------------------------------------ +/// Enables the 48MHz USB clock. +//------------------------------------------------------------------------------ +static inline void UDP_EnableUsbClock(void) +{ + AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP; +} + +//------------------------------------------------------------------------------ +/// Disables the 48MHz USB clock. +//------------------------------------------------------------------------------ +static inline void UDP_DisableUsbClock(void) +{ + AT91C_BASE_PMC->PMC_SCDR = AT91C_PMC_UDP; +} + +//------------------------------------------------------------------------------ +/// Enables the UDP transceiver. +//------------------------------------------------------------------------------ +static inline void UDP_EnableTransceiver(void) +{ + AT91C_BASE_UDP->UDP_TXVC &= ~AT91C_UDP_TXVDIS; +} + +//------------------------------------------------------------------------------ +/// Disables the UDP transceiver. +//------------------------------------------------------------------------------ +static inline void UDP_DisableTransceiver(void) +{ + AT91C_BASE_UDP->UDP_TXVC |= AT91C_UDP_TXVDIS; +} + +//------------------------------------------------------------------------------ +/// Handles a completed transfer on the given endpoint, invoking the +/// configured callback if any. +/// \param bEndpoint Number of the endpoint for which the transfer has completed. +/// \param bStatus Status code returned by the transfer operation +//------------------------------------------------------------------------------ +static void UDP_EndOfTransfer(unsigned char bEndpoint, char bStatus) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + + // Check that endpoint was sending or receiving data + if( (pEndpoint->state == UDP_ENDPOINT_RECEIVING) + || (pEndpoint->state == UDP_ENDPOINT_SENDING)) { + + Transfer *pTransfer = (Transfer *)&(pEndpoint->transfer); + + TRACE_DEBUG_WP("EoT "); + + // Endpoint returns in Idle state + pEndpoint->state = UDP_ENDPOINT_IDLE; + + // Invoke callback is present + if (pTransfer->fCallback != 0) { + + ((TransferCallback) pTransfer->fCallback) + (pTransfer->pArgument, + bStatus, + pTransfer->transferred, + pTransfer->remaining + pTransfer->buffered); + } + else { + TRACE_DEBUG_WP("NoCB "); + } + } + else if ( (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM) + || (pEndpoint->state == UDP_ENDPOINT_SENDINGM) ) { + + MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer); + + TRACE_DEBUG_WP("EoMT "); + + // Endpoint returns in Idle state + pEndpoint->state = UDP_ENDPOINT_IDLE; + // Invoke callback + if (pTransfer->fCallback != 0) { + + ((MblTransferCallback) pTransfer->fCallback) + (pTransfer->pArgument, + bStatus, + 0); + } + else { + TRACE_DEBUG_WP("NoCB "); + } + } +} + +//------------------------------------------------------------------------------ +/// Clears the correct reception flag (bank 0 or bank 1) of an endpoint +/// \param bEndpoint Index of endpoint +//------------------------------------------------------------------------------ +static void UDP_ClearRxFlag(unsigned char bEndpoint) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + + // Clear flag and change banks + if (pEndpoint->bank == 0) { + + CLEAR_CSR(bEndpoint, AT91C_UDP_RX_DATA_BK0); + // Swap bank if in dual-fifo mode + if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) { + + pEndpoint->bank = 1; + } + } + else { + + CLEAR_CSR(bEndpoint, AT91C_UDP_RX_DATA_BK1); + pEndpoint->bank = 0; + } +} + +//------------------------------------------------------------------------------ +/// Update multi-buffer-transfer descriptors. +/// \param pTransfer Pointer to instance MblTransfer. +/// \param size Size of bytes that processed. +/// \param forceEnd Force the buffer END. +/// \return 1 if current buffer ended. +//------------------------------------------------------------------------------ +static char UDP_MblUpdate(MblTransfer *pTransfer, + USBDTransferBuffer * pBi, + unsigned short size, + unsigned char forceEnd) +{ + // Update transfer descriptor + pBi->remaining -= size; + // Check if current buffer ended + if (pBi->remaining == 0 || forceEnd) { + + // Process to next buffer + if ((++ pTransfer->currBuffer) == pTransfer->listSize) { + if (pTransfer->circList) { + pTransfer->currBuffer = 0; + } + else { + pTransfer->allUsed = 1; + } + } + // All buffer in the list is processed + if (pTransfer->currBuffer == pTransfer->freedBuffer) { + pTransfer->allUsed = 1; + } + // Continue transfer, prepare for next operation + if (pTransfer->allUsed == 0) { + pBi = &pTransfer->pMbl[pTransfer->currBuffer]; + pBi->buffered = 0; + pBi->transferred = 0; + pBi->remaining = pBi->size; + } + return 1; + } + return 0; +} + +//------------------------------------------------------------------------------ +/// Transfers a data payload from the current tranfer buffer to the endpoint +/// FIFO +/// \param bEndpoint Number of the endpoint which is sending data. +//------------------------------------------------------------------------------ +static char UDP_MblWriteFifo(unsigned char bEndpoint) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer); + USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->currBuffer]); + signed int size; + + volatile unsigned char * pBytes; + volatile char bufferEnd = 1; + + // Get the number of bytes to send + size = pEndpoint->size; + if (size > pBi->remaining) { + + size = pBi->remaining; + } + + TRACE_DEBUG_WP("w%d.%d ", pTransfer->currBuffer, size); + if (size == 0) { + + return 1; + } + + pTransfer->pLastLoaded = pBi; + pBytes = &(pBi->pBuffer[pBi->transferred + pBi->buffered]); + pBi->buffered += size; + bufferEnd = UDP_MblUpdate(pTransfer, pBi, size, 0); + + // Write packet in the FIFO buffer + if (size) { + signed int c8 = size >> 3; + signed int c1 = size & 0x7; + //printf("%d[%x] ", pBi->transferred, pBytes); + for (; c8; c8 --) { + AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + + AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + } + for (; c1; c1 --) { + AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + } + } + return bufferEnd; +} +/* +//------------------------------------------------------------------------------ +/// Transfers a data payload from an endpoint FIFO to the current transfer +/// buffer, if NULL packet received, the current buffer is ENDed. +/// \param bEndpoint Endpoint number. +/// \param wPacketSize Size of received data packet +/// \return 1 if the buffer ENDed. +//------------------------------------------------------------------------------ +static char UDP_MblReadFifo(unsigned char bEndpoint, unsigned short wPacketSize) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer); + USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->currBuffer]); + char bufferEnd; + + // Check that the requested size is not bigger than the remaining transfer + if (wPacketSize > pTransfer->remaining) { + + pTransfer->buffered += wPacketSize - pTransfer->remaining; + wPacketSize = pTransfer->remaining; + } + + // Update transfer descriptor information + pBi->transferred += wPacketSize; + bufferEnd = UDP_MblUpdate(pTransfer, + wPacketSize, + (wPacketSize < pEndpoint->size)); + + // Retrieve packet + if (wPacketSize) { + unsigned char * pBytes = &pBi->pBuffer[pBi->transferred]; + signed int c8 = wPacketSize >> 3; + signed int c1 = wPacketSize & 0x7; + for (; c8; c8 --) { + *(pBytes ++) = AT91C_BASE_UDP->UDP_FDR[bEndpoint]; + *(pBytes ++) = AT91C_BASE_UDP->UDP_FDR[bEndpoint]; + *(pBytes ++) = AT91C_BASE_UDP->UDP_FDR[bEndpoint]; + *(pBytes ++) = AT91C_BASE_UDP->UDP_FDR[bEndpoint]; + + *(pBytes ++) = AT91C_BASE_UDP->UDP_FDR[bEndpoint]; + *(pBytes ++) = AT91C_BASE_UDP->UDP_FDR[bEndpoint]; + *(pBytes ++) = AT91C_BASE_UDP->UDP_FDR[bEndpoint]; + *(pBytes ++) = AT91C_BASE_UDP->UDP_FDR[bEndpoint]; + } + for (; c1; c1 --) { + *(pBytes ++) = AT91C_BASE_UDP->UDP_FDR[bEndpoint]; + } + } + return bufferEnd; +} +*/ +//------------------------------------------------------------------------------ +/// Transfers a data payload from the current tranfer buffer to the endpoint +/// FIFO +/// \param bEndpoint Number of the endpoint which is sending data. +//------------------------------------------------------------------------------ +static void UDP_WritePayload(unsigned char bEndpoint) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); + signed int size; + + // Get the number of bytes to send + size = pEndpoint->size; + if (size > pTransfer->remaining) { + + size = pTransfer->remaining; + } + + // Update transfer descriptor information + pTransfer->buffered += size; + pTransfer->remaining -= size; + + // Write packet in the FIFO buffer + while (size > 0) { + + AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pTransfer->pData); + pTransfer->pData++; + size--; + } +} + + +//------------------------------------------------------------------------------ +/// Transfers a data payload from an endpoint FIFO to the current transfer buffer +/// \param bEndpoint Endpoint number. +/// \param wPacketSize Size of received data packet +//------------------------------------------------------------------------------ +static void UDP_ReadPayload(unsigned char bEndpoint, int wPacketSize) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); + + // Check that the requested size is not bigger than the remaining transfer + if (wPacketSize > pTransfer->remaining) { + + pTransfer->buffered += wPacketSize - pTransfer->remaining; + wPacketSize = pTransfer->remaining; + } + + // Update transfer descriptor information + pTransfer->remaining -= wPacketSize; + pTransfer->transferred += wPacketSize; + + // Retrieve packet + while (wPacketSize > 0) { + + *(pTransfer->pData) = (char) AT91C_BASE_UDP->UDP_FDR[bEndpoint]; + pTransfer->pData++; + wPacketSize--; + } +} + +//------------------------------------------------------------------------------ +/// Received SETUP packet from endpoint 0 FIFO +/// \param pRequest Generic USB SETUP request sent over Control endpoints +//------------------------------------------------------------------------------ +static void UDP_ReadRequest(USBGenericRequest *pRequest) +{ + unsigned char *pData = (unsigned char *)pRequest; + unsigned int i; + + // Copy packet + for (i = 0; i < 8; i++) { + + *pData = (unsigned char) AT91C_BASE_UDP->UDP_FDR[0]; + pData++; + } +} + +//------------------------------------------------------------------------------ +/// Reset all endpoint transfer descriptors +//------------------------------------------------------------------------------ +static void UDP_ResetEndpoints( void ) +{ + Endpoint *pEndpoint; + Transfer *pTransfer; + unsigned char bEndpoint; + + // Reset the transfer descriptor of every endpoint + for (bEndpoint = 0; bEndpoint < CHIP_USB_NUMENDPOINTS; bEndpoint++) { + + pEndpoint = &(endpoints[bEndpoint]); + pTransfer = (Transfer*)&(pEndpoint->transfer); + + // Reset endpoint transfer descriptor + pTransfer->pData = 0; + pTransfer->transferred = -1; + pTransfer->buffered = -1; + pTransfer->remaining = -1; + pTransfer->fCallback = 0; + pTransfer->pArgument = 0; + + // Reset endpoint state + pEndpoint->bank = 0; + pEndpoint->state = UDP_ENDPOINT_DISABLED; + } +} + +//------------------------------------------------------------------------------ +/// Disable all endpoints (except control endpoint 0), aborting current +/// transfers if necessary +//------------------------------------------------------------------------------ +static void UDP_DisableEndpoints( void ) + +{ + unsigned char bEndpoint; + + // Disable each endpoint, terminating any pending transfer + // Control endpoint 0 is not disabled + for (bEndpoint = 1; bEndpoint < CHIP_USB_NUMENDPOINTS; bEndpoint++) { + + UDP_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED); + endpoints[bEndpoint].state = UDP_ENDPOINT_DISABLED; + } +} + +//------------------------------------------------------------------------------ +/// Checks if an ongoing transfer on an endpoint has been completed. +/// \param bEndpoint Endpoint number. +/// \return 1 if the current transfer on the given endpoint is complete; +/// otherwise 0. +//------------------------------------------------------------------------------ +static unsigned char UDP_IsTransferFinished(unsigned char bEndpoint) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); + + // Check if it is a Control endpoint + // -> Control endpoint must always finish their transfer with a zero-length + // packet + if ((AT91C_BASE_UDP->UDP_CSR[bEndpoint] & AT91C_UDP_EPTYPE) + == AT91C_UDP_EPTYPE_CTRL) { + + return (pTransfer->buffered < pEndpoint->size); + } + // Other endpoints only need to transfer all the data + else { + + return (pTransfer->buffered <= pEndpoint->size) + && (pTransfer->remaining == 0); + } +} + +//------------------------------------------------------------------------------ +/// Endpoint interrupt handler. +/// Handle IN/OUT transfers, received SETUP packets and STALLing +/// \param bEndpoint Index of endpoint +//------------------------------------------------------------------------------ +static void UDP_EndpointHandler(unsigned char bEndpoint) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); + MblTransfer *pMblt = (MblTransfer*)&(pEndpoint->transfer); + unsigned int status = AT91C_BASE_UDP->UDP_CSR[bEndpoint]; + unsigned short wPacketSize; + USBGenericRequest request; + + TRACE_DEBUG_WP("E%d ", bEndpoint); + TRACE_DEBUG_WP("st:0x%X ", status); + + // Handle interrupts + // IN packet sent + if ((status & AT91C_UDP_TXCOMP) != 0) { + + TRACE_DEBUG_WP("Wr "); + + // Check that endpoint was in MBL Sending state + if (pEndpoint->state == UDP_ENDPOINT_SENDINGM) { + + USBDTransferBuffer * pMbli = pMblt->pLastLoaded; + unsigned char bufferEnd = 0; + + TRACE_DEBUG_WP("TxM%d.%d ", pMblt->allUsed, pMbli->buffered); + + // End of transfer ? + if (pMblt->allUsed && pMbli->buffered == 0) { + + pMbli->transferred += pMbli->buffered; + pMbli->buffered = 0; + + // Disable interrupt + AT91C_BASE_UDP->UDP_IDR = 1 << bEndpoint; + UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + CLEAR_CSR(bEndpoint, AT91C_UDP_TXCOMP); + } + else { + + // Transfer remaining data + TRACE_DEBUG_WP("%d ", pEndpoint->size); + + if (pMbli->buffered > pEndpoint->size) { + pMbli->transferred += pEndpoint->size; + pMbli->buffered -= pEndpoint->size; + } + else { + pMbli->transferred += pMbli->buffered; + pMbli->buffered = 0; + } + + // Send next packet + if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) == 1) { + + // No double buffering + bufferEnd = UDP_MblWriteFifo(bEndpoint); + SET_CSR(bEndpoint, AT91C_UDP_TXPKTRDY); + CLEAR_CSR(bEndpoint, AT91C_UDP_TXCOMP); + } + else { + // Double buffering + SET_CSR(bEndpoint, AT91C_UDP_TXPKTRDY); + CLEAR_CSR(bEndpoint, AT91C_UDP_TXCOMP); + bufferEnd = UDP_MblWriteFifo(bEndpoint); + } + + if (bufferEnd && pMblt->fCallback) { + ((MblTransferCallback) pTransfer->fCallback) + (pTransfer->pArgument, + USBD_STATUS_PARTIAL_DONE, + 1); + } + } + } + // Check that endpoint was in Sending state + else if (pEndpoint->state == UDP_ENDPOINT_SENDING) { + + // End of transfer ? + if (UDP_IsTransferFinished(bEndpoint)) { + + pTransfer->transferred += pTransfer->buffered; + pTransfer->buffered = 0; + + // Disable interrupt if this is not a control endpoint + if ((status & AT91C_UDP_EPTYPE) != AT91C_UDP_EPTYPE_CTRL) { + + AT91C_BASE_UDP->UDP_IDR = 1 << bEndpoint; + } + + UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + CLEAR_CSR(bEndpoint, AT91C_UDP_TXCOMP); + } + else { + + // Transfer remaining data + TRACE_DEBUG_WP(" %d ", pEndpoint->size); + + pTransfer->transferred += pEndpoint->size; + pTransfer->buffered -= pEndpoint->size; + + // Send next packet + if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) == 1) { + + // No double buffering + UDP_WritePayload(bEndpoint); + SET_CSR(bEndpoint, AT91C_UDP_TXPKTRDY); + CLEAR_CSR(bEndpoint, AT91C_UDP_TXCOMP); + } + else { + // Double buffering + SET_CSR(bEndpoint, AT91C_UDP_TXPKTRDY); + CLEAR_CSR(bEndpoint, AT91C_UDP_TXCOMP); + UDP_WritePayload(bEndpoint); + } + } + } + else { + // Acknowledge interrupt + TRACE_ERROR("Error Wr%d, %x\n\r", bEndpoint, pEndpoint->state); + CLEAR_CSR(bEndpoint, AT91C_UDP_TXCOMP); + } + } + + // OUT packet received + if ((status & UDP_RXDATA) != 0) { + + TRACE_DEBUG_WP("Rd "); + + // Check that the endpoint is in Receiving state + if (pEndpoint->state != UDP_ENDPOINT_RECEIVING) { + + // Check if an ACK has been received on a Control endpoint + if (((status & AT91C_UDP_EPTYPE) == AT91C_UDP_EPTYPE_CTRL) + && ((status & AT91C_UDP_RXBYTECNT) == 0)) { + + // Acknowledge the data and finish the current transfer + UDP_ClearRxFlag(bEndpoint); + UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + } + // Check if the data has been STALLed + else if ((status & AT91C_UDP_FORCESTALL) != 0) { + + // Discard STALLed data + TRACE_DEBUG_WP("Discard "); + UDP_ClearRxFlag(bEndpoint); + } + // NAK the data + else { + + TRACE_DEBUG_WP("Nak "); + AT91C_BASE_UDP->UDP_IDR = 1 << bEndpoint; + } + } + // Endpoint is in Read state + else { + + // Retrieve data and store it into the current transfer buffer + wPacketSize = (unsigned short) (status >> 16); + TRACE_DEBUG_WP("%d ", wPacketSize); + UDP_ReadPayload(bEndpoint, wPacketSize); + UDP_ClearRxFlag(bEndpoint); + + // Check if the transfer is finished + if ((pTransfer->remaining == 0) || (wPacketSize < pEndpoint->size)) { + + // Disable interrupt if this is not a control endpoint + if ((status & AT91C_UDP_EPTYPE) != AT91C_UDP_EPTYPE_CTRL) { + + AT91C_BASE_UDP->UDP_IDR = 1 << bEndpoint; + } + UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + } + } + } + + // STALL sent + if ((status & AT91C_UDP_STALLSENT) != 0) { + + TRACE_WARNING( "Sta 0x%X [%d] ", status, bEndpoint); + + // If the endpoint is not halted, clear the STALL condition + CLEAR_CSR(bEndpoint, AT91C_UDP_STALLSENT); + if (pEndpoint->state != UDP_ENDPOINT_HALTED) { + + TRACE_WARNING( "_ " ); + CLEAR_CSR(bEndpoint, AT91C_UDP_FORCESTALL); + } + } + + // SETUP packet received + if ((status & AT91C_UDP_RXSETUP) != 0) { + + TRACE_DEBUG_WP("Stp "); + + // If a transfer was pending, complete it + // Handles the case where during the status phase of a control write + // transfer, the host receives the device ZLP and ack it, but the ack + // is not received by the device + if ((pEndpoint->state == UDP_ENDPOINT_RECEIVING) + || (pEndpoint->state == UDP_ENDPOINT_SENDING)) { + + UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + } + // Copy the setup packet + UDP_ReadRequest(&request); + + // Set the DIR bit before clearing RXSETUP in Control IN sequence + if (USBGenericRequest_GetDirection(&request) == USBGenericRequest_IN) { + + SET_CSR(bEndpoint, AT91C_UDP_DIR); + } + // Acknowledge setup packet + CLEAR_CSR(bEndpoint, AT91C_UDP_RXSETUP); + + // Forward the request to the upper layer + USBDCallbacks_RequestReceived(&request); + } + +} + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +/// USB device interrupt handler +/// Manages device resume, suspend, end of bus reset. +/// Forwards endpoint interrupts to the appropriate handler. +//------------------------------------------------------------------------------ +void USBD_IrqHandler(void) +{ + unsigned int status; + int eptnum = 0; + + // Get interrupt status + // Some interrupts may get masked depending on the device state + status = AT91C_BASE_UDP->UDP_ISR; + status &= AT91C_BASE_UDP->UDP_IMR; + + if (deviceState < USBD_STATE_POWERED) { + + status &= AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM; + AT91C_BASE_UDP->UDP_ICR = ~status; + } + + // Return immediately if there is no interrupt to service + if (status == 0) { + + TRACE_DEBUG_WP(".\n\r"); + return; + } + + // Toggle USB LED if the device is active + if (deviceState >= USBD_STATE_POWERED) { + + LED_Set(USBD_LEDUSB); + } + + // Service interrupts + + //// Start Of Frame (SOF) + //if (ISSET(dStatus, AT91C_UDP_SOFINT)) { + // + // TRACE_DEBUG("SOF"); + // + // // Invoke the SOF callback + // USB_StartOfFrameCallback(pUsb); + // + // // Acknowledge interrupt + // AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_SOFINT; + // dStatus &= ~AT91C_UDP_SOFINT; + //} + + // Resume + if ((status & (AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM)) != 0) { + + TRACE_INFO_WP("Res "); + + // Don't do anything if the device was not suspended + if (deviceState == USBD_STATE_SUSPENDED) { + + // The device enters its previous state + UDP_EnablePeripheralClock(); + UDP_EnableUsbClock(); + + // Enable the transceiver if the device was past the Default + // state + deviceState = previousDeviceState; + if (deviceState >= USBD_STATE_DEFAULT) { + + UDP_EnableTransceiver(); + + // Invoke the Resume callback + USBDCallbacks_Resumed(); + } + } + + // Clear and disable resume interrupts + AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_WAKEUP + | AT91C_UDP_RXRSM + | AT91C_UDP_RXSUSP; + AT91C_BASE_UDP->UDP_IDR = AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM; + } + + // Suspend + // This interrupt is always treated last (hence the '==') + if (status == AT91C_UDP_RXSUSP) { + + TRACE_INFO_WP("Susp "); + + // Don't do anything if the device is already suspended + if (deviceState != USBD_STATE_SUSPENDED) { + + // The device enters the Suspended state + // Enable wakeup + AT91C_BASE_UDP->UDP_IER = AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM; + + // Acknowledge interrupt + AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_RXSUSP; + + // Switch to the Suspended state + previousDeviceState = deviceState; + deviceState = USBD_STATE_SUSPENDED; + // Invoke the Suspended callback + USBDCallbacks_Suspended(); + UDP_DisableTransceiver(); + UDP_DisablePeripheralClock(); + UDP_DisableUsbClock(); + } + } + #if 0 + // Resume + else if ((status & (AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM)) != 0) { + + TRACE_INFO_WP("Res "); + + // Don't do anything if the device was not suspended + if (deviceState == USBD_STATE_SUSPENDED) { + + // The device enters its previous state + UDP_EnablePeripheralClock(); + UDP_EnableUsbClock(); + + // Enable the transceiver if the device was past the Default + // state + deviceState = previousDeviceState; + if (deviceState >= USBD_STATE_DEFAULT) { + + UDP_EnableTransceiver(); + + // Invoke the Resume callback + USBDCallbacks_Resumed(); + } + } + + // Clear and disable resume interrupts + AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_WAKEUP + | AT91C_UDP_RXRSM + | AT91C_UDP_RXSUSP; + AT91C_BASE_UDP->UDP_IDR = AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM; + } + #endif + // End of bus reset + else if ((status & AT91C_UDP_ENDBUSRES) != 0) { + + TRACE_INFO_WP("EoBRes "); + + // The device enters the Default state + deviceState = USBD_STATE_DEFAULT; + UDP_EnableTransceiver(); + UDP_ResetEndpoints(); + UDP_DisableEndpoints(); + USBD_ConfigureEndpoint(0); + + // Flush and enable the Suspend interrupt + AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_WAKEUP + | AT91C_UDP_RXRSM + | AT91C_UDP_RXSUSP; + AT91C_BASE_UDP->UDP_IER = AT91C_UDP_RXSUSP; + + //// Enable the Start Of Frame (SOF) interrupt if needed + //if (pUsb->pCallbacks->startOfFrame != 0) { + // + // AT91C_BASE_UDP->UDP_IER = AT91C_UDP_SOFINT; + //} + + // Invoke the Reset callback + USBDCallbacks_Reset(); + + // Acknowledge end of bus reset interrupt + AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_ENDBUSRES; + } + // Endpoint interrupts + else { + + status &= ((1 << CHIP_USB_NUMENDPOINTS) - 1); + while (status != 0) { + + // Check if endpoint has a pending interrupt + if ((status & (1 << eptnum)) != 0) { + + UDP_EndpointHandler(eptnum); + status &= ~(1 << eptnum); + + if (status != 0) { + + TRACE_INFO_WP("\n\r - "); + } + } + eptnum++; + } + } + + // Toggle LED back to its previous state + TRACE_DEBUG_WP("!"); + TRACE_INFO_WP("\n\r"); + if (deviceState >= USBD_STATE_POWERED) { + + LED_Clear(USBD_LEDUSB); + } +} + +//------------------------------------------------------------------------------ +/// Configures an endpoint according to its Endpoint Descriptor. +/// \param pDescriptor Pointer to an Endpoint descriptor. +//------------------------------------------------------------------------------ +void USBD_ConfigureEndpoint(const USBEndpointDescriptor *pDescriptor) +{ + Endpoint *pEndpoint; + unsigned char bEndpoint; + unsigned char bType; + unsigned char bEndpointDir; + + // NULL descriptor -> Control endpoint 0 + if (pDescriptor == 0) { + + bEndpoint = 0; + pEndpoint = &(endpoints[bEndpoint]); + bType= USBEndpointDescriptor_CONTROL; + bEndpointDir = 0; + pEndpoint->size = CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0); + } + else { + + bEndpoint = USBEndpointDescriptor_GetNumber(pDescriptor); + pEndpoint = &(endpoints[bEndpoint]); + bType = USBEndpointDescriptor_GetType(pDescriptor); + bEndpointDir = USBEndpointDescriptor_GetDirection(pDescriptor); + pEndpoint->size = USBEndpointDescriptor_GetMaxPacketSize(pDescriptor); + } + + // Abort the current transfer is the endpoint was configured and in + // Write or Read state + if ((pEndpoint->state == UDP_ENDPOINT_RECEIVING) + || (pEndpoint->state == UDP_ENDPOINT_SENDING) + || (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM) + || (pEndpoint->state == UDP_ENDPOINT_SENDINGM)) { + + UDP_EndOfTransfer(bEndpoint, USBD_STATUS_RESET); + } + pEndpoint->state = UDP_ENDPOINT_IDLE; + + // Reset Endpoint Fifos + AT91C_BASE_UDP->UDP_RSTEP |= (1 << bEndpoint); + AT91C_BASE_UDP->UDP_RSTEP &= ~(1 << bEndpoint); + + // Configure endpoint + SET_CSR(bEndpoint, (unsigned int)AT91C_UDP_EPEDS + | (bType << 8) | (bEndpointDir << 10)); + if (bType != USBEndpointDescriptor_CONTROL) { + + } + else { + + AT91C_BASE_UDP->UDP_IER = (1 << bEndpoint); + } + + TRACE_INFO_WP("CfgEpt%d ", bEndpoint); +} + +//------------------------------------------------------------------------------ +/// Sends data through a USB endpoint. Sets up the transfer descriptor, +/// writes one or two data payloads (depending on the number of FIFO bank +/// for the endpoint) and then starts the actual transfer. The operation is +/// complete when all the data has been sent. +/// +/// *If the size of the buffer is greater than the size of the endpoint +/// (or twice the size if the endpoint has two FIFO banks), then the buffer +/// must be kept allocated until the transfer is finished*. This means that +/// it is not possible to declare it on the stack (i.e. as a local variable +/// of a function which returns after starting a transfer). +/// +/// \param bEndpoint Endpoint number. +/// \param pData Pointer to a buffer with the data to send. +/// \param dLength Size of the data buffer. +/// \param fCallback Optional callback function to invoke when the transfer is +/// complete. +/// \param pArgument Optional argument to the callback function. +/// \return USBD_STATUS_SUCCESS if the transfer has been started; +/// otherwise, the corresponding error status code. +//------------------------------------------------------------------------------ +char USBD_Write( unsigned char bEndpoint, + const void *pData, + unsigned int dLength, + TransferCallback fCallback, + void *pArgument ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); + + // Check that the endpoint is in Idle state + if (pEndpoint->state != UDP_ENDPOINT_IDLE) { + + return USBD_STATUS_LOCKED; + } + TRACE_DEBUG_WP("Write%d(%d) ", bEndpoint, dLength); + + // Setup the transfer descriptor + pTransfer->pData = (void *) pData; + pTransfer->remaining = dLength; + pTransfer->buffered = 0; + pTransfer->transferred = 0; + pTransfer->fCallback = fCallback; + pTransfer->pArgument = pArgument; + + // Send the first packet + pEndpoint->state = UDP_ENDPOINT_SENDING; + while((AT91C_BASE_UDP->UDP_CSR[bEndpoint]&AT91C_UDP_TXPKTRDY)==AT91C_UDP_TXPKTRDY); + UDP_WritePayload(bEndpoint); + SET_CSR(bEndpoint, AT91C_UDP_TXPKTRDY); + + // If double buffering is enabled and there is data remaining, + // prepare another packet + if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) && (pTransfer->remaining > 0)) { + + UDP_WritePayload(bEndpoint); + } + + // Enable interrupt on endpoint + AT91C_BASE_UDP->UDP_IER = 1 << bEndpoint; + + return USBD_STATUS_SUCCESS; +} + +//------------------------------------------------------------------------------ +/// Sends data frames through a USB endpoint. Sets up the transfer descriptor +/// list, writes one or two data payloads (depending on the number of FIFO bank +/// for the endpoint) and then starts the actual transfer. The operation is +/// complete when all the data has been sent. +/// +/// *If the size of the frame is greater than the size of the endpoint +/// (or twice the size if the endpoint has two FIFO banks), then the buffer +/// must be kept allocated until the frame is finished*. This means that +/// it is not possible to declare it on the stack (i.e. as a local variable +/// of a function which returns after starting a transfer). +/// +/// \param bEndpoint Endpoint number. +/// \param pMbl Pointer to a frame (USBDTransferBuffer) list that describes +/// the buffer list to send. +/// \param wListSize Size of the frame list. +/// \param bCircList Circle the list. +/// \param wStartNdx For circled list only, the first buffer index to transfer. +/// \param fCallback Optional callback function to invoke when the transfer is +/// complete. +/// \param pArgument Optional argument to the callback function. +/// \return USBD_STATUS_SUCCESS if the transfer has been started; +/// otherwise, the corresponding error status code. +/// \see USBDTransferBuffer, MblTransferCallback, USBD_MblReuse +//------------------------------------------------------------------------------ +char USBD_MblWrite( unsigned char bEndpoint, + void *pMbl, + unsigned short wListSize, + unsigned char bCircList, + unsigned short wStartNdx, + MblTransferCallback fCallback, + void *pArgument ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer); + unsigned short i; + + // EP0 is not suitable for Mbl + if (bEndpoint == 0) { + + return USBD_STATUS_INVALID_PARAMETER; + } + + // Check that the endpoint is in Idle state + if (pEndpoint->state != UDP_ENDPOINT_IDLE) { + + return USBD_STATUS_LOCKED; + } + pEndpoint->state = UDP_ENDPOINT_SENDINGM; + + TRACE_DEBUG_WP("WriteM%d(0x%x,%d) ", bEndpoint, pMbl, wListSize); + + // Start from first if not circled list + if (!bCircList) wStartNdx = 0; + + // Setup the transfer descriptor + pTransfer->pMbl = (USBDTransferBuffer*)pMbl; + pTransfer->listSize = wListSize; + pTransfer->fCallback = fCallback; + pTransfer->pArgument = pArgument; + pTransfer->currBuffer = wStartNdx; + pTransfer->freedBuffer = 0; + pTransfer->pLastLoaded = &(((USBDTransferBuffer*)pMbl)[wStartNdx]); + pTransfer->circList = bCircList; + pTransfer->allUsed = 0; + + // Clear all buffer + for (i = 0; i < wListSize; i ++) { + + pTransfer->pMbl[i].transferred = 0; + pTransfer->pMbl[i].buffered = 0; + pTransfer->pMbl[i].remaining = pTransfer->pMbl[i].size; + } + + // Send the first packet + while((AT91C_BASE_UDP->UDP_CSR[bEndpoint]&AT91C_UDP_TXPKTRDY) + ==AT91C_UDP_TXPKTRDY); + UDP_MblWriteFifo(bEndpoint); + SET_CSR(bEndpoint, AT91C_UDP_TXPKTRDY); + + // If double buffering is enabled and there is data remaining, + // prepare another packet + if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) + && (pTransfer->pMbl[pTransfer->currBuffer].remaining > 0)) { + + UDP_MblWriteFifo(bEndpoint); + } + + // Enable interrupt on endpoint + AT91C_BASE_UDP->UDP_IER = 1 << bEndpoint; + + return USBD_STATUS_SUCCESS; +} + +//------------------------------------------------------------------------------ +/// Reads incoming data on an USB endpoint This methods sets the transfer +/// descriptor and activate the endpoint interrupt. The actual transfer is +/// then carried out by the endpoint interrupt handler. The Read operation +/// finishes either when the buffer is full, or a short packet (inferior to +/// endpoint maximum size) is received. +/// +/// *The buffer must be kept allocated until the transfer is finished*. +/// \param bEndpoint Endpoint number. +/// \param pData Pointer to a data buffer. +/// \param dLength Size of the data buffer in bytes. +/// \param fCallback Optional end-of-transfer callback function. +/// \param pArgument Optional argument to the callback function. +/// \return USBD_STATUS_SUCCESS if the read operation has been started; +/// otherwise, the corresponding error code. +//------------------------------------------------------------------------------ +char USBD_Read(unsigned char bEndpoint, + void *pData, + unsigned int dLength, + TransferCallback fCallback, + void *pArgument) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); + + // Return if the endpoint is not in IDLE state + if (pEndpoint->state != UDP_ENDPOINT_IDLE) { + + return USBD_STATUS_LOCKED; + } + + // Endpoint enters Receiving state + pEndpoint->state = UDP_ENDPOINT_RECEIVING; + TRACE_DEBUG_WP("Read%d(%d) ", bEndpoint, dLength); + + // Set the transfer descriptor + pTransfer->pData = pData; + pTransfer->remaining = dLength; + pTransfer->buffered = 0; + pTransfer->transferred = 0; + pTransfer->fCallback = fCallback; + pTransfer->pArgument = pArgument; + + // Enable interrupt on endpoint + AT91C_BASE_UDP->UDP_IER = 1 << bEndpoint; + + return USBD_STATUS_SUCCESS; +} + +//------------------------------------------------------------------------------ +/// Reuse first used/released buffer with new buffer address and size to be used +/// in transfer again. Only valid when frame list is ringed. Can be used for +/// both read & write. +/// \param bEndpoint Endpoint number. +/// \param pNewBuffer Pointer to new buffer with data to send (0 to keep last). +/// \param wNewSize Size of the data buffer +//------------------------------------------------------------------------------ +char USBD_MblReuse( unsigned char bEndpoint, + unsigned char *pNewBuffer, + unsigned short wNewSize ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer); + USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->freedBuffer]); + + TRACE_DEBUG_WP("MblReuse(%d), st%x, circ%d\n\r", + bEndpoint, pEndpoint->state, pTransfer->circList); + + // Only for Multi-buffer-circle list + if (bEndpoint != 0 + && (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM + || pEndpoint->state == UDP_ENDPOINT_SENDINGM) + && pTransfer->circList) { + } + else { + + return USBD_STATUS_WRONG_STATE; + } + + // Check if there is freed buffer + if (pTransfer->freedBuffer == pTransfer->currBuffer + && !pTransfer->allUsed) { + + return USBD_STATUS_LOCKED; + } + + // Update transfer information + if ((++ pTransfer->freedBuffer) == pTransfer->listSize) + pTransfer->freedBuffer = 0; + if (pNewBuffer) { + pBi->pBuffer = pNewBuffer; + pBi->size = wNewSize; + } + pBi->buffered = 0; + pBi->transferred = 0; + pBi->remaining = pBi->size; + + // At least one buffer is not processed + pTransfer->allUsed = 0; + return USBD_STATUS_SUCCESS; +} + +//------------------------------------------------------------------------------ +/// Sets the HALT feature on the given endpoint (if not already in this state). +/// \param bEndpoint Endpoint number. +//------------------------------------------------------------------------------ +void USBD_Halt(unsigned char bEndpoint) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + + // Check that endpoint is enabled and not already in Halt state + if ((pEndpoint->state != UDP_ENDPOINT_DISABLED) + && (pEndpoint->state != UDP_ENDPOINT_HALTED)) { + + TRACE_DEBUG_WP("Halt%d ", bEndpoint); + + // Abort the current transfer if necessary + UDP_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED); + + // Put endpoint into Halt state + SET_CSR(bEndpoint, AT91C_UDP_FORCESTALL); + pEndpoint->state = UDP_ENDPOINT_HALTED; + + // Enable the endpoint interrupt + AT91C_BASE_UDP->UDP_IER = 1 << bEndpoint; + } +} + +//------------------------------------------------------------------------------ +/// Clears the Halt feature on the given endpoint. +/// \param bEndpoint Index of endpoint +//------------------------------------------------------------------------------ +void USBD_Unhalt(unsigned char bEndpoint) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + + // Check if the endpoint is enabled + //if (pEndpoint->state != UDP_ENDPOINT_DISABLED) { + if (pEndpoint->state == UDP_ENDPOINT_HALTED) { + + TRACE_DEBUG_WP("Unhalt%d ", bEndpoint); + + // Return endpoint to Idle state + pEndpoint->state = UDP_ENDPOINT_IDLE; + + // Clear FORCESTALL flag + CLEAR_CSR(bEndpoint, AT91C_UDP_FORCESTALL); + + // Reset Endpoint Fifos, beware this is a 2 steps operation + AT91C_BASE_UDP->UDP_RSTEP |= 1 << bEndpoint; + AT91C_BASE_UDP->UDP_RSTEP &= ~(1 << bEndpoint); + } +} + +//------------------------------------------------------------------------------ +/// Returns the current Halt status of an endpoint. +/// \param bEndpoint Index of endpoint +/// \return 1 if the endpoint is currently halted; otherwise 0 +//------------------------------------------------------------------------------ +unsigned char USBD_IsHalted(unsigned char bEndpoint) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + unsigned char status = 0; + + if (pEndpoint->state == UDP_ENDPOINT_HALTED) { + + status = 1; + } + return( status ); +} + +//------------------------------------------------------------------------------ +/// Indicates if the device is running in high or full-speed. Always returns 0 +/// since UDP does not support high-speed mode. +//------------------------------------------------------------------------------ +unsigned char USBD_IsHighSpeed(void) +{ + return 0; +} + +//------------------------------------------------------------------------------ +/// Causes the given endpoint to acknowledge the next packet it receives +/// with a STALL handshake. +/// \param bEndpoint Endpoint number. +/// \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED. +//------------------------------------------------------------------------------ +unsigned char USBD_Stall(unsigned char bEndpoint) + +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + + // Check that endpoint is in Idle state + if (pEndpoint->state != UDP_ENDPOINT_IDLE) { + + TRACE_WARNING("UDP_Stall: Endpoint%d locked\n\r", bEndpoint); + return USBD_STATUS_LOCKED; + } + + TRACE_DEBUG_WP("Stall%d ", bEndpoint); + SET_CSR(bEndpoint, AT91C_UDP_FORCESTALL); + + return USBD_STATUS_SUCCESS; +} + +//------------------------------------------------------------------------------ +/// Starts a remote wake-up procedure. +//------------------------------------------------------------------------------ +void USBD_RemoteWakeUp(void) +{ + // Device is NOT suspended + if (deviceState != USBD_STATE_SUSPENDED) { + + TRACE_WARNING("USBD_RemoteWakeUp: Device is not suspended\n\r"); + return; + } + + + UDP_EnablePeripheralClock(); + UDP_EnableUsbClock(); + UDP_EnableTransceiver(); + + TRACE_INFO_WP("RWUp "); + + // Activates a remote wakeup (edge on ESR), then clear ESR + AT91C_BASE_UDP->UDP_GLBSTATE |= AT91C_UDP_ESR; + AT91C_BASE_UDP->UDP_GLBSTATE &= ~AT91C_UDP_ESR; +} + +//------------------------------------------------------------------------------ +/// Sets the device address to the given value. +/// \param address New device address. +//------------------------------------------------------------------------------ +void USBD_SetAddress(unsigned char address) +{ + TRACE_INFO_WP("SetAddr(%d) ", address); + + // Set address + AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN | address; + + // If the address is 0, the device returns to the Default state + if (address == 0) { + + AT91C_BASE_UDP->UDP_GLBSTATE = 0; + deviceState = USBD_STATE_DEFAULT; + } + // If the address is non-zero, the device enters the Address state + else { + + AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN; + deviceState = USBD_STATE_ADDRESS; + } +} + +//------------------------------------------------------------------------------ +/// Sets the current device configuration. +/// \param cfgnum - Configuration number to set. +//------------------------------------------------------------------------------ +void USBD_SetConfiguration(unsigned char cfgnum) +{ + TRACE_INFO_WP("SetCfg(%d) ", cfgnum); + + // If the configuration number if non-zero, the device enters the + // Configured state + if (cfgnum != 0) { + + // Enter Configured state + deviceState = USBD_STATE_CONFIGURED; + AT91C_BASE_UDP->UDP_GLBSTATE |= AT91C_UDP_CONFG; + } + // If the configuration number is zero, the device goes back to the Address + // state + else { + + deviceState = USBD_STATE_ADDRESS; + AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN; + + // Abort all transfers + UDP_DisableEndpoints(); + } +} + +//------------------------------------------------------------------------------ +/// Connects the pull-up on the D+ line of the USB. +//------------------------------------------------------------------------------ +void USBD_Connect(void) +{ + TRACE_DEBUG("Conn "); + +#if defined(CHIP_USB_PULLUP_EXTERNAL) + const Pin pinPullUp = PIN_USB_PULLUP; + if (pinPullUp.type == PIO_OUTPUT_0) { + + PIO_Set(&pinPullUp); + } + else { + + PIO_Clear(&pinPullUp); + } +#elif defined(CHIP_USB_PULLUP_INTERNAL) + AT91C_BASE_UDP->UDP_TXVC |= AT91C_UDP_PUON; +#elif defined(CHIP_USB_PULLUP_MATRIX) + AT91C_BASE_MATRIX->MATRIX_USBPCR |= AT91C_MATRIX_USBPCR_PUON; +#elif !defined(CHIP_USB_PULLUP_ALWAYSON) + #error Unsupported pull-up type. +#endif +} + +//------------------------------------------------------------------------------ +/// Disconnects the pull-up from the D+ line of the USB. +//------------------------------------------------------------------------------ +void USBD_Disconnect(void) +{ + TRACE_DEBUG("Disc "); + +#if defined(CHIP_USB_PULLUP_EXTERNAL) + const Pin pinPullUp = PIN_USB_PULLUP; + if (pinPullUp.type == PIO_OUTPUT_0) { + + PIO_Clear(&pinPullUp); + } + else { + + PIO_Set(&pinPullUp); + } +#elif defined(CHIP_USB_PULLUP_INTERNAL) + AT91C_BASE_UDP->UDP_TXVC &= ~AT91C_UDP_PUON; +#elif defined(CHIP_USB_PULLUP_MATRIX) + AT91C_BASE_MATRIX->MATRIX_USBPCR &= ~AT91C_MATRIX_USBPCR_PUON; +#elif !defined(CHIP_USB_PULLUP_ALWAYSON) + #error Unsupported pull-up type. +#endif + + // Device returns to the Powered state + if (deviceState > USBD_STATE_POWERED) { + + deviceState = USBD_STATE_POWERED; + } + + if (previousDeviceState > USBD_STATE_POWERED) { + + previousDeviceState = USBD_STATE_POWERED; + } +} + +//------------------------------------------------------------------------------ +/// Initializes the USB driver. +//------------------------------------------------------------------------------ +void USBD_Init(void) +{ + TRACE_INFO_WP("USBD_Init\n\r"); + + // Reset endpoint structures + UDP_ResetEndpoints(); + + // Configure the pull-up on D+ and disconnect it +#if defined(CHIP_USB_PULLUP_EXTERNAL) + const Pin pinPullUp = PIN_USB_PULLUP; + PIO_Configure(&pinPullUp, 1); +#elif defined(CHIP_USB_PULLUP_INTERNAL) + AT91C_BASE_UDP->UDP_TXVC &= ~AT91C_UDP_PUON; +#elif defined(CHIP_USB_PULLUP_MATRIX) + AT91C_BASE_MATRIX->MATRIX_USBPCR &= ~AT91C_MATRIX_USBPCR_PUON; +#elif !defined(CHIP_USB_PULLUP_ALWAYSON) + #error Missing pull-up definition. +#endif + + // Device is in the Attached state + deviceState = USBD_STATE_SUSPENDED; + previousDeviceState = USBD_STATE_POWERED; + UDP_EnablePeripheralClock(); + UDP_EnableUsbClock(); + + AT91C_BASE_UDP->UDP_IDR = 0xFE; + + AT91C_BASE_UDP->UDP_IER = AT91C_UDP_WAKEUP; + + // Configure interrupts + USBDCallbacks_Initialized(); +} + +//------------------------------------------------------------------------------ +/// Configure USB Speed, should be invoked before USB attachment. +/// \param forceFS Force to use FS mode. +//------------------------------------------------------------------------------ +void USBD_ConfigureSpeed(unsigned char forceFS) +{ +} + +//------------------------------------------------------------------------------ +/// Returns the current state of the USB device. +/// \return Device current state. +//------------------------------------------------------------------------------ +unsigned char USBD_GetState(void) +{ + return deviceState; +} + diff --git a/usb/device/core/USBD_UDPHS.c b/usb/device/core/USBD_UDPHS.c new file mode 100644 index 0000000..f02fa55 --- /dev/null +++ b/usb/device/core/USBD_UDPHS.c @@ -0,0 +1,2384 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "USBD.h" +#include "USBDCallbacks.h" +#include "USBDDriver.h" +#include +#include +#include +#include +#include +#include +#include + +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +/// Maximum number of endpoints interrupts. +#define NUM_IT_MAX \ + (AT91C_BASE_UDPHS->UDPHS_IPFEATURES & AT91C_UDPHS_EPT_NBR_MAX) +/// Maximum number of endpoint DMA interrupts +#define NUM_IT_MAX_DMA \ + ((AT91C_BASE_UDPHS->UDPHS_IPFEATURES & AT91C_UDPHS_DMA_CHANNEL_NBR)>>4) +/// Bits that should be shifted to access DMA control bits. +#define SHIFT_DMA 24 +/// Bits that should be shifted to access interrupt bits. +#define SHIFT_INTERUPT 8 + +/// Max size of the FMA FIFO +#define DMA_MAX_FIFO_SIZE 65536 + +#define EPT_VIRTUAL_SIZE 16384 + +//------------------------------------------------------------------------------ +/// \page "Endpoint states" +/// This page lists the endpoint states. +/// !States +// - UDP_ENDPOINT_DISABLED +// - UDP_ENDPOINT_HALTED +// - UDP_ENDPOINT_IDLE +// - UDP_ENDPOINT_SENDING +// - UDP_ENDPOINT_RECEIVING + +/// Endpoint states: Endpoint is disabled +#define UDP_ENDPOINT_DISABLED 0 +/// Endpoint states: Endpoint is halted (i.e. STALLs every request) +#define UDP_ENDPOINT_HALTED 1 +/// Endpoint states: Endpoint is idle (i.e. ready for transmission) +#define UDP_ENDPOINT_IDLE 2 +/// Endpoint states: Endpoint is sending data +#define UDP_ENDPOINT_SENDING 3 +/// Endpoint states: Endpoint is receiving data +#define UDP_ENDPOINT_RECEIVING 4 +/// Endpoint states: Endpoint is sending MBL +#define UDP_ENDPOINT_SENDINGM 5 +/// Endpoint states: Endpoint is receiving MBL +#define UDP_ENDPOINT_RECEIVINGM 6 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Macros +//------------------------------------------------------------------------------ + +/// Check if DMA is used to transfer data +#define UDP_IsDmaUsed(ep) (CHIP_USB_ENDPOINTS_DMA(ep)) + +//------------------------------------------------------------------------------ +// Structures +//------------------------------------------------------------------------------ + +/// Describes an ongoing transfer on a UDP endpoint. +typedef struct +{ + /// Pointer to a data buffer used for emission/reception. + char *pData; + /// Number of bytes which have been written into the UDP internal FIFO + /// buffers. + int buffered; + /// Number of bytes which have been sent/received. + int transferred; + /// Number of bytes which have not been buffered/transferred yet. + int remaining; + /// Optional callback to invoke when the transfer completes. + TransferCallback fCallback; + /// Optional argument to the callback function. + void *pArgument; +} Transfer; + +/// Describes Multi Buffer List transfer on a UDP endpoint. +typedef struct { + /// Pointer to frame list + USBDTransferBuffer *pMbl; + /// Pointer to last loaded buffer + USBDTransferBuffer *pLastLoaded; + /// List size + unsigned short listSize; + /// Current processing frame + unsigned short currBuffer; + /// First freed frame to re-use + unsigned short freedBuffer; + /// Frame setting, circle frame list + unsigned char circList; + /// All buffer listed is used + unsigned char allUsed; + /// Optional callback to invoke when the transfer completes. + MblTransferCallback fCallback; + /// Optional argument to the callback function. + void *pArgument; +} MblTransfer; + +/// Describes DMA Link List transfer on a UDPHS endpoint. +typedef struct { + /// Pointer to frame list + USBDDmaDescriptor *pMbl; + /// Pointer to current buffer + USBDDmaDescriptor *pCurrBuffer; + /// Pointer to freed buffer + USBDDmaDescriptor *pFreedBuffer; + /// List size + unsigned short listSize; + /// Frame setting, circle frame list + unsigned char circList; + /// All buffer listed is used + unsigned char allUsed; + /// Optional callback to invoke when the transfer completes. + MblTransferCallback fCallback; + /// Optional argument to the callback function. + void *pArgument; +} DmaLlTransfer; + +//------------------------------------------------------------------------------ +/// Describes the state of an endpoint of the UDP controller. +//------------------------------------------------------------------------------ +typedef struct +{ + /// Current endpoint state. + volatile unsigned char state; + /// Current reception bank (0 or 1). + unsigned char bank; + /// Maximum packet size for the endpoint. + unsigned short size; + /// Describes an ongoing transfer (if current state is either + /// or ) + union { + Transfer singleTransfer; + MblTransfer mblTransfer; + DmaLlTransfer dmaTransfer; + } transfer; + /// Special case for send a ZLP + unsigned char sendZLP; +} Endpoint; + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +/// Holds the internal state for each endpoint of the UDP. +static Endpoint endpoints[CHIP_USB_NUMENDPOINTS]; +/// Device current state. +static unsigned char deviceState; +/// Indicates the previous device state +static unsigned char previousDeviceState; + +/// 7.1.20 Test Mode Support +/// Test codes for the USB HS test mode. +static const char test_packet_buffer[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // JKJKJKJK * 9 + 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA, // JJKKJJKK * 8 + 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE, // JJJJKKKK * 8 + 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // JJJJJJJKKKKKKK * 8 + 0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD, // JJJJJJJK * 8 + 0xFC,0x7E,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD,0x7E // {JKKKKKKK * 10}, JK +}; + +// Force HS +static const unsigned char forceUsbFS = 0; + +//------------------------------------------------------------------------------ +// Internal Functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Disables the BIAS of the USB controller +//------------------------------------------------------------------------------ +static inline void UDPHS_DisableBIAS( void ) +{ + AT91C_BASE_PMC->PMC_UCKR &= ~(unsigned int)AT91C_CKGR_BIASEN_ENABLED; +} + +//------------------------------------------------------------------------------ +/// Enables the BIAS of the USB controller +//------------------------------------------------------------------------------ +static inline void UDPHS_EnableBIAS( void ) +{ + UDPHS_DisableBIAS(); + AT91C_BASE_PMC->PMC_UCKR |= AT91C_CKGR_BIASEN_ENABLED; +} + +//------------------------------------------------------------------------------ +/// Enable UDPHS Peripheral +//------------------------------------------------------------------------------ +static inline void UDPHS_EnablePeripheral( void ) +{ +#if !defined (PMC_BY_HARD) + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDPHS); +#endif +} + +//------------------------------------------------------------------------------ +/// Enable UDPHS clock +//------------------------------------------------------------------------------ +static inline void UDPHS_EnableUsbClock( void ) +{ +#if !defined (PMC_BY_HARD) + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDPHS); + // Enable 480MHZ + //AT91C_BASE_CKGR->CKGR_UCKR |= (AT91C_CKGR_PLLCOUNT & (3 << 20)) | AT91C_CKGR_UPLLEN; + AT91C_BASE_CKGR->CKGR_UCKR |= ((0xf << 20) & (3 << 20)) | AT91C_CKGR_UPLLEN; + // Wait until UTMI PLL is locked + while ((AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCKU) == 0); +#endif +} + +//------------------------------------------------------------------------------ +/// Disable UDPHS clock +//------------------------------------------------------------------------------ +static inline void UDPHS_DisableUsbClock( void ) +{ +#if !defined (PMC_BY_HARD) + AT91C_BASE_PMC->PMC_PCDR = (1 << AT91C_ID_UDPHS); + // 480MHZ + AT91C_BASE_CKGR->CKGR_UCKR &= ~(unsigned int)AT91C_CKGR_UPLLEN; +#endif +} + +//------------------------------------------------------------------------------ +/// Handles a completed transfer on the given endpoint, invoking the +/// configured callback if any. +/// \param bEndpoint Number of the endpoint for which the transfer has completed. +/// \param bStatus Status code returned by the transfer operation +//------------------------------------------------------------------------------ +static void UDPHS_EndOfTransfer( unsigned char bEndpoint, char bStatus ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); + + // Check that endpoint was sending or receiving data + if( (pEndpoint->state == UDP_ENDPOINT_RECEIVING) + || (pEndpoint->state == UDP_ENDPOINT_SENDING) ) { + + TRACE_DEBUG_WP("Eo"); + if(pEndpoint->state == UDP_ENDPOINT_SENDING) { + pEndpoint->sendZLP = 0; + } + // Endpoint returns in Idle state + pEndpoint->state = UDP_ENDPOINT_IDLE; + + // Invoke callback is present + if (pTransfer->fCallback != 0) { + + ((TransferCallback) pTransfer->fCallback) + (pTransfer->pArgument, + bStatus, + pTransfer->transferred, + pTransfer->remaining + pTransfer->buffered); + } + else { + TRACE_DEBUG_WP("No callBack\n\r"); + } + } + else if ( (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM) + || (pEndpoint->state == UDP_ENDPOINT_SENDINGM) ) { + + MblTransfer* pMblt = (MblTransfer*)&(pEndpoint->transfer); + MblTransferCallback fCallback; + void* pArg; + + TRACE_DEBUG_WP("EoMT "); + + #ifdef DMA + { DmaLlTransfer *pDmat = (DmaLlTransfer*)&(pEndpoint->transfer); + fCallback = UDP_IsDmaUsed(bEndpoint) ? + pDmat->fCallback : pMblt->fCallback; + pArg = UDP_IsDmaUsed(bEndpoint) ? + pDmat->pArgument : pMblt->pArgument; + } + #else + fCallback = pMblt->fCallback; + pArg = pMblt->pArgument; + #endif + + // Endpoint returns in Idle state + pEndpoint->state = UDP_ENDPOINT_IDLE; + // Invoke callback + if (fCallback != 0) { + + (fCallback)(pArg, bStatus, 0); + } + else { + TRACE_DEBUG_WP("NoCB "); + } + } +} + +//------------------------------------------------------------------------------ +/// Clears the correct RX flag in endpoint status register +/// \param bEndpoint Index of endpoint +//------------------------------------------------------------------------------ +static void UDPHS_ClearRxFlag( unsigned char bEndpoint ) +{ + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCLRSTA = AT91C_UDPHS_RX_BK_RDY; +} + +//------------------------------------------------------------------------------ +/// Update multi-buffer-transfer descriptors. +/// \param pTransfer Pointer to instance MblTransfer. +/// \param size Size of bytes that processed. +/// \param forceEnd Force the buffer END. +/// \return 1 if current buffer ended. +//------------------------------------------------------------------------------ +static char UDPHS_MblUpdate(MblTransfer *pTransfer, + USBDTransferBuffer * pBi, + unsigned short size, + unsigned char forceEnd) +{ + // Update transfer descriptor + pBi->remaining -= size; + // Check if current buffer ended + if (pBi->remaining == 0 || forceEnd) { + + // Process to next buffer + if ((++ pTransfer->currBuffer) == pTransfer->listSize) { + if (pTransfer->circList) { + pTransfer->currBuffer = 0; + } + else { + pTransfer->allUsed = 1; + } + } + // All buffer in the list is processed + if (pTransfer->currBuffer == pTransfer->freedBuffer) { + pTransfer->allUsed = 1; + } + // Continue transfer, prepare for next operation + if (pTransfer->allUsed == 0) { + pBi = &pTransfer->pMbl[pTransfer->currBuffer]; + pBi->buffered = 0; + pBi->transferred = 0; + pBi->remaining = pBi->size; + } + return 1; + } + return 0; +} +/* +void UDPHS_WriteFifo(volatile char* pFifo, + unsigned char* pBuffer, + unsigned int size) +{ + register unsigned int c8 = size >> 3; + register unsigned int c1 = size & 0x7; + for (; c8; c8 --) { + *pFifo = *(pBuffer ++); + *pFifo = *(pBuffer ++); + *pFifo = *(pBuffer ++); + *pFifo = *(pBuffer ++); + + *pFifo = *(pBuffer ++); + *pFifo = *(pBuffer ++); + *pFifo = *(pBuffer ++); + *pFifo = *(pBuffer ++); + } + for (; c1; c1 --) { + *pFifo = *(pBuffer ++); + } +} +*/ +//------------------------------------------------------------------------------ +/// Transfers a data payload from the current tranfer buffer to the endpoint +/// FIFO +/// \param bEndpoint Number of the endpoint which is sending data. +//------------------------------------------------------------------------------ +static char UDPHS_MblWriteFifo(unsigned char bEndpoint) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer); + USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->currBuffer]); + volatile char *pFifo; + signed int size; + + volatile unsigned char * pBytes; + volatile char bufferEnd = 1; + + // Get the number of bytes to send + size = pEndpoint->size; + if (size > pBi->remaining) { + + size = pBi->remaining; + } + + TRACE_DEBUG_WP("w%d.%d ", pTransfer->currBuffer, size); + if (size == 0) { + + return 1; + } + + pTransfer->pLastLoaded = pBi; + pBytes = &(pBi->pBuffer[pBi->transferred + pBi->buffered]); + pBi->buffered += size; + bufferEnd = UDPHS_MblUpdate(pTransfer, pBi, size, 0); + + // Write packet in the FIFO buffer + pFifo = (char*)((unsigned int *)AT91C_BASE_UDPHS_EPTFIFO + + (EPT_VIRTUAL_SIZE * bEndpoint)); + if (size) { + signed int c8 = size >> 3; + signed int c1 = size & 0x7; + //printf("%d[%x] ", pBi->transferred, pBytes); + for (; c8; c8 --) { + *(pFifo++) = *(pBytes ++); + *(pFifo++) = *(pBytes ++); + *(pFifo++) = *(pBytes ++); + *(pFifo++) = *(pBytes ++); + + *(pFifo++) = *(pBytes ++); + *(pFifo++) = *(pBytes ++); + *(pFifo++) = *(pBytes ++); + *(pFifo++) = *(pBytes ++); + } + for (; c1; c1 --) { + *(pFifo++) = *(pBytes ++); + } + } + return bufferEnd; +} + +//------------------------------------------------------------------------------ +/// Transfers a data payload from the current tranfer buffer to the endpoint +/// FIFO +/// \param bEndpoint Number of the endpoint which is sending data. +//------------------------------------------------------------------------------ +static void UDPHS_WritePayload( unsigned char bEndpoint ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); + char *pFifo; + signed int size; + unsigned int dCtr; + + pFifo = (char*)((unsigned int *)AT91C_BASE_UDPHS_EPTFIFO + (EPT_VIRTUAL_SIZE * bEndpoint)); + + // Get the number of bytes to send + size = pEndpoint->size; + if (size > pTransfer->remaining) { + + size = pTransfer->remaining; + } + + // Update transfer descriptor information + pTransfer->buffered += size; + pTransfer->remaining -= size; + + // Write packet in the FIFO buffer + dCtr = 0; + while (size > 0) { + + pFifo[dCtr] = *(pTransfer->pData); + pTransfer->pData++; + size--; + dCtr++; + } +} + +//------------------------------------------------------------------------------ +/// Transfers a data payload from an endpoint FIFO to the current transfer buffer +/// \param bEndpoint Endpoint number. +/// \param wPacketSize Size of received data packet +//------------------------------------------------------------------------------ +static void UDPHS_ReadPayload( unsigned char bEndpoint, int wPacketSize ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); + char *pFifo; + unsigned char dBytes=0; + + pFifo = (char*)((unsigned int *)AT91C_BASE_UDPHS_EPTFIFO + (EPT_VIRTUAL_SIZE * bEndpoint)); + + // Check that the requested size is not bigger than the remaining transfer + if (wPacketSize > pTransfer->remaining) { + + pTransfer->buffered += wPacketSize - pTransfer->remaining; + wPacketSize = pTransfer->remaining; + } + + // Update transfer descriptor information + pTransfer->remaining -= wPacketSize; + pTransfer->transferred += wPacketSize; + + // Retrieve packet + while (wPacketSize > 0) { + + *(pTransfer->pData) = pFifo[dBytes]; + pTransfer->pData++; + wPacketSize--; + dBytes++; + } +} + + +//------------------------------------------------------------------------------ +/// Received SETUP packet from endpoint 0 FIFO +/// \param pRequest Generic USB SETUP request sent over Control endpoints +//------------------------------------------------------------------------------ +static void UDPHS_ReadRequest( USBGenericRequest *pRequest ) +{ + unsigned int *pData = (unsigned int *)pRequest; + unsigned int fifo; + + fifo = (AT91C_BASE_UDPHS_EPTFIFO->UDPHS_READEPT0[0]); + *pData = fifo; + fifo = (AT91C_BASE_UDPHS_EPTFIFO->UDPHS_READEPT0[0]); + pData++; + *pData = fifo; + //TRACE_ERROR("SETUP: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n\r", pData[0],pData[1],pData[2],pData[3],pData[4],pData[5],pData[6],pData[7]); +} + +//------------------------------------------------------------------------------ +/// Reset all endpoint transfer descriptors +//------------------------------------------------------------------------------ +static void UDPHS_ResetEndpoints( void ) +{ + Endpoint *pEndpoint; + Transfer *pTransfer; + unsigned char bEndpoint; + + // Reset the transfer descriptor of every endpoint + for( bEndpoint = 0; bEndpoint < CHIP_USB_NUMENDPOINTS; bEndpoint++ ) { + + pEndpoint = &(endpoints[bEndpoint]); + pTransfer = (Transfer*)&(pEndpoint->transfer); + + // Reset endpoint transfer descriptor + pTransfer->pData = 0; + pTransfer->transferred = -1; + pTransfer->buffered = -1; + pTransfer->remaining = -1; + pTransfer->fCallback = 0; + pTransfer->pArgument = 0; + + // Reset endpoint state + pEndpoint->bank = 0; + pEndpoint->state = UDP_ENDPOINT_DISABLED; + // Reset ZLP + pEndpoint->sendZLP = 0; + } +} + + +//------------------------------------------------------------------------------ +/// Disable all endpoints (except control endpoint 0), aborting current +/// transfers if necessary +//------------------------------------------------------------------------------ +static void UDPHS_DisableEndpoints( void ) +{ + unsigned char bEndpoint; + + // Disable each endpoint, terminating any pending transfer + // Control endpoint 0 is not disabled + for( bEndpoint = 1; bEndpoint < CHIP_USB_NUMENDPOINTS; bEndpoint++ ) { + + UDPHS_EndOfTransfer( bEndpoint, USBD_STATUS_ABORTED ); + endpoints[bEndpoint].state = UDP_ENDPOINT_DISABLED; + } +} + +//------------------------------------------------------------------------------ +/// Endpoint interrupt handler. +/// Handle IN/OUT transfers, received SETUP packets and STALLing +/// \param bEndpoint Index of endpoint +//------------------------------------------------------------------------------ +static void UDPHS_EndpointHandler( unsigned char bEndpoint ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); + MblTransfer *pMblt = (MblTransfer*)&(pEndpoint->transfer); + unsigned int status = AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSTA; + unsigned short wPacketSize; + USBGenericRequest request; + + TRACE_DEBUG_WP("E%d ", bEndpoint); + TRACE_DEBUG_WP("st:0x%X ", status); + + // Handle interrupts + // IN packet sent + if( (AT91C_UDPHS_TX_PK_RDY == (AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTL & AT91C_UDPHS_TX_PK_RDY)) + && (0 == (status & AT91C_UDPHS_TX_PK_RDY )) ) { + + TRACE_DEBUG_WP("Wr "); + + // Check that endpoint was sending multi-buffer-list + if( pEndpoint->state == UDP_ENDPOINT_SENDINGM ) { + + USBDTransferBuffer * pMbli = pMblt->pLastLoaded; + + TRACE_DEBUG_WP("TxM%d.%d,%d ", + pMblt->allUsed, pMbli->buffered, pMbli->remaining); + + // End of transfer ? + if (pMblt->allUsed && pMbli->remaining == 0) { + + pMbli->transferred += pMbli->buffered; + pMbli->buffered = 0; + + // Disable interrupt + AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1<UDPHS_EPT[bEndpoint].UDPHS_EPTCTLDIS = + AT91C_UDPHS_TX_PK_RDY; + UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + } + else { + + // Transfer remaining data + TRACE_DEBUG_WP("%d ", pEndpoint->size); + + if (pMbli->buffered > pEndpoint->size) { + pMbli->transferred += pEndpoint->size; + pMbli->buffered -= pEndpoint->size; + } + else { + pMbli->transferred += pMbli->buffered; + pMbli->buffered = 0; + } + + // Send next packet + UDPHS_MblWriteFifo(bEndpoint); + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSETSTA = + AT91C_UDPHS_TX_PK_RDY; + + if (pMbli->remaining == 0 && pMbli->buffered == 0) { + + if (pMblt->fCallback) { + ((MblTransferCallback) pTransfer->fCallback) + (pTransfer->pArgument, + USBD_STATUS_PARTIAL_DONE, + 1); + } + } + } + } + + // Check that endpoint was in Sending state + if( pEndpoint->state == UDP_ENDPOINT_SENDING ) { + + if (pTransfer->buffered > 0) { + pTransfer->transferred += pTransfer->buffered; + pTransfer->buffered = 0; + } + + if( ((pTransfer->buffered)==0) + &&((pTransfer->transferred)==0) + &&((pTransfer->remaining)==0) + &&(pEndpoint->sendZLP == 0)) { + pEndpoint->sendZLP = 1; + } + + // End of transfer ? + if( (pTransfer->remaining > 0) + ||(pEndpoint->sendZLP == 1)) { + + pEndpoint->sendZLP = 2; + TRACE_DEBUG_WP("\n\r1pTransfer->buffered %d \n\r", pTransfer->buffered); + TRACE_DEBUG_WP("1pTransfer->transferred %d \n\r", pTransfer->transferred); + TRACE_DEBUG_WP("1pTransfer->remaining %d \n\r", pTransfer->remaining); + + // Transfer remaining data + TRACE_DEBUG_WP(" %d ", pEndpoint->size); + + // Send next packet + UDPHS_WritePayload(bEndpoint); + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSETSTA = AT91C_UDPHS_TX_PK_RDY; + } + else { + TRACE_DEBUG_WP("\n\r0pTransfer->buffered %d \n\r", pTransfer->buffered); + TRACE_DEBUG_WP("0pTransfer->transferred %d \n\r", pTransfer->transferred); + TRACE_DEBUG_WP("0pTransfer->remaining %d \n\r", pTransfer->remaining); + + TRACE_DEBUG_WP(" %d ", pTransfer->transferred); + + // Disable interrupt if this is not a control endpoint + if( AT91C_UDPHS_EPT_TYPE_CTL_EPT != (AT91C_UDPHS_EPT_TYPE&(AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG)) ) { + + AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1<UDPHS_EPT[bEndpoint].UDPHS_EPTCTLDIS = AT91C_UDPHS_TX_PK_RDY; + + UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + pEndpoint->sendZLP = 0; + } + } + else { + + TRACE_DEBUG("Error Wr %d", pEndpoint->sendZLP); + } + } + + // OUT packet received + if( AT91C_UDPHS_RX_BK_RDY == (status & AT91C_UDPHS_RX_BK_RDY) ) { + + TRACE_DEBUG_WP("Rd "); + + // Check that the endpoint is in Receiving state + if (pEndpoint->state != UDP_ENDPOINT_RECEIVING) { + + // Check if an ACK has been received on a Control endpoint + if( (0 == (AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG & AT91C_UDPHS_EPT_TYPE)) + && (0 == (status & AT91C_UDPHS_BYTE_COUNT)) ) { + + // Control endpoint, 0 bytes received + // Acknowledge the data and finish the current transfer + TRACE_DEBUG_WP("Ack "); + UDPHS_ClearRxFlag(bEndpoint); + UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + //todo remove endoftranfer and test + } + // Check if the data has been STALLed + else if( AT91C_UDPHS_FRCESTALL == (status & AT91C_UDPHS_FRCESTALL)) { + + // Discard STALLed data + TRACE_DEBUG_WP("Discard "); + UDPHS_ClearRxFlag(bEndpoint); + } + // NAK the data + else { + + TRACE_DEBUG_WP("Nak "); + AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1<>20); + + TRACE_DEBUG_WP("%d ", wPacketSize); + UDPHS_ReadPayload(bEndpoint, wPacketSize); + UDPHS_ClearRxFlag(bEndpoint); + + // Check if the transfer is finished + if ((pTransfer->remaining == 0) || (wPacketSize < pEndpoint->size)) { + + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLDIS = AT91C_UDPHS_RX_BK_RDY; + + // Disable interrupt if this is not a control endpoint + if( AT91C_UDPHS_EPT_TYPE_CTL_EPT != (AT91C_UDPHS_EPT_TYPE & (AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG)) ) { + + AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1<UDPHS_EPT[bEndpoint].UDPHS_EPTCLRSTA = AT91C_UDPHS_STALL_SNT; + + // If the endpoint is not halted, clear the STALL condition + if (pEndpoint->state != UDP_ENDPOINT_HALTED) { + + TRACE_WARNING( "_ " ); + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCLRSTA = AT91C_UDPHS_FRCESTALL; + } + } + + // SETUP packet received + if( AT91C_UDPHS_RX_SETUP == (status & AT91C_UDPHS_RX_SETUP) ) { + + TRACE_DEBUG_WP("Stp "); + + // If a transfer was pending, complete it + // Handles the case where during the status phase of a control write + // transfer, the host receives the device ZLP and ack it, but the ack + // is not received by the device + if ((pEndpoint->state == UDP_ENDPOINT_RECEIVING) + || (pEndpoint->state == UDP_ENDPOINT_SENDING)) { + + UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + } + // Copy the setup packet + UDPHS_ReadRequest(&request); + + // Acknowledge setup packet + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCLRSTA = AT91C_UDPHS_RX_SETUP; + + // Forward the request to the upper layer + USBDCallbacks_RequestReceived(&request); + } + +} + +//------------------------------------------------------------------------------ +// Interrupt service routine +//------------------------------------------------------------------------------ +#ifdef DMA +//---------------------------------------------------------------------------- +/// Endpoint DMA interrupt handler. +/// This function (ISR) handles dma interrupts +/// \param bEndpoint Index of endpoint +//---------------------------------------------------------------------------- +static void UDPHS_DmaHandler( unsigned char bEndpoint ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); + int justTransferred; + unsigned int status; + unsigned char result = USBD_STATUS_SUCCESS; + + status = AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMASTATUS; + TRACE_DEBUG_WP("DmaE%d,%x ", bEndpoint, status); + + if (pEndpoint->state == UDP_ENDPOINT_SENDINGM) { + + DmaLlTransfer *pDmat = (DmaLlTransfer*)&(pEndpoint->transfer); + USBDDmaDescriptor *pDi = pDmat->pCurrBuffer; + USBDDmaDescriptor *pNi = (USBDDmaDescriptor*)AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMANXTDSC; + unsigned char bufCnt = 0; + + if (AT91C_UDPHS_END_BF_ST == (status & AT91C_UDPHS_END_BF_ST)) { + + // Stop loading descriptors + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL &= + ~((unsigned int)AT91C_UDPHS_LDNXT_DSC); + + //printf("%x,%x|", + // (char)status, + // (short)AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMANXTDSC); + + while( pDi->pNxtDesc != pNi ) { + + // All descriptor processed + if (pDi == 0) break; + if (pDi->used) break; + + // Current descriptor processed + /* + pDi->ctrlSettings = 0 + //|AT91C_UDPHS_CHANN_ENB + //| AT91C_UDPHS_LDNXT_DSC + //| AT91C_UDPHS_END_TR_EN + //| AT91C_UDPHS_END_TR_IT + //| AT91C_UDPHS_END_B_EN + //| AT91C_UDPHS_END_BUFFIT + //| AT91C_UDPHS_DESC_LD_IT + ; */ + pDi->used = 1; // Flag as used + bufCnt ++; + pDi = pDi->pNxtDesc; + } + pDmat->pCurrBuffer = pDi; + + if (bufCnt) { + + if (pDmat->fCallback) { + + pDmat->fCallback(pDmat->pArgument, + ((result == USBD_STATUS_SUCCESS) ? + USBD_STATUS_PARTIAL_DONE : result), + bufCnt); + } + } + + if ( (pNi == 0) + || (pNi->used && pNi) ) { + + // Disable DMA endpoint interrupt + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = 0; + AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1 << SHIFT_DMA << bEndpoint); + + TRACE_DEBUG_WP("EoMDT "); + //printf("E:N%x,C%d ", (short)pNi, bufCnt); + + UDPHS_EndOfTransfer(bEndpoint, result); + } + else { + + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL |= + (AT91C_UDPHS_LDNXT_DSC); + } + } + else { + + TRACE_ERROR("UDPHS: Dma(0x%X)\n\r", status); + result = USBD_STATUS_ABORTED; + UDPHS_EndOfTransfer(bEndpoint, result); + } + return; + } + else if (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM) { + return; + } + + // Disable DMA interrupt to avoid receiving 2 interrupts (B_EN and TR_EN) + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL &= + ~(unsigned int)(AT91C_UDPHS_END_TR_EN | AT91C_UDPHS_END_B_EN); + + AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1 << SHIFT_DMA << bEndpoint); + + if( AT91C_UDPHS_END_BF_ST == (status & AT91C_UDPHS_END_BF_ST) ) { + + TRACE_DEBUG_WP("EndBuffer "); + + // BUFF_COUNT holds the number of untransmitted bytes. + // BUFF_COUNT is equal to zero in case of good transfer + justTransferred = pTransfer->buffered + - ((status & (unsigned int)AT91C_UDPHS_BUFF_COUNT) >> 16); + pTransfer->transferred += justTransferred; + + pTransfer->buffered = + ((status & (unsigned int)AT91C_UDPHS_BUFF_COUNT) >> 16); + + pTransfer->remaining -= justTransferred; + + TRACE_DEBUG_WP("\n\r1pTransfer->buffered %d \n\r", pTransfer->buffered); + TRACE_DEBUG_WP("1pTransfer->transferred %d \n\r", pTransfer->transferred); + TRACE_DEBUG_WP("1pTransfer->remaining %d \n\r", pTransfer->remaining); + + if( (pTransfer->remaining + pTransfer->buffered) > 0 ) { + + // Prepare an other transfer + if( pTransfer->remaining > DMA_MAX_FIFO_SIZE ) { + + pTransfer->buffered = DMA_MAX_FIFO_SIZE; + } + else { + pTransfer->buffered = pTransfer->remaining; + } + + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMAADDRESS = + (unsigned int)((pTransfer->pData) + (pTransfer->transferred)); + + // Clear unwanted interrupts + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMASTATUS; + + // Enable DMA endpoint interrupt + AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_DMA << bEndpoint); + // DMA config for receive the good size of buffer, or an error buffer + + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = 0; // raz + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = + ( ((pTransfer->buffered << 16) & AT91C_UDPHS_BUFF_COUNT) + | AT91C_UDPHS_END_TR_EN + | AT91C_UDPHS_END_TR_IT + | AT91C_UDPHS_END_B_EN + | AT91C_UDPHS_END_BUFFIT + | AT91C_UDPHS_CHANN_ENB ); + } + } + else if( AT91C_UDPHS_END_TR_ST == (status & AT91C_UDPHS_END_TR_ST) ) { + + TRACE_DEBUG_WP("EndTransf "); + + pTransfer->transferred = pTransfer->buffered + - ((status & (unsigned int)AT91C_UDPHS_BUFF_COUNT) >> 16); + pTransfer->remaining = 0; + TRACE_DEBUG_WP("\n\r0pTransfer->buffered %d \n\r", pTransfer->buffered); + TRACE_DEBUG_WP("0pTransfer->transferred %d \n\r", pTransfer->transferred); + TRACE_DEBUG_WP("0pTransfer->remaining %d \n\r", pTransfer->remaining); + } + else { + + TRACE_ERROR("UDPHS_DmaHandler: Error (0x%08X)\n\r", status); + result = USBD_STATUS_ABORTED; + } + + // Invoke callback + if( pTransfer->remaining == 0 ) { + + TRACE_DEBUG_WP("EOT "); + UDPHS_EndOfTransfer(bEndpoint, result); + } +} +#endif + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// USB device interrupt handler +/// Manages device resume, suspend, end of bus reset. +/// Forwards endpoint interrupts to the appropriate handler. +//------------------------------------------------------------------------------ +void USBD_IrqHandler(void) +{ + unsigned int status; + unsigned char numIT; + + if (deviceState >= USBD_STATE_POWERED) { + + LED_Set(USBD_LEDUSB); + } + + // Get interrupts status + status = AT91C_BASE_UDPHS->UDPHS_INTSTA; + status &= AT91C_BASE_UDPHS->UDPHS_IEN; + + // Handle all UDPHS interrupts + TRACE_DEBUG_WP("H"); + while (status != 0) { + + // Start Of Frame (SOF) + if ((status & AT91C_UDPHS_IEN_SOF) != 0) { + + TRACE_DEBUG_WP("SOF "); + + // Invoke the SOF callback + //USB_StartOfFrameCallback(pUsb); + + // Acknowledge interrupt + AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_IEN_SOF; + status &= ~(unsigned int)AT91C_UDPHS_IEN_SOF; + } + // Suspend + // This interrupt is always treated last (hence the '==') + else if (status == AT91C_UDPHS_DET_SUSPD) { + + TRACE_DEBUG_WP("S"); + + // The device enters the Suspended state + // MCK + UDPCK must be off + // Pull-Up must be connected + // Transceiver must be disabled + + LED_Clear(USBD_LEDUSB); + + UDPHS_DisableBIAS(); + + // Enable wakeup + AT91C_BASE_UDPHS->UDPHS_IEN |= AT91C_UDPHS_WAKE_UP | AT91C_UDPHS_ENDOFRSM; + AT91C_BASE_UDPHS->UDPHS_IEN &= ~(unsigned int)AT91C_UDPHS_DET_SUSPD; + + // Acknowledge interrupt + AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_DET_SUSPD | AT91C_UDPHS_WAKE_UP; + previousDeviceState = deviceState; + deviceState = USBD_STATE_SUSPENDED; + UDPHS_DisableUsbClock(); + + // Invoke the Suspend callback + USBDCallbacks_Suspended(); + } + // Resume + else if( ((status & AT91C_UDPHS_WAKE_UP) != 0) // line activity + || ((status & AT91C_UDPHS_ENDOFRSM) != 0)) { // pc wakeup + { + // Invoke the Resume callback + USBDCallbacks_Resumed(); + + TRACE_DEBUG_WP("R"); + + UDPHS_EnableUsbClock(); + UDPHS_EnableBIAS(); + + // The device enters Configured state + // MCK + UDPCK must be on + // Pull-Up must be connected + // Transceiver must be enabled + + deviceState = previousDeviceState; + + AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_WAKE_UP | AT91C_UDPHS_ENDOFRSM | AT91C_UDPHS_DET_SUSPD; + + AT91C_BASE_UDPHS->UDPHS_IEN |= AT91C_UDPHS_ENDOFRSM | AT91C_UDPHS_DET_SUSPD; + AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_WAKE_UP | AT91C_UDPHS_ENDOFRSM; + AT91C_BASE_UDPHS->UDPHS_IEN &= ~(unsigned int)AT91C_UDPHS_WAKE_UP; + } + } + // End of bus reset + else if ((status & AT91C_UDPHS_ENDRESET) == AT91C_UDPHS_ENDRESET) { + +// TRACE_DEBUG_WP("EoB "); + + // The device enters the Default state + deviceState = USBD_STATE_DEFAULT; + // MCK + UDPCK are already enabled + // Pull-Up is already connected + // Transceiver must be enabled + // Endpoint 0 must be enabled + + UDPHS_ResetEndpoints(); + UDPHS_DisableEndpoints(); + USBD_ConfigureEndpoint(0); + + // Flush and enable the Suspend interrupt + AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_WAKE_UP | AT91C_UDPHS_DET_SUSPD; + + //// Enable the Start Of Frame (SOF) interrupt if needed + //if (pCallbacks->startOfFrame != 0) + //{ + // AT91C_BASE_UDPHS->UDPHS_IEN |= AT91C_UDPHS_IEN_SOF; + //} + + // Invoke the Reset callback + USBDCallbacks_Reset(); + + // Acknowledge end of bus reset interrupt + AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_ENDRESET; + + AT91C_BASE_UDPHS->UDPHS_IEN |= AT91C_UDPHS_DET_SUSPD; + } + // Handle upstream resume interrupt + else if (status & AT91C_UDPHS_UPSTR_RES) { + + TRACE_DEBUG_WP("ExtRes "); + + // - Acknowledge the IT + AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_UPSTR_RES; + } + // Endpoint interrupts + else { +#ifndef DMA + // Handle endpoint interrupts + for (numIT = 0; numIT < NUM_IT_MAX; numIT++) { + + if ((status & (1 << SHIFT_INTERUPT << numIT)) != 0) { + + UDPHS_EndpointHandler(numIT); + } + } +#else + // Handle endpoint control interrupt + if ((status & (1 << SHIFT_INTERUPT << 0)) != 0) { + + UDPHS_EndpointHandler( 0 ); + } + else { + + numIT = 1; + while((status&(0x7E<UDPHS_INTSTA; + status &= AT91C_BASE_UDPHS->UDPHS_IEN; + + TRACE_DEBUG_WP("\n\r"); + if (status != 0) { + + TRACE_DEBUG_WP(" - "); + } + } + + if (deviceState >= USBD_STATE_POWERED) { + + LED_Clear(USBD_LEDUSB); + } +} + +//------------------------------------------------------------------------------ +/// Configure an endpoint with the provided endpoint descriptor +/// \param pDdescriptor Pointer to the endpoint descriptor +//------------------------------------------------------------------------------ +void USBD_ConfigureEndpoint(const USBEndpointDescriptor *pDescriptor) +{ + Endpoint *pEndpoint; + unsigned char bEndpoint; + unsigned char bType; + unsigned char bEndpointDir; + //unsigned char bInterval = 0; + unsigned char bNbTrans = 1; + unsigned char bSizeEpt = 0; + unsigned char bHs = ((AT91C_BASE_UDPHS->UDPHS_INTSTA & AT91C_UDPHS_SPEED) + > 0); + + // NULL descriptor -> Control endpoint 0 + if (pDescriptor == 0) { + + bEndpoint = 0; + pEndpoint = &(endpoints[bEndpoint]); + bType = USBEndpointDescriptor_CONTROL; + bEndpointDir = 0; + pEndpoint->size = CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0); + pEndpoint->bank = CHIP_USB_ENDPOINTS_BANKS(0); + } + else { + + // The endpoint number + bEndpoint = USBEndpointDescriptor_GetNumber(pDescriptor); + pEndpoint = &(endpoints[bEndpoint]); + // Transfer type: Control, Isochronous, Bulk, Interrupt + bType = USBEndpointDescriptor_GetType(pDescriptor); + // interval + //bInterval = USBEndpointDescriptor_GetInterval(pDescriptor); + // Direction, ignored for control endpoints + bEndpointDir = USBEndpointDescriptor_GetDirection(pDescriptor); + pEndpoint->size = USBEndpointDescriptor_GetMaxPacketSize(pDescriptor); + pEndpoint->bank = CHIP_USB_ENDPOINTS_BANKS(bEndpoint); + + // Convert descriptor value to EP configuration + if (bHs) { // HS Interval, *125us + + // MPS: Bit12,11 specify NB_TRANS + bNbTrans = ((pEndpoint->size >> 11) & 0x3); + if (bNbTrans == 3) + bNbTrans = 1; + else + bNbTrans ++; + + // Mask, bit 10..0 is the size + pEndpoint->size &= 0x3FF; + } + } + + // Abort the current transfer is the endpoint was configured and in + // Write or Read state + if( (pEndpoint->state == UDP_ENDPOINT_RECEIVING) + || (pEndpoint->state == UDP_ENDPOINT_SENDING) + || (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM) + || (pEndpoint->state == UDP_ENDPOINT_SENDINGM) ) { + + UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_RESET); + } + pEndpoint->state = UDP_ENDPOINT_IDLE; + + // Disable endpoint + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLDIS = (unsigned int)AT91C_UDPHS_SHRT_PCKT + | AT91C_UDPHS_BUSY_BANK + | AT91C_UDPHS_NAK_OUT + | AT91C_UDPHS_NAK_IN + | AT91C_UDPHS_STALL_SNT + | AT91C_UDPHS_RX_SETUP + | AT91C_UDPHS_TX_PK_RDY + | AT91C_UDPHS_TX_COMPLT + | AT91C_UDPHS_RX_BK_RDY + | AT91C_UDPHS_ERR_OVFLW + | AT91C_UDPHS_MDATA_RX + | AT91C_UDPHS_DATAX_RX + | AT91C_UDPHS_NYET_DIS + | AT91C_UDPHS_INTDIS_DMA + | AT91C_UDPHS_AUTO_VALID + | AT91C_UDPHS_EPT_DISABL; + + // Reset Endpoint Fifos + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCLRSTA = AT91C_UDPHS_TOGGLESQ | AT91C_UDPHS_FRCESTALL; + AT91C_BASE_UDPHS->UDPHS_EPTRST = 1<size <= 8 ) { + bSizeEpt = 0; + } + else if ( pEndpoint->size <= 16 ) { + bSizeEpt = 1; + } + else if ( pEndpoint->size <= 32 ) { + bSizeEpt = 2; + } + else if ( pEndpoint->size <= 64 ) { + bSizeEpt = 3; + } + else if ( pEndpoint->size <= 128 ) { + bSizeEpt = 4; + } + else if ( pEndpoint->size <= 256 ) { + bSizeEpt = 5; + } + else if ( pEndpoint->size <= 512 ) { + bSizeEpt = 6; + } + else if ( pEndpoint->size <= 1024 ) { + bSizeEpt = 7; + } //else { + // sizeEpt = 0; // control endpoint + //} + + // Configure endpoint + if (bType == USBEndpointDescriptor_CONTROL) { + + // Enable endpoint IT for control endpoint + AT91C_BASE_UDPHS->UDPHS_IEN |= (1<UDPHS_EPT[bEndpoint].UDPHS_EPTCFG = bSizeEpt + | ( bEndpointDir << 3) + | ( bType << 4) + | ((pEndpoint->bank) << 6) + | ( bNbTrans << 8) + ; + + while( (signed int)AT91C_UDPHS_EPT_MAPD != (signed int)((AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG) & (unsigned int)AT91C_UDPHS_EPT_MAPD) ) { + + // resolved by clearing the reset IT in good place + TRACE_ERROR("PB bEndpoint: 0x%X\n\r", bEndpoint); + TRACE_ERROR("PB bSizeEpt: 0x%X\n\r", bSizeEpt); + TRACE_ERROR("PB bEndpointDir: 0x%X\n\r", bEndpointDir); + TRACE_ERROR("PB bType: 0x%X\n\r", bType); + TRACE_ERROR("PB pEndpoint->bank: 0x%X\n\r", pEndpoint->bank); + TRACE_ERROR("PB UDPHS_EPTCFG: 0x%X\n\r", AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG); + for(;;); + } + + if (bType == USBEndpointDescriptor_CONTROL) { + + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_RX_BK_RDY + | AT91C_UDPHS_RX_SETUP + | AT91C_UDPHS_EPT_ENABL; + } + else { +#ifndef DMA + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_EPT_ENABL; +#else + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_AUTO_VALID + | AT91C_UDPHS_EPT_ENABL; +#endif + } + +} + +//------------------------------------------------------------------------------ +/// Sends data through an USB endpoint (IN) +/// Sets up the transfer descriptor, write one or two data payloads +/// (depending on the number of FIFO banks for the endpoint) and then +/// starts the actual transfer. The operation is complete when all +/// the data has been sent. +/// \param bEndpoint Index of endpoint +/// \param *pData Data to be written +/// \param dLength Data length to be send +/// \param fCallback Callback to be call after the success command +/// \param *pArgument Callback argument +/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS +//------------------------------------------------------------------------------ +char USBD_Write( unsigned char bEndpoint, + const void *pData, + unsigned int dLength, + TransferCallback fCallback, + void *pArgument ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); + + // Return if the endpoint is not in IDLE state + if (pEndpoint->state != UDP_ENDPOINT_IDLE) { + + return USBD_STATUS_LOCKED; + } + + TRACE_DEBUG_WP("Write%d(%d) ", bEndpoint, dLength); + pEndpoint->sendZLP = 0; + // Setup the transfer descriptor + pTransfer->pData = (void *) pData; + pTransfer->remaining = dLength; + pTransfer->buffered = 0; + pTransfer->transferred = 0; + pTransfer->fCallback = fCallback; + pTransfer->pArgument = pArgument; + + // Send one packet + pEndpoint->state = UDP_ENDPOINT_SENDING; + +#ifdef DMA + // Test if endpoint type control + if(AT91C_UDPHS_EPT_TYPE_CTL_EPT == (AT91C_UDPHS_EPT_TYPE&(AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG))) { +#endif + // Enable endpoint IT + AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_INTERUPT << bEndpoint); + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_TX_PK_RDY; + +#ifdef DMA + } + else { + if( CHIP_USB_ENDPOINTS_DMA(bEndpoint) == 0 ) { + TRACE_FATAL("Endpoint has no DMA\n\r"); + } + if( pTransfer->remaining == 0 ) { + // DMA not handle ZLP + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSETSTA = AT91C_UDPHS_TX_PK_RDY; + // Enable endpoint IT + AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_INTERUPT << bEndpoint); + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_TX_PK_RDY; + } + else { + // Others endpoints (not control) + if( pTransfer->remaining > DMA_MAX_FIFO_SIZE ) { + + // Transfer the max + pTransfer->buffered = DMA_MAX_FIFO_SIZE; + } + else { + // Transfer the good size + pTransfer->buffered = pTransfer->remaining; + } + + TRACE_DEBUG_WP("\n\r_WR[%x]:%d ", pTransfer->pData, pTransfer->remaining ); + TRACE_DEBUG_WP("B:%d ", pTransfer->buffered ); + TRACE_DEBUG_WP("T:%d ", pTransfer->transferred ); + + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMAADDRESS = (unsigned int)(pTransfer->pData); + + // Clear unwanted interrupts + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMASTATUS; + // Enable DMA endpoint interrupt + AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_DMA << bEndpoint); + // DMA config + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = 0; // raz + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = + ( ((pTransfer->buffered << 16) & AT91C_UDPHS_BUFF_COUNT) + | AT91C_UDPHS_END_B_EN + | AT91C_UDPHS_END_BUFFIT + | AT91C_UDPHS_CHANN_ENB ); + } + } +#endif + + return USBD_STATUS_SUCCESS; +} + +//------------------------------------------------------------------------------ +/// Sends data frames through a USB endpoint. Sets up the transfer descriptor +/// list, writes one or two data payloads (depending on the number of FIFO bank +/// for the endpoint) and then starts the actual transfer. The operation invoke +/// a callback with RC USBD_STATUS_PARTIAL_DONE each time when a buffer is +/// transferred and is complete when all the data has been sent. +/// +/// *If the size of the frame is greater than the size of the endpoint +/// (or twice the size if the endpoint has two FIFO banks), then the buffer +/// must be kept allocated until the frame is finished*. This means that +/// it is not possible to declare it on the stack (i.e. as a local variable +/// of a function which returns after starting a transfer). +/// +/// \param bEndpoint Endpoint number. +/// \param pMbl Pointer to a frame list with the data to send. +/// Two different list is supported, for EPs that support DMA, +/// the frame is described by USBDDmaDescriptor link list, +/// for EPs that uses FIFO the frame is described by +/// USBDTransferBuffer array. +/// For DMA transfer, the size of each frame is limited by the +/// max size of one DMA transfer. When using DMA, the frame list +/// size and size of each frame should be larger so that more +/// efficiency is achieved and CPU could have more time on +/// handler of each buffer end event. +/// \param wListSize Size of the frame list. +/// \param bCircList Circle the list. +/// \param wStartNdx Starting buffer index in the list. +/// \param fCallback Optional callback function to invoke when the transfer is +/// complete. +/// \param pArgument Optional argument to the callback function. +/// \return USBD_STATUS_SUCCESS if the transfer has been started; +/// otherwise, the corresponding error status code. +/// \see USBDDmaDescriptor, USBDTransferBuffer +//------------------------------------------------------------------------------ +char USBD_MblWrite( unsigned char bEndpoint, + void *pMbl, + unsigned short wListSize, + unsigned char bCircList, + unsigned short wStartNdx, + MblTransferCallback fCallback, + void *pArgument ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer); + unsigned short i; + + // EP0 is not suitable for Mbl + if (bEndpoint == 0) { + + return USBD_STATUS_INVALID_PARAMETER; + } + + // Check that the endpoint is in Idle state + if (pEndpoint->state != UDP_ENDPOINT_IDLE) { + + //return USBD_STATUS_LOCKED; + } + // Setup state + pEndpoint->state = UDP_ENDPOINT_SENDINGM; + + TRACE_DEBUG_WP("WriteM%d(0x%x,%d) ", bEndpoint, pMbl, wListSize); + + // Start from first if not circled list + if (!bCircList) wStartNdx = 0; + +#ifdef DMA + if (UDP_IsDmaUsed(bEndpoint)) { + + DmaLlTransfer *pDmallt = (DmaLlTransfer*)&(pEndpoint->transfer); + USBDDmaDescriptor * pDi = (USBDDmaDescriptor*)pMbl; + + // DMA config + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = 0; + AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1 << SHIFT_DMA << bEndpoint); + + // Setup the transfer descriptor + pDmallt->pMbl = (USBDDmaDescriptor*)pMbl; + pDmallt->listSize = wListSize; + pDmallt->fCallback = fCallback; + pDmallt->pArgument = pArgument; + pDmallt->circList = bCircList; + pDmallt->allUsed = 0; + + // Check all buffers, fill settings + for (i = 0; i < wListSize - 1; i ++) { + + if (pDi->bufferLength > DMA_MAX_FIFO_SIZE) { + + TRACE_ERROR("DMA buffer size %d exceeds max %d\n\r", + pDi->bufferLength, DMA_MAX_FIFO_SIZE); + return USBD_STATUS_INVALID_PARAMETER; + } + + // Channel control value + pDi->ctrlSettings = AT91C_UDPHS_CHANN_ENB + | AT91C_UDPHS_LDNXT_DSC + | AT91C_UDPHS_END_TR_EN + //| AT91C_UDPHS_END_TR_IT + | AT91C_UDPHS_END_B_EN + | AT91C_UDPHS_END_BUFFIT + | AT91C_UDPHS_DESC_LD_IT + ; + pDi->used = 0; + pDi = pDi->pNxtDesc; + } + + // Circled list check + pDi->used = 0; + if (bCircList) { + + pDi->pNxtDesc = pDmallt->pMbl; + pDi->ctrlSettings = AT91C_UDPHS_CHANN_ENB + | AT91C_UDPHS_LDNXT_DSC + | AT91C_UDPHS_END_TR_EN + //| AT91C_UDPHS_END_TR_IT + | AT91C_UDPHS_END_B_EN + | AT91C_UDPHS_END_BUFFIT + //| AT91C_UDPHS_DESC_LD_IT + ; + } + else { + + pDi->pNxtDesc = 0; + pDi->ctrlSettings = AT91C_UDPHS_CHANN_ENB + //| AT91C_UDPHS_LDNXT_DSC + | AT91C_UDPHS_END_TR_EN + //| AT91C_UDPHS_END_TR_IT + | AT91C_UDPHS_END_B_EN + | AT91C_UDPHS_END_BUFFIT + //| AT91C_UDPHS_DESC_LD_IT + ; + } + + // Start from 'wStartNdx'th descriptor + pDi = (USBDDmaDescriptor*)pMbl; + for (;wStartNdx; wStartNdx --) { + pDi = pDi->pNxtDesc; + } + pDmallt->pCurrBuffer = (USBDDmaDescriptor*)pDi; + pDmallt->pFreedBuffer = (USBDDmaDescriptor*)pDi; + + // Disable DMA when interrupt happenned + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_INTDIS_DMA; + + // Clear unwanted interrupts + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMASTATUS; + // Enable DMA endpoint interrupt + AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_DMA << bEndpoint); + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMANXTDSC = (unsigned int)pMbl; + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = AT91C_UDPHS_LDNXT_DSC + //| AT91C_UDPHS_END_TR_EN + //| AT91C_UDPHS_END_TR_IT + //| AT91C_UDPHS_END_B_EN + //| AT91C_UDPHS_END_BUFFIT + //| AT91C_UDPHS_DESC_LD_IT + ; + + return USBD_STATUS_SUCCESS; + } +#endif + + // DMA is not used + { + unsigned char nbBanks = CHIP_USB_ENDPOINTS_BANKS(bEndpoint); + + // Setup the transfer descriptor + pTransfer->pMbl = (USBDTransferBuffer*)pMbl; + pTransfer->listSize = wListSize; + pTransfer->fCallback = fCallback; + pTransfer->pArgument = pArgument; + pTransfer->currBuffer = wStartNdx; + pTransfer->freedBuffer = 0; + pTransfer->pLastLoaded = &(((USBDTransferBuffer*)pMbl)[wStartNdx]); + pTransfer->circList = bCircList; + pTransfer->allUsed = 0; + + // Clear all buffer + for (i = 0; i < wListSize; i ++) { + + pTransfer->pMbl[i].transferred = 0; + pTransfer->pMbl[i].buffered = 0; + pTransfer->pMbl[i].remaining = pTransfer->pMbl[i].size; + } + + // Fill data into FIFO + for (; + nbBanks && pTransfer->pMbl[pTransfer->currBuffer].remaining; + nbBanks --) { + + UDPHS_MblWriteFifo(bEndpoint); + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSETSTA = + AT91C_UDPHS_TX_PK_RDY; + } + + // Enable interrup + AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_INTERUPT << bEndpoint); + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = 0 + //| AT91C_UDPHS_TX_COMPLT + | AT91C_UDPHS_TX_PK_RDY + ; + return USBD_STATUS_SUCCESS; + } +} + +//------------------------------------------------------------------------------ +/// Reads incoming data on an USB endpoint (OUT) +/// \param bEndpoint Index of endpoint +/// \param *pData Data to be readen +/// \param dLength Data length to be receive +/// \param fCallback Callback to be call after the success command +/// \param *pArgument Callback argument +/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS +//------------------------------------------------------------------------------ +char USBD_Read( unsigned char bEndpoint, + void *pData, + unsigned int dLength, + TransferCallback fCallback, + void *pArgument ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); + + // Return if the endpoint is not in IDLE state + if (pEndpoint->state != UDP_ENDPOINT_IDLE) { + + return USBD_STATUS_LOCKED; + } + + TRACE_DEBUG_WP("Read%d(%d) ", bEndpoint, dLength); + + // Endpoint enters Receiving state + pEndpoint->state = UDP_ENDPOINT_RECEIVING; + + // Set the transfer descriptor + pTransfer->pData = pData; + pTransfer->remaining = dLength; + pTransfer->buffered = 0; + pTransfer->transferred = 0; + pTransfer->fCallback = fCallback; + pTransfer->pArgument = pArgument; + +#ifdef DMA + // Test if endpoint type control + if(AT91C_UDPHS_EPT_TYPE_CTL_EPT == (AT91C_UDPHS_EPT_TYPE&(AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG))) { +#endif + // Control endpoint + // Enable endpoint IT + AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_INTERUPT << bEndpoint); + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_RX_BK_RDY; +#ifdef DMA + } + else { + if( CHIP_USB_ENDPOINTS_DMA(bEndpoint) == 0 ) { + TRACE_FATAL("Endpoint has no DMA\n\r"); + } + TRACE_DEBUG_WP("Read%d(%d) ", bEndpoint, dLength); + + // Others endpoints (not control) + if( pTransfer->remaining > DMA_MAX_FIFO_SIZE ) { + + // Transfer the max + pTransfer->buffered = DMA_MAX_FIFO_SIZE; + } + else { + // Transfer the good size + pTransfer->buffered = pTransfer->remaining; + } + + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMAADDRESS = (unsigned int)(pTransfer->pData); + + // Clear unwanted interrupts + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMASTATUS; + + // Enable DMA endpoint interrupt + AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_DMA << bEndpoint); + + TRACE_DEBUG_WP("\n\r_RR:%d ", pTransfer->remaining ); + TRACE_DEBUG_WP("B:%d ", pTransfer->buffered ); + TRACE_DEBUG_WP("T:%d ", pTransfer->transferred ); + + // DMA config + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = 0; // raz + AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = + ( ((pTransfer->buffered << 16) & AT91C_UDPHS_BUFF_COUNT) + | AT91C_UDPHS_END_TR_EN + | AT91C_UDPHS_END_TR_IT + | AT91C_UDPHS_END_B_EN + | AT91C_UDPHS_END_BUFFIT + | AT91C_UDPHS_CHANN_ENB ); + } +#endif + + return USBD_STATUS_SUCCESS; +} + +//------------------------------------------------------------------------------ +/// Reuse first used/released buffer with new buffer address and size to be used +/// in transfer again. Only valid when frame list is ringed. Can be used for +/// both read & write. +/// \param bEndpoint Endpoint number. +/// \param pNewBuffer Pointer to new buffer with data to send (0 to keep last). +/// \param wNewSize Size of the data buffer +//------------------------------------------------------------------------------ +char USBD_MblReuse( unsigned char bEndpoint, + unsigned char *pNewBuffer, + unsigned short wNewSize ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer); + USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->freedBuffer]); + + // Only for Multi-buffer-circle list + if (bEndpoint != 0 + && (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM + || pEndpoint->state == UDP_ENDPOINT_SENDINGM)) { + } + else { + + return USBD_STATUS_WRONG_STATE; + } + + TRACE_DEBUG_WP("MblReuse(%d), st%x, circ%d\n\r", + bEndpoint, pEndpoint->state, pTransfer->circList); + +#ifdef DMA + if (UDP_IsDmaUsed(bEndpoint)) { + + DmaLlTransfer *pDmallt = (DmaLlTransfer*)&(pEndpoint->transfer); + USBDDmaDescriptor *pDi = pDmallt->pFreedBuffer; + + // ONLY for circled list + if (!pDmallt->circList) { + + return USBD_STATUS_WRONG_STATE; + } + + // Check if there is freed buffer + if ((pDi == 0) || (pDi && !pDi->used) ) { + + return USBD_STATUS_LOCKED; + } + + // Update transfer information + pDmallt->pFreedBuffer = pDi->pNxtDesc; + if (pNewBuffer) { + + pDi->pDataAddr = pNewBuffer; + pDi->bufferLength = wNewSize; + } + /* + pDi->ctrlSettings = AT91C_UDPHS_CHANN_ENB + | AT91C_UDPHS_LDNXT_DSC + | AT91C_UDPHS_END_TR_EN + //| AT91C_UDPHS_END_TR_IT + | AT91C_UDPHS_END_B_EN + | AT91C_UDPHS_END_BUFFIT + | AT91C_UDPHS_DESC_LD_IT + ; */ + pDi->used = 0; + + pDmallt->allUsed = 0; + + return USBD_STATUS_SUCCESS; + } +#endif + + // DMA is not used + { + + // ONLY for circled list + if (!pTransfer->circList) { + + return USBD_STATUS_WRONG_STATE; + } + + // Check if there is freed buffer + if (pTransfer->freedBuffer == pTransfer->currBuffer + && !pTransfer->allUsed) { + + return USBD_STATUS_LOCKED; + } + + // Update transfer information + if ((++ pTransfer->freedBuffer) == pTransfer->listSize) + pTransfer->freedBuffer = 0; + if (pNewBuffer) { + + pBi->pBuffer = pNewBuffer; + pBi->size = wNewSize; + } + pBi->buffered = 0; + pBi->transferred = 0; + pBi->remaining = pBi->size; + + // At least one buffer is not processed + pTransfer->allUsed = 0; + } + + return USBD_STATUS_SUCCESS; +} + +//------------------------------------------------------------------------------ +/// Put endpoint into Halt state +/// \param bEndpoint Index of endpoint +//------------------------------------------------------------------------------ +void USBD_Halt( unsigned char bEndpoint ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + + TRACE_INFO("usbd_Halt%d ", bEndpoint); + // Check that endpoint is enabled and not already in Halt state + if( (pEndpoint->state != UDP_ENDPOINT_DISABLED) + && (pEndpoint->state != UDP_ENDPOINT_HALTED) ) { + + TRACE_INFO("Halt%d ", bEndpoint); + + // Abort the current transfer if necessary + UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED); + + // Put endpoint into Halt state + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSETSTA = AT91C_UDPHS_FRCESTALL; + pEndpoint->state = UDP_ENDPOINT_HALTED; + +#ifdef DMA + // Test if endpoint type control + if(AT91C_UDPHS_EPT_TYPE_CTL_EPT == (AT91C_UDPHS_EPT_TYPE&(AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG))) { +#endif + // Enable the endpoint interrupt + AT91C_BASE_UDPHS->UDPHS_IEN |= (1<UDPHS_IEN |= (1<state != UDP_ENDPOINT_DISABLED) { + if (pEndpoint->state == UDP_ENDPOINT_HALTED) { + + TRACE_DEBUG_WP("Unhalt%d ", bEndpoint); + + // Return endpoint to Idle state + pEndpoint->state = UDP_ENDPOINT_IDLE; + + // Clear FORCESTALL flag + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCLRSTA = AT91C_UDPHS_TOGGLESQ | AT91C_UDPHS_FRCESTALL; + + // Reset Endpoint Fifos + AT91C_BASE_UDPHS->UDPHS_EPTRST = (1<state == UDP_ENDPOINT_HALTED) { + status = 1; + } + return( status ); +} + +//------------------------------------------------------------------------------ +/// IS High Speed device working in High Speed ? +/// \return 1 if the device is in High Speed; otherwise 0 (Full Speed) +//------------------------------------------------------------------------------ +unsigned char USBD_IsHighSpeed( void ) +{ + unsigned char status = 0; + + if( AT91C_UDPHS_SPEED == (AT91C_BASE_UDPHS->UDPHS_INTSTA & AT91C_UDPHS_SPEED) ) + { + // High Speed + TRACE_DEBUG_WP("High Speed\n\r"); + status = 1; + } + else { + TRACE_DEBUG_WP("Full Speed\n\r"); + } + return( status ); +} + + +//------------------------------------------------------------------------------ +/// Causes the endpoint to acknowledge the next received packet with a STALL +/// handshake. +/// Further packets are then handled normally. +/// \param bEndpoint Index of endpoint +/// \return Operation result code: USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS +//------------------------------------------------------------------------------ +unsigned char USBD_Stall( unsigned char bEndpoint ) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + + // Check that endpoint is in Idle state + if (pEndpoint->state != UDP_ENDPOINT_IDLE) { + + TRACE_WARNING("UDP_Stall: Endpoint%d locked\n\r", bEndpoint); + return USBD_STATUS_LOCKED; + } + + TRACE_DEBUG_WP("Stall%d ", bEndpoint); + + AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSETSTA = AT91C_UDPHS_FRCESTALL; + + return USBD_STATUS_SUCCESS; +} + +//------------------------------------------------------------------------------ +/// Activates a remote wakeup procedure +//------------------------------------------------------------------------------ +void USBD_RemoteWakeUp(void) +{ + TRACE_DEBUG_WP("Remote WakeUp\n\r"); + + // Device is currently suspended + if (deviceState == USBD_STATE_SUSPENDED) { + + TRACE_DEBUG_WP("RW\n\r"); + UDPHS_EnableUsbClock(); + + // Activates a remote wakeup + AT91C_BASE_UDPHS->UDPHS_CTRL |= AT91C_UDPHS_REWAKEUP; + + while ((AT91C_BASE_UDPHS->UDPHS_CTRL&AT91C_UDPHS_REWAKEUP) == AT91C_UDPHS_REWAKEUP) { + + TRACE_DEBUG_WP("W"); + } + UDPHS_EnableBIAS(); + } + // Device is NOT suspended + else { + + TRACE_WARNING("USBD_RemoteWakeUp: Device is not suspended\n\r"); + } +} + +//------------------------------------------------------------------------------ +/// Sets the device address +/// \param address Adress to be set +//------------------------------------------------------------------------------ +void USBD_SetAddress( unsigned char address ) +{ + TRACE_DEBUG_WP("SetAddr(%d) ", address); + + // Set address + AT91C_BASE_UDPHS->UDPHS_CTRL &= ~(unsigned int)AT91C_UDPHS_DEV_ADDR; // RAZ Address + AT91C_BASE_UDPHS->UDPHS_CTRL |= address | AT91C_UDPHS_FADDR_EN; + + // If the address is 0, the device returns to the Default state + if (address == 0) { + deviceState = USBD_STATE_DEFAULT; + } + // If the address is non-zero, the device enters the Address state + else { + deviceState = USBD_STATE_ADDRESS; + } +} + +//------------------------------------------------------------------------------ +/// Changes the device state from Address to Configured, or from Configured +/// to Address. +/// This method directly access the last received SETUP packet to decide on +/// what to do. +/// \param cfgnum configuration number +//------------------------------------------------------------------------------ +void USBD_SetConfiguration( unsigned char cfgnum ) +{ + TRACE_DEBUG_WP("SetCfg(%d) ", cfgnum); + + // Check the request + if( cfgnum != 0 ) { + + // Enter Configured state + deviceState = USBD_STATE_CONFIGURED; + } + // If the configuration number is zero, the device goes back to the Address + // state + else { + + // Go back to Address state + deviceState = USBD_STATE_ADDRESS; + + // Abort all transfers + UDPHS_DisableEndpoints(); + } +} + +//------------------------------------------------------------------------------ +/// Enables the pull-up on the D+ line to connect the device to the USB. +//------------------------------------------------------------------------------ +void USBD_Connect( void ) +{ + TRACE_DEBUG_WP("Conn "); +#if defined(CHIP_USB_PULLUP_INTERNAL) + AT91C_BASE_UDPHS->UDPHS_CTRL &= ~(unsigned int)AT91C_UDPHS_DETACH; // Pull Up on DP + AT91C_BASE_UDPHS->UDPHS_CTRL |= AT91C_UDPHS_PULLD_DIS; // Disable Pull Down + +#elif defined(CHIP_USB_PULLUP_INTERNAL_BY_MATRIX) + TRACE_DEBUG_WP("PUON 1\n\r"); + AT91C_BASE_MATRIX->MATRIX_USBPCR |= AT91C_MATRIX_USBPCR_PUON; + +#elif defined(CHIP_USB_PULLUP_EXTERNAL) + +#ifdef PIN_USB_PULLUP + const Pin pinPullUp = PIN_USB_PULLUP; + if( pinPullUp.type == PIO_OUTPUT_0 ) { + + PIO_Set(&pinPullUp); + } + else { + + PIO_Clear(&pinPullUp); + } +#else + #error unsupported now +#endif + +#elif !defined(CHIP_USB_PULLUP_ALWAYSON) + #error Unsupported pull-up type. + +#endif +} + +//------------------------------------------------------------------------------ +/// Disables the pull-up on the D+ line to disconnect the device from the bus. +//------------------------------------------------------------------------------ +void USBD_Disconnect( void ) +{ + TRACE_DEBUG_WP("Disc "); + +#if defined(CHIP_USB_PULLUP_INTERNAL) + AT91C_BASE_UDPHS->UDPHS_CTRL |= AT91C_UDPHS_DETACH; // detach + AT91C_BASE_UDPHS->UDPHS_CTRL &= ~(unsigned int)AT91C_UDPHS_PULLD_DIS; // Enable Pull Down + +#elif defined(CHIP_USB_PULLUP_INTERNAL_BY_MATRIX) + AT91C_BASE_MATRIX->MATRIX_USBPCR &= ~AT91C_MATRIX_USBPCR_PUON; + +#elif defined(CHIP_USB_PULLUP_EXTERNAL) + +#ifdef PIN_USB_PULLUP + const Pin pinPullUp = PIN_USB_PULLUP; + if (pinPullUp.type == PIO_OUTPUT_0) { + + PIO_Clear(&pinPullUp); + } + else { + + PIO_Set(&pinPullUp); + } +#else + #error unsupported now +#endif + +#elif !defined(CHIP_USB_PULLUP_ALWAYSON) + #error Unsupported pull-up type. + +#endif + + // Device returns to the Powered state + if (deviceState > USBD_STATE_POWERED) { + + deviceState = USBD_STATE_POWERED; + } + if (previousDeviceState > USBD_STATE_POWERED) { + + previousDeviceState = USBD_STATE_POWERED; + } +} + +//------------------------------------------------------------------------------ +/// Certification test for High Speed device. +/// \param bIndex Test to be done +//------------------------------------------------------------------------------ +void USBD_Test( unsigned char bIndex ) +{ + char *pFifo; + unsigned char i; + + AT91C_BASE_UDPHS->UDPHS_IEN &= ~(unsigned int)AT91C_UDPHS_DET_SUSPD; // remove suspend for TEST + AT91C_BASE_UDPHS->UDPHS_TST |= AT91C_UDPHS_SPEED_CFG_HS; // force High Speed (remove suspend) + + switch( bIndex ) { + + case USBFeatureRequest_TESTPACKET: + TRACE_DEBUG_WP("TEST_PACKET "); + + AT91C_BASE_UDPHS->UDPHS_DMA[1].UDPHS_DMACONTROL = 0; + AT91C_BASE_UDPHS->UDPHS_DMA[2].UDPHS_DMACONTROL = 0; + + // Configure endpoint 2, 64 bytes, direction IN, type BULK, 1 bank + AT91C_BASE_UDPHS->UDPHS_EPT[2].UDPHS_EPTCFG = AT91C_UDPHS_EPT_SIZE_64 | AT91C_UDPHS_EPT_DIR_IN | AT91C_UDPHS_EPT_TYPE_BUL_EPT | AT91C_UDPHS_BK_NUMBER_1; + while( (signed int)(AT91C_BASE_UDPHS->UDPHS_EPT[2].UDPHS_EPTCFG & (unsigned int)AT91C_UDPHS_EPT_MAPD) != (signed int)AT91C_UDPHS_EPT_MAPD ) {} + + AT91C_BASE_UDPHS->UDPHS_EPT[2].UDPHS_EPTCTLENB = AT91C_UDPHS_EPT_ENABL; + + // Write FIFO + pFifo = (char*)((unsigned int *)(AT91C_BASE_UDPHS_EPTFIFO->UDPHS_READEPT0) + (EPT_VIRTUAL_SIZE * 2)); + for( i=0; iUDPHS_TST |= AT91C_UDPHS_TST_PKT; + // Send packet + AT91C_BASE_UDPHS->UDPHS_EPT[2].UDPHS_EPTSETSTA = AT91C_UDPHS_TX_PK_RDY; + break; + + case USBFeatureRequest_TESTJ: + TRACE_DEBUG_WP("TEST_J "); + AT91C_BASE_UDPHS->UDPHS_TST = AT91C_UDPHS_TST_J; + break; + + case USBFeatureRequest_TESTK: + TRACE_DEBUG_WP("TEST_K "); + AT91C_BASE_UDPHS->UDPHS_TST = AT91C_UDPHS_TST_K; + break; + + case USBFeatureRequest_TESTSE0NAK: + TRACE_DEBUG_WP("TEST_SEO_NAK "); + AT91C_BASE_UDPHS->UDPHS_IEN = 0; // for test + break; + + case USBFeatureRequest_TESTSENDZLP: + //while( 0 != (AT91C_BASE_UDPHS->UDPHS_EPT[0].UDPHS_EPTSTA & AT91C_UDPHS_TX_PK_RDY ) ) {} + AT91C_BASE_UDPHS->UDPHS_EPT[0].UDPHS_EPTSETSTA = AT91C_UDPHS_TX_PK_RDY; + //while( 0 != (AT91C_BASE_UDPHS->UDPHS_EPT[0].UDPHS_EPTSTA & AT91C_UDPHS_TX_PK_RDY ) ) {} + TRACE_DEBUG_WP("SEND_ZLP "); + break; + } + TRACE_DEBUG_WP("\n\r"); +} + + +//------------------------------------------------------------------------------ +/// Initializes the specified USB driver +/// This function initializes the current FIFO bank of endpoints, +/// configures the pull-up and VBus lines, disconnects the pull-up and +/// then trigger the Init callback. +//------------------------------------------------------------------------------ +void USBD_Init(void) +{ + unsigned char i; + + TRACE_DEBUG_WP("USBD Init()\n\r"); + + // Reset endpoint structures + UDPHS_ResetEndpoints(); + + // Enables the UDPHS peripheral + UDPHS_EnablePeripheral(); + + // XCHQ[2010.1.21]: From IP recomendation, the order for init is: + // - reset IP (EN_UDPHS), - enable PLL 480M, - enable USB Clock + + // Enables the USB Clock + // UDPHS_EnableUsbClock(); + + // Configure the pull-up on D+ and disconnect it +#if defined(CHIP_USB_PULLUP_INTERNAL) + AT91C_BASE_UDPHS->UDPHS_CTRL |= AT91C_UDPHS_DETACH; // detach + AT91C_BASE_UDPHS->UDPHS_CTRL |= AT91C_UDPHS_PULLD_DIS; // Disable Pull Down + +#elif defined(CHIP_USB_PULLUP_INTERNAL_BY_MATRIX) + TRACE_DEBUG_WP("PUON 0\n\r"); + AT91C_BASE_MATRIX->MATRIX_USBPCR &= ~AT91C_MATRIX_USBPCR_PUON; + +#elif defined(CHIP_USB_PULLUP_EXTERNAL) +#ifdef PIN_USB_PULLUP + const Pin pinPullUp = PIN_USB_PULLUP; + PIO_Configure(&pinPullUp, 1); + if (pinPullUp.type == PIO_OUTPUT_0) { + + PIO_Clear(&pinPullUp); + } + else { + + PIO_Set(&pinPullUp); + } +#else + #error unsupported now +#endif +#elif !defined(CHIP_USB_PULLUP_ALWAYSON) + #error Unsupported pull-up type. + +#endif + + // Reset and enable IP UDPHS + AT91C_BASE_UDPHS->UDPHS_CTRL &= ~(unsigned int)AT91C_UDPHS_EN_UDPHS; + AT91C_BASE_UDPHS->UDPHS_CTRL |= AT91C_UDPHS_EN_UDPHS; + // Enable and disable of the transceiver is automaticaly done by the IP. + + // Enables the USB Clock + // (XCHQ[2010.1.21], IP recomendation, setup clock after reset IP) + UDPHS_EnableUsbClock(); + + // With OR without DMA !!! + // Initialization of DMA + for( i=1; i<=((AT91C_BASE_UDPHS->UDPHS_IPFEATURES & AT91C_UDPHS_DMA_CHANNEL_NBR)>>4); i++ ) { + + // RESET endpoint canal DMA: + // DMA stop channel command + AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMACONTROL = 0; // STOP command + + // Disable endpoint + AT91C_BASE_UDPHS->UDPHS_EPT[i].UDPHS_EPTCTLDIS = (unsigned int)AT91C_UDPHS_SHRT_PCKT + | AT91C_UDPHS_BUSY_BANK + | AT91C_UDPHS_NAK_OUT + | AT91C_UDPHS_NAK_IN + | AT91C_UDPHS_STALL_SNT + | AT91C_UDPHS_RX_SETUP + | AT91C_UDPHS_TX_PK_RDY + | AT91C_UDPHS_TX_COMPLT + | AT91C_UDPHS_RX_BK_RDY + | AT91C_UDPHS_ERR_OVFLW + | AT91C_UDPHS_MDATA_RX + | AT91C_UDPHS_DATAX_RX + | AT91C_UDPHS_NYET_DIS + | AT91C_UDPHS_INTDIS_DMA + | AT91C_UDPHS_AUTO_VALID + | AT91C_UDPHS_EPT_DISABL; + + // Clear status endpoint + AT91C_BASE_UDPHS->UDPHS_EPT[i].UDPHS_EPTCLRSTA = AT91C_UDPHS_TOGGLESQ + | AT91C_UDPHS_FRCESTALL + | AT91C_UDPHS_RX_BK_RDY + | AT91C_UDPHS_TX_COMPLT + | AT91C_UDPHS_RX_SETUP + | AT91C_UDPHS_STALL_SNT + | AT91C_UDPHS_NAK_IN + | AT91C_UDPHS_NAK_OUT; + + // Reset endpoint config + AT91C_BASE_UDPHS->UDPHS_EPT[i].UDPHS_EPTCTLENB = 0; + + // Reset DMA channel (Buff count and Control field) + AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMACONTROL = AT91C_UDPHS_LDNXT_DSC; // NON STOP command + + // Reset DMA channel 0 (STOP) + AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMACONTROL = 0; // STOP command + + // Clear DMA channel status (read the register for clear it) + AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMASTATUS = AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMASTATUS; + + } + + AT91C_BASE_UDPHS->UDPHS_TST = forceUsbFS ? AT91C_UDPHS_SPEED_CFG_FS : 0; + AT91C_BASE_UDPHS->UDPHS_IEN = 0; + AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_UPSTR_RES + | AT91C_UDPHS_ENDOFRSM + | AT91C_UDPHS_WAKE_UP + | AT91C_UDPHS_ENDRESET + | AT91C_UDPHS_IEN_SOF + | AT91C_UDPHS_MICRO_SOF + | AT91C_UDPHS_DET_SUSPD; + + // Device is in the Attached state + deviceState = USBD_STATE_SUSPENDED; + previousDeviceState = USBD_STATE_POWERED; + + // Enable interrupts + AT91C_BASE_UDPHS->UDPHS_IEN = AT91C_UDPHS_ENDOFRSM + | AT91C_UDPHS_WAKE_UP + | AT91C_UDPHS_DET_SUSPD; + + // Disable USB clocks + UDPHS_DisableUsbClock(); + + // Configure interrupts + USBDCallbacks_Initialized(); +} + +//------------------------------------------------------------------------------ +/// Configure USB Speed, should be invoked before USB attachment. +/// \param forceFS Force to use FS mode. +//------------------------------------------------------------------------------ +void USBD_ConfigureSpeed(unsigned char forceFS) +{ + if (forceFS) { + AT91C_BASE_UDPHS->UDPHS_TST |= AT91C_UDPHS_SPEED_CFG_FS; + } + else { + AT91C_BASE_UDPHS->UDPHS_TST &= ~(unsigned int)AT91C_UDPHS_SPEED_CFG_FS; + } +} + + +//------------------------------------------------------------------------------ +/// Returns the current state of the USB device. +/// \return Device current state. +//------------------------------------------------------------------------------ +unsigned char USBD_GetState( void ) +{ + return deviceState; +} + + diff --git a/usb/device/core/core.dir b/usb/device/core/core.dir new file mode 100644 index 0000000..fcf0dc0 --- /dev/null +++ b/usb/device/core/core.dir @@ -0,0 +1,41 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// !Purpose +/// +/// This directory contains structures, definitions and functions for AT91 UDP. +/// They can be divided into two groups: +/// - Hardware layer: low-level operations on the USB UDP controller +/// - USBD_OTGHS.c USBD_UDP.c USBD_UDPHS.c +/// - USB Device API: other files in the directory, offers hardware-independent +/// methods and structures +//------------------------------------------------------------------------------ + diff --git a/usb/device/device.dir b/usb/device/device.dir new file mode 100644 index 0000000..2988e1e --- /dev/null +++ b/usb/device/device.dir @@ -0,0 +1,655 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// !!!Purpose +/// +/// This directory provides definitions, structs and functions for USB %device +/// applications with Atmel AT91 microcontrollers and USB %device framework. +/// +/// You can develop your own USB %device products based on the class-specific +/// driver code provided, or just take them as a refference. +/// +/// !!!Contents +/// There are two groups for the implement: +/// -# The hardware interface driver for USB peripheral on AT91 +/// microcontrollers (UDP or UDPHS), this is a part of the "AT91 USB +/// framework". +/// - "core": hardware interface driver for AT91 USB peripheral +/// -# The %device class driver to class-specific %device. +/// - "audio-speaker" +/// - "ccid" +/// - "cdc-serial" +/// - "hid-keyboard" +/// - "massstorage" +/// +/// For more information about what a particular group contains, please refer to +/// its documentation page. +/// +/// \note +/// Depending on the project, not all the subdirectories will be available +/// (i.e. the #ccid# directory will not be in projects without USB CCID +/// function). +//------------------------------------------------------------------------------ + +/** + \page "USBD API" + + See "USBD API Structures" and "USBD API Methods".\n + + !!!USBD API Structures + + Several specific structures are used by the USBD API to perform various + operations, such as invoking callbacks or accessing the USBD controller. + + There are two %main structures: + - USBDDriver: + It is the %main structure of the USB API. It should be instanciated + in class-specific USB %device driver or user application. + - USBDDriverDescriptors: + It is a list of all descriptors used by a USB %device driver. It + should be instanciated in class-specific USB %device driver or + user application and passed to USBD by USBDDriver_Initialize. + + !!!USBD API Methods + + The USB API provides serveral methods to perform the following operations: + - Changing the %device state + - USBD_Init + - USBD_Connect, USBD_Disconnect + - USBD_SetAddress + - USBD_SetConfiguration + - USBD_GetState + - "USB Device State Diagram" + - Handling events coming from the USB controller + - USBD_IrqHandler + - Modifying the behavior of an endpoint + - USBD_ConfigureEndpoint + - USBD_Stall + - USBD_Halt + - USBD_Unhalt + - USBD_IsHalted + - Transferring data + - USBD_Write + - USBD_Read + - USBD_IsoWrite + - Special functions + - USBD_RemoteWakeUp + + See "USBD API Methods" for detailed informations. + +*/ + +/** + \page "USBD API Structures" + + !!!USBD API Structures + + Several specific structures are used by the USBD API to perform various + operations, such as invoking callbacks or accessing the USBD controller. + + There are two %main structures: + - USBDDriver: + It is the %main structure of the USB API. It should be instanciated + in class-specific USB %device driver or user application. + - USBDDriverDescriptors: + It is a list of all descriptors used by a USB %device driver. It + should be instanciated in class-specific USB %device driver or + user application and passed to USBD by USBDDriver_Initialize. + + */ + +/** + \page "USBD API Methods" + + !!!USB API methods + + The USB API provides serveral methods to perform the following operations: + - Changing the %device state + - USBD_Init + - USBD_Connect, USBD_Disconnect + - USBD_SetAddress + - USBD_SetConfiguration + - USBD_GetState + - "USB Device State Diagram" + - Handling events coming from the USB controller + - USBD_IrqHandler + - Modifying the behavior of an endpoint + - USBD_ConfigureEndpoint + - USBD_Stall + - USBD_Halt + - USBD_Unhalt + - USBD_IsHalted + - Transferring data + - USBD_Write + - USBD_Read + - USBD_IsoWrite + - Special functions + - USBD_RemoteWakeUp + + !!!Controlling the Device State + + Chapter 9 of the USB specification 2.0 describes the various states a %device + can be in. Most of the methods of this API are used to change between those + states. + + !!USBD_Init + + USBD_Init is the first method to call in a user application. Technically, it + must occur just before entering the Attached state. It performs the following + actions: + - USB Device driver and endpoint state initialization + - D+ pull-up configuration and disabling + - UDP hardware initialization (Peripheral and clock init) + + A USB %device uses a pull-up on the D+ line to signal its connection to the + host. Depending on the USB controller present on the chip, either an + internal or external pull-up is used. In both cases, its configuration is + performed directly by this method. Please refer to the documentation of a + particular controller for more information about the D+ pull-up. + + The ini callback has to perform several mandatory operations at this point. + You can find the default operations in USBDCallbacks_Initialized. + + !!USBD_Connect, USBD_Disconnect + + These two methods control the state of the D+ upll-up. This makes it possible + to connect of disconnect the %device by software when needed. USBD_Connect + changes the %device state from Powered to Default, while USBD_Disconnect + changes from either Default, Address or Configured to Powered. + + !!USBD_SetAddress + + USBD_SetAddress extracts the information from the last received + SETUP packet to either change the %device state from Default to + Address or from Address to Default. The difference is made + depending on the value of the wValue field of the request. + + This method must only be called right after the SET_ADDRESS + request is received. + + !!USBD_SetConfiguration + + This function operates in a way similar to USBD_SetAddress. When the SETUP + packet containing a SET_CONFIGURATION request is received, + USBD_SetConfiguration should be called to extract the new configuration + value to adopt. If the wValue field of the request is non-zero, then the + %device must adopt the new configuration and enter the Configuration state; + otherwise, it returns (or stays) in the Address state. + + !!USBD_GetState + + As its name implies, USBD_GetState simply returns the current state of the USB + driver. See state definitions on "USB %device states". + - USBD_STATE_SUSPENDED + - USBD_STATE_ATTACHED + - USBD_STATE_POWERED + - USBD_STATE_DEFAULT + - USBD_STATE_ADDRESS + - USBD_STATE_CONFIGURED + + !!Device State Diagram + See "USB Device State Diagram" + + !!!Event Handling (USBD_IrqHandler) + Several events can occur at the USB controller level: + - End of bus reset + - Reception of a SETUP packet + - Change of bus activity (active -> idle -> active ..) + - Completin of an endpoint operation + - ... + + Whenever such an event occurs, it must be forwarded to the USBD API to be + handled in an appropriate way. The USBD_IrqHandler performs this + functionality, so the controller interrupt must be configured to call it. + + Several #callbacks# can be triggered depending on the event notified by + the controller: + - Suspend, when the bus is idle + - Resume, when the bus becomes active again + - NewRequest, when a setup packet is received on a control endpoint + - StartOfFrame, every 1 ms (for full-speed controllers) or 125us (for high- + speed controllers) + + More information about these callbacks and their expected behavior can be + found in "USBD Callback API". + + !!!Endpoint Behavior Modification + + The USBD API offers following functions to control how an endpoint operates. + - USBD_ConfigureEndpoint + - USBD_Stall + - USBD_Halt + - USBD_Unhalt + - USBD_IsHalted + + !!USBD_ConfigureEndpoint + USBD_ConfigureEndpoint is used to configure an endpoint at the USB controller + level. An appropriate endpoint descriptor must be provided to do that. The + descriptor is used to configure the endpoint type (either Control, Bulk, + Interrupt or Isochronous), direction (IN or OUT) and address. + + Control endpoint 0 is automatically configured by the USBD API when the End of + bus reset event is signalled by the USB controller. Therefore, there is no need + to do it manually. + + !!USBD_Stall + The USBD_Stall method causes and endpoint to acknowledge its next received + packet with a STALL handshake. Further packets are then handled normally. + + Most of the time, this method should be used with endpoint 0 to signal the + host that the %device cannot process a command. + + !!USBD_Halt, USBD_Unhalt, USBD_IsHalted + USBD_Halt sets the Halt status of an endpoint. When in Halt mode, every + received packet is acknowledged with a STALL handshake instead of being + handled normally. + + #}USB_Halt#} can be called either with the USB_SET_FEATURE, USB_CLEAR_FEATURE + or USB_GET_STATUS parameter to modify the endpoint Halt state. + + USBD_Unhalt clears the Halt status of an endpoint. + + USBD_IsHalted gets the Halt status of an endpoint. + + !!!Data Transfer + Data transfer (IN or OUT) on an endpoint can be performed by calling two + methods, USBD_Write and USBD_Read. + + !!USBD_Write + The USBD_Write function sends a data payload on a specific endpoint. If the + data payload equals or exceeds the maximum packet size of the endpoint, then + several IN transactions are necessary. This method should only be called on an + IN or Control endpoint. + + The write is performed #asynchronously#, i.e., the function returns immediately + without waiting for the transfer to finish. When the transfer is complete, an + optional user-provided callback function is called. This makes it possible to + create an #OS-friendly synchronous function# by locking and unlocking a + semaphore before and after each write. + + This function handles double-buffering, if it is supported by the USB + controller and if it has been enabled for the endpoint. Do not forget that + using double-buffering is mandatory for isochronous transactions. + + - #Note# + The double-buffering this function supported is only in period of each + write action. That is, when the function is invoked to start transfer + trunk of data, the data is automatically splitted to several IN + transactions and ping-pong is started on the 2nd transaction. But when + all the data of the trunk is finished the ping-pong is stopped. So it can + not process the list of buffer that should use double-buffering all the + time. See USBD_IsoWrite for such kind of operations. + + !!USBD_Read + The USBD_Read reads incoming data on an endpoint. The transfer stops either + when the provided buffer is full, or a short packet (size inferior to the + endpoint maximum packet size) is received. This method must only be called on + an OUT or Control endpoint. + + The read is performed #asynchronously#, i.e., the function returns immediately + without waiting for the transfer to finish. When the transfer is complete, an + optional user-provided callback function is called. This makes it possible to + create an #OS-friendly synchronous function# by locking and unlocking a + semaphore before and after each read. + + This function handles #double-buffering#, if it is supported by the USB + controller and if it has been enabled for the endpoint. Do not forget that + using double-buffering is mandatory for isochronous transactions. + + !!USBD_IsoWrite + The USBD_IsoWrite function sends a buffer list on a specific endpoint. The each + buffer's payload should be equals or less than the maximum packet size of the + endpoint. The transfer ends when all buffera are sent out. And the buffer is + previously sent can be filled with new data before the transfer ends. To + maitain a ring buffer for the outgoing stream. This method should only be + called on an ISO IN endpoint. + + The write is performed #asynchronously#, i.e., the function returns immediately + without waiting for the transfer to finish. When the transfer is complete, an + optional user-provided callback function is called. This makes it possible to + create an #OS-friendly synchronous function# by locking and unlocking a + semaphore before and after each write. + + This function handles double-buffering, if it is supported by the USB + controller and if it has been enabled for the endpoint. Do not forget that + using double-buffering is mandatory for isochronous transactions. + + !!!Special Functions + + - USBD_RemoteWakeUp: This method starts a remote wakeup procedure. This makes + it possible for a suspended %device to wake a host with may itself be + suspended. + +*/ + +/** + \page "USB Device State Diagram" + + \image USBDeviceStateDiagram.png "Changing the Device State" + +*/ + +/* (Image Link Backup) +USBDeviceStateDiagram.png + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +USBDCallbackInvocationFlowchart.png +*/ + +/** + \page "USBD Callback API" + + !!!Callback API + + The callback API is a means of communication between the user application and + the USBD API. When particular operations must be performed, the USB driver + calls serveral external functions, refferred to as #callbacks#. They can also + be invoked to notify the user application of pending events. + + Defining all callbacks is not mandatory. For example, if the %device shall not + enter low-power mode, then it is appropriate not to provide a Suspend callback. + If a callback is mandatory, this is notified in its description. + + See USBDCallbacks.h for callback definitions. + + !!!Callback Invocation + The following events can trigger a callback: + - USB initialization: USBDCallbacks_Initialized + - End of bus reset: USBDCallbacks_Reset + - Device suspend: USBDCallbacks_Suspended + - Device resume: USBDCallbacks_Resumed + - SETUP request received: USBDCallbacks_RequestReceived + - Start of a new USB frame + + \image USBDCallbackInvocationFlowchart.png "Callback Invocation Flowchart" + + !!Init + The USBDCallbacks_Initialized callback is invoked when the USBD_Init method is + called. It has to perform several mandatory steps to make it possible to use + the API: + - If an OS is used, perform any specific operation to install the driver + - Configure USB controller interrupt + - Configure Vbus monitoring PIO and interrupt ( but it's in app layer now ) + The USB controller interrupt must be configured to #call the + USBD_IrqHandler# API function when triggered. This is necessary to have + events happening at the USB controller level handled appropriately by the API. + + If a PIO pin is connected to VBus, it is possible to monitor it by configuring + the pin as an input and enabling the PIO interrupt. The interrupt service + routine should simply check the Vbus status and then %call the USBD_Connect + and USBD_Disconnect$ function to put %device into right state. + + Finally, if an OS is being used, then the driver should probably be installed + prior to use. Interrupt configuration may also be done differently. Please + refer to the documentation of the OS for more information. + + This callback is #mandatory#. + + !!Reset + When an End of bus reset has been detected, the USBDCallbacks_Reset callback + is triggered. The callback should perform #initialization# or #re- + initialization# of the user-level application. For example, a class driver + like MSD should re-initialize its internal state when a USB reset is performed. + + !!Suspend + When the USB %device enters the Suspended state, the USB API notifies this state + change by invoking the USBDCallbacks_Suspended callback. This can happen either + when the bus is idle or when the %device is disconnected from the USB. + + If the %device should enter low-power mode when suspended, then this callback + must perform the required operations to do so, e.g., switching to a slow clock, + disabling PLLs, etc. + + - }Note: The electrical specification of the USB 2.0 defines a maximum current + consumption of 500uA for suspended %device. This includes the current passing + through pull-ups and upll-downs.} + + !!Resume + The USBDCallbacks_Resumed callback is invoked when the USB %device leaves the + Suspended state and returns to its previous state (either Powered, Default, + Address or Configured). This may happen when activity is detected on the USB, + or when the %device gets connected. + + If the %device was in low-power mode because of the Suspend callback, then this + callback must perform the necessary poerations to return the %device into a + normal operation mode, e.g., switching to a fast clock. + + !!NewRequest + When a SETUP request is received on a control endpoint, the USBD API layer + triggers the USBDCallbacks_RequestReceived callback to notify the user + application. The received request can then be accessed through the + corresponding USBGenericRequest structure. + + SETUP packets are used for class-specific requests (e.g. }GetMaxLUN} in MSD) + as well as standard USB requests (e.g. }SetConfiguration}). The former are + described in }USB Device Class Documents}, such as the }Mass Storage Bulk + Only 1.0}, the latter are defined in the USB Specification 2.0. + + - }Note: that SETUP requests which are not understood by the %device should + be acknowledged with a STALL handshake. This notifies the host that the + %device cannot process the command.} + + This callback is #mandatory#. + + !!StartOfFrame + Every 1ms (for a full-speed %device) or 125us (for a high-speed %device) a + new USB frame starts. A callback can be invoked whenever this occurs. + + Because the start-of-frame interrupt %puts some stress on the processor + (since it is called a lot), it is only activated the corresponding + callback is defined (#now it's NOT defined in current framework#). + +*/ + +/** + \page "USBD Standard Request Handler" + + !!!Standard Request Handler + + Chapter 9 of the USB specification 2.0 defines a set of standard requests + which have to be implemented by all devices. Since most class drivers treat + those requests in the standard way, the USB framework provides a way to easily + do that. + + !!!USBDDriver_RequestHandler + + USBDDriver_RequestHandler handles the standard requests in an appropriate way. + It can answer the following commands: + + - GET_DESCRIPTOR + - SET_ADDRESS + - SET_CONFIGURATION + - GET_CONFIGURATION + - CLEAR_FEATURE + - SET_FEATURE + - GET_STATUS + + Simply using this standard request handler enables a %device to be enumerated + correctly. + + !!Get Descriptor + The GET_DESCRIPTOR request is used by the host to retrieve information about + the %device by means of several descriptors. + + The standard request handler simply sends the corresponding descriptor to the + host. How these descriptors are provided to the function is discussed in + Structures. + + !!Set Address + Whenever the host wants to change the %device state from Default to Address, or + vice-versa, it sends a SET_ADDRESS request. The wValue field contains the new + address of the %device; if it is null, then the %device returns to the Default + state. + + The USBD_SetAddress function is called to perform this operation. Note that a + zero-length packet must be sent prior to doing that, to acknowledge the SETUP + transfer. + + !!Set Configuration & GetConfiguration + The SET_CONFIGURATION request makes it possible for the host to select between + one or more configurations for the %device. GET_CONFIGURATION is used to + retrieve the currently selected one. + + Those two requests are handled in a very basic way by + USBDDriver_RequestHandler: it assumes that the %device has only one + configuration. Therefore, the SET_CONFIGURATION request is simply acknowledged + with a zero-length packet, and GET_CONFIGURATION is answered with either 0 + or 1. If the user application needs more than one configuration, it will be + the duty of the class driver handler to service those requests. + + In addition, when the SET_CONFIGURATION request causes the %device to enter the + Configured state, the standard request handler calls the USBD_ConfigureEndpoint + method for each endpoint used by the %device; + + !!Clear Feature, Set Feature & Get Status + Several features of a %device can either be activated or deactivated by the USB + host: + - Remote wakeup + - Endpoint Halt state + Three requests can be used to either set, clear or get the status of these two + features: SET_FEATURE, CLEAR_FEATURE and GET_STATUS. + + The USBDDriver_RequestHandler method answers a Halt state operation by calling + the USBD_Halt method on the endpoint with the request. + + !!!Structures + Several pieces of information must be known to the USBDDriver_RequestHandler + to be able to process some SETUP commands. For example, all the descriptors + (configuration, etc.) used by the %device are needed since they must be sent + to the host when a GET_DESCRIPTOR is received. + + The USBGenericRequest structure is a "standard USB class driver" object used + to hold the required information. It must be passed as an argument to the + USBDDriver_RequestHandler method. Another structure, USBDDriverDescriptors, is + used to store the descriptors list. + + !!!Usage + The NewRequest callback is used to notify the user application that a new SETUP + request has been received. SETUP request can either be class-specific or + standard. + + The correct way to handle incoming requests is to first process class-specific + requests using a class handler. For example, a Mass Storage implementation will + define the NewRequest callback to call MSDDriver_RequestHandler. This function + will handle the necessary requests, and forward the rest to + USBDDriver_RequestHandler. + + If a request cannot be processed, USBDDriver_RequestHandler will STALL control + endpoint 0. + +*/ + +/** + \page "VID, PID, SN & Strings" + + This page collects the definition for USB %device to indicate the Vendor and + Product information. + + + If you need only the functions in demo %driver, you can easily modify these + definitions to change your device's Identification and Display strings. + + They are defined in the driver c code file that suffixed with + "DriverDescriptors" under the driver directory. + + !!!VID, PID & SN in Device Descriptor + + Defined as const and used in USBDeviceDescriptor instance initialization. + Gives identivication to the USB %device by VID and PID. The INF installation + file should mach the VID & PID so that the %device can be installed. + +\code +const USBDeviceDescriptor deviceDescriptor = {...}; +\endcode + + - "audio-speaker": "Audio Speaker Device Codes" + - ccid: "CCID Device IDs" + - "cdc-serial": "CDC Serial Device IDs" + - "hid-keyboard": "HID Device Descriptor IDs" + - massstorage: "MSD Device Descriptor IDs" + + !!!Strings + + The strings gives additional information on the USB %device, normally string + description about the vendor, product and serial number. + + The strings are defined as a list to initialize the driver's + USBDDriverDescriptors instance: + + - "audio-speaker": auddSpeakerDriverDescriptors + - ccid: ccidDriverDescriptors + - "cdc-serial": cdcdSerialDriverDescriptors + - "hid-keyboard": hiddKeyboardDriverDescriptors + - massstorage: msdDriverDescriptors + +\code +// String descriptors +const unsigned char *stringDescriptors[] = { + + languageIdDescriptor, + manufacturerDescriptor, + productDescriptor, + serialNumberDescriptor, +}; +\endcode +*/ diff --git a/usb/device/hid-keyboard/HIDClassArch.png b/usb/device/hid-keyboard/HIDClassArch.png new file mode 100644 index 0000000..6d09580 Binary files /dev/null and b/usb/device/hid-keyboard/HIDClassArch.png differ diff --git a/usb/device/hid-keyboard/HIDDKeyboardCallbacks.h b/usb/device/hid-keyboard/HIDDKeyboardCallbacks.h new file mode 100644 index 0000000..6bbfaea --- /dev/null +++ b/usb/device/hid-keyboard/HIDDKeyboardCallbacks.h @@ -0,0 +1,57 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit HIDDKeyboardCallbacks + + !!!Purpose + + Definitions of callbacks used by the HID keyboard device driver to + notify the application of events. + + !!!Usage + + -# Re-implement any number of these callbacks anywhere in the program; + they will be called automatically by the driver when the related + event occurs. +*/ + +#ifndef HIDDKEYBOARDCALLBACKS_H +#define HIDDKEYBOARDCALLBACKS_H + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern void HIDDKeyboardCallbacks_LedsChanged(unsigned char numLockStatus, + unsigned char capsLockStatus, + unsigned char scrollLockStatus); + +#endif //#ifndef HIDDKEYBOARDCALLBACKS_H + diff --git a/usb/device/hid-keyboard/HIDDKeyboardCallbacks_LedsChanged.c b/usb/device/hid-keyboard/HIDDKeyboardCallbacks_LedsChanged.c new file mode 100644 index 0000000..be8963d --- /dev/null +++ b/usb/device/hid-keyboard/HIDDKeyboardCallbacks_LedsChanged.c @@ -0,0 +1,59 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "HIDDKeyboardCallbacks.h" +#include + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Indicates that the status of one or more LEDs has been changed by the +/// host. +/// \param numLockStatus Indicates the current status of the num. lock key. +/// \param capsLockStatus Indicates the current status of the caps lock key. +/// \param scrollLockStatus Indicates the current status of the scroll lock key. +//------------------------------------------------------------------------------ +void HIDDKeyboardCallbacks_LedsChanged( + unsigned char numLockStatus, + unsigned char capsLockStatus, + unsigned char scrollLockStatus) +{ + TRACE_INFO( + "LEDs status: %d, %d, %d\n\r", + numLockStatus, + capsLockStatus, + scrollLockStatus); +} + diff --git a/usb/device/hid-keyboard/HIDDKeyboardDriver.c b/usb/device/hid-keyboard/HIDDKeyboardDriver.c new file mode 100644 index 0000000..e244cb5 --- /dev/null +++ b/usb/device/hid-keyboard/HIDDKeyboardDriver.c @@ -0,0 +1,477 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "HIDDKeyboardDriver.h" +#include "HIDDKeyboardDriverDescriptors.h" +#include "HIDDKeyboardCallbacks.h" +#include "HIDDKeyboardInputReport.h" +#include "HIDDKeyboardOutputReport.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Internal types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Driver structure for an HID device implementing keyboard functionalities. +//------------------------------------------------------------------------------ +typedef struct { + + /// Standard USB device driver instance. + USBDDriver usbdDriver; + /// Idle rate (in milliseconds) of the input report. + unsigned char inputReportIdleRate; + /// Input report instance. + HIDDKeyboardInputReport inputReport; + /// Output report instance. + HIDDKeyboardOutputReport outputReport; + +} HIDDKeyboardDriver; + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +/// Static instance of the HID keyboard device driver. +static HIDDKeyboardDriver hiddKeyboardDriver; + +//------------------------------------------------------------------------------ +// Internal functions +//------------------------------------------------------------------------------ + +/** + Returns the descriptor requested by the host. + +\param type Descriptor type. +\param length Maximum number of bytes to send. +\return 1 if the request has been handled by this function, otherwise 0. +*/ +static unsigned char HIDDKeyboardDriver_GetDescriptor(unsigned char type, + unsigned char length) +{ + const USBConfigurationDescriptor *pConfiguration; + HIDDescriptor *hidDescriptors[2]; + + switch (type) { + + case HIDGenericDescriptor_REPORT: + TRACE_INFO_WP("Report "); + + // Adjust length and send report descriptor + if (length > HIDDKeyboardDriverDescriptors_REPORTSIZE) { + + length = HIDDKeyboardDriverDescriptors_REPORTSIZE; + } + USBD_Write(0, &hiddReportDescriptor, length, 0, 0); + break; + + case HIDGenericDescriptor_HID: + TRACE_INFO_WP("HID "); + + // Configuration descriptor is different depending on configuration + if (USBD_IsHighSpeed()) { + + pConfiguration = hiddKeyboardDriver.usbdDriver.pDescriptors->pHsConfiguration; + } + else { + + pConfiguration = hiddKeyboardDriver.usbdDriver.pDescriptors->pFsConfiguration; + } + + // Parse the device configuration to get the HID descriptor + USBConfigurationDescriptor_Parse( + pConfiguration, + 0, + 0, + (USBGenericDescriptor **) hidDescriptors); + + // Adjust length and send HID descriptor + if (length > sizeof(HIDDescriptor)) { + + length = sizeof(HIDDescriptor); + } + USBD_Write(0, hidDescriptors[0], length, 0, 0); + break; + + default: + return 0; + } + + return 1; +} + +/** + Sends the current Idle rate of the input report to the host. +*/ +static void HIDDKeyboardDriver_GetIdle() +{ + TRACE_INFO_WP("gIdle "); + + USBD_Write(0, &(hiddKeyboardDriver.inputReportIdleRate), 1, 0, 0); +} + +/** + Retrieves the new idle rate of the input report from the USB host. + + \param idleRate New input report idle rate. +*/ +static void HIDDKeyboardDriver_SetIdle(unsigned char idleRate) +{ + TRACE_INFO_WP("sIdle(%d) ", idleRate); + + hiddKeyboardDriver.inputReportIdleRate = idleRate; + USBD_Write(0, 0, 0, 0, 0); +} + +/** + Sends the requested report to the host. + +\param type Report type. +\param length Maximum number of bytes to send. +*/ +static void HIDDKeyboardDriver_GetReport(unsigned char type, + unsigned short length) +{ + TRACE_INFO_WP("gReport "); + + // Check report type + switch (type) { + + case HIDReportRequest_INPUT: + TRACE_INFO_WP("In "); + + // Adjust size and send report + if (length > sizeof(HIDDKeyboardInputReport)) { + + length = sizeof(HIDDKeyboardInputReport); + } + USBD_Write(0, // Endpoint #0 + &(hiddKeyboardDriver.inputReport), + length, + 0, // No callback + 0); + break; + + case HIDReportRequest_OUTPUT: + TRACE_INFO_WP("Out "); + + // Adjust size and send report + if (length > sizeof(HIDDKeyboardOutputReport)) { + + length = sizeof(HIDDKeyboardOutputReport); + } + USBD_Write(0, // Endpoint #0 + &(hiddKeyboardDriver.outputReport), + length, + 0, // No callback + 0); + break; + + default: + USBD_Stall(0); + } +} + +/** + Callback invoked when an output report has been received from the host. + Forward the new status of the LEDs to the user program via the + HIDDKeyboardCallbacks_LedsChanged callback. +*/ +static void HIDDKeyboardDriver_ReportReceived() +{ + TRACE_INFO_WP("oReport "); + + // Trigger callback + HIDDKeyboardCallbacks_LedsChanged( + HIDDKeyboardOutputReport_GetNumLockStatus(&(hiddKeyboardDriver.outputReport)), + HIDDKeyboardOutputReport_GetCapsLockStatus(&(hiddKeyboardDriver.outputReport)), + HIDDKeyboardOutputReport_GetScrollLockStatus(&(hiddKeyboardDriver.outputReport))); + + // Restart transfer + USBD_Read(HIDDKeyboardDriverDescriptors_INTERRUPTOUT, + &(hiddKeyboardDriver.outputReport), + sizeof(HIDDKeyboardOutputReport), + (TransferCallback) HIDDKeyboardDriver_ReportReceived, + 0); // No argument for callback function +} + +/** + Retrieves the new value of a report from the host and saves it. + +\param type Report type. +\param length Report length. +*/ +static void HIDDKeyboardDriver_SetReport(unsigned char type, + unsigned short length) +{ + TRACE_INFO_WP("sReport "); + + // Check report type + switch (type) { + + case HIDReportRequest_INPUT: + // SET_REPORT requests on input reports are ignored + USBD_Stall(0); + break; + + case HIDReportRequest_OUTPUT: + // Check report length + if (length != sizeof(HIDDKeyboardOutputReport)) { + + USBD_Stall(0); + } + else { + + USBD_Read(0, // Endpoint #0 + &(hiddKeyboardDriver.outputReport), + length, + (TransferCallback) HIDDKeyboardDriver_ReportReceived, + 0); // No argument to the callback function + } + break; + + default: + USBD_Stall(0); + } +} + +//------------------------------------------------------------------------------ +// Optional RequestReceived() callback re-implementation +//------------------------------------------------------------------------------ +#if !defined(NOAUTOCALLBACK) + +void USBDCallbacks_RequestReceived(const USBGenericRequest *request) +{ + HIDDKeyboardDriver_RequestHandler(request); +} + +#endif + +//------------------------------------------------------------------------------ +// ConfigurationChanged() callback re-implementation +//------------------------------------------------------------------------------ +void USBDDriverCallbacks_ConfigurationChanged(unsigned char cfgnum) +{ + if (cfgnum > 0) { + + // Start receiving output reports + USBD_Read(HIDDKeyboardDriverDescriptors_INTERRUPTOUT, + &(hiddKeyboardDriver.outputReport), + sizeof(HIDDKeyboardOutputReport), + (TransferCallback) HIDDKeyboardDriver_ReportReceived, + 0); // No argument for callback function + } +} + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +/** + Initializes the HID keyboard device driver. +*/ +void HIDDKeyboardDriver_Initialize() +{ + hiddKeyboardDriver.inputReportIdleRate = 0; + HIDDKeyboardInputReport_Initialize(&(hiddKeyboardDriver.inputReport)); + HIDDKeyboardOutputReport_Initialize(&(hiddKeyboardDriver.outputReport)); + USBDDriver_Initialize(&(hiddKeyboardDriver.usbdDriver), + &hiddKeyboardDriverDescriptors, + 0); // Multiple interface settings not supported + USBD_Init(); +} + +/** + Handles HID-specific SETUP request sent by the host. + + \param request Pointer to a USBGenericRequest instance. +*/ +void HIDDKeyboardDriver_RequestHandler(const USBGenericRequest *request) +{ + TRACE_INFO_WP("NewReq "); + + // Check if this is a standard request + if (USBGenericRequest_GetType(request) == USBGenericRequest_STANDARD) { + + // This is a standard request + switch (USBGenericRequest_GetRequest(request)) { + + case USBGenericRequest_GETDESCRIPTOR: + // Check if this is a HID descriptor, otherwise forward it to + // the standard driver + if (!HIDDKeyboardDriver_GetDescriptor( + USBGetDescriptorRequest_GetDescriptorType(request), + USBGenericRequest_GetLength(request))) { + + USBDDriver_RequestHandler(&(hiddKeyboardDriver.usbdDriver), + request); + } + break; + + default: + USBDDriver_RequestHandler(&(hiddKeyboardDriver.usbdDriver), + request); + } + } + // Check if this is a class request + else if (USBGenericRequest_GetType(request) == USBGenericRequest_CLASS) { + + // This is a class-specific request + switch (USBGenericRequest_GetRequest(request)) { + + case HIDGenericRequest_GETIDLE: + HIDDKeyboardDriver_GetIdle(); + break; + + case HIDGenericRequest_SETIDLE: + HIDDKeyboardDriver_SetIdle(HIDIdleRequest_GetIdleRate(request)); + break; + + case HIDGenericRequest_GETREPORT: + HIDDKeyboardDriver_GetReport( + HIDReportRequest_GetReportType(request), + USBGenericRequest_GetLength(request)); + break; + + case HIDGenericRequest_SETREPORT: + HIDDKeyboardDriver_SetReport( + HIDReportRequest_GetReportType(request), + USBGenericRequest_GetLength(request)); + break; + + default: + TRACE_WARNING( + "HIDDKeyboardDriver_RequestHandler: Unknown REQ 0x%02X\n\r", + USBGenericRequest_GetRequest(request)); + USBD_Stall(0); + } + } + else { + + // Vendor request ? + USBD_Stall(0); + } +} + +/** + Reports a change in which keys are currently pressed or release to the + host. + +\param pressedKeys Pointer to an array of key codes indicating keys that have + been pressed since the last call to HIDDKeyboardDriver_ChangeKeys. +\param pressedKeysSize Number of key codes in the pressedKeys array. +\param releasedKeys Pointer to an array of key codes indicates keys that have + been released since the last call to HIDDKeyboardDriver_ChangeKeys. +\param releasedKeysSize Number of key codes in the releasedKeys array. +\return USBD_STATUS_SUCCESS if the report has been sent to the host; + otherwise an error code. +*/ +unsigned char HIDDKeyboardDriver_ChangeKeys(unsigned char *pressedKeys, + unsigned char pressedKeysSize, + unsigned char *releasedKeys, + unsigned char releasedKeysSize) +{ + // Press keys + while (pressedKeysSize > 0) { + + // Check if this is a standard or modifier key + if (HIDKeypad_IsModifierKey(*pressedKeys)) { + + // Set the corresponding bit in the input report + HIDDKeyboardInputReport_PressModifierKey( + &(hiddKeyboardDriver.inputReport), + *pressedKeys); + } + else { + + HIDDKeyboardInputReport_PressStandardKey( + &(hiddKeyboardDriver.inputReport), + *pressedKeys); + } + + pressedKeysSize--; + pressedKeys++; + } + + // Release keys + while (releasedKeysSize > 0) { + + // Check if this is a standard or modifier key + if (HIDKeypad_IsModifierKey(*releasedKeys)) { + + // Set the corresponding bit in the input report + HIDDKeyboardInputReport_ReleaseModifierKey( + &(hiddKeyboardDriver.inputReport), + *releasedKeys); + } + else { + + HIDDKeyboardInputReport_ReleaseStandardKey( + &(hiddKeyboardDriver.inputReport), + *releasedKeys); + } + + releasedKeysSize--; + releasedKeys++; + } + + // Send input report through the interrupt IN endpoint + return USBD_Write(HIDDKeyboardDriverDescriptors_INTERRUPTIN, + &(hiddKeyboardDriver.inputReport), + sizeof(HIDDKeyboardInputReport), + 0, + 0); +} + +//------------------------------------------------------------------------------ +/// Starts a remote wake-up sequence if the host has explicitely enabled it +/// by sending the appropriate SET_FEATURE request. +//------------------------------------------------------------------------------ +void HIDDKeyboardDriver_RemoteWakeUp(void) +{ + // Remote wake-up has been enabled + if (USBDDriver_IsRemoteWakeUpEnabled(&(hiddKeyboardDriver.usbdDriver))) { + + USBD_RemoteWakeUp(); + } +} + diff --git a/usb/device/hid-keyboard/HIDDKeyboardDriver.h b/usb/device/hid-keyboard/HIDDKeyboardDriver.h new file mode 100644 index 0000000..42dc0a2 --- /dev/null +++ b/usb/device/hid-keyboard/HIDDKeyboardDriver.h @@ -0,0 +1,75 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit HIDDKeyboardDriver + + !!!Purpose + + Definition of methods for using a HID keyboard device driver. + + !!!Usage + + -# Re-implement the USBDCallbacks_RequestReceived callback to forward + requests to HIDDKeyboardDriver_RequestHandler. This is done + automatically unless the NOAUTOCALLBACK symbol is defined during + compilation. + -# Initialize the driver using HIDDKeyboardDriver_Initialize. The + USB driver is automatically initialized by this method. + -# Call the HIDDKeyboardDriver_ChangeKeys method when one or more + keys are pressed/released. +*/ + +#ifndef HIDDKEYBOARDDRIVER_H +#define HIDDKEYBOARDDRIVER_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern void HIDDKeyboardDriver_Initialize(); + +extern void HIDDKeyboardDriver_RequestHandler(const USBGenericRequest *request); + +extern unsigned char HIDDKeyboardDriver_ChangeKeys( + unsigned char *pressedKeys, + unsigned char pressedKeysSize, + unsigned char *releasedKeys, + unsigned char releasedKeysSize); + +extern void HIDDKeyboardDriver_RemoteWakeUp(void); + +#endif //#ifndef HIDDKEYBOARDDRIVER_H + diff --git a/usb/device/hid-keyboard/HIDDKeyboardDriverDescriptors.c b/usb/device/hid-keyboard/HIDDKeyboardDriverDescriptors.c new file mode 100644 index 0000000..51dfb48 --- /dev/null +++ b/usb/device/hid-keyboard/HIDDKeyboardDriverDescriptors.c @@ -0,0 +1,420 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: HIDDKeyboardDriverDescriptors + + About: Purpose + Declaration of the descriptors used by the HID device keyboard driver. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "HIDDKeyboardDriverDescriptors.h" +#include "HIDDKeyboardInputReport.h" +#include "HIDDKeyboardOutputReport.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Device Descriptor IDs" +/// This page lists VID, PID & Release number. +/// +/// !IDs +/// - HIDDKeyboardDriverDescriptors_PRODUCTID +/// - HIDDKeyboardDriverDescriptors_VENDORID +/// - HIDDKeyboardDriverDescriptors_RELEASE + +/// Device product ID. +#define HIDDKeyboardDriverDescriptors_PRODUCTID 0x6127 +/// Device vendor ID. +#define HIDDKeyboardDriverDescriptors_VENDORID 0x03EB +/// Device release number. +#define HIDDKeyboardDriverDescriptors_RELEASE 0x0100 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Internal types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// List of descriptors that make up the configuration descriptors of a +/// device using the HID keyboard driver. +//------------------------------------------------------------------------------ +typedef struct { + + /// Configuration descriptor. + USBConfigurationDescriptor configuration; + /// Interface descriptor. + USBInterfaceDescriptor interface; + /// HID descriptor. + HIDDescriptor hid; + /// Interrupt IN endpoint descriptor. + USBEndpointDescriptor interruptIn; + /// Interrupt OUT endpoint descriptor. + USBEndpointDescriptor interruptOut; + +} __attribute__ ((packed)) HIDDKeyboardDriverConfigurationDescriptors; + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +/// Device descriptor. +static const USBDeviceDescriptor deviceDescriptor = { + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + HIDDeviceDescriptor_CLASS, + HIDDeviceDescriptor_SUBCLASS, + HIDDeviceDescriptor_PROTOCOL, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + HIDDKeyboardDriverDescriptors_VENDORID, + HIDDKeyboardDriverDescriptors_PRODUCTID, + HIDDKeyboardDriverDescriptors_RELEASE, + 1, // Index of manufacturer description + 2, // Index of product description + 3, // Index of serial number description + 1 // One possible configuration +}; + +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) +/// Device qualifier descriptor (high-speed only). +static const USBDeviceQualifierDescriptor qualifierDescriptor = { + + sizeof(USBDeviceQualifierDescriptor), + USBGenericDescriptor_DEVICEQUALIFIER, + HIDDeviceDescriptor_CLASS, + HIDDeviceDescriptor_SUBCLASS, + HIDDeviceDescriptor_PROTOCOL, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + 1, // One possible configuration + 0 // Reserved +}; +#endif + +/// Configuration descriptor. +static const HIDDKeyboardDriverConfigurationDescriptors configurationDescriptors = { + + // Configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(HIDDKeyboardDriverConfigurationDescriptors), + 1, // One interface in this configuration + 1, // This is configuration #1 + 0, // No associated string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + // Interface descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0 + 0, // This is alternate setting #0 + 2, // Two endpoints used + HIDInterfaceDescriptor_CLASS, + HIDInterfaceDescriptor_SUBCLASS_NONE, + HIDInterfaceDescriptor_PROTOCOL_NONE, + 0 // No associated string descriptor + }, + // HID descriptor + { + sizeof(HIDDescriptor), + HIDGenericDescriptor_HID, + HIDDescriptor_HID1_11, + 0, // Device is not localized, no country code + 1, // One HID-specific descriptor (apart from this one) + HIDGenericDescriptor_REPORT, + HIDDKeyboardDriverDescriptors_REPORTSIZE + }, + // Interrupt IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + HIDDKeyboardDriverDescriptors_INTERRUPTIN), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardInputReport), + HIDDKeyboardDriverDescriptors_INTERRUPTIN_POLLING + }, + // Interrupt OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + HIDDKeyboardDriverDescriptors_INTERRUPTOUT), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardOutputReport), + HIDDKeyboardDriverDescriptors_INTERRUPTIN_POLLING + } +}; + +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) +/// Other-speed configuration descriptor. +static const HIDDKeyboardDriverConfigurationDescriptors otherSpeedDescriptors = { + + // Configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_OTHERSPEEDCONFIGURATION, + sizeof(HIDDKeyboardDriverConfigurationDescriptors), + 1, // One interface in this configuration + 1, // This is configuration #1 + 0, // No associated string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + // Interface descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0 + 0, // This is alternate setting #0 + 2, // Two endpoints used + HIDInterfaceDescriptor_CLASS, + HIDInterfaceDescriptor_SUBCLASS_NONE, + HIDInterfaceDescriptor_PROTOCOL_NONE, + 0 // No associated string descriptor + }, + // HID descriptor + { + sizeof(HIDDescriptor), + HIDGenericDescriptor_HID, + HIDDescriptor_HID1_11, + 0, // Device is not localized, no country code + 1, // One HID-specific descriptor (apart from this one) + HIDGenericDescriptor_REPORT, + HIDDKeyboardDriverDescriptors_REPORTSIZE + }, + // Interrupt IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + HIDDKeyboardDriverDescriptors_INTERRUPTIN), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardInputReport), + HIDDKeyboardDriverDescriptors_INTERRUPTIN_POLLING + }, + // Interrupt OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + HIDDKeyboardDriverDescriptors_INTERRUPTOUT), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardOutputReport), + HIDDKeyboardDriverDescriptors_INTERRUPTOUT_POLLING + } +}; +#endif + +/// Language ID string descriptor. +static const unsigned char languageIdDescriptor[] = { + + USBStringDescriptor_LENGTH(1), + USBGenericDescriptor_STRING, + USBStringDescriptor_ENGLISH_US +}; + +/// Manufacturer name. +static const unsigned char manufacturerDescriptor[] = { + + USBStringDescriptor_LENGTH(5), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('M'), + USBStringDescriptor_UNICODE('E'), + USBStringDescriptor_UNICODE('L') +}; + +/// Product name. +static const unsigned char productDescriptor[] = { + + USBStringDescriptor_LENGTH(23), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('M'), + USBStringDescriptor_UNICODE('E'), + USBStringDescriptor_UNICODE('L'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('9'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('H'), + USBStringDescriptor_UNICODE('I'), + USBStringDescriptor_UNICODE('D'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('K'), + USBStringDescriptor_UNICODE('E'), + USBStringDescriptor_UNICODE('Y'), + USBStringDescriptor_UNICODE('B'), + USBStringDescriptor_UNICODE('O'), + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('R'), + USBStringDescriptor_UNICODE('D') +}; + +/// Product serial number. +static const unsigned char serialNumberDescriptor[] = { + + USBStringDescriptor_LENGTH(12), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('0'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE('2'), + USBStringDescriptor_UNICODE('3'), + USBStringDescriptor_UNICODE('4'), + USBStringDescriptor_UNICODE('5'), + USBStringDescriptor_UNICODE('6'), + USBStringDescriptor_UNICODE('7'), + USBStringDescriptor_UNICODE('8'), + USBStringDescriptor_UNICODE('9'), + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('F') +}; + +/// Array of pointers to string descriptors. +static const unsigned char *stringDescriptors[] = { + + languageIdDescriptor, + manufacturerDescriptor, + productDescriptor, + serialNumberDescriptor +}; + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +/// List of descriptors used by the HID keyboard driver. +USBDDriverDescriptors hiddKeyboardDriverDescriptors = { + + &deviceDescriptor, + (USBConfigurationDescriptor *) &configurationDescriptors, +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + &qualifierDescriptor, + (USBConfigurationDescriptor *) &otherSpeedDescriptors, + &deviceDescriptor, + (USBConfigurationDescriptor *) &configurationDescriptors, + &qualifierDescriptor, + (USBConfigurationDescriptor *) &otherSpeedDescriptors, +#else + 0, // No full-speed device qualifier descriptor + 0, // No full-speed other speed configuration + 0, // No high-speed device descriptor + 0, // No high-speed configuration descriptor + 0, // No high-speed device qualifier descriptor + 0, // No high-speed other speed configuration descriptor +#endif + stringDescriptors, + 4 // Four string descriptors in list +}; + +/// Report descriptor used by the driver. +const unsigned char hiddReportDescriptor[] = { + + HIDReport_GLOBAL_USAGEPAGE + 1, HIDGenericDesktop_PAGEID, + HIDReport_LOCAL_USAGE + 1, HIDGenericDesktop_KEYBOARD, + HIDReport_COLLECTION + 1, HIDReport_COLLECTION_APPLICATION, + + // Input report: modifier keys + HIDReport_GLOBAL_REPORTSIZE + 1, 1, + HIDReport_GLOBAL_REPORTCOUNT + 1, 8, + HIDReport_GLOBAL_USAGEPAGE + 1, HIDKeypad_PAGEID, + HIDReport_LOCAL_USAGEMINIMUM + 1, + HIDDKeyboardDriverDescriptors_FIRSTMODIFIERKEY, + HIDReport_LOCAL_USAGEMAXIMUM + 1, + HIDDKeyboardDriverDescriptors_LASTMODIFIERKEY, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, 0, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, 1, + HIDReport_INPUT + 1, HIDReport_VARIABLE, + + // Input report: standard keys + HIDReport_GLOBAL_REPORTCOUNT + 1, 3, + HIDReport_GLOBAL_REPORTSIZE + 1, 8, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, + HIDDKeyboardDriverDescriptors_FIRSTSTANDARDKEY, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, + HIDDKeyboardDriverDescriptors_LASTSTANDARDKEY, + HIDReport_GLOBAL_USAGEPAGE + 1, HIDKeypad_PAGEID, + HIDReport_LOCAL_USAGEMINIMUM + 1, + HIDDKeyboardDriverDescriptors_FIRSTSTANDARDKEY, + HIDReport_LOCAL_USAGEMAXIMUM + 1, + HIDDKeyboardDriverDescriptors_LASTSTANDARDKEY, + HIDReport_INPUT + 1, 0 /* Data array */, + + // Output report: LEDs + HIDReport_GLOBAL_REPORTCOUNT + 1, 3, + HIDReport_GLOBAL_REPORTSIZE + 1, 1, + HIDReport_GLOBAL_USAGEPAGE + 1, HIDLeds_PAGEID, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, 0, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, 1, + HIDReport_LOCAL_USAGEMINIMUM + 1, HIDLeds_NUMLOCK, + HIDReport_LOCAL_USAGEMAXIMUM + 1, HIDLeds_SCROLLLOCK, + HIDReport_OUTPUT + 1, HIDReport_VARIABLE, + + // Output report: padding + HIDReport_GLOBAL_REPORTCOUNT + 1, 1, + HIDReport_GLOBAL_REPORTSIZE + 1, 5, + HIDReport_OUTPUT + 1, HIDReport_CONSTANT, + + HIDReport_ENDCOLLECTION +}; + diff --git a/usb/device/hid-keyboard/HIDDKeyboardDriverDescriptors.h b/usb/device/hid-keyboard/HIDDKeyboardDriverDescriptors.h new file mode 100644 index 0000000..9a2dc2f --- /dev/null +++ b/usb/device/hid-keyboard/HIDDKeyboardDriverDescriptors.h @@ -0,0 +1,114 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit HIDDKeyboardDriverDescriptors + + !!!Purpose + + Definitions of the descriptors required by the HID device keyboard + driver. + + !!!Usage + + -# Use the hiddKeyboardDriverDescriptors variable to initialize a + USBDDriver instance. + -# Send hiddReportDescriptor to the host when a GET_DESCRIPTOR request + for the report descriptor is received. +*/ + +#ifndef HIDDKEYBOARDDRIVERDESCRIPTORS_H +#define HIDDKEYBOARDDRIVERDESCRIPTORS_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Endpoints" +/// This page lists endpoint addresses and polling settings. +/// +/// !Endpoints +/// - HIDDKeyboardDriverDescriptors_INTERRUPTIN +/// - HIDDKeyboardDriverDescriptors_INTERRUPTOUT +/// +/// !Polling Rates +/// - HIDDKeyboardDriverDescriptors_INTERRUPTIN_POLLING +/// - HIDDKeyboardDriverDescriptors_INTERRUPTOUT_POLLING + +/// Interrupt IN endpoint number. +#define HIDDKeyboardDriverDescriptors_INTERRUPTIN 1 +/// Interrupt IN endpoint polling rate (in milliseconds). +#define HIDDKeyboardDriverDescriptors_INTERRUPTIN_POLLING 10 +/// Interrupt OUT endpoint number. +#define HIDDKeyboardDriverDescriptors_INTERRUPTOUT 2 +/// Interrupt OUT endpoint polling rate (in milliseconds). +#define HIDDKeyboardDriverDescriptors_INTERRUPTOUT_POLLING 10 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Keypad keys" +/// This page lists definition for HID keypad keys. +/// +/// !Keys +/// - HIDDKeyboardDriverDescriptors_FIRSTMODIFIERKEY +/// - HIDDKeyboardDriverDescriptors_LASTMODIFIERKEY +/// - HIDDKeyboardDriverDescriptors_FIRSTSTANDARDKEY +/// - HIDDKeyboardDriverDescriptors_LASTSTANDARDKEY + +/// Key code of the first accepted modifier key. +#define HIDDKeyboardDriverDescriptors_FIRSTMODIFIERKEY HIDKeypad_LEFTCONTROL +/// Key code of the last accepted modifier key. +#define HIDDKeyboardDriverDescriptors_LASTMODIFIERKEY HIDKeypad_RIGHTGUI +/// Key code of the first accepted standard key. +#define HIDDKeyboardDriverDescriptors_FIRSTSTANDARDKEY 0 +/// Key code of the last accepted standard key. +#define HIDDKeyboardDriverDescriptors_LASTSTANDARDKEY HIDKeypad_NUMLOCK +//------------------------------------------------------------------------------ + +/// Size of the report descriptor in bytes. +#define HIDDKeyboardDriverDescriptors_REPORTSIZE 61 + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +extern USBDDriverDescriptors hiddKeyboardDriverDescriptors; + +extern const unsigned char hiddReportDescriptor[]; + +#endif //#ifndef HIDDKEYBOARDDRIVERDESCRIPTORS_H + diff --git a/usb/device/hid-keyboard/HIDDKeyboardInputReport.c b/usb/device/hid-keyboard/HIDDKeyboardInputReport.c new file mode 100644 index 0000000..3257bdb --- /dev/null +++ b/usb/device/hid-keyboard/HIDDKeyboardInputReport.c @@ -0,0 +1,164 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: HIDDKeyboardInputReport implementation + + About: Purpose + Implementation of the HIDDKeyboardInputReport class. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "HIDDKeyboardInputReport.h" +#include "HIDDKeyboardDriverDescriptors.h" +#include + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes a keyboard input report instance. +/// \param report Pointer to a HIDDKeyboardInputReport instance. +//------------------------------------------------------------------------------ +void HIDDKeyboardInputReport_Initialize(HIDDKeyboardInputReport *report) +{ + unsigned int i; + + report->bmModifierKeys = 0; + for (i = 0; i < HIDDKeyboardInputReport_MAXKEYPRESSES; i++) { + + report->pressedKeys[i] = 0; + } +} + +//------------------------------------------------------------------------------ +/// Reports a standard key as being pressed. +/// \param report Pointer to a HIDDKeyboardInputReport instance. +/// \param key Key code of the standard key. +//------------------------------------------------------------------------------ +void HIDDKeyboardInputReport_PressStandardKey(HIDDKeyboardInputReport *report, + unsigned char key) +{ + ASSERT(key <= HIDDKeyboardDriverDescriptors_LASTSTANDARDKEY, + "Invalid standard key code (%d)\n\r", + key); + + // Find first available slot + unsigned int i = 0; + unsigned char found = 0; + while ((i < HIDDKeyboardInputReport_MAXKEYPRESSES) && !found) { + + // Free slot: no key referenced (code = 0) or ErrorRollOver + if ((report->pressedKeys[i] == 0) + || (report->pressedKeys[i] == HIDKeypad_ERRORROLLOVER)) { + + found = 1; + report->pressedKeys[i] = key; + } + + i++; + } + + // Report ErrorRollOver in all fields if too many keys are pressed + if (!found) { + + for (i=0; i < HIDDKeyboardInputReport_MAXKEYPRESSES; i++) { + + report->pressedKeys[i] = HIDKeypad_ERRORROLLOVER; + } + } +} + +//------------------------------------------------------------------------------ +/// Reports a standard key as not being pressed anymore. +/// \param report Pointer to a HIDDKeyboardInputReport instance. +/// \param key Key code of the standard key +//------------------------------------------------------------------------------ +void HIDDKeyboardInputReport_ReleaseStandardKey(HIDDKeyboardInputReport *report, + unsigned char key) +{ + ASSERT(key <= HIDDKeyboardDriverDescriptors_LASTSTANDARDKEY, + "Invalid standard key code (%d)\n\r", + key); + + // Look for key in array + unsigned int i = 0; + unsigned char found = 0; + while ((i < HIDDKeyboardInputReport_MAXKEYPRESSES) && !found) { + + if (report->pressedKeys[i] == key) { + + found = 1; + report->pressedKeys[i] = 0; + } + + i++; + } +} + +//------------------------------------------------------------------------------ +/// Reports a modifier key as being currently pressed. +/// \param report Pointer to a HIDDKeyboardInputReport instance. +/// \param key Key code of the modifier key. +//------------------------------------------------------------------------------ +void HIDDKeyboardInputReport_PressModifierKey(HIDDKeyboardInputReport *report, + unsigned char key) +{ + ASSERT((key >= HIDDKeyboardDriverDescriptors_FIRSTMODIFIERKEY) + && (key <= HIDDKeyboardDriverDescriptors_LASTMODIFIERKEY), + "Invalid standard key code (%d)\n\r", + key); + + // Set corresponding bit + unsigned char bit = key - HIDDKeyboardDriverDescriptors_FIRSTMODIFIERKEY; + report->bmModifierKeys |= 1 << bit; +} + +//------------------------------------------------------------------------------ +/// Reports a modifier key as not being pressed anymore. +/// \param report Pointer to a HIDDKeyboardInputReport instance. +/// \param key Key code of the modifier key. +//------------------------------------------------------------------------------ +void HIDDKeyboardInputReport_ReleaseModifierKey(HIDDKeyboardInputReport *report, + unsigned char key) +{ + ASSERT((key >= HIDDKeyboardDriverDescriptors_FIRSTMODIFIERKEY) + && (key <= HIDDKeyboardDriverDescriptors_LASTMODIFIERKEY), + "Invalid standard key code (%d)\n\r", + key); + + // Clear corresponding bit + unsigned char bit = key - HIDDKeyboardDriverDescriptors_FIRSTMODIFIERKEY; + report->bmModifierKeys &= ~(1 << bit); +} + diff --git a/usb/device/hid-keyboard/HIDDKeyboardInputReport.h b/usb/device/hid-keyboard/HIDDKeyboardInputReport.h new file mode 100644 index 0000000..7eeafd8 --- /dev/null +++ b/usb/device/hid-keyboard/HIDDKeyboardInputReport.h @@ -0,0 +1,149 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit HIDDKeyboardInputReport.h + + !!!Purpose + + Class for manipulating HID keyboard input reports. + + !!!Usage + + -# Initialize a newly created input report with + HIDDKeyboardInputReport_Initialize. + -# Change the standard keys that are pressed and released using + HIDDKeyboardInputReport_PressStandardKey and + HIDDKeyboardInputReport_ReleaseStandardKey. + -# Change the modifier keys that are currently pressed and released + using HIDDKeyboardInputReport_PressModifierKey and + HIDDKeyboardInputReport_ReleaseModifierKey. +*/ + +#ifndef HIDDKEYBOARDINPUTREPORT_H +#define HIDDKEYBOARDINPUTREPORT_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +/// Maximum number of simultaneous key presses. +#define HIDDKeyboardInputReport_MAXKEYPRESSES 3 + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// HID input report structure used by the keyboard driver to notify the +/// host of pressed keys. +/// +/// The first byte is used to report the state of modifier keys. The +/// other three contains the keycodes of the currently pressed keys. +//------------------------------------------------------------------------------ +typedef struct { + + /// State of modifier keys. + unsigned char bmModifierKeys:8; + /// Key codes of pressed keys. + unsigned char pressedKeys[HIDDKeyboardInputReport_MAXKEYPRESSES]; + +} __attribute__ ((packed)) HIDDKeyboardInputReport; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ +/* + Function: HIDDKeyboardInputReport_Initialize + Initializes a keyboard input report instance. + + Parameters: + report - Pointer to a HIDDKeyboardInputReport instance. +*/ +extern void HIDDKeyboardInputReport_Initialize(HIDDKeyboardInputReport *report); + +/* + Function: HIDDKeyboardInputReport_PressStandardKey + Reports a standard key as being pressed. + + Parameters: + report - Pointer to a HIDDKeyboardInputReport instance. + key - Key code of the standard key. +*/ +extern void HIDDKeyboardInputReport_PressStandardKey( + HIDDKeyboardInputReport *report, + unsigned char key); + +/* + Function: HIDDKeyboardInputReport_ReleaseStandardKey + Reports a standard key as not being pressed anymore. + + Parameters: + report - Pointer to a HIDDKeyboardInputReport instance. + key - Key code of the standard key +*/ +extern void HIDDKeyboardInputReport_ReleaseStandardKey( + HIDDKeyboardInputReport *report, + unsigned char key); + +/* + Function: HIDDKeyboardInputReport_PressModifierKey + Reports a modifier key as being currently pressed. + + Parameters: + report - Pointer to a HIDDKeyboardInputReport instance. + key - Key code of the modifier key. +*/ +extern void HIDDKeyboardInputReport_PressModifierKey( + HIDDKeyboardInputReport *report, + unsigned char key); + +/* + Function: HIDDKeyboardInputReport_ReleaseModifierKey + Reports a modifier key as not being pressed anymore. + + Parameters: + report - Pointer to a HIDDKeyboardInputReport instance. + key - Key code of the modifier key. +*/ +extern void HIDDKeyboardInputReport_ReleaseModifierKey( + HIDDKeyboardInputReport *report, + unsigned char key); + +#endif //#ifndef HIDDKEYBOARDINPUTREPORT_H + diff --git a/usb/device/hid-keyboard/HIDDKeyboardOutputReport.c b/usb/device/hid-keyboard/HIDDKeyboardOutputReport.c new file mode 100644 index 0000000..f79d7ac --- /dev/null +++ b/usb/device/hid-keyboard/HIDDKeyboardOutputReport.c @@ -0,0 +1,94 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: HIDDKeyboardOutputReport implementation + + About: Purpose + Implementation of the HIDDKeyboardOutputReport class. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "HIDDKeyboardOutputReport.h" + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes a keyboard output report. +/// \param report Pointer to a HIDDKeyboardOutputReport instance. +//------------------------------------------------------------------------------ +void HIDDKeyboardOutputReport_Initialize(HIDDKeyboardOutputReport *report) +{ + report->numLockStatus = 0; + report->capsLockStatus = 0; + report->scrollLockStatus = 0; + report->padding = 0; +} + +//------------------------------------------------------------------------------ +/// Indicates the current status of the num. lock LED according to the +/// given report. +/// \param report Pointer to a HIDDKeyboardOutputReport instance. +/// \return 1 if the num. lock LED is light on; otherwise 0. +//------------------------------------------------------------------------------ +unsigned char HIDDKeyboardOutputReport_GetNumLockStatus( + const HIDDKeyboardOutputReport *report) +{ + return report->numLockStatus; +} + +//------------------------------------------------------------------------------ +/// Indicates the current status of the caps lock LED according to the +/// given report. +/// \param report Pointer to a HIDDKeyboardOutputReport instance. +/// \return 1 if the caps lock LED is light on; otherwise 0. +//------------------------------------------------------------------------------ +unsigned char HIDDKeyboardOutputReport_GetCapsLockStatus( + const HIDDKeyboardOutputReport *report) +{ + return report->capsLockStatus; +} + +//------------------------------------------------------------------------------ +/// Indicates the current status of the scroll lock LED according to the +/// given report. +/// \param report Pointer to a HIDDKeyboardOutputReport instance. +/// \return 1 if the scroll lock LED is light on; otherwise 0. +//------------------------------------------------------------------------------ +unsigned char HIDDKeyboardOutputReport_GetScrollLockStatus( + const HIDDKeyboardOutputReport *report) +{ + return report->scrollLockStatus; +} + diff --git a/usb/device/hid-keyboard/HIDDKeyboardOutputReport.h b/usb/device/hid-keyboard/HIDDKeyboardOutputReport.h new file mode 100644 index 0000000..760df1b --- /dev/null +++ b/usb/device/hid-keyboard/HIDDKeyboardOutputReport.h @@ -0,0 +1,96 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit HIDDKeyboardOutputReport + + !!!Purpose + + Definition of a class for manipulating HID keyboard output reports. + + !!!Usage + + -# Initialize a newly-created output report instance with + HIDDKeyboardOutputReport_Initialize. + -# Retrieve the status of the three LEDs using + HIDDKeyboardOutputReport_GetNumLockStatus, + HIDDKeyboardOutputReport_GetCapsLockStatus and + HIDDKeyboardOutputReport_GetScrollLockStatus. +*/ + +#ifndef HIDKEYBOARDOUTPUTREPORT_H +#define HIDKEYBOARDOUTPUTREPORT_H + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// HID output report structure used by the host to control the state of +/// the keyboard LEDs. +/// +/// Only the first three bits are relevant, the other 5 are used as +/// padding bits. +//------------------------------------------------------------------------------ +typedef struct { + + unsigned char numLockStatus:1, /// State of the num. lock LED. + capsLockStatus:1, /// State of the caps lock LED. + scrollLockStatus:1, /// State of the scroll lock LED. + padding:5; /// Padding bits. + +} __attribute__ ((packed)) HIDDKeyboardOutputReport; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern void HIDDKeyboardOutputReport_Initialize( + HIDDKeyboardOutputReport *report); + +extern unsigned char HIDDKeyboardOutputReport_GetNumLockStatus( + const HIDDKeyboardOutputReport *report); + +extern unsigned char HIDDKeyboardOutputReport_GetCapsLockStatus( + const HIDDKeyboardOutputReport *report); + +extern unsigned char HIDDKeyboardOutputReport_GetScrollLockStatus( + const HIDDKeyboardOutputReport *report); + +#endif //#ifndef HIDKEYBOARDOUTPUTREPORT_H + diff --git a/usb/device/hid-keyboard/hid-keyboard.dir b/usb/device/hid-keyboard/hid-keyboard.dir new file mode 100644 index 0000000..923a362 --- /dev/null +++ b/usb/device/hid-keyboard/hid-keyboard.dir @@ -0,0 +1,787 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// +/// !!!Purpose +/// +/// This directory provides definitions, structs and functions for a USB HID +/// %device - USB HID Keyboard driver, to implement an USB keyboard %device. +/// +/// !!!Contents +/// +/// There are three things for the implement of the USB HID Keyboard driver: +/// - Implement the USB HID driver structs and functions for the %device, +/// to initialize, to handle HID-specific requests and dispach +/// standard requests in USBD callbacks, to read/write through assigned USB +/// endpoints, +/// - Create the HID Keyboard device's descriptors that should be passed to +/// the USBDDriver instance on initialization, so that the host can +/// recognize the %device as a USB Keyboard %device. +/// - Implement methods to update the keyboard keys status, so that host can +/// get it through USB. +/// +/// For more information about what a particular group contains, please refer to +/// "USB HID Keyboard". +//------------------------------------------------------------------------------ + +/** + \page "USB HID Keyboard" + This page describes how to use the "AT91 USB device framework" to produce a USB + HID Keyboard driver, which appears as a USB keyboard on host. + + Details about the USB and the HID class can be found in the }USB specification + 2.0} and the }HID specification 1.11}, respectively. + + !!!References + - "AT91 USB device framework" + - "USB Device Enumeration" + - + Universal Serial Bus Revision 2.0 specification + (.zip file format, size 9.80 MB) + - + Device Class Definition for HID 1.11 + - + HID Usage Tables 1.12 + + !!!HID Basic + See "USB HID Basic". + + !!!Architecture + See "USB Device Framework Architecture". + + !!!Descriptors + + ... + + !!Device Descriptor + The Device descriptor of an HID %device is very basic, since the HID class + code is only specified at the Interface level. Thus, it only contains + standard values, as shown below: +\code +static const USBDeviceDescriptor deviceDescriptor = { + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + HIDDeviceDescriptor_CLASS, + HIDDeviceDescriptor_SUBCLASS, + HIDDeviceDescriptor_PROTOCOL, + BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0), + HIDDKeyboardDriverDescriptors_VENDORID, + HIDDKeyboardDriverDescriptors_PRODUCTID, + HIDDKeyboardDriverDescriptors_RELEASE, + 1, // Index of manufacturer description + 2, // Index of product description + 3, // Index of serial number description + 1 // One possible configuration +}; +\endcode + Note that the Vendor ID is a special value attributed by the USB-IF + organization. The product ID can be chosen freely by the vendor. + + !!Configuration Descriptor + Since one interface is required by the HID specification, this must be + specified in the Configuration descriptor. There is no other value of + interest to put here. +\code +// Configuration descriptor +{ + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(HIDDKeyboardDriverConfigurationDescriptors), + 1, // One interface in this configuration + 1, // This is configuration #1 + 0, // No associated string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) +}, +\endcode + When the Configuration descriptor is requested by the host (by using the + GET_DESCRIPTOR command), the %device must also sent all the related + descriptors, i.e. Interface, Endpoint and Class-Specific descriptors. It is + convenient to create a single structure to hold all this data, for sending + everything in one chunk. In the example software, a + HIDDKeyboardDriverConfigurationDescriptors structure has been declared for + that. + + !!HID Class Interface Descriptor + Since a keyboard %device needs to transmit as well as receive data, two + Interrupt (IN & OUT) endpoints are needed. This must be indicated in the + Interface descriptor. Conversely to the mouse example, the Boot protocol is + not implemented here, since there are more constraints on a keyboard %device. +\code +// Interface descriptor +{ + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0 + 0, // This is alternate setting #0 + 2, // Two endpoints used + HIDInterfaceDescriptor_CLASS, + HIDInterfaceDescriptor_SUBCLASS_NONE, + HIDInterfaceDescriptor_PROTOCOL_NONE, + 0 // No associated string descriptor +}, +\endcode + + !!HID Descriptor + While a HID keyboard produces two different reports, one Input and one Output, + only one Report descriptor can be used to describe them. Since having Physical + descriptors is also useless for a keyboard, there will only be one HID class + descriptor specified here. + + For a keyboard, the }bCountryCode} field can be used to specify the language + of the key caps. As this is optional, it is simply set to 00h in the example: +\code +// HID descriptor +{ + sizeof(HIDDescriptor), + HIDGenericDescriptor_HID, + HIDDescriptor_HID1_11, + 0, // Device is not localized, no country code + 1, // One HID-specific descriptor (apart from this one) + HIDGenericDescriptor_REPORT, + HIDDKeyboardDriverDescriptors_REPORTSIZE +}, +\endcode + + !!Report Descriptor + Two current reports are defined in the Report descriptor. The first one is + used to notify the host of which keys are pressed, with both modifier keys + (alt, ctrl, etc.) and alphanumeric keys. The second report is necessary for + the host to send the LED (num lock, caps lock, etc.) states. + + The Report descriptor starts with the global %device functionality, described + with a #Usage Page# and a #Usage# items: +\code +const unsigned char hiddReportDescriptor[] = { + + HIDReport_GLOBAL_USAGEPAGE + 1, HIDGenericDesktop_PAGEID, + HIDReport_LOCAL_USAGE + 1, HIDGenericDesktop_KEYBOARD, +\endcode + + As in the mouse example, the }Generic Desktop} page is used. This time, the + specific usage is the }Keyboard} one. An Application collection is then + defined to group the reports together: +\code + HIDReport_COLLECTION + 1, HIDReport_COLLECTION_APPLICATION, +\endcode + + The first report to be defined is the modifier keys. They are represented as a + bitmap field, indicating whether or not each key is pressed. A single byte is + used to map keys \#224-231 defined in the }HID Usage Tables} document: + LeftControl, LeftShift, LeftAlt, LeftGUI (e.g. Windows key), + RightControl, RightShift, RightAlt and RightGUI. + The }Keypad} usage page must be specified for this report, and since this is a + bitmap value, the data is flagged as }Variable}: +\code + // Input report: modifier keys + HIDReport_GLOBAL_REPORTSIZE + 1, 1, + HIDReport_GLOBAL_REPORTCOUNT + 1, 8, + HIDReport_GLOBAL_USAGEPAGE + 1, HIDKeypad_PAGEID, + HIDReport_LOCAL_USAGEMINIMUM + 1, + HIDDKeyboardDriverDescriptors_FIRSTMODIFIERKEY, + HIDReport_LOCAL_USAGEMAXIMUM + 1, + HIDDKeyboardDriverDescriptors_LASTMODIFIERKEY, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, 0, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, 1, + HIDReport_INPUT + 1, HIDReport_VARIABLE, +\endcode + + Then, the actual alphanumeric key report is described. This is done by + defining several bytes of data, one for each pressed key. In the example, + up to three keys can be pressed at the same time (and detected) by the user. + Once again, the usage page is set to }Keypad}. This time however, the data + must be specified as an }Array}, since the same control (the keypad) produces + several values: +\code + // Input report: standard keys + HIDReport_GLOBAL_REPORTCOUNT + 1, 3, + HIDReport_GLOBAL_REPORTSIZE + 1, 8, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, + HIDDKeyboardDriverDescriptors_FIRSTSTANDARDKEY, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, + HIDDKeyboardDriverDescriptors_LASTSTANDARDKEY, + HIDReport_GLOBAL_USAGEPAGE + 1, HIDKeypad_PAGEID, + HIDReport_LOCAL_USAGEMINIMUM + 1, + HIDDKeyboardDriverDescriptors_FIRSTSTANDARDKEY, + HIDReport_LOCAL_USAGEMAXIMUM + 1, + HIDDKeyboardDriverDescriptors_LASTSTANDARDKEY, + HIDReport_INPUT + 1, 0 /* Data array */, +\endcode + + The LED array is then defined, with the associated usage page. The Report + descriptor is formatted in this order to avoid redefining unchanged }Global} + items, in order to save memory. This time again, the LED status is reported as + a bitmap field. Three LEDs are used here: Num Lock, Caps Lock and Scroll Lock + (IDs 01h to 03h). It is important to note that this is an #Output# report: +\code + // Output report: LEDs + HIDReport_GLOBAL_REPORTCOUNT + 1, 3, + HIDReport_GLOBAL_REPORTSIZE + 1, 1, + HIDReport_GLOBAL_USAGEPAGE + 1, HIDLeds_PAGEID, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, 0, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, 1, + HIDReport_LOCAL_USAGEMINIMUM + 1, HIDLeds_NUMLOCK, + HIDReport_LOCAL_USAGEMAXIMUM + 1, HIDLeds_SCROLLLOCK, + HIDReport_OUTPUT + 1, HIDReport_VARIABLE, +\endcode + + Since the previous report only contains 3 bits, the data must be padded to a + multiple of one byte. This is done by using constant Output data, as follows: +\code + // Output report: padding + HIDReport_GLOBAL_REPORTCOUNT + 1, 1, + HIDReport_GLOBAL_REPORTSIZE + 1, 5, + HIDReport_OUTPUT + 1, HIDReport_CONSTANT, +\endcode + + The last item, }End Collection}, is necessary to close the previously opened + }Application Collection}. +\code + HIDReport_ENDCOLLECTION +}; +\endcode + + The Input and Output reports defined by this descriptor can be modeled by the + following structures: +\code +// HID Input Report +typedef struct { + + // State of modifier keys. + unsigned char bmModifierKeys:8; + // Key codes of pressed keys. + unsigned char pressedKeys[HIDDKeyboardInputReport_MAXKEYPRESSES]; + +} __attribute__ ((packed)) HIDDKeyboardInputReport; // GCC +// HID Output Report +typedef struct { + + unsigned char numLockStatus:1, // State of the num. lock LED. + capsLockStatus:1, // State of the caps lock LED. + scrollLockStatus:1, // State of the scroll lock LED. + padding:5; // Padding bits. + +} __attribute__ ((packed)) HIDDKeyboardOutputReport; // GCC +\endcode + + An instance of each one of the reports is stored in a HIDDKeyboardDriver + structure, which holds the standard class driver and HID keyboard-specific + data. + + !!Physical Descriptor + A Physical descriptor is useless for a keyboard %device, so none are defined + in this example. + + !!Endpoint Descriptor + Following the Interface and HID-specific descriptors, the two necessary + endpoints are defined. +\code +// Interrupt IN endpoint descriptor +{ + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + HIDDKeyboardDriverDescriptors_INTERRUPTIN), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardInputReport), + HIDDKeyboardDriverDescriptors_INTERRUPTIN_POLLING +}, +// Interrupt OUT endpoint descriptor +{ + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + HIDDKeyboardDriverDescriptors_INTERRUPTOUT), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardOutputReport), + HIDDKeyboardDriverDescriptors_INTERRUPTIN_POLLING +} +\endcode + + !!String Descriptors + Please refer to "Usage: USBD VID, PID & Strings". + + !!!Class-specific requests + A driver request handler should first differentiate between class-specific and + standard requests using the corresponding bits in the }bmRequestType} field. + In most cases, standard requests can be immediately forwarded to the standard + request handler method; class-specific methods must be decoded and treated by + the custom handler. + + !!GetDescriptor + Three values have been added by the HID specification for the #GET_DESCRIPTOR# + request. The high byte of the }wValue} field contains the type of the + requested descriptor; in addition to the standard types, the #HID + specification# adds the #HID descriptor# (21h), the #Report descriptor# + (22h) and the #Physical descriptor# (23h) types. + + There is no particular action to perform besides sending the descriptor. This + can be done by using the USBD_Write method, after the requested descriptor has + been identified: +\code +switch (USBGenericRequest_GetRequest(request)) { + + case USBGenericRequest_GETDESCRIPTOR: + // Check if this is a HID descriptor, + // otherwise forward it to + // the standard driver + if (!HIDDKeyboardDriver_GetDescriptor( + USBGetDescriptorRequest_GetDescriptorType(request), + USBGenericRequest_GetLength(request))) { + + USBDDriver_RequestHandler(&(hiddKeyboardDriver.usbdDriver), + request); + } + break; + + default: + USBDDriver_RequestHandler(&(hiddKeyboardDriver.usbdDriver), + request); +} +\endcode + A slight complexity of the GET_DESCRIPTOR and SET_DESCRIPTOR requests is that + those are standard requests, but the standard request handler + (USBDDriver_RequestHandler) must not always be called to treat them (since + they may refer to HID descriptors). The solution is to first identify + GET/SET_DESCRIPTOR requests, treat the HID-specific cases and, finally, + forward any other request to the standard handler. + + In this case, a GET_DESCRIPTOR request for the Physical descriptor is first + forwarded to the standard handler, and STALLed there because it is not + recognized. This is done because the %device does not have any Physical + descriptors, and thus, does not need to handle the associated request. + + !!SetDescriptor + This request is optional and is never issued by most hosts. It is not + implemented in this example. + + !!GetReport + Since the HID keyboard defines two different reports, the Report Type value + specified by this request (upper byte of the }wValue} field) must be examined + to decide which report to send. If the type value is 01h, then the Input + report must be returned; if it is 02h, the Output report is requested: +\code +case HIDGenericRequest_GETREPORT: +//------------------------------- + type = HIDReportRequest_GetReportType(request); + length = USBGenericRequest_GetLength(request); + switch (type) { + + case HIDReportRequest_INPUT: + + // Adjust size and send report + if (length > sizeof(HIDDKeyboardInputReport)) { + + length = sizeof(HIDDKeyboardInputReport); + } + USBD_Write(0, // Endpoint #0 + &(hiddKeyboardDriver.inputReport), + length, + 0, // No callback + 0); + break; + + case HIDReportRequest_OUTPUT: + + // Adjust size and send report + if (length > sizeof(HIDDKeyboardOutputReport)) { + + length = sizeof(HIDDKeyboardOutputReport); + } + USBD_Write(0, // Endpoint #0 + &(hiddKeyboardDriver.outputReport), + length, + 0, // No callback + 0); + break; + + default: + USBD_Stall(0); + } +break; +\endcode + + !!SetReport + For an HID keyboard, the #SET_REPORT# command can be sent by the host to + change the state of the LEDs. Normally, the dedicated Interrupt OUT endpoint + will be used for this; but in some cases, using the default Control endpoint + can save some bandwidth on the host side. + + Note that the SET_REPORT request can be directed at the Input report of the + keyboard; in this case, it can be safely discarded, according to the HID + specification. Normally, most host drivers only target the Output report. The + Report Type value is stored in the upper byte of the }wValue} field. + + The length of the data phase to follow is stored in the }wLength} field of the + request. It should be equal to the total length of the Output report. If it is + different, the report status must still be updated with the received data as + best as possible. + + When the reception of the new data is completed, some processing must be done + to enable/disable the corresponding LEDs. This is done in the callback + function passed as an argument to USBD_Read: +\code +case HIDGenericRequest_SETREPORT: +//------------------------------- + type = HIDReportRequest_GetReportType(request); + length = USBGenericRequest_GetLength(request); + switch(type) { + + case HIDReportRequest_INPUT: + // SET_REPORT requests on input reports are ignored + USBD_Stall(0); + break; + + case HIDReportRequest_OUTPUT: + // Check report length + if (length != sizeof(HIDDKeyboardOutputReport)) { + + USBD_Stall(0); + } + else { + + USBD_Read(0, // Endpoint #0 + &(hiddKeyboardDriver.outputReport), + length, + (TransferCallback) HIDDKeyboardDriver_ReportReceived, + 0); // No argument to the callback function + } + break; + + default: + USBD_Stall(0); + } +break; +\endcode + + !!SetIdle + In this case study, the #SET_IDLE# request is used to set a delay before a key + is repeated. This is common behavior on keyboard devices. Usually, this delay + is set to about 500 ms by the host. + + The only action here is to store the new Idle rate. The management of this + setting must be done in the main function, since Interrupt IN reports are sent + from there. + + In practice, it is not necessary to perform any action, apart from sending a + zero-length packet to acknowledge it. The main application however has to make + sure that only new reports are sent by the %device. +\code +case HIDGenericRequest_SETIDLE: +//----------------------------- + hiddKeyboardDriver.inputReportIdleRate = + HIDIdleRequest_GetIdleRate(request); + USBD_Write(0, 0, 0, 0, 0); +break; +\endcode + + !!GetIdle + The only necessary operation for this request is to send the previously saved + Idle rate. This is done by calling the USBD_Write method with the one-byte + variable as its parameter: +\code +case HIDGenericRequest_GETIDLE: +//----------------------------- + USBD_Write(0, &(hiddKeyboardDriver.inputReportIdleRate), 1, 0, 0); +break; +\endcode + + !!GetProtocol, SetProtocol + This HID keyboard example does not support the Boot protocol, so there is no + need to implement the SET_PROTOCOL and GET_PROTOCOL requests. This means they + can be safely STALLed when received. + + !!!Main Application + Like the mouse example, the main program must perform two different + operations. First, it has to monitor the physical inputs used as keys. In the + example software, the buttons present on the evaluation boards are used to + produce several modifier and alphanumeric keys. + + Also, the main program is in charge of sending reports as they are modified, + taking into account the Idle rate specified by the host. Idle rate management + can be carried out by firing/resetting a timer once a new report is sent; if + the timer expires, this means the Input report has not changed since. + According to the HID specification, a single instance of the report must be + sent in this case. + + Finally, the HID specification also defines that if too many keys are pressed + at the same time, the %device should report an }ErrorRollOver} usage value + (01h) in every byte of the key array. This has to be handled by the main + application as well. + +*/ + +/** + \page "USB HID Mouse" + This page describes how to implement a mouse %device using the HID class and + the "AT91 USB device framework". Details about the USB and the HID class can + be found in the }USB specification 2.0} and the }HID specification 1.11} + documents, respectively. + + !!!References + - "AT91 USB device framework" + - "USB Device Enumeration" + - + Universal Serial Bus Revision 2.0 specification + (.zip file format, size 9.80 MB) + - + Device Class Definition for HID 1.11 + - + HID Usage Tables 1.12 + + + +*/ + +/** + \page "USB HID Basic" + + This page gives generic details on the HID class, including its purpose, + architecture and how it is supported by various operating systems. + + !!!Purpose + + The HID class has been specifically designed for Human Interface Devices, + i.e., devices which are manipulated by humans to control a computer or an + electronic %device. This includes common peripherals such as a keyboard, a + mouse or a joystick, as well as many other interfaces: remote controllers, + switches, buttons, dedicated game controls, and so on. + + It is also possible to use the HID class for devices which do not require + human interaction, but still deliver information in a similar format. For + example, devices like a thermometer or a battery indicator are supported. + + In addition, the HID class also makes it possible to not only receive data + from devices but also to send commands to them. Indeed, many devices offer + some kind of display to give back information to the user, e.g., the LEDs on a + keyboard. + + Finally, since it is quite simple to send and receive data using the HID + class, it can be used as a generic means of communication between a %device + and a host. This is made possible because of the very flexible framework + defined in the HID specification. + + In this document, three uses of the HID class will be detailed step-by-step, + each showing one particular feature of the class. The first example shows the + interaction with a simple mouse. In the second example, a keyboard is + implemented to demonstrate the possibility to send data to a peripheral. The + last example explains how to use HID as a simple two-way communication + channel. + + !!!Architecture + ... + + !!Interface + An HID %device only needs #one interface descriptor#. It should have the HID + interface class code in its bInterfaceClass field. There are special subclass + and protocol codes to specify if the HID %device is a mouse or a keyboard, and + must be supported by the BIOS. In such a case, the interface must be declared + as a Boot Interface, and the type of the %device (mouse or keyboard) must be + given in the bInterfaceProtocol field. + + !!Endpoints + Up to three endpoints can be used with an HID interface. The first two are the + default Control endpoint 0, as well as an Interrupt IN endpoint. They are + mandatory and shall always be declared. An optional Interrupt OUT endpoint can + be added as well. + + Endpoint 0 is used for class-specific requests, as well as receiving data from + the host if no Interrupt OUT endpoint has been defined. In addition, the host + can also explicitly request or send report data through this endpoint. + + The Interrupt IN and OUT pipes are used for sending asynchronous data to the + host, and to receive low-latency information. + + \image HIDClassArch.png "HID Class Driver Architecture" + + !!Class-Specific Descriptors + There are three class-specific descriptors defined in the }HID specification + 1.11}: the HID descriptor, the report descriptor and the physical descriptor. + + !HID Descriptor + The HID descriptor gives information about the HID specification revision + used, the country for which a %device is localized, and lists the number of + class-specific descriptors, including their length and type. + + HID Descriptor Format +||Field||Size(bytes)||Description +|bLength|1|Total length of the HID descriptor +|bDescriptorType|1|HID descriptor type (21h) +|bcdHID|2|HID specification release number in BCD format +|bCountryCode|1|Code of the country for which the %device is located.\n + Should be 0 if the %device is not localized. +|bNumDescriptors|1|Number of class-specific descriptors used by the %device. +|bDescriptorType|1|Type of the first class-specific descriptor. +|bDescriptorLength|1|Total length of the first class-specific descriptor. +|[bDescriptorType]|1|Type of the second class-specific descriptor. +|[bDescriptorLength]|1|Total length of the second class-specific descriptor. +|...| | + + There is always at least one Report descriptor for an HID %device, so the + corresponding fields must be present in the HID descriptor. If other + descriptors are defined, they must also be described here. + + !Report Descriptor + A HID %device must have at least one #Report descriptor#. It defines the type + of data manipulated by the %device, which is referred to as report. When the + %device wants to notify that the cursor has moved, for example, it sends the + corresponding report in the format previously defined in the Report + descriptor. + + This descriptor is quite different from others, as it does not have a fixed + table of values. Instead, it is made up of a variable number of items, which + collectively identify the information that a host can expect from or send to + the %device. + + There are five categories of items: + - #Input# items, which define the format and type of the data sent by the + %device. + - #Output# items, which define the format and type of the data expected by + the %device + - #Feature# items, which define data sent to or received from the %device, + and not intended for the end user, such as configuration parameters. +- #Collection# items, which identify a set of data as related to the same + group. +- #End Collection# items, which close other Collection items. + + Usually, a Report descriptor defines only one use (report) for a %device, e.g., + a mouse. However, it is possible to declare several reports to perform + different tasks, e.g., mouse & keyboard. This is done by assigning a different + #Report ID# to each report; this makes it possible for the %device to send + both reports through the same Interrupt endpoint, while still permitting the + host to correctly identify the data. Using only a single endpoint for several + functionalities is very powerful, as the remaining ones can then be used by + other interfaces (CDC, MSD, etc.) for an even more versatile %device. + + More details about Report descriptors will be given in the implementation + examples. For more information about the possible items, tags and values, + please refer to the }HID specification 1.11.} + + !Physical Descriptor + A #Physical descriptor# can be used to give information about which human body + part is used to activate a particular control. While this is a useless piece + of information for most devices, it can be relevant for complex devices which + provide many similar controls. In such a case, a Physical descriptor allows an + application to assign its functionalities more appropriately; for example, a + game controller often has a large number of buttons, with some of them more + accessible than the others. Those buttons would be assigned the most useful + actions. + + Since physical descriptors are not used very often, and are not useful in the + case studies described in this document, they will not be discussed further. + + !!Class-specific Requests + ... + + !GetDescriptor + While #GET_DESCRIPTOR# is a standard request (defined in the }USB + specification 2.0}), new descriptor type values have been added for the HID + class. They make it possible for the host to request the HID descriptor, + Report descriptor and Physical descriptors used by the %device. + + When requesting a HID-specific descriptor, the }wIndex} field of the request + must be set to the HID interface number. For standard requests, this field is + either set to 0 or, for String descriptors, to the index of the language ID + used. + + !SetDescriptor + Similarly, #SET_DESCRIPTOR# is a standard request with added HID-specific + values. It is used by the host to change the HID descriptors of a %device. + This is an optional request, and has few practical uses. + + !GetReport + The host can explicitly ask the %device for a report by using the #GET_REPORT# + request. However, it should be used primarily to get the state of feature + items and absolute values at initialization time, not for consistent %device + polling. + + The requested report is identified either by its Report ID (if they are used), + and/or by its type (Input, Output or Feature). + + Please note that a GET_REPORT request is different from a GET_DESCRIPTOR + request for the Report descriptor. The latter returns the whole Report + descriptor, i.e., all the items declared. The former returns the data defined + by this descriptor. + + !SetReport + #SET_REPORT# is similar to GET_REPORT, except this request is used for + changing the state of a report, instead of simply retrieving it. + + For an Input report, this request can either be considered meaningless, or can + be used to reset the current status of a control. For example, it could be + used to calibrate the neutral position of a joystick. + + !SetIdle + This request is used to specify the minimum amount of time, called #Idle + rate#, that a %device must wait before transmitting a report if its state has + not changed. This means the %device must NAK all polls on its Interrupt IN + endpoint until the report state changes, or the guarding period expires. + + The SET_IDLE command can either be issued for a particular duration, or for an + undefined period of time. The upper byte of the wValue field is used to + specify this duration. In addition, if the %device generates multiple reports, + the Report ID of the target report to affect can be specified in the lower + byte. + + In practice, this request is often used with a keyboard to put a small delay + before a key is repeated continuously. For a mouse, it must be set to 0, + meaning that the %device should never report an unchanged state. + + !GetIdle + The GET_IDLE request is issued by the host to retrieve the current Idle rate + of the %device. A particular Report can be specified with its Report ID. + + !GetProtocol + This request returns the protocol currently used by the %device. This can + either be the Report protocol (}wValue} set to 0) or the Boot protocol + (}wValue} set to 1). Since a %device supporting the Boot protocol can operate + differently depending on which mode it is in, the host system can retrieve or + change this mode with the GET_PROTOCOL and SET_PROTOCOL requests. + + This request is only need for devices supporting the Boot protocol. + + !SetProtocol + Whenever an HID %device starts up, it should use the Report protocol by + default. However, the host driver shall still use the SET_PROTOCOL + request to specify if the %device should use the Report protocol or the + Boot protocol. + + !!!Host Drivers + Most operating systems provide a generic HID driver which automatically + handles standard devices, such as keyboard, mice and joystick. In addition, + the driver can also be used by the application to easily access custom and + vendor-specific devices. + +*/ \ No newline at end of file diff --git a/usb/device/hid-mouse/HIDDMouseDriver.c b/usb/device/hid-mouse/HIDDMouseDriver.c new file mode 100644 index 0000000..dc2378c --- /dev/null +++ b/usb/device/hid-mouse/HIDDMouseDriver.c @@ -0,0 +1,392 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "HIDDMouseDriver.h" +#include "HIDDMouseDriverDescriptors.h" +#include "HIDDMouseInputReport.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Internal Defines +//------------------------------------------------------------------------------ + +/// Tag bit (Always 1) +#define HIDDMouse_TAG (1 << 3) + +/// Xsign bit +#define HIDDMouse_Xsign (1 << 4) + +/// Ysign bit +#define HIDDMouse_Ysign (1 << 5) + + +//------------------------------------------------------------------------------ +// Internal types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Driver structure for an HID device implementing keyboard functionalities. +//------------------------------------------------------------------------------ +typedef struct { + + /// Standard USB device driver instance. + USBDDriver usbdDriver; + /// Idle rate (in milliseconds) of the input report. + unsigned char inputReportIdleRate; + /// + unsigned char inputProtocol; + /// Input report instance. + HIDDMouseInputReport inputReport; + +} HIDDMouseDriver; + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +/// Static instance of the HID mouse device driver. +static HIDDMouseDriver hiddMouseDriver; + +//------------------------------------------------------------------------------ +// Internal functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Returns the descriptor requested by the host. +/// \param type Descriptor type. +/// \param length Maximum number of bytes to send. +/// \return 1 if the request has been handled by this function, otherwise 0. +//------------------------------------------------------------------------------ +static unsigned char HIDDMouseDriver_GetDescriptor(unsigned char type, + unsigned char length) +{ + const USBConfigurationDescriptor *pConfiguration; + HIDDescriptor *hidDescriptors[2]; + + switch (type) { + + case HIDGenericDescriptor_REPORT: + TRACE_INFO("Report "); + + // Adjust length and send report descriptor + if (length > HIDDMouseDriverDescriptors_REPORTSIZE) { + + length = HIDDMouseDriverDescriptors_REPORTSIZE; + } + USBD_Write(0, &hiddReportDescriptor, length, 0, 0); + break; + + case HIDGenericDescriptor_HID: + TRACE_INFO("HID "); + + // Configuration descriptor is different depending on configuration + if (USBD_IsHighSpeed()) { + + pConfiguration = + hiddMouseDriver.usbdDriver.pDescriptors->pHsConfiguration; + } + else { + + pConfiguration = + hiddMouseDriver.usbdDriver.pDescriptors->pFsConfiguration; + } + + // Parse the device configuration to get the HID descriptor + USBConfigurationDescriptor_Parse(pConfiguration, 0, 0, + (USBGenericDescriptor **) &hidDescriptors[0]); + + // Adjust length and send HID descriptor + if (length > sizeof(HIDDescriptor)) { + + length = sizeof(HIDDescriptor); + } + USBD_Write(0, hidDescriptors[0], length, 0, 0); + break; + + default: + return 0; + } + + return 1; +} + +//------------------------------------------------------------------------------ +/// Sends the current Idle rate of the input report to the host. +//------------------------------------------------------------------------------ +static void HIDDMouseDriver_GetIdle() +{ + TRACE_INFO("gIdle "); + + USBD_Write(0, &(hiddMouseDriver.inputReportIdleRate), 1, 0, 0); +} + +//------------------------------------------------------------------------------ +/// Retrieves the new idle rate of the input report from the USB host. +/// \param idleRate New input report idle rate. +//------------------------------------------------------------------------------ +static void HIDDMouseDriver_SetIdle(unsigned char idleRate) +{ + TRACE_INFO("sIdle(%d) ", idleRate); + + hiddMouseDriver.inputReportIdleRate = idleRate; + USBD_Write(0, 0, 0, 0, 0); +} + +//------------------------------------------------------------------------------ +/// Sends the requested report to the host. +/// \param type Report type. +/// \param length Maximum number of bytes to send. +//------------------------------------------------------------------------------ +static void HIDDMouseDriver_GetReport(unsigned char type, + unsigned short length) +{ + TRACE_INFO("gReport "); + + // Check report type + switch (type) { + + case HIDReportRequest_INPUT: + TRACE_INFO("In "); + + // Adjust size and send report + if (length > sizeof(HIDDMouseInputReport)) { + + length = sizeof(HIDDMouseInputReport); + } + USBD_Write(0, // Endpoint #0 + &(hiddMouseDriver.inputReport), + length, + 0, // No callback + 0); + break; + + default: + USBD_Stall(0); + } +} + +//------------------------------------------------------------------------------ +/// Retrieves the new value of a report from the host and saves it. +/// \param type Report type. +/// \param length Report length. +//------------------------------------------------------------------------------ +static void HIDDMouseDriver_SetReport(unsigned char type, + unsigned short length) +{ + TRACE_INFO("sReport "); + + // Check report type + switch (type) { + + case HIDReportRequest_INPUT: + // SET_REPORT requests on input reports are ignored + USBD_Stall(0); + break; + + default: + USBD_Stall(0); + } +} + +//------------------------------------------------------------------------------ +// Optional RequestReceived() callback re-implementation +//------------------------------------------------------------------------------ +#if !defined(NOAUTOCALLBACK) + +//------------------------------------------------------------------------------ +/// Callback function when new request receivce from host +/// \param request Pointer to the USBGenericRequest instance +//------------------------------------------------------------------------------ +void USBDCallbacks_RequestReceived(const USBGenericRequest *request) +{ + HIDDMouseDriver_RequestHandler(request); +} + +#endif + +//------------------------------------------------------------------------------ +// ConfigurationChanged() callback re-implementation +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Callback function when configureation changed +/// \param cfgnum New configuration number +//------------------------------------------------------------------------------ +void USBDDriverCallbacks_ConfigurationChanged(unsigned char cfgnum) +{ + if (cfgnum > 0) { + + } +} + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes the HID Mouse %device driver. +//------------------------------------------------------------------------------ +void HIDDMouseDriver_Initialize(void) +{ + hiddMouseDriver.inputReportIdleRate = 0; + HIDDMouseInputReport_Initialize(&(hiddMouseDriver.inputReport)); + USBDDriver_Initialize(&(hiddMouseDriver.usbdDriver), + &hiddMouseDriverDescriptors, + 0); // Multiple interface settings not supported + USBD_Init(); +} + +//------------------------------------------------------------------------------ +/// Handles HID-specific SETUP request sent by the host. +/// \param request Pointer to a USBGenericRequest instance +//------------------------------------------------------------------------------ +void HIDDMouseDriver_RequestHandler(const USBGenericRequest *request) +{ + TRACE_INFO("NewReq "); + + // Check if this is a standard request + if (USBGenericRequest_GetType(request) == USBGenericRequest_STANDARD) { + + // This is a standard request + switch (USBGenericRequest_GetRequest(request)) { + + case USBGenericRequest_GETDESCRIPTOR: + // Check if this is a HID descriptor, otherwise forward it to + // the standard driver + if (!HIDDMouseDriver_GetDescriptor( + USBGetDescriptorRequest_GetDescriptorType(request), + USBGenericRequest_GetLength(request))) { + + USBDDriver_RequestHandler(&(hiddMouseDriver.usbdDriver), + request); + } + break; + + default: + USBDDriver_RequestHandler(&(hiddMouseDriver.usbdDriver), + request); + } + } + // Check if this is a class request + else if (USBGenericRequest_GetType(request) == USBGenericRequest_CLASS) { + + // This is a class-specific request + switch (USBGenericRequest_GetRequest(request)) { + + case HIDGenericRequest_GETIDLE: + HIDDMouseDriver_GetIdle(); + break; + + case HIDGenericRequest_SETIDLE: + HIDDMouseDriver_SetIdle(HIDIdleRequest_GetIdleRate(request)); + break; + + case HIDGenericRequest_GETREPORT: + HIDDMouseDriver_GetReport( + HIDReportRequest_GetReportType(request), + USBGenericRequest_GetLength(request)); + break; + + case HIDGenericRequest_SETREPORT: + HIDDMouseDriver_SetReport( + HIDReportRequest_GetReportType(request), + USBGenericRequest_GetLength(request)); + break; + + case HIDGenericRequest_GETPROTOCOL: + USBD_Write(0, &hiddMouseDriver.inputProtocol, 1, 0, 0); + break; + + case HIDGenericRequest_SETPROTOCOL: + hiddMouseDriver.inputProtocol = request->wValue; + USBD_Write(0, 0, 0, 0, 0); + break; + + default: + TRACE_WARNING( + "HIDDMouseDriver_RequestHandler: Unknown request 0x%02X\n\r", + USBGenericRequest_GetRequest(request)); + USBD_Stall(0); + } + } + else { + + // Vendor request ? + USBD_Stall(0); + } +} + +//------------------------------------------------------------------------------ +/// Update the Mouse button status and location changes via input report +/// to host +/// \param bmButtons Bit map of the button status +/// \param deltaX Movment on X direction +/// \param deltaY Movment on Y direction +//------------------------------------------------------------------------------ +unsigned char HIDDMouseDriver_ChangePoints(unsigned char bmButtons, + signed char deltaX, + signed char deltaY) +{ + hiddMouseDriver.inputReport.bmButtons = (bmButtons & 0x07) + | HIDDMouse_TAG; + hiddMouseDriver.inputReport.bX = deltaX; + hiddMouseDriver.inputReport.bY = deltaY; + // Send input report through the interrupt IN endpoint + return USBD_Write(HIDDMouseDriverDescriptors_INTERRUPTIN, + &(hiddMouseDriver.inputReport), + sizeof(HIDDMouseInputReport), + 0, + 0); +} + +//------------------------------------------------------------------------------ +/// Starts a remote wake-up sequence if the host has explicitely enabled it +/// by sending the appropriate SET_FEATURE request. +//------------------------------------------------------------------------------ +void HIDDMouseDriver_RemoteWakeUp(void) +{ + // Remote wake-up has been enabled + if (USBDDriver_IsRemoteWakeUpEnabled(&(hiddMouseDriver.usbdDriver))) { + + USBD_RemoteWakeUp(); + } +} + diff --git a/usb/device/hid-mouse/HIDDMouseDriver.h b/usb/device/hid-mouse/HIDDMouseDriver.h new file mode 100644 index 0000000..94dac3a --- /dev/null +++ b/usb/device/hid-mouse/HIDDMouseDriver.h @@ -0,0 +1,107 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of methods for using a HID mouse device driver. + + !!!Usage + + -# Re-implement the USBDCallbacks_RequestReceived callback to forward + requests to HIDDMouseDriver_RequestHandler. This is done + automatically unless the NOAUTOCALLBACK symbol is defined during + compilation. + -# Initialize the driver using HIDDMouseDriver_Initialize. The + USB driver is automatically initialized by this method. + -# Call the HIDDMouseDriver_ChangePoints method when one or more + keys are pressed/released. +*/ + +#ifndef HIDDKEYBOARDDRIVER_H +#define HIDDKEYBOARDDRIVER_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Mouse Button bitmaps" +/// ... +/// !Bits +/// - HIDDMouse_LEFT_BUTTON +/// - HIDDMouse_RIGHT_BUTTON +/// - HIDDMouse_MIDDLE_BUTTON + +/// Left mouse button +#define HIDDMouse_LEFT_BUTTON (1 << 0) + +/// Right mouse button +#define HIDDMouse_RIGHT_BUTTON (1 << 1) + +/// Middle mouse button +#define HIDDMouse_MIDDLE_BUTTON (1 << 2) + +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ +/* + Function: HIDDMouseDriver_Initialize + Initializes the HID keyboard device driver. +*/ +extern void HIDDMouseDriver_Initialize(void); + +/* + Function: HIDDMouseDriver_RequestHandler + Handles HID-specific SETUP request sent by the host. + + Parameters: + request - Pointer to a USBGenericRequest instance. +*/ +extern void HIDDMouseDriver_RequestHandler(const USBGenericRequest *request); + +extern unsigned char HIDDMouseDriver_ChangePoints(unsigned char bmButtons, + signed char deltaX, + signed char deltaY); + +extern void HIDDMouseDriver_RemoteWakeUp(void); + +#endif //#ifndef HIDDKEYBOARDDRIVER_H + diff --git a/usb/device/hid-mouse/HIDDMouseDriverDescriptors.c b/usb/device/hid-mouse/HIDDMouseDriverDescriptors.c new file mode 100644 index 0000000..6a66d83 --- /dev/null +++ b/usb/device/hid-mouse/HIDDMouseDriverDescriptors.c @@ -0,0 +1,385 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: HIDDMouseDriverDescriptors + + About: Purpose + Declaration of the descriptors used by the HID device keyboard driver. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "HIDDMouseDriverDescriptors.h" +#include "HIDDMouseInputReport.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Mouse Device Descriptor IDs" +/// ... +/// +/// !IDs +/// - HIDDMouseDriverDescriptors_PRODUCTID +/// - HIDDMouseDriverDescriptors_VENDORID +/// - HIDDMouseDriverDescriptors_RELEASE + +/// Device product ID. +#define HIDDMouseDriverDescriptors_PRODUCTID 0x6200 +/// Device vendor ID. +#define HIDDMouseDriverDescriptors_VENDORID 0x03EB +/// Device release number. +#define HIDDMouseDriverDescriptors_RELEASE 0x0100 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Internal types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// List of descriptors that make up the configuration descriptors of a +/// %device using the HID Mouse driver. +//------------------------------------------------------------------------------ +typedef struct { + + /// Configuration descriptor. + USBConfigurationDescriptor configuration; + /// Interface descriptor. + USBInterfaceDescriptor interface; + /// HID descriptor. + HIDDescriptor hid; + /// Interrupt IN endpoint descriptor. + USBEndpointDescriptor interruptIn; + +} __attribute__ ((packed)) HIDDMouseDriverConfigurationDescriptors; + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +/// Device descriptor. +static const USBDeviceDescriptor deviceDescriptor = { + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + HIDDeviceDescriptor_CLASS, + HIDDeviceDescriptor_SUBCLASS, + HIDDeviceDescriptor_PROTOCOL, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + HIDDMouseDriverDescriptors_VENDORID, + HIDDMouseDriverDescriptors_PRODUCTID, + HIDDMouseDriverDescriptors_RELEASE, + 1, // Index of manufacturer description + 2, // Index of product description + 3, // Index of serial number description + 1 // One possible configuration +}; + +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) +/// Device qualifier descriptor (high-speed only). +static const USBDeviceQualifierDescriptor qualifierDescriptor = { + + sizeof(USBDeviceQualifierDescriptor), + USBGenericDescriptor_DEVICEQUALIFIER, + HIDDeviceDescriptor_CLASS, + HIDDeviceDescriptor_SUBCLASS, + HIDDeviceDescriptor_PROTOCOL, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + 1, // One possible configuration + 0 // Reserved +}; +#endif + +/// Configuration descriptor. +static const HIDDMouseDriverConfigurationDescriptors configurationDescriptors = { + + // Configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(HIDDMouseDriverConfigurationDescriptors), + 1, // One interface in this configuration + 1, // This is configuration #1 + 0, // No associated string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + // Interface descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0 + 0, // This is alternate setting #0 + 1, // One endpoints used + HIDInterfaceDescriptor_CLASS, + HIDInterfaceDescriptor_SUBCLASS_NONE, + HIDInterfaceDescriptor_PROTOCOL_MOUSE, + 0 // No associated string descriptor + }, + // HID descriptor + { + sizeof(HIDDescriptor), + HIDGenericDescriptor_HID, + HIDDescriptor_HID1_11, + 0, // Device is not localized, no country code + 1, // One HID-specific descriptor (apart from this one) + HIDGenericDescriptor_REPORT, + HIDDMouseDriverDescriptors_REPORTSIZE + }, + // Interrupt IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + HIDDMouseDriverDescriptors_INTERRUPTIN), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDMouseInputReport), + HIDDMouseDriverDescriptors_INTERRUPTIN_POLLING + } +}; + +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) +/// Other-speed configuration descriptor. +static const HIDDMouseDriverConfigurationDescriptors otherSpeedDescriptors = { + + // Configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_OTHERSPEEDCONFIGURATION, + sizeof(HIDDMouseDriverConfigurationDescriptors), + 1, // One interface in this configuration + 1, // This is configuration #1 + 0, // No associated string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + // Interface descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0 + 0, // This is alternate setting #0 + 2, // Two endpoints used + HIDInterfaceDescriptor_CLASS, + HIDInterfaceDescriptor_SUBCLASS_NONE, + HIDInterfaceDescriptor_PROTOCOL_MOUSE, + 0 // No associated string descriptor + }, + // HID descriptor + { + sizeof(HIDDescriptor), + HIDGenericDescriptor_HID, + HIDDescriptor_HID1_11, + 0, // Device is not localized, no country code + 1, // One HID-specific descriptor (apart from this one) + HIDGenericDescriptor_REPORT, + HIDDMouseDriverDescriptors_REPORTSIZE + }, + // Interrupt IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + HIDDMouseDriverDescriptors_INTERRUPTIN), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDMouseInputReport), + HIDDMouseDriverDescriptors_INTERRUPTIN_POLLING + } +}; +#endif + +/* + Variables: String descriptors + languageIdDescriptor - Language ID string descriptor. + manufacturerDescriptor - Manufacturer name. + productDescriptor - Product name. + serialNumberDescriptor - Product serial number. + stringDescriptors - Array of pointers to string descriptors. +*/ +static const unsigned char languageIdDescriptor[] = { + + USBStringDescriptor_LENGTH(1), + USBGenericDescriptor_STRING, + USBStringDescriptor_ENGLISH_US +}; + +static const unsigned char manufacturerDescriptor[] = { + + USBStringDescriptor_LENGTH(5), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('M'), + USBStringDescriptor_UNICODE('E'), + USBStringDescriptor_UNICODE('L') +}; + +static const unsigned char productDescriptor[] = { + + USBStringDescriptor_LENGTH(19), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('M'), + USBStringDescriptor_UNICODE('E'), + USBStringDescriptor_UNICODE('L'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('9'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('H'), + USBStringDescriptor_UNICODE('I'), + USBStringDescriptor_UNICODE('D'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('M'), + USBStringDescriptor_UNICODE('O'), + USBStringDescriptor_UNICODE('U'), + USBStringDescriptor_UNICODE('S'), + USBStringDescriptor_UNICODE('E'), +}; + +static const unsigned char serialNumberDescriptor[] = { + + USBStringDescriptor_LENGTH(12), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('0'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE('2'), + USBStringDescriptor_UNICODE('3'), + USBStringDescriptor_UNICODE('4'), + USBStringDescriptor_UNICODE('5'), + USBStringDescriptor_UNICODE('6'), + USBStringDescriptor_UNICODE('7'), + USBStringDescriptor_UNICODE('8'), + USBStringDescriptor_UNICODE('9'), + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('F') +}; + +static const unsigned char *stringDescriptors[] = { + + languageIdDescriptor, + manufacturerDescriptor, + productDescriptor, + serialNumberDescriptor +}; + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +/// List of descriptors used by the HID keyboard driver. +USBDDriverDescriptors hiddMouseDriverDescriptors = { + + &deviceDescriptor, + (USBConfigurationDescriptor *) &configurationDescriptors, +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + &qualifierDescriptor, + (USBConfigurationDescriptor *) &otherSpeedDescriptors, + &deviceDescriptor, + (USBConfigurationDescriptor *) &configurationDescriptors, + &qualifierDescriptor, + (USBConfigurationDescriptor *) &otherSpeedDescriptors, +#else + 0, // No full-speed device qualifier descriptor + 0, // No full-speed other speed configuration + 0, // No high-speed device descriptor + 0, // No high-speed configuration descriptor + 0, // No high-speed device qualifier descriptor + 0, // No high-speed other speed configuration descriptor +#endif + stringDescriptors, + 4 // Four string descriptors in list +}; + +/// Report descriptor used by the driver. +const unsigned char hiddReportDescriptor[] = { + + // Global Usage Page + HIDReport_GLOBAL_USAGEPAGE + 1, HIDGenericDesktop_PAGEID, + // Collection: Application + HIDReport_LOCAL_USAGE + 1, HIDGenericDesktop_MOUSE, + HIDReport_COLLECTION + 1, HIDReport_COLLECTION_APPLICATION, + // Physical collection: Pointer + HIDReport_LOCAL_USAGE + 1, HIDGenericDesktop_POINTER, + HIDReport_COLLECTION + 1, HIDReport_COLLECTION_PHYSICAL, + + // Input report: buttons + HIDReport_GLOBAL_USAGEPAGE + 1, HIDButton_PAGEID, + HIDReport_GLOBAL_REPORTCOUNT + 1, 3, + HIDReport_GLOBAL_REPORTSIZE + 1, 1, + HIDReport_LOCAL_USAGEMINIMUM + 1, 1, + HIDReport_LOCAL_USAGEMAXIMUM + 1, 3, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, 0, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, 1, + HIDReport_INPUT + 1, HIDReport_VARIABLE, // 3 button bits + + // Input report: padding + HIDReport_GLOBAL_REPORTCOUNT + 1, 1, + HIDReport_GLOBAL_REPORTSIZE + 1, 5, + HIDReport_INPUT + 1, HIDReport_CONSTANT, // 5 bit padding + + // Input report: pointer + HIDReport_GLOBAL_USAGEPAGE + 1, HIDGenericDesktop_PAGEID, + HIDReport_GLOBAL_REPORTSIZE + 1, 8, + HIDReport_GLOBAL_REPORTCOUNT + 1, 2, + HIDReport_LOCAL_USAGE + 1, HIDGenericDesktop_X, + HIDReport_LOCAL_USAGE + 1, HIDGenericDesktop_Y, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, (unsigned char) -127, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, 127, + HIDReport_INPUT + 1, HIDReport_VARIABLE | HIDReport_RELATIVE, + + HIDReport_ENDCOLLECTION, + HIDReport_ENDCOLLECTION +}; + diff --git a/usb/device/hid-mouse/HIDDMouseDriverDescriptors.h b/usb/device/hid-mouse/HIDDMouseDriverDescriptors.h new file mode 100644 index 0000000..4f27dec --- /dev/null +++ b/usb/device/hid-mouse/HIDDMouseDriverDescriptors.h @@ -0,0 +1,86 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definitions of the descriptors required by the HID device keyboard + driver. + + !!!Usage + -# Use the hiddMouseDriverDescriptors variable to initialize a + USBDDriver instance. + -# Send hiddReportDescriptor to the host when a GET_DESCRIPTOR request + for the report descriptor is received. +*/ + +#ifndef HIDDKEYBOARDDRIVERDESCRIPTORS_H +#define HIDDKEYBOARDDRIVERDESCRIPTORS_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ +/* + Constants: Endpoints + HIDDMouseDriverDescriptors_INTERRUPTIN - Interrupt IN endpoint number. + HIDDMouseDriverDescriptors_INTERRUPTIN_POLLING - Interrupt IN endpoint + polling rate (in milliseconds). +*/ +#define HIDDMouseDriverDescriptors_INTERRUPTIN 1 +#define HIDDMouseDriverDescriptors_INTERRUPTIN_POLLING 10 + +/* + Constants: Report descriptor + HIDDMouseDriverDescriptors_REPORTSIZE - Size of the report descriptor + in bytes. +*/ +#define HIDDMouseDriverDescriptors_REPORTSIZE 50 + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ +/* + Variables: HID keyboard driver descriptors + hiddMouseDriverDescriptors - List of descriptors used by the HID + keyboard driver. + hiddReportDescriptor - Report descriptor used by the driver. +*/ +extern USBDDriverDescriptors hiddMouseDriverDescriptors; +extern const unsigned char hiddReportDescriptor[]; + +#endif //#ifndef HIDDKEYBOARDDRIVERDESCRIPTORS_H + diff --git a/usb/device/hid-mouse/HIDDMouseInputReport.c b/usb/device/hid-mouse/HIDDMouseInputReport.c new file mode 100644 index 0000000..1c1c979 --- /dev/null +++ b/usb/device/hid-mouse/HIDDMouseInputReport.c @@ -0,0 +1,72 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: HIDDMouseInputReport implementation + + About: Purpose + Implementation of the HIDDMouseInputReport class. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "HIDDMouseInputReport.h" +#include "HIDDMouseDriverDescriptors.h" +#include + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes a mouse input report instance. +/// \param report Pointer to a HIDDMouseInputReport instance. +//------------------------------------------------------------------------------ +void HIDDMouseInputReport_Initialize(HIDDMouseInputReport *report) +{ + report->bmButtons = 0; + report->bX = 0; + report->bY = 0; +} + +/* +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +void HIDDMouseInputReport_UpdateButtons(HIDDMouseInputReport *report) +{ +} + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +void HIDDMouseInputReport_UpdateAxis(HIDDMouseInputReport *report) +{ +} +*/ diff --git a/usb/device/hid-mouse/HIDDMouseInputReport.h b/usb/device/hid-mouse/HIDDMouseInputReport.h new file mode 100644 index 0000000..ca074fd --- /dev/null +++ b/usb/device/hid-mouse/HIDDMouseInputReport.h @@ -0,0 +1,93 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Class for manipulating HID Mouse input reports. + + !!!Usage + + -# Initialize a newly created input report with + HIDDMouseInputReport_Initialize +*/ + +#ifndef HIDDKEYBOARDINPUTREPORT_H +#define HIDDKEYBOARDINPUTREPORT_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Mouse Keys" + +/// Mouse Left Click Button +#define HIDDMouseInputReport_LEFT_BUTTON (1 << 0) +/// Mouse Right Click Button +#define HIDDMouseInputReport_RIGHT_BUTTON (1 << 1) +/// Mouse Middle Button +#define HIDDMouseInputReport_MIDDLE_BUTTON (1 << 2) +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// HID input report structure used by the Mouse driver to notify the +/// host of pressed keys. +//------------------------------------------------------------------------------ +typedef struct { + + unsigned char bmButtons; /// Bitmap state of three mouse buttons. + signed char bX; /// Pointer displacement along the X axis. + signed char bY; /// Pointer displacement along the Y axis. + +} __attribute__ ((packed)) HIDDMouseInputReport; // GCC + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern void HIDDMouseInputReport_Initialize(HIDDMouseInputReport *report); + +#endif //#ifndef HIDDKEYBOARDINPUTREPORT_H + diff --git a/usb/device/hid-mouse/hid-mouse.dir b/usb/device/hid-mouse/hid-mouse.dir new file mode 100644 index 0000000..9dd733b --- /dev/null +++ b/usb/device/hid-mouse/hid-mouse.dir @@ -0,0 +1,544 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// +/// !!!Purpose +/// +/// This directory provides definitions, structs and functions for a USB HID +/// %device - USB HID Mouse driver, to implement an USB Mouse %device. +/// +/// !!!Contents +/// +/// There are three things for the implement of the USB HID Mouse driver: +/// - Implement the USB HID driver structs and functions for the %device, +/// to initialize, to handle HID-specific requests and dispach +/// standard requests in USBD callbacks, to read/write through assigned USB +/// endpoints, +/// - Create the HID Mouse device's descriptors that should be passed to +/// the USBDDriver instance on initialization, so that the host can +/// recognize the %device as a USB Mouse %device. +/// - Implement methods to update the Mouse keys status, so that host can +/// get it through USB. +/// +/// For more information about what a particular group contains, please refer to +/// "USB HID Mouse". +//------------------------------------------------------------------------------ + +/** + \page "USB HID Mouse" + This page describes how to use the "AT91 USB device framework" to produce a USB + HID Mouse driver, which appears as a USB Mouse on host. + + Details about the USB and the HID class can be found in the }USB specification + 2.0} and the }HID specification 1.11}, respectively. + + !!!References + - "AT91 USB device framework" + - "USB Device Enumeration" + - + Universal Serial Bus Revision 2.0 specification + (.zip file format, size 9.80 MB) + - + Device Class Definition for HID 1.11 + - + HID Usage Tables 1.12 + + !!!HID Basic + See "USB HID Basic". + + !!!Architecture + See "USB Device Framework Architecture". + + !!!Descriptors + + ... + + !!Device Descriptor + The Device descriptor of an HID %device is very basic, since the HID class + code is only specified at the Interface level. Thus, it only contains + standard values, as shown below: +\code +static const USBDeviceDescriptor deviceDescriptor = { + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + HIDDeviceDescriptor_CLASS, + HIDDeviceDescriptor_SUBCLASS, + HIDDeviceDescriptor_PROTOCOL, + BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0), + HIDDMouseDriverDescriptors_VENDORID, + HIDDMouseDriverDescriptors_PRODUCTID, + HIDDMouseDriverDescriptors_RELEASE, + 1, // Index of manufacturer description + 2, // Index of product description + 3, // Index of serial number description + 1 // One possible configuration +}; +\endcode + Note that the Vendor ID is a special value attributed by the USB-IF + organization. The product ID can be chosen freely by the vendor. + + !!Configuration Descriptor + Since one interface is required by the HID specification, this must be + specified in the Configuration descriptor. There is no other value of + interest to put here. +\code +// Configuration descriptor +{ + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(HIDDMouseDriverConfigurationDescriptors), + 1, // One interface in this configuration + 1, // This is configuration #1 + 0, // No associated string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) +}, +\endcode + When the Configuration descriptor is requested by the host (by using the + GET_DESCRIPTOR command), the %device must also sent all the related + descriptors, i.e. Interface, Endpoint and Class-Specific descriptors. It is + convenient to create a single structure to hold all this data, for sending + everything in one chunk. In the example software, a + HIDDMouseDriverConfigurationDescriptors structure has been declared for + that. + + !!HID Class Interface Descriptor + Since a Mouse %device needs to transmit as well as receive data, two + Interrupt (IN & OUT) endpoints are needed. This must be indicated in the + Interface descriptor. Conversely to the mouse example, the Boot protocol is + not implemented here, since there are more constraints on a Mouse %device. +\code +// Interface descriptor +{ + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0 + 0, // This is alternate setting #0 + 2, // Two endpoints used + HIDInterfaceDescriptor_CLASS, + HIDInterfaceDescriptor_SUBCLASS_NONE, + HIDInterfaceDescriptor_PROTOCOL_NONE, + 0 // No associated string descriptor +}, +\endcode + + !!HID Descriptor + While a HID Mouse produces two different reports, one Input and one Output, + only one Report descriptor can be used to describe them. Since having Physical + descriptors is also useless for a Mouse, there will only be one HID class + descriptor specified here. + + For a Mouse, the }bCountryCode} field can be used to specify the language + of the key caps. As this is optional, it is simply set to 00h in the example: +\code +// HID descriptor +{ + sizeof(HIDDescriptor), + HIDGenericDescriptor_HID, + HIDDescriptor_HID1_11, + 0, // Device is not localized, no country code + 1, // One HID-specific descriptor (apart from this one) + HIDGenericDescriptor_REPORT, + HIDDMouseDriverDescriptors_REPORTSIZE +}, +\endcode + + !!Report Descriptor + Two current reports are defined in the Report descriptor. The first one is + used to notify the host of which keys are pressed, with both modifier keys + (alt, ctrl, etc.) and alphanumeric keys. The second report is necessary for + the host to send the LED (num lock, caps lock, etc.) states. + + The Report descriptor starts with the global %device functionality, described + with a #Usage Page# and a #Usage# items: +\code +const unsigned char hiddReportDescriptor[] = { + + HIDReport_GLOBAL_USAGEPAGE + 1, HIDGenericDesktop_PAGEID, + HIDReport_LOCAL_USAGE + 1, HIDGenericDesktop_Mouse, +\endcode + + As in the mouse example, the }Generic Desktop} page is used. This time, the + specific usage is the }Mouse} one. An Application collection is then + defined to group the reports together: +\code + HIDReport_COLLECTION + 1, HIDReport_COLLECTION_APPLICATION, +\endcode + + The first report to be defined is the modifier keys. They are represented as a + bitmap field, indicating whether or not each key is pressed. A single byte is + used to map keys \#224-231 defined in the }HID Usage Tables} document: + LeftControl, LeftShift, LeftAlt, LeftGUI (e.g. Windows key), + RightControl, RightShift, RightAlt and RightGUI. + The }Keypad} usage page must be specified for this report, and since this is a + bitmap value, the data is flagged as }Variable}: +\code + // Input report: modifier keys + HIDReport_GLOBAL_REPORTSIZE + 1, 1, + HIDReport_GLOBAL_REPORTCOUNT + 1, 8, + HIDReport_GLOBAL_USAGEPAGE + 1, HIDKeypad_PAGEID, + HIDReport_LOCAL_USAGEMINIMUM + 1, + HIDDMouseDriverDescriptors_FIRSTMODIFIERKEY, + HIDReport_LOCAL_USAGEMAXIMUM + 1, + HIDDMouseDriverDescriptors_LASTMODIFIERKEY, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, 0, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, 1, + HIDReport_INPUT + 1, HIDReport_VARIABLE, +\endcode + + Then, the actual alphanumeric key report is described. This is done by + defining several bytes of data, one for each pressed key. In the example, + up to three keys can be pressed at the same time (and detected) by the user. + Once again, the usage page is set to }Keypad}. This time however, the data + must be specified as an }Array}, since the same control (the keypad) produces + several values: +\code + // Input report: standard keys + HIDReport_GLOBAL_REPORTCOUNT + 1, 3, + HIDReport_GLOBAL_REPORTSIZE + 1, 8, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, + HIDDMouseDriverDescriptors_FIRSTSTANDARDKEY, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, + HIDDMouseDriverDescriptors_LASTSTANDARDKEY, + HIDReport_GLOBAL_USAGEPAGE + 1, HIDKeypad_PAGEID, + HIDReport_LOCAL_USAGEMINIMUM + 1, + HIDDMouseDriverDescriptors_FIRSTSTANDARDKEY, + HIDReport_LOCAL_USAGEMAXIMUM + 1, + HIDDMouseDriverDescriptors_LASTSTANDARDKEY, + HIDReport_INPUT + 1, 0 /* Data array */, +\endcode + + The LED array is then defined, with the associated usage page. The Report + descriptor is formatted in this order to avoid redefining unchanged }Global} + items, in order to save memory. This time again, the LED status is reported as + a bitmap field. Three LEDs are used here: Num Lock, Caps Lock and Scroll Lock + (IDs 01h to 03h). It is important to note that this is an #Output# report: +\code + // Output report: LEDs + HIDReport_GLOBAL_REPORTCOUNT + 1, 3, + HIDReport_GLOBAL_REPORTSIZE + 1, 1, + HIDReport_GLOBAL_USAGEPAGE + 1, HIDLeds_PAGEID, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, 0, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, 1, + HIDReport_LOCAL_USAGEMINIMUM + 1, HIDLeds_NUMLOCK, + HIDReport_LOCAL_USAGEMAXIMUM + 1, HIDLeds_SCROLLLOCK, + HIDReport_OUTPUT + 1, HIDReport_VARIABLE, +\endcode + + Since the previous report only contains 3 bits, the data must be padded to a + multiple of one byte. This is done by using constant Output data, as follows: +\code + // Output report: padding + HIDReport_GLOBAL_REPORTCOUNT + 1, 1, + HIDReport_GLOBAL_REPORTSIZE + 1, 5, + HIDReport_OUTPUT + 1, HIDReport_CONSTANT, +\endcode + + The last item, }End Collection}, is necessary to close the previously opened + }Application Collection}. +\code + HIDReport_ENDCOLLECTION +}; +\endcode + + The Input and Output reports defined by this descriptor can be modeled by the + following structures: +\code +// HID Input Report +typedef struct { + + // State of modifier keys. + unsigned char bmModifierKeys:8; + // Key codes of pressed keys. + unsigned char pressedKeys[HIDDMouseInputReport_MAXKEYPRESSES]; + +} __attribute__ ((packed)) HIDDMouseInputReport; // GCC +// HID Output Report +typedef struct { + + unsigned char numLockStatus:1, // State of the num. lock LED. + capsLockStatus:1, // State of the caps lock LED. + scrollLockStatus:1, // State of the scroll lock LED. + padding:5; // Padding bits. + +} __attribute__ ((packed)) HIDDMouseOutputReport; // GCC +\endcode + + An instance of each one of the reports is stored in a HIDDMouseDriver + structure, which holds the standard class driver and HID Mouse-specific + data. + + !!Physical Descriptor + A Physical descriptor is useless for a Mouse %device, so none are defined + in this example. + + !!Endpoint Descriptor + Following the Interface and HID-specific descriptors, the two necessary + endpoints are defined. +\code +// Interrupt IN endpoint descriptor +{ + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + HIDDMouseDriverDescriptors_INTERRUPTIN), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDMouseInputReport), + HIDDMouseDriverDescriptors_INTERRUPTIN_POLLING +}, +// Interrupt OUT endpoint descriptor +{ + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + HIDDMouseDriverDescriptors_INTERRUPTOUT), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDMouseOutputReport), + HIDDMouseDriverDescriptors_INTERRUPTIN_POLLING +} +\endcode + + !!String Descriptors + Please refer to "Usage: USBD VID, PID & Strings". + + !!!Class-specific requests + A driver request handler should first differentiate between class-specific and + standard requests using the corresponding bits in the }bmRequestType} field. + In most cases, standard requests can be immediately forwarded to the standard + request handler method; class-specific methods must be decoded and treated by + the custom handler. + + !!GetDescriptor + Three values have been added by the HID specification for the #GET_DESCRIPTOR# + request. The high byte of the }wValue} field contains the type of the + requested descriptor; in addition to the standard types, the #HID + specification# adds the #HID descriptor# (21h), the #Report descriptor# + (22h) and the #Physical descriptor# (23h) types. + + There is no particular action to perform besides sending the descriptor. This + can be done by using the USBD_Write method, after the requested descriptor has + been identified: +\code +switch (USBGenericRequest_GetRequest(request)) { + + case USBGenericRequest_GETDESCRIPTOR: + // Check if this is a HID descriptor, + // otherwise forward it to + // the standard driver + if (!HIDDMouseDriver_GetDescriptor( + USBGetDescriptorRequest_GetDescriptorType(request), + USBGenericRequest_GetLength(request))) { + + USBDDriver_RequestHandler(&(hiddMouseDriver.usbdDriver), + request); + } + break; + + default: + USBDDriver_RequestHandler(&(hiddMouseDriver.usbdDriver), + request); +} +\endcode + A slight complexity of the GET_DESCRIPTOR and SET_DESCRIPTOR requests is that + those are standard requests, but the standard request handler + (USBDDriver_RequestHandler) must not always be called to treat them (since + they may refer to HID descriptors). The solution is to first identify + GET/SET_DESCRIPTOR requests, treat the HID-specific cases and, finally, + forward any other request to the standard handler. + + In this case, a GET_DESCRIPTOR request for the Physical descriptor is first + forwarded to the standard handler, and STALLed there because it is not + recognized. This is done because the %device does not have any Physical + descriptors, and thus, does not need to handle the associated request. + + !!SetDescriptor + This request is optional and is never issued by most hosts. It is not + implemented in this example. + + !!GetReport + Since the HID Mouse defines two different reports, the Report Type value + specified by this request (upper byte of the }wValue} field) must be examined + to decide which report to send. If the type value is 01h, then the Input + report must be returned; if it is 02h, the Output report is requested: +\code +case HIDGenericRequest_GETREPORT: +//------------------------------- + type = HIDReportRequest_GetReportType(request); + length = USBGenericRequest_GetLength(request); + switch (type) { + + case HIDReportRequest_INPUT: + + // Adjust size and send report + if (length > sizeof(HIDDMouseInputReport)) { + + length = sizeof(HIDDMouseInputReport); + } + USBD_Write(0, // Endpoint #0 + &(hiddMouseDriver.inputReport), + length, + 0, // No callback + 0); + break; + + case HIDReportRequest_OUTPUT: + + // Adjust size and send report + if (length > sizeof(HIDDMouseOutputReport)) { + + length = sizeof(HIDDMouseOutputReport); + } + USBD_Write(0, // Endpoint #0 + &(hiddMouseDriver.outputReport), + length, + 0, // No callback + 0); + break; + + default: + USBD_Stall(0); + } +break; +\endcode + + !!SetReport + For an HID Mouse, the #SET_REPORT# command can be sent by the host to + change the state of the LEDs. Normally, the dedicated Interrupt OUT endpoint + will be used for this; but in some cases, using the default Control endpoint + can save some bandwidth on the host side. + + Note that the SET_REPORT request can be directed at the Input report of the + Mouse; in this case, it can be safely discarded, according to the HID + specification. Normally, most host drivers only target the Output report. The + Report Type value is stored in the upper byte of the }wValue} field. + + The length of the data phase to follow is stored in the }wLength} field of the + request. It should be equal to the total length of the Output report. If it is + different, the report status must still be updated with the received data as + best as possible. + + When the reception of the new data is completed, some processing must be done + to enable/disable the corresponding LEDs. This is done in the callback + function passed as an argument to USBD_Read: +\code +case HIDGenericRequest_SETREPORT: +//------------------------------- + type = HIDReportRequest_GetReportType(request); + length = USBGenericRequest_GetLength(request); + switch(type) { + + case HIDReportRequest_INPUT: + // SET_REPORT requests on input reports are ignored + USBD_Stall(0); + break; + + case HIDReportRequest_OUTPUT: + // Check report length + if (length != sizeof(HIDDMouseOutputReport)) { + + USBD_Stall(0); + } + else { + + USBD_Read(0, // Endpoint #0 + &(hiddMouseDriver.outputReport), + length, + (TransferCallback) HIDDMouseDriver_ReportReceived, + 0); // No argument to the callback function + } + break; + + default: + USBD_Stall(0); + } +break; +\endcode + + !!SetIdle + In this case study, the #SET_IDLE# request is used to set a delay before a key + is repeated. This is common behavior on Mouse devices. Usually, this delay + is set to about 500 ms by the host. + + The only action here is to store the new Idle rate. The management of this + setting must be done in the main function, since Interrupt IN reports are sent + from there. + + In practice, it is not necessary to perform any action, apart from sending a + zero-length packet to acknowledge it. The main application however has to make + sure that only new reports are sent by the %device. +\code +case HIDGenericRequest_SETIDLE: +//----------------------------- + hiddMouseDriver.inputReportIdleRate = + HIDIdleRequest_GetIdleRate(request); + USBD_Write(0, 0, 0, 0, 0); +break; +\endcode + + !!GetIdle + The only necessary operation for this request is to send the previously saved + Idle rate. This is done by calling the USBD_Write method with the one-byte + variable as its parameter: +\code +case HIDGenericRequest_GETIDLE: +//----------------------------- + USBD_Write(0, &(hiddMouseDriver.inputReportIdleRate), 1, 0, 0); +break; +\endcode + + !!GetProtocol, SetProtocol + This HID Mouse example does not support the Boot protocol, so there is no + need to implement the SET_PROTOCOL and GET_PROTOCOL requests. This means they + can be safely STALLed when received. + + !!!Main Application + Like the mouse example, the main program must perform two different + operations. First, it has to monitor the physical inputs used as keys. In the + example software, the buttons present on the evaluation boards are used to + produce several modifier and alphanumeric keys. + + Also, the main program is in charge of sending reports as they are modified, + taking into account the Idle rate specified by the host. Idle rate management + can be carried out by firing/resetting a timer once a new report is sent; if + the timer expires, this means the Input report has not changed since. + According to the HID specification, a single instance of the report must be + sent in this case. + + Finally, the HID specification also defines that if too many keys are pressed + at the same time, the %device should report an }ErrorRollOver} usage value + (01h) in every byte of the key array. This has to be handled by the main + application as well. + +*/ \ No newline at end of file diff --git a/usb/device/hid-transfer/HIDDTransferDriver.c b/usb/device/hid-transfer/HIDDTransferDriver.c new file mode 100644 index 0000000..0810474 --- /dev/null +++ b/usb/device/hid-transfer/HIDDTransferDriver.c @@ -0,0 +1,479 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "HIDDTransferDriver.h" +#include "HIDDTransferDriverDesc.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//------------------------------------------------------------------------------ +// Internal types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Driver structure for an HID device implementing keyboard functionalities. +//------------------------------------------------------------------------------ +typedef struct { + + /// Standard USB device driver instance. + USBDDriver usbdDriver; + + // OUT Report - block input + unsigned short iReportLen; + unsigned char iReportBuf[HIDDTransferDriver_REPORTSIZE]; + + // IN Report - block output + unsigned short oReportLen; + unsigned char oReportBuf[HIDDTransferDriver_REPORTSIZE]; + + // Interrupt OUT Data - input + /// Input data length + unsigned short iLen; + /// Input (report) Buffer + unsigned char iBuf[HIDDTransferDriver_REPORTSIZE]; + + // Nothing more now... + +} HIDDTransferDriver; + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +/// Static instance of the HID Transfer device driver. +static HIDDTransferDriver hiddTransferDriver; + +//------------------------------------------------------------------------------ +// Internal functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Returns the descriptor requested by the host. +/// \param type Descriptor type. +/// \param length Maximum number of bytes to send. +/// \return 1 if the request has been handled by this function, otherwise 0. +//------------------------------------------------------------------------------ +static unsigned char HIDDTransferDriver_GetDescriptor(unsigned char type, + unsigned char length) +{ + const USBConfigurationDescriptor *pConfiguration; + HIDDescriptor *hidDescriptors[2]; + + switch (type) { + + case HIDGenericDescriptor_REPORT: + TRACE_INFO("Report "); + + // Adjust length and send report descriptor + if (length > HIDDTransferDriverDescriptors_REPORTSIZE) { + + length = HIDDTransferDriverDescriptors_REPORTSIZE; + } + USBD_Write(0, &hiddReportDescriptor, length, 0, 0); + break; + + case HIDGenericDescriptor_HID: + TRACE_INFO("HID "); + + // Configuration descriptor is different depending on configuration + if (USBD_IsHighSpeed()) { + + pConfiguration = + hiddTransferDriver.usbdDriver.pDescriptors->pHsConfiguration; + } + else { + + pConfiguration = + hiddTransferDriver.usbdDriver.pDescriptors->pFsConfiguration; + } + + // Parse the device configuration to get the HID descriptor + USBConfigurationDescriptor_Parse(pConfiguration, 0, 0, + (USBGenericDescriptor **) &hidDescriptors[0]); + + // Adjust length and send HID descriptor + if (length > sizeof(HIDDescriptor)) { + + length = sizeof(HIDDescriptor); + } + USBD_Write(0, hidDescriptors[0], length, 0, 0); + break; + + default: + return 0; + } + + return 1; +} + +//------------------------------------------------------------------------------ +/// Callback function when SetReport request data received from host +/// \param pArg Pointer to additional argument struct +/// \param status Result status +/// \param transferred Number of bytes transferred +/// \param remaining Number of bytes that are not transferred yet +//------------------------------------------------------------------------------ +static void HIDDTransferDriver_ReportReceived(void *pArg, + unsigned char status, + unsigned int transferred, + unsigned int remaining) +{ + hiddTransferDriver.iReportLen = transferred; + USBD_Write(0, 0, 0, 0, 0); +} + +//------------------------------------------------------------------------------ +/// Callback function when GetReport request data sent to host +/// \param pArg Pointer to additional argument struct +/// \param status Result status +/// \param transferred Number of bytes transferred +/// \param remaining Number of bytes that are not transferred yet +//------------------------------------------------------------------------------ +static void HIDDTransferDriver_ReportSent(void *pArg, + unsigned char status, + unsigned int transferred, + unsigned int remaining) +{ + USBD_Read(0, 0, 0, 0, 0); +} + +//------------------------------------------------------------------------------ +/// Callback function when interrupt OUT data received from host +/// \param pArg Pointer to additional argument +/// \param status Result status +/// \param transferred Number of bytes transferred +/// \param remaining Number of bytes that are not transferred yet +//------------------------------------------------------------------------------ +static void HIDDTransferDriver_DataReceived(void *pArg, + unsigned char status, + unsigned int transferred, + unsigned int remaining) +{ + hiddTransferDriver.iLen = transferred; + + USBD_Read(HIDDTransferDriverDescriptors_INTERRUPTOUT, + hiddTransferDriver.iBuf, + HIDDTransferDriver_REPORTSIZE, + (TransferCallback)HIDDTransferDriver_DataReceived, + 0); +} + +//------------------------------------------------------------------------------ +// Optional RequestReceived() callback re-implementation +//------------------------------------------------------------------------------ +#if !defined(NOAUTOCALLBACK) + +//------------------------------------------------------------------------------ +/// Callback function when new request receivce from host +/// \param request Pointer to the USBGenericRequest instance +//------------------------------------------------------------------------------ +void USBDCallbacks_RequestReceived(const USBGenericRequest *request) +{ + HIDDTransferDriver_RequestHandler(request); +} + +#endif + +//------------------------------------------------------------------------------ +// ConfigurationChanged() callback re-implementation +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Callback function when configureation changed +/// \param cfgnum New configuration number +//------------------------------------------------------------------------------ +void USBDDriverCallbacks_ConfigurationChanged(unsigned char cfgnum) +{ + if (cfgnum > 0) { + + hiddTransferDriver.iLen = 0; + USBD_Read(HIDDTransferDriverDescriptors_INTERRUPTOUT, + hiddTransferDriver.iBuf, + HIDDTransferDriver_REPORTSIZE, + HIDDTransferDriver_DataReceived, + 0); + } +} + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +/// Initializes the HID Transfer %device driver. +//------------------------------------------------------------------------------ +void HIDDTransferDriver_Initialize() +{ + hiddTransferDriver.iReportLen = 0; + + USBDDriver_Initialize(&(hiddTransferDriver.usbdDriver), + &hiddTransferDriverDescriptors, + 0); // Multiple interface settings not supported + USBD_Init(); +} + +//------------------------------------------------------------------------------ +/// Handles HID-specific SETUP request sent by the host. +/// \param request Pointer to a USBGenericRequest instance +//------------------------------------------------------------------------------ +void HIDDTransferDriver_RequestHandler(const USBGenericRequest *request) +{ + TRACE_INFO("NewReq "); + + // Check if this is a standard request + if (USBGenericRequest_GetType(request) == USBGenericRequest_STANDARD) { + + // This is a standard request + switch (USBGenericRequest_GetRequest(request)) { + + case USBGenericRequest_GETDESCRIPTOR: + // Check if this is a HID descriptor, otherwise forward it to + // the standard driver + if (!HIDDTransferDriver_GetDescriptor( + USBGetDescriptorRequest_GetDescriptorType(request), + USBGenericRequest_GetLength(request))) { + + USBDDriver_RequestHandler(&(hiddTransferDriver.usbdDriver), + request); + } + break; + + case USBGenericRequest_CLEARFEATURE: + /* Check which is the requested feature */ + switch (USBFeatureRequest_GetFeatureSelector(request)) { + case USBFeatureRequest_ENDPOINTHALT: + { unsigned char ep = + USBGenericRequest_GetEndpointNumber(request); + if (USBD_IsHalted(ep)) { + /* Unhalt endpoint restart OUT EP + */ + USBD_Unhalt(ep); + if (ep == HIDDTransferDriverDescriptors_INTERRUPTOUT) { + hiddTransferDriver.iLen = 0; + USBD_Read(HIDDTransferDriverDescriptors_INTERRUPTOUT, + hiddTransferDriver.iBuf, + HIDDTransferDriver_REPORTSIZE, + HIDDTransferDriver_DataReceived, + 0); + } + } + /* and send a zero-length packet */ + USBD_Write(0, 0, 0, 0, 0); + return; /* Done, no others */ + } + } + + default: + USBDDriver_RequestHandler(&(hiddTransferDriver.usbdDriver), + request); + } + } + // Check if this is a class request + else if (USBGenericRequest_GetType(request) == USBGenericRequest_CLASS) { + + unsigned short length = USBGenericRequest_GetLength(request); + unsigned char type = HIDReportRequest_GetReportType(request); + + switch (USBGenericRequest_GetRequest(request)) { + + case HIDGenericRequest_SETREPORT: + + if (length <= HIDDTransferDriver_REPORTSIZE && + type == HIDReportRequest_OUTPUT) { + + USBD_Read(0, + hiddTransferDriver.iReportBuf, + length, + HIDDTransferDriver_ReportReceived, + 0); // No argument to the callback function + } + else { + + USBD_Stall(0); + } + break; + + case HIDGenericRequest_GETREPORT: + + if (length <= HIDDTransferDriver_REPORTSIZE && + type == HIDReportRequest_INPUT) { + + USBD_Write(0, + hiddTransferDriver.oReportBuf, + length, + HIDDTransferDriver_ReportSent, + 0); + } + else { + + USBD_Stall(0); + } + break; + + default: + TRACE_WARNING( + "HIDDTransferDriver_RequestHandler: request 0x%02X\n\r", + USBGenericRequest_GetRequest(request)); + USBD_Stall(0); + } + } + else { + + // Vendor request ? + USBD_Stall(0); + } +} + +//------------------------------------------------------------------------------ +/// Try to read request buffer of SetReport. +/// Set pData to 0 to get current data length only. +/// \param pData Pointer to data buffer +/// \param dLength Data buffer length +/// \return Number of bytes read +//------------------------------------------------------------------------------ +unsigned short HIDDTransferDriver_ReadReport(void *pData, + unsigned int dLength) +{ + if (pData == 0) { + + return hiddTransferDriver.iReportLen; + } + + if (dLength > HIDDTransferDriver_REPORTSIZE) { + + dLength = HIDDTransferDriver_REPORTSIZE; + } + if (dLength > hiddTransferDriver.iReportLen) { + + dLength = hiddTransferDriver.iReportLen; + } + hiddTransferDriver.iReportLen = 0; + memcpy(pData, hiddTransferDriver.iReportBuf, dLength); + + return dLength; +} + +//------------------------------------------------------------------------------ +/// Try to read request buffer of interrupt OUT EP. +/// Set pData to 0 to get current data length only. +/// \param pData Pointer to data buffer +/// \param dLength Data buffer length +/// \return Number of bytes read +//------------------------------------------------------------------------------ +unsigned short HIDDTransferDriver_Read(void *pData, + unsigned int dLength) +{ + if (pData == 0) { + + return hiddTransferDriver.iLen; + } + + if (dLength > HIDDTransferDriver_REPORTSIZE) { + + dLength = HIDDTransferDriver_REPORTSIZE; + } + if (dLength > hiddTransferDriver.iLen) { + + dLength = hiddTransferDriver.iLen; + } + hiddTransferDriver.iLen = 0; + memcpy(pData, hiddTransferDriver.iBuf, dLength); + + return dLength; +} + +//------------------------------------------------------------------------------ +/// Set data in IN report buffer, which will be sent when GetReport request +/// issued. +/// \param pData Pointer to the data sent. +/// \param dLength The data length. +//------------------------------------------------------------------------------ +void HIDDTransferDriver_SetReport(const void *pData, + unsigned int dLength) +{ + if (pData == 0 || dLength == 0) + return; + if (dLength != HIDDTransferDriver_REPORTSIZE) { + dLength = HIDDTransferDriver_REPORTSIZE; + } + if (hiddTransferDriver.oReportLen) { + TRACE_INFO("Changing IN report!\n\r"); + } + memcpy(hiddTransferDriver.oReportBuf, pData, dLength); + hiddTransferDriver.oReportLen = dLength; +} + +//------------------------------------------------------------------------------ +/// Write data through USB interrupt IN EP. +/// \param pData Pointer to the data sent. +/// \param dLength The data length. +/// \param fCallback Callback function invoked when transferring done. +/// \param pArg Pointer to additional arguments. +//------------------------------------------------------------------------------ +unsigned char HIDDTransferDriver_Write(const void *pData, + unsigned int dLength, + TransferCallback fCallback, + void *pArg) +{ + if (dLength != HIDDTransferDriver_REPORTSIZE) { + + dLength = HIDDTransferDriver_REPORTSIZE; + } + return USBD_Write(HIDDTransferDriverDescriptors_INTERRUPTIN, + pData, dLength, + fCallback, pArg); +} + +//------------------------------------------------------------------------------ +/// Starts a remote wake-up sequence if the host has explicitely enabled it +/// by sending the appropriate SET_FEATURE request. +//------------------------------------------------------------------------------ +void HIDDTransferDriver_RemoteWakeUp(void) +{ + // Remote wake-up has been enabled + if (USBDDriver_IsRemoteWakeUpEnabled(&(hiddTransferDriver.usbdDriver))) { + + USBD_RemoteWakeUp(); + } +} + diff --git a/usb/device/hid-transfer/HIDDTransferDriver.h b/usb/device/hid-transfer/HIDDTransferDriver.h new file mode 100644 index 0000000..f374ae0 --- /dev/null +++ b/usb/device/hid-transfer/HIDDTransferDriver.h @@ -0,0 +1,87 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of methods for using a HID transfer %device driver. + + !!!Usage + + -# Re-implement the USBDCallbacks_RequestReceived callback to forward + requests to HIDDTransferDriver_RequestHandler. This is done + automatically unless the NOAUTOCALLBACK symbol is defined during + compilation. + -# Initialize the driver using HIDDTransferDriver_Initialize. The + USB driver is automatically initialized by this method. + -# Call the HIDDTransferDriver_Write method when sendint data to host. + -# Call the HIDDTransferRead, HIDDTransferReadReport when checking and getting + received data from host. +*/ + +#ifndef HIDDKEYBOARDDRIVER_H +#define HIDDKEYBOARDDRIVER_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern void HIDDTransferDriver_Initialize(); + +extern void HIDDTransferDriver_RequestHandler(const USBGenericRequest *request); + +extern unsigned short HIDDTransferDriver_Read(void *pData, + unsigned int dLength); + +extern unsigned short HIDDTransferDriver_ReadReport(void *pData, + unsigned int dLength); + +extern unsigned char HIDDTransferDriver_Write(const void *pData, + unsigned int size, + TransferCallback callback, + void *pArg); + + +extern void HIDDTransferDriver_RemoteWakeUp(void); + +#endif //#ifndef HIDDKEYBOARDDRIVER_H + diff --git a/usb/device/hid-transfer/HIDDTransferDriverDesc.c b/usb/device/hid-transfer/HIDDTransferDriverDesc.c new file mode 100644 index 0000000..5cd6363 --- /dev/null +++ b/usb/device/hid-transfer/HIDDTransferDriverDesc.c @@ -0,0 +1,417 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* + Title: HIDDTransferDriverDescriptors + + About: Purpose + Declaration of the descriptors used by the HID device Transfer driver. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "HIDDTransferDriverDesc.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Transfer Device Descriptor IDs" +/// ... +/// +/// !IDs +/// - HIDDTransferDriverDescriptors_PRODUCTID +/// - HIDDTransferDriverDescriptors_VENDORID +/// - HIDDTransferDriverDescriptors_RELEASE + +/// Device product ID. +#define HIDDTransferDriverDescriptors_PRODUCTID 0x6201 +/// Device vendor ID. +#define HIDDTransferDriverDescriptors_VENDORID 0x03EB +/// Device release number. +#define HIDDTransferDriverDescriptors_RELEASE 0x0100 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Macros +//------------------------------------------------------------------------------ + +/// Returns the minimum between two values. +#define MIN(a, b) ((a < b) ? a : b) + +//------------------------------------------------------------------------------ +// Internal types +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +/// List of descriptors that make up the configuration descriptors of a +/// device using the HID Transfer driver. +//------------------------------------------------------------------------------ +typedef struct { + + /// Configuration descriptor. + USBConfigurationDescriptor configuration; + /// Interface descriptor. + USBInterfaceDescriptor interface; + /// HID descriptor. + HIDDescriptor hid; + /// Interrupt IN endpoint descriptor. + USBEndpointDescriptor interruptIn; + /// Interrupt OUT endpoint descriptor. + USBEndpointDescriptor interruptOut; + +} __attribute__ ((packed)) HIDDTransferDriverConfigurationDescriptors; + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +/// Device descriptor. +static const USBDeviceDescriptor deviceDescriptor = { + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + HIDDeviceDescriptor_CLASS, + HIDDeviceDescriptor_SUBCLASS, + HIDDeviceDescriptor_PROTOCOL, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + HIDDTransferDriverDescriptors_VENDORID, + HIDDTransferDriverDescriptors_PRODUCTID, + HIDDTransferDriverDescriptors_RELEASE, + 1, // Index of manufacturer description + 2, // Index of product description + 3, // Index of serial number description + 1 // One possible configuration +}; + +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) +/// Device qualifier descriptor (high-speed only). +static const USBDeviceQualifierDescriptor qualifierDescriptor = { + + sizeof(USBDeviceQualifierDescriptor), + USBGenericDescriptor_DEVICEQUALIFIER, + HIDDeviceDescriptor_CLASS, + HIDDeviceDescriptor_SUBCLASS, + HIDDeviceDescriptor_PROTOCOL, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + 1, // One possible configuration + 0 // Reserved +}; +#endif + +/// Configuration descriptor. +static const HIDDTransferDriverConfigurationDescriptors configurationDescriptors = { + + // Configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(HIDDTransferDriverConfigurationDescriptors), + 1, // One interface in this configuration + 1, // This is configuration #1 + 0, // No associated string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + // Interface descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0 + 0, // This is alternate setting #0 + 2, // Two endpoints used + HIDInterfaceDescriptor_CLASS, + HIDInterfaceDescriptor_SUBCLASS_NONE, + HIDInterfaceDescriptor_PROTOCOL_NONE, + 0 // No associated string descriptor + }, + // HID descriptor + { + sizeof(HIDDescriptor), + HIDGenericDescriptor_HID, + HIDDescriptor_HID1_11, + 0, // Device is not localized, no country code + 1, // One HID-specific descriptor (apart from this one) + HIDGenericDescriptor_REPORT, + HIDDTransferDriverDescriptors_REPORTSIZE + }, + // Interrupt IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + HIDDTransferDriverDescriptors_INTERRUPTIN), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE( + HIDDTransferDriverDescriptors_INTERRUPTIN), + MIN(USBEndpointDescriptor_MAXINTERRUPTSIZE_FS, + HIDDTransferDriver_REPORTSIZE)), + HIDDTransferDriverDescriptors_INTERRUPTIN_POLLING + }, + // Interrupt OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + HIDDTransferDriverDescriptors_INTERRUPTOUT), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE( + HIDDTransferDriverDescriptors_INTERRUPTOUT), + MIN(USBEndpointDescriptor_MAXINTERRUPTSIZE_FS, + HIDDTransferDriver_REPORTSIZE)), + HIDDTransferDriverDescriptors_INTERRUPTOUT_POLLING + } +}; + +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) +/// Other-speed configuration descriptor. +static const HIDDTransferDriverConfigurationDescriptors otherSpeedDescriptors = { + + // Configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_OTHERSPEEDCONFIGURATION, + sizeof(HIDDTransferDriverConfigurationDescriptors), + 1, // One interface in this configuration + 1, // This is configuration #1 + 0, // No associated string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + // Interface descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0 + 0, // This is alternate setting #0 + 2, // Two endpoints used + HIDInterfaceDescriptor_CLASS, + HIDInterfaceDescriptor_SUBCLASS_NONE, + HIDInterfaceDescriptor_PROTOCOL_NONE, + 0 // No associated string descriptor + }, + // HID descriptor + { + sizeof(HIDDescriptor), + HIDGenericDescriptor_HID, + HIDDescriptor_HID1_11, + 0, // Device is not localized, no country code + 1, // One HID-specific descriptor (apart from this one) + HIDGenericDescriptor_REPORT, + HIDDTransferDriverDescriptors_REPORTSIZE + }, + // Interrupt IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + HIDDTransferDriverDescriptors_INTERRUPTIN), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE( + HIDDTransferDriverDescriptors_INTERRUPTIN), + MIN(USBEndpointDescriptor_MAXINTERRUPTSIZE_HS, + HIDDTransferDriver_REPORTSIZE)), + HIDDTransferDriverDescriptors_INTERRUPTIN_POLLING + }, + // Interrupt OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + HIDDTransferDriverDescriptors_INTERRUPTIN), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE( + HIDDTransferDriverDescriptors_INTERRUPTOUT), + MIN(USBEndpointDescriptor_MAXINTERRUPTSIZE_HS, + HIDDTransferDriver_REPORTSIZE)), + HIDDTransferDriverDescriptors_INTERRUPTIN_POLLING + } +}; +#endif + +/* + Variables: String descriptors + languageIdDescriptor - Language ID string descriptor. + manufacturerDescriptor - Manufacturer name. + productDescriptor - Product name. + serialNumberDescriptor - Product serial number. + stringDescriptors - Array of pointers to string descriptors. +*/ +static const unsigned char languageIdDescriptor[] = { + + USBStringDescriptor_LENGTH(1), + USBGenericDescriptor_STRING, + USBStringDescriptor_ENGLISH_US +}; + +static const unsigned char manufacturerDescriptor[] = { + + USBStringDescriptor_LENGTH(5), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('M'), + USBStringDescriptor_UNICODE('E'), + USBStringDescriptor_UNICODE('L') +}; + +static const unsigned char productDescriptor[] = { + + USBStringDescriptor_LENGTH(22), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('M'), + USBStringDescriptor_UNICODE('E'), + USBStringDescriptor_UNICODE('L'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('9'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('H'), + USBStringDescriptor_UNICODE('I'), + USBStringDescriptor_UNICODE('D'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('R'), + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('N'), + USBStringDescriptor_UNICODE('S'), + USBStringDescriptor_UNICODE('F'), + USBStringDescriptor_UNICODE('E'), + USBStringDescriptor_UNICODE('R'), +}; + +static const unsigned char serialNumberDescriptor[] = { + + USBStringDescriptor_LENGTH(12), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('0'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE('2'), + USBStringDescriptor_UNICODE('3'), + USBStringDescriptor_UNICODE('4'), + USBStringDescriptor_UNICODE('5'), + USBStringDescriptor_UNICODE('6'), + USBStringDescriptor_UNICODE('7'), + USBStringDescriptor_UNICODE('8'), + USBStringDescriptor_UNICODE('9'), + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('F') +}; + +static const unsigned char *stringDescriptors[] = { + + languageIdDescriptor, + manufacturerDescriptor, + productDescriptor, + serialNumberDescriptor +}; + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +/// List of descriptors used by the HID Transfer driver. +USBDDriverDescriptors hiddTransferDriverDescriptors = { + + &deviceDescriptor, + (USBConfigurationDescriptor *) &configurationDescriptors, +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + &qualifierDescriptor, + (USBConfigurationDescriptor *) &otherSpeedDescriptors, + &deviceDescriptor, + (USBConfigurationDescriptor *) &configurationDescriptors, + &qualifierDescriptor, + (USBConfigurationDescriptor *) &otherSpeedDescriptors, +#else + 0, // No full-speed device qualifier descriptor + 0, // No full-speed other speed configuration + 0, // No high-speed device descriptor + 0, // No high-speed configuration descriptor + 0, // No high-speed device qualifier descriptor + 0, // No high-speed other speed configuration descriptor +#endif + stringDescriptors, + 4 // Four string descriptors in list +}; + +/// Report descriptor used by the driver. +const unsigned char hiddReportDescriptor[] = { + + // Global Usage Page + HIDReport_GLOBAL_USAGEPAGE + 2, 0xFF, 0xFF, // Vendor-defined + // Collection: Application + HIDReport_LOCAL_USAGE + 1, 0xFF, // Vendor-defined + HIDReport_COLLECTION + 1, HIDReport_COLLECTION_APPLICATION, + // Input report: Vendor-defined + HIDReport_LOCAL_USAGE + 1, 0xFF, // Vendor-defined usage + HIDReport_GLOBAL_REPORTCOUNT + 1, HIDDTransferDriver_REPORTSIZE, + HIDReport_GLOBAL_REPORTSIZE + 1, 8, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, (unsigned char) -128, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, (unsigned char) 127, + HIDReport_INPUT + 1, 0, // No Modifiers + + // Output report: vendor-defined + HIDReport_LOCAL_USAGE + 1, 0xFF, // Vendor-defined usage + HIDReport_GLOBAL_REPORTCOUNT + 1, HIDDTransferDriver_REPORTSIZE, + HIDReport_GLOBAL_REPORTSIZE + 1, 8, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, (unsigned char) -128, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, (unsigned char) 127, + HIDReport_OUTPUT + 1, 0, // No Modifiers + + HIDReport_ENDCOLLECTION +}; + diff --git a/usb/device/hid-transfer/HIDDTransferDriverDesc.h b/usb/device/hid-transfer/HIDDTransferDriverDesc.h new file mode 100644 index 0000000..6b9beb7 --- /dev/null +++ b/usb/device/hid-transfer/HIDDTransferDriverDesc.h @@ -0,0 +1,87 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definitions of the descriptors required by the HID transfer %device driver. + + !!!Usage + + -# Use the hiddTransferDriverDescriptors variable to initialize a + USBDDriver instance. + -# Send hiddReportDescriptor to the host when a GET_DESCRIPTOR request + for the report descriptor is received. +*/ + +#ifndef HIDDKEYBOARDDRIVERDESCRIPTORS_H +#define HIDDKEYBOARDDRIVERDESCRIPTORS_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +/// Interrupt IN endpoint number. +#define HIDDTransferDriverDescriptors_INTERRUPTIN 1 +/// Polling rate in ms +#define HIDDTransferDriverDescriptors_INTERRUPTIN_POLLING 50 +/// Interrupt IN endpoint polling rate (in milliseconds). +#define HIDDTransferDriverDescriptors_INTERRUPTOUT 2 +/// Polling rate in ms +#define HIDDTransferDriverDescriptors_INTERRUPTOUT_POLLING 50 + +/// Size of the report descriptor in bytes. +#define HIDDTransferDriverDescriptors_REPORTSIZE 32 + +/// Size of the input and output report, in bytes +#define HIDDTransferDriver_REPORTSIZE 32 + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ +/* + Variables: HID keyboard driver descriptors + hiddTransferDriverDescriptors - List of descriptors used by the HID + keyboard driver. + hiddReportDescriptor - Report descriptor used by the driver. +*/ +extern USBDDriverDescriptors hiddTransferDriverDescriptors; +extern const unsigned char hiddReportDescriptor[]; + +#endif //#ifndef HIDDKEYBOARDDRIVERDESCRIPTORS_H + diff --git a/usb/device/hid-transfer/hid-transfer.dir b/usb/device/hid-transfer/hid-transfer.dir new file mode 100644 index 0000000..a478e50 --- /dev/null +++ b/usb/device/hid-transfer/hid-transfer.dir @@ -0,0 +1,473 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// +/// !!!Purpose +/// +/// This directory provides definitions, structs and functions for a USB HID +/// %device - USB HID Transfer driver, to implement an USB HID compatible +/// %device for customized data transmitting. +/// +/// !!!Contents +/// +/// There are three things for the implement of the USB HID Transfer driver: +/// - Implement the USB HID driver structs and functions for the %device, +/// to initialize, to handle HID-specific requests and dispach +/// standard requests in USBD callbacks, to read/write through assigned USB +/// endpoints, +/// - Create the HID Transfer device's descriptors that should be passed to +/// the USBDDriver instance on initialization, so that the host can +/// recognize the %device as a USB Transfer %device. +/// - Implement methods to read/write data through interrupt endpoints, so that +/// host and device can exchange data. +/// +/// For more information about what a particular group contains, please refer to +/// "USB HID Transfer". +//------------------------------------------------------------------------------ + +/** + \page "USB HID Transfer" + This page describes how to use the "AT91 USB device framework" to produce a USB + HID Transfer driver, which appears as a USB HID complient device on host. + + Details about the USB and the HID class can be found in the }USB specification + 2.0} and the }HID specification 1.11}, respectively. + + !!!References + - "AT91 USB device framework" + - "USB Device Enumeration" + - + Universal Serial Bus Revision 2.0 specification + (.zip file format, size 9.80 MB) + - + Device Class Definition for HID 1.11 + - + HID Usage Tables 1.12 + + !!!HID Basic + See "USB HID Basic". + + !!!Architecture + See "USB Device Framework Architecture". + + !!!Descriptors + + ... + + !!Device Descriptor + The Device descriptor of an HID %device is very basic, since the HID class + code is only specified at the Interface level. Thus, it only contains + standard values, as shown below: +\code +static const USBDeviceDescriptor deviceDescriptor = { + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + HIDDeviceDescriptor_CLASS, + HIDDeviceDescriptor_SUBCLASS, + HIDDeviceDescriptor_PROTOCOL, + BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0), + HIDDKeyboardDriverDescriptors_VENDORID, + HIDDKeyboardDriverDescriptors_PRODUCTID, + HIDDKeyboardDriverDescriptors_RELEASE, + 1, // Index of manufacturer description + 2, // Index of product description + 3, // Index of serial number description + 1 // One possible configuration +}; +\endcode + Note that the Vendor ID is a special value attributed by the USB-IF + organization. The product ID can be chosen freely by the vendor. + + !!Configuration Descriptor + Since one interface is required by the HID specification, this must be + specified in the Configuration descriptor. There is no other value of + interest to put here. +\code +// Configuration descriptor +{ + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(HIDDKeyboardDriverConfigurationDescriptors), + 1, // One interface in this configuration + 1, // This is configuration #1 + 0, // No associated string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) +}, +\endcode + When the Configuration descriptor is requested by the host (by using the + GET_DESCRIPTOR command), the %device must also sent all the related + descriptors, i.e. Interface, Endpoint and Class-Specific descriptors. It is + convenient to create a single structure to hold all this data, for sending + everything in one chunk. In the example software, a + HIDDKeyboardDriverConfigurationDescriptors structure has been declared for + that. + + !!HID Class Interface Descriptor + Since a keyboard %device needs to transmit as well as receive data, two + Interrupt (IN & OUT) endpoints are needed. This must be indicated in the + Interface descriptor. Conversely to the mouse example, the Boot protocol is + not implemented here, since there are more constraints on a keyboard %device. +\code +// Interface descriptor +{ + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0 + 0, // This is alternate setting #0 + 2, // Two endpoints used + HIDInterfaceDescriptor_CLASS, + HIDInterfaceDescriptor_SUBCLASS_NONE, + HIDInterfaceDescriptor_PROTOCOL_NONE, + 0 // No associated string descriptor +}, +\endcode + + !!HID Descriptor + While a HID keyboard produces two different reports, one Input and one Output, + only one Report descriptor can be used to describe them. Since having Physical + descriptors is also useless for a keyboard, there will only be one HID class + descriptor specified here. + + For a keyboard, the }bCountryCode} field can be used to specify the language + of the key caps. As this is optional, it is simply set to 00h in the example: +\code +// HID descriptor +{ + sizeof(HIDDescriptor), + HIDGenericDescriptor_HID, + HIDDescriptor_HID1_11, + 0, // Device is not localized, no country code + 1, // One HID-specific descriptor (apart from this one) + HIDGenericDescriptor_REPORT, + HIDDKeyboardDriverDescriptors_REPORTSIZE +}, +\endcode + + !!Report Descriptor + Two current reports are defined in the Report descriptor. The first one is + used to notify the host of which keys are pressed, with both modifier keys + (alt, ctrl, etc.) and alphanumeric keys. The second report is necessary for + the host to send the LED (num lock, caps lock, etc.) states. + + The Report descriptor starts with the global %device functionality, described + with a #Usage Page# and a #Usage# items: +\code +const unsigned char hiddReportDescriptor[] = { + + HIDReport_GLOBAL_USAGEPAGE + 2, 0xFF, 0xFF, // Vendor-defined + HIDReport_LOCAL_USAGE + 1, 0xFF, // Vendor-defined +\endcode + + An Application collection is then defined to group the reports together: +\code + HIDReport_COLLECTION + 1, HIDReport_COLLECTION_APPLICATION, +\endcode + + The first report to be defined is the input report, all data in the buffer + is vendor defined: +\code + // Input report: Vendor-defined + HIDReport_LOCAL_USAGE + 1, 0xFF, // Vendor-defined usage + HIDReport_GLOBAL_REPORTCOUNT + 1, HIDDTransferDriver_REPORTSIZE, + HIDReport_GLOBAL_REPORTSIZE + 1, 8, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, (unsigned char) -128, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, (unsigned char) 127, + HIDReport_INPUT + 1, 0, // No Modifiers +\endcode + + The output report is then defined, data is for the user to decode: +\code + // Output report: vendor-defined + HIDReport_LOCAL_USAGE + 1, 0xFF, // Vendor-defined usage + HIDReport_GLOBAL_REPORTCOUNT + 1, HIDDTransferDriver_REPORTSIZE, + HIDReport_GLOBAL_REPORTSIZE + 1, 8, + HIDReport_GLOBAL_LOGICALMINIMUM + 1, (unsigned char) -128, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, (unsigned char) 127, + HIDReport_OUTPUT + 1, 0, // No Modifiers +\endcode + + The last item, }End Collection}, is necessary to close the previously opened + }Application Collection}. +\code + HIDReport_ENDCOLLECTION +}; +\endcode + + The input report and output report are all user defined. We define the first + byte as bit map of push buttons and LEDs, remaining bytes as data. + + !!Physical Descriptor + A Physical descriptor is useless for a general transfer %device, so none is + defined in this example. + + !!Endpoint Descriptor + Following the Interface and HID-specific descriptors, the two necessary + endpoints are defined. +\code +// Interrupt IN endpoint descriptor +{ + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + HIDDKeyboardDriverDescriptors_INTERRUPTIN), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardInputReport), + HIDDKeyboardDriverDescriptors_INTERRUPTIN_POLLING +}, +// Interrupt OUT endpoint descriptor +{ + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + HIDDKeyboardDriverDescriptors_INTERRUPTOUT), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardOutputReport), + HIDDKeyboardDriverDescriptors_INTERRUPTIN_POLLING +} +\endcode + + !!String Descriptors + Please refer to "Usage: USBD VID, PID & Strings". + + !!!Class-specific requests + A driver request handler should first differentiate between class-specific and + standard requests using the corresponding bits in the }bmRequestType} field. + In most cases, standard requests can be immediately forwarded to the standard + request handler method; class-specific methods must be decoded and treated by + the custom handler. + + !!GetDescriptor + Three values have been added by the HID specification for the #GET_DESCRIPTOR# + request. The high byte of the }wValue} field contains the type of the + requested descriptor; in addition to the standard types, the #HID + specification# adds the #HID descriptor# (21h), the #Report descriptor# + (22h) and the #Physical descriptor# (23h) types. + + There is no particular action to perform besides sending the descriptor. This + can be done by using the USBD_Write method, after the requested descriptor has + been identified: +\code +switch (USBGenericRequest_GetRequest(request)) { + + case USBGenericRequest_GETDESCRIPTOR: + // Check if this is a HID descriptor, + // otherwise forward it to + // the standard driver + if (!HIDDKeyboardDriver_GetDescriptor( + USBGetDescriptorRequest_GetDescriptorType(request), + USBGenericRequest_GetLength(request))) { + + USBDDriver_RequestHandler(&(hiddKeyboardDriver.usbdDriver), + request); + } + break; + + default: + USBDDriver_RequestHandler(&(hiddKeyboardDriver.usbdDriver), + request); +} +\endcode + A slight complexity of the GET_DESCRIPTOR and SET_DESCRIPTOR requests is that + those are standard requests, but the standard request handler + (USBDDriver_RequestHandler) must not always be called to treat them (since + they may refer to HID descriptors). The solution is to first identify + GET/SET_DESCRIPTOR requests, treat the HID-specific cases and, finally, + forward any other request to the standard handler. + + In this case, a GET_DESCRIPTOR request for the Physical descriptor is first + forwarded to the standard handler, and STALLed there because it is not + recognized. This is done because the %device does not have any Physical + descriptors, and thus, does not need to handle the associated request. + + !!SetDescriptor + This request is optional and is never issued by most hosts. It is not + implemented in this example. + + !!GetReport + Since the HID keyboard defines two different reports, the Report Type value + specified by this request (upper byte of the }wValue} field) must be examined + to decide which report to send. If the type value is 01h, then the Input + report must be returned; if it is 02h, the Output report is requested: +\code +case HIDGenericRequest_GETREPORT: +//------------------------------- + type = HIDReportRequest_GetReportType(request); + length = USBGenericRequest_GetLength(request); + switch (type) { + + case HIDReportRequest_INPUT: + + // Adjust size and send report + if (length > sizeof(HIDDKeyboardInputReport)) { + + length = sizeof(HIDDKeyboardInputReport); + } + USBD_Write(0, // Endpoint #0 + &(hiddKeyboardDriver.inputReport), + length, + 0, // No callback + 0); + break; + + case HIDReportRequest_OUTPUT: + + // Adjust size and send report + if (length > sizeof(HIDDKeyboardOutputReport)) { + + length = sizeof(HIDDKeyboardOutputReport); + } + USBD_Write(0, // Endpoint #0 + &(hiddKeyboardDriver.outputReport), + length, + 0, // No callback + 0); + break; + + default: + USBD_Stall(0); + } +break; +\endcode + + !!SetReport + For an HID keyboard, the #SET_REPORT# command can be sent by the host to + change the state of the LEDs. Normally, the dedicated Interrupt OUT endpoint + will be used for this; but in some cases, using the default Control endpoint + can save some bandwidth on the host side. + + Note that the SET_REPORT request can be directed at the Input report of the + keyboard; in this case, it can be safely discarded, according to the HID + specification. Normally, most host drivers only target the Output report. The + Report Type value is stored in the upper byte of the }wValue} field. + + The length of the data phase to follow is stored in the }wLength} field of the + request. It should be equal to the total length of the Output report. If it is + different, the report status must still be updated with the received data as + best as possible. + + When the reception of the new data is completed, some processing must be done + to enable/disable the corresponding LEDs. This is done in the callback + function passed as an argument to USBD_Read: +\code +case HIDGenericRequest_SETREPORT: +//------------------------------- + type = HIDReportRequest_GetReportType(request); + length = USBGenericRequest_GetLength(request); + switch(type) { + + case HIDReportRequest_INPUT: + // SET_REPORT requests on input reports are ignored + USBD_Stall(0); + break; + + case HIDReportRequest_OUTPUT: + // Check report length + if (length != sizeof(HIDDKeyboardOutputReport)) { + + USBD_Stall(0); + } + else { + + USBD_Read(0, // Endpoint #0 + &(hiddKeyboardDriver.outputReport), + length, + (TransferCallback) HIDDKeyboardDriver_ReportReceived, + 0); // No argument to the callback function + } + break; + + default: + USBD_Stall(0); + } +break; +\endcode + + !!SetIdle + In this case study, the #SET_IDLE# request is used to set a delay before a key + is repeated. This is common behavior on keyboard devices. Usually, this delay + is set to about 500 ms by the host. + + The only action here is to store the new Idle rate. The management of this + setting must be done in the main function, since Interrupt IN reports are sent + from there. + + In practice, it is not necessary to perform any action, apart from sending a + zero-length packet to acknowledge it. The main application however has to make + sure that only new reports are sent by the %device. +\code +case HIDGenericRequest_SETIDLE: +//----------------------------- + hiddKeyboardDriver.inputReportIdleRate = + HIDIdleRequest_GetIdleRate(request); + USBD_Write(0, 0, 0, 0, 0); +break; +\endcode + + !!GetIdle + The only necessary operation for this request is to send the previously saved + Idle rate. This is done by calling the USBD_Write method with the one-byte + variable as its parameter: +\code +case HIDGenericRequest_GETIDLE: +//----------------------------- + USBD_Write(0, &(hiddKeyboardDriver.inputReportIdleRate), 1, 0, 0); +break; +\endcode + + !!GetProtocol, SetProtocol + This HID keyboard example does not support the Boot protocol, so there is no + need to implement the SET_PROTOCOL and GET_PROTOCOL requests. This means they + can be safely STALLed when received. + + !!!Main Application + Like the mouse example, the main program must perform two different + operations. First, it has to monitor the physical inputs used as keys. In the + example software, the buttons present on the evaluation boards are used to + produce several modifier and alphanumeric keys. + + Also, the main program is in charge of sending reports as they are modified, + taking into account the Idle rate specified by the host. Idle rate management + can be carried out by firing/resetting a timer once a new report is sent; if + the timer expires, this means the Input report has not changed since. + According to the HID specification, a single instance of the report must be + sent in this case. + + Finally, the HID specification also defines that if too many keys are pressed + at the same time, the %device should report an }ErrorRollOver} usage value + (01h) in every byte of the key array. This has to be handled by the main + application as well. + +*/ \ No newline at end of file diff --git a/usb/device/massstorage/MSD.h b/usb/device/massstorage/MSD.h new file mode 100644 index 0000000..decab4a --- /dev/null +++ b/usb/device/massstorage/MSD.h @@ -0,0 +1,233 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// !Purpose +/// +/// Mass Storage class definitions. +/// +/// See +/// - +/// USB Mass Storage Class Spec. Overview +/// - +/// USB Mass Storage Class Bulk-Only Transport +/// +/// !Usage +/// +/// -# Uses "MSD Requests" to check incoming requests from USB Host. +/// -# Uses "MSD Subclass Codes" and "MSD Protocol Codes" to fill %device +/// interface descriptors for a MSD %device. +/// -# Handle the incoming Bulk data with "MSD CBW Definitions" and MSCbw +/// structure. +/// -# Prepare the outgoing Bulk data with "MSD CSW Definitions" and MSCsw +/// structure. +//------------------------------------------------------------------------------ + +#ifndef MSD_H +#define MSD_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "MSD Requests" +/// This page lists MSD-specific requests ( Actually for Bulk-only protocol ). +/// +/// !Requests +/// - MSD_BULK_ONLY_RESET +/// - MSD_GET_MAX_LUN + +/// Reset the mass storage %device and its associated interface. +#define MSD_BULK_ONLY_RESET 0xFF +/// Return the maximum LUN number supported by the %device. +#define MSD_GET_MAX_LUN 0xFE +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "MSD Subclass Codes" +/// This page lists the Subclass Codes for bInterfaceSubClass field. +/// (Table 2.1, USB Mass Storage Class Spec. Overview) +/// +/// !SubClasses +/// - MSD_SUBCLASS_RBC +/// - MSD_SUBCLASS_SFF_MCC +/// - MSD_SUBCLASS_QIC +/// - MSD_SUBCLASS_UFI +/// - MSD_SUBCLASS_SFF +/// - MSD_SUBCLASS_SCSI + +/// Reduced Block Commands (RBC) T10 +#define MSD_SUBCLASS_RBC 0x01 +/// C/DVD devices +#define MSD_SUBCLASS_SFF_MCC 0x02 +/// Tape device +#define MSD_SUBCLASS_QIC 0x03 +/// Floppy disk drive (FDD) device +#define MSD_SUBCLASS_UFI 0x04 +/// Floppy disk drive (FDD) device +#define MSD_SUBCLASS_SFF 0x05 +/// SCSI transparent command set +#define MSD_SUBCLASS_SCSI 0x06 +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +/// \page "MSD Protocol Codes" +/// This page lists the Transport Protocol codes for MSD. +/// (Table 3.1, USB Mass Storage Class Spec. Overview) +/// +/// !Protocols +/// - MSD_PROTOCOL_CBI_COMPLETION +/// - MSD_PROTOCOL_CBI +/// - MSD_PROTOCOL_BULK_ONLY + +/// Control/Bulk/Interrupt (CBI) Transport (with command complete interrupt) +#define MSD_PROTOCOL_CBI_COMPLETION 0x00 +/// Control/Bulk/Interrupt (CBI) Transport (no command complete interrupt) +#define MSD_PROTOCOL_CBI 0x01 +/// Bulk-Only Transport +#define MSD_PROTOCOL_BULK_ONLY 0x50 +//------------------------------------------------------------------------------ + +/// Test unit control: +#define CTRL_NOT_READY 0x00 +#define CTRL_GOOD 0x01 +#define CTRL_BUSY 0x02 + +//------------------------------------------------------------------------------ +/// \page "MSD CBW Definitions" +/// This page lists the Command Block Wrapper (CBW) definitions. +/// +/// !Constants +/// - MSD_CBW_SIZE +/// - MSD_CBW_SIGNATURE +/// +/// !Fields +/// - MSD_CBW_DEVICE_TO_HOST + +/// Command Block Wrapper Size +#define MSD_CBW_SIZE 31 +/// 'USBC' 0x43425355 +#define MSD_CBW_SIGNATURE 0x43425355 + +/// CBW bmCBWFlags field +#define MSD_CBW_DEVICE_TO_HOST (1 << 7) +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "MSD CSW Definitions" +/// This page lists the Command Status Wrapper (CSW) definitions. +/// +/// !Constants +/// - MSD_CSW_SIZE +/// - MSD_CSW_SIGNATURE +/// +/// !Command Block Status Values +/// (Table 5.3 , USB Mass Storage Class Bulk-Only Transport) +/// - MSD_CSW_COMMAND_PASSED +/// - MSD_CSW_COMMAND_FAILED +/// - MSD_CSW_PHASE_ERROR + +/// Command Status Wrapper Size +#define MSD_CSW_SIZE 13 +/// 'USBS' 0x53425355 +#define MSD_CSW_SIGNATURE 0x53425355 + +/// Command Passed (good status) +#define MSD_CSW_COMMAND_PASSED 0 +/// Command Failed +#define MSD_CSW_COMMAND_FAILED 1 +/// Phase Error +#define MSD_CSW_PHASE_ERROR 2 +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Structures +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Command Block Wrapper (CBW), +/// See Table 5.1, USB Mass Storage Class Bulk-Only Transport. +/// +/// The CBW shall start on a packet boundary and shall end as a +/// short packet with exactly 31 (1Fh) bytes transferred. +//------------------------------------------------------------------------------ +typedef struct { + + /// 'USBC' 0x43425355 (little endian) + unsigned int dCBWSignature; + /// Must be the same as dCSWTag + unsigned int dCBWTag; + /// Number of bytes transfer + unsigned int dCBWDataTransferLength; + /// Indicates the directin of the transfer: + /// 0x80=IN=device-to-host, + /// 0x00=OUT=host-to-device + unsigned char bmCBWFlags; + /// bits 0->3: bCBWLUN + unsigned char bCBWLUN :4, + bReserved1:4; /// reserved + /// bits 0->4: bCBWCBLength + unsigned char bCBWCBLength:5, + bReserved2 :3; /// reserved + /// Command block + unsigned char pCommand[16]; + +} MSCbw; + +//------------------------------------------------------------------------------ +/// Command Status Wrapper (CSW), +/// See Table 5.2, USB Mass Storage Class Bulk-Only Transport. +//------------------------------------------------------------------------------ +typedef struct +{ + /// 'USBS' 0x53425355 (little endian) + unsigned int dCSWSignature; + /// Must be the same as dCBWTag + unsigned int dCSWTag; + /// For Data-Out the device shall report in the dCSWDataResidue the + /// difference between the amount of data expected as stated in the + /// dCBWDataTransferLength, and the actual amount of data processed by + /// the device. For Data-In the device shall report in the dCSWDataResidue + /// the difference between the amount of data expected as stated in the + /// dCBWDataTransferLength and the actual amount of relevant data sent by + /// the device. The dCSWDataResidue shall not exceed the value sent in the + /// dCBWDataTransferLength. + unsigned int dCSWDataResidue; + /// Indicates the success or failure of the command. + unsigned char bCSWStatus; + +} MSCsw; + +#endif //#ifndef MSD_H + diff --git a/usb/device/massstorage/MSDAppArch.png b/usb/device/massstorage/MSDAppArch.png new file mode 100644 index 0000000..eec0f15 Binary files /dev/null and b/usb/device/massstorage/MSDAppArch.png differ diff --git a/usb/device/massstorage/MSDDStateMachine.c b/usb/device/massstorage/MSDDStateMachine.c new file mode 100644 index 0000000..bc69a49 --- /dev/null +++ b/usb/device/massstorage/MSDDStateMachine.c @@ -0,0 +1,607 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//----------------------------------------------------------------------------- +// Includes +//----------------------------------------------------------------------------- + +#include "SBCMethods.h" +#include "MSDDStateMachine.h" + +//----------------------------------------------------------------------------- +// Internal functions +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +/// Returns the expected transfer length and direction (IN, OUT or don't care) +/// from the host point-of-view. +/// \param cbw Pointer to the CBW to examinate +/// \param pLength Expected length of command +/// \param pType Expected direction of command +//----------------------------------------------------------------------------- +static void MSDD_GetCommandInformation(MSCbw *cbw, + unsigned int *length, + unsigned char *type) +{ + // Expected host transfer direction and length + (*length) = cbw->dCBWDataTransferLength; + + if (*length == 0) { + + (*type) = MSDD_NO_TRANSFER; + } + else if ((cbw->bmCBWFlags & MSD_CBW_DEVICE_TO_HOST) != 0) { + + (*type) = MSDD_DEVICE_TO_HOST; + } + else { + + (*type) = MSDD_HOST_TO_DEVICE; + } +} + +//----------------------------------------------------------------------------- +/// Pre-processes a command by checking the differences between the host and +/// device expectations in term of transfer type and length. +/// Once one of the thirteen cases is identified, the actions to do during the +/// post-processing phase are stored in the dCase variable of the command +/// state. +/// \param pMsdDriver Pointer to a MSDDriver instance +/// \return 1 if the command is supported, false otherwise +//----------------------------------------------------------------------------- +static unsigned char MSDD_PreProcessCommand(MSDDriver *pMsdDriver) +{ + unsigned int hostLength = 0; + unsigned int deviceLength = 0; + unsigned char hostType; + unsigned char deviceType; + unsigned char isCommandSupported; + MSDCommandState *commandState = &(pMsdDriver->commandState); + MSCsw *csw = &(commandState->csw); + MSCbw *cbw = &(commandState->cbw); + MSDLun *lun = &(pMsdDriver->luns[(unsigned char) cbw->bCBWLUN]); + + // Get information about the command + // Host-side + MSDD_GetCommandInformation(cbw, &hostLength, &hostType); + + // Device-side + isCommandSupported = SBC_GetCommandInformation(cbw->pCommand, + &deviceLength, + &deviceType, + lun); + + // Initialize data residue and result status + csw->dCSWDataResidue = 0; + csw->bCSWStatus = MSD_CSW_COMMAND_PASSED; + + // Check if the command is supported + if (isCommandSupported) { + + // Identify the command case + if(hostType == MSDD_NO_TRANSFER) { + + // Case 1 (Hn = Dn) + if(deviceType == MSDD_NO_TRANSFER) { + + //TRACE_WARNING("Case 1\n\r"); + commandState->postprocess = 0; + commandState->length = 0; + } + else if(deviceType == MSDD_DEVICE_TO_HOST) { + + // Case 2 (Hn < Di) + TRACE_WARNING( + "MSDD_PreProcessCommand: Case 2\n\r"); + commandState->postprocess = MSDD_CASE_PHASE_ERROR; + commandState->length = 0; + } + else { //if(deviceType == MSDD_HOST_TO_DEVICE) { + + // Case 3 (Hn < Do) + TRACE_WARNING( + "MSDD_PreProcessCommand: Case 3\n\r"); + commandState->postprocess = MSDD_CASE_PHASE_ERROR; + commandState->length = 0; + } + } + + // Case 4 (Hi > Dn) + else if(hostType == MSDD_DEVICE_TO_HOST) { + + if(deviceType == MSDD_NO_TRANSFER) { + + TRACE_WARNING( + "MSDD_PreProcessCommand: Case 4\n\r"); + commandState->postprocess = MSDD_CASE_STALL_IN; + commandState->length = 0; + csw->dCSWDataResidue = hostLength; + } + else if(deviceType == MSDD_DEVICE_TO_HOST) { + + if(hostLength > deviceLength) { + + // Case 5 (Hi > Di) + TRACE_WARNING( + "MSDD_PreProcessCommand: Case 5\n\r"); + commandState->postprocess = MSDD_CASE_STALL_IN; + commandState->length = deviceLength; + csw->dCSWDataResidue = hostLength - deviceLength; + } + else if(hostLength == deviceLength) { + + // Case 6 (Hi = Di) + commandState->postprocess = 0; + commandState->length = deviceLength; + } + else { //if(hostLength < deviceLength) { + + // Case 7 (Hi < Di) + TRACE_WARNING( + "MSDD_PreProcessCommand: Case 7\n\r"); + commandState->postprocess = MSDD_CASE_PHASE_ERROR; + commandState->length = hostLength; + } + } + else { //if(deviceType == MSDD_HOST_TO_DEVICE) { + + // Case 8 (Hi <> Do) + TRACE_WARNING( + "MSDD_PreProcessCommand: Case 8\n\r"); + commandState->postprocess = + MSDD_CASE_STALL_IN | MSDD_CASE_PHASE_ERROR; + commandState->length = 0; + } + } + else if(hostType == MSDD_HOST_TO_DEVICE) { + + if(deviceType == MSDD_NO_TRANSFER) { + + // Case 9 (Ho > Dn) + TRACE_WARNING( + "MSDD_PreProcessCommand: Case 9\n\r"); + commandState->postprocess = MSDD_CASE_STALL_OUT; + commandState->length = 0; + csw->dCSWDataResidue = hostLength; + } + else if(deviceType == MSDD_DEVICE_TO_HOST) { + + // Case 10 (Ho <> Di) + TRACE_WARNING( + "MSDD_PreProcessCommand: Case 10\n\r"); + commandState->postprocess = + MSDD_CASE_STALL_OUT | MSDD_CASE_PHASE_ERROR; + commandState->length = 0; + } + else { //if(deviceType == MSDD_HOST_TO_DEVICE) { + + if(hostLength > deviceLength) { + + // Case 11 (Ho > Do) + TRACE_WARNING( + "MSDD_PreProcessCommand: Case 11\n\r"); + commandState->postprocess = MSDD_CASE_STALL_OUT; +// commandState->length = deviceLength; +// csw->dCSWDataResidue = hostLength - deviceLength; + commandState->length = 0; + csw->dCSWDataResidue = deviceLength; + } + else if(hostLength == deviceLength) { + + // Case 12 (Ho = Do) + //TRACE_WARNING( + // "MSDD_PreProcessCommand: Case 12\n\r"); + commandState->postprocess = 0; + commandState->length = deviceLength; + } + else { //if(hostLength < deviceLength) { + + // Case 13 (Ho < Do) + TRACE_WARNING( + "MSDD_PreProcessCommand: Case 13\n\r"); + commandState->postprocess = MSDD_CASE_PHASE_ERROR; + commandState->length = hostLength; + } + } + } + } + + return isCommandSupported; +} + +//----------------------------------------------------------------------------- +/// Post-processes a command given the case identified during the +/// pre-processing step. +/// Depending on the case, one of the following actions can be done: +/// - Bulk IN endpoint is stalled +/// - Bulk OUT endpoint is stalled +/// - CSW status set to phase error +/// \param pMsdDriver Pointer to a MSDDriver instance +/// \return If the device is halted +//----------------------------------------------------------------------------- +static unsigned char MSDD_PostProcessCommand(MSDDriver *pMsdDriver) +{ + MSDCommandState *commandState = &(pMsdDriver->commandState); + MSCsw *csw = &(commandState->csw); + unsigned char haltStatus = 0; + + // STALL Bulk IN endpoint ? + if ((commandState->postprocess & MSDD_CASE_STALL_IN) != 0) { + + TRACE_INFO_WP("StallIn "); + MSDD_Halt(MSDD_CASE_STALL_IN); + haltStatus = 1; + } + + // STALL Bulk OUT endpoint ? + if ((commandState->postprocess & MSDD_CASE_STALL_OUT) != 0) { + + TRACE_INFO_WP("StallOut "); + MSDD_Halt(MSDD_CASE_STALL_OUT); + haltStatus = 1; + } + + // Set CSW status code to phase error ? + if ((commandState->postprocess & MSDD_CASE_PHASE_ERROR) != 0) { + + TRACE_INFO_WP("PhaseErr "); + csw->bCSWStatus = MSD_CSW_PHASE_ERROR; + } + + return haltStatus; +} + +//----------------------------------------------------------------------------- +/// Processes the latest command received by the %device. +/// \param pMsdDriver Pointer to a MSDDriver instance +/// \return 1 if the command has been completed, false otherwise. +//----------------------------------------------------------------------------- +static unsigned char MSDD_ProcessCommand(MSDDriver * pMsdDriver) +{ + unsigned char status; + MSDCommandState *commandState = &(pMsdDriver->commandState); + MSCbw *cbw = &(commandState->cbw); + MSCsw *csw = &(commandState->csw); + MSDLun *lun = &(pMsdDriver->luns[(unsigned char) cbw->bCBWLUN]); + unsigned char isCommandComplete = 0; + + // Check if LUN is valid + if (cbw->bCBWLUN > pMsdDriver->maxLun) { + + TRACE_WARNING( + "MSDD_ProcessCommand: LUN %d not exist\n\r", cbw->bCBWLUN); + status = MSDD_STATUS_ERROR; + } + else { + + // Process command + if (pMsdDriver->maxLun > 0) { + + TRACE_INFO_WP("LUN%d ", cbw->bCBWLUN); + } + + status = SBC_ProcessCommand(lun, commandState); + } + + // Check command result code + if (status == MSDD_STATUS_PARAMETER) { + + TRACE_WARNING( + "MSDD_ProcessCommand: Unknown cmd 0x%02X\n\r", + cbw->pCommand[0]); + + // Update sense data + SBC_UpdateSenseData(&(lun->requestSenseData), + SBC_SENSE_KEY_ILLEGAL_REQUEST, + SBC_ASC_INVALID_FIELD_IN_CDB, + 0); + + // Result codes + csw->bCSWStatus = MSD_CSW_COMMAND_FAILED; + isCommandComplete = 1; + + // stall the request, IN or OUT + if (((cbw->bmCBWFlags & MSD_CBW_DEVICE_TO_HOST) == 0) + && (cbw->dCBWDataTransferLength > 0)) { + + // Stall the OUT endpoint : host to device + // MSDD_Halt(MSDD_CASE_STALL_OUT); + commandState->postprocess = MSDD_CASE_STALL_OUT; + TRACE_INFO_WP("StaOUT "); + } + else { + + // Stall the IN endpoint : device to host + // MSDD_Halt(MSDD_CASE_STALL_IN); + commandState->postprocess = MSDD_CASE_STALL_IN; + TRACE_INFO_WP("StaIN "); + } + } + else if (status == MSDD_STATUS_ERROR) { + + TRACE_WARNING("MSD_ProcessCommand: Cmd %x fail\n\r", + ((SBCCommand*)commandState->cbw.pCommand)->bOperationCode); + + // Update sense data + SBC_UpdateSenseData(&(lun->requestSenseData), + SBC_SENSE_KEY_MEDIUM_ERROR, + SBC_ASC_INVALID_FIELD_IN_CDB, + 0); + + // Result codes + csw->bCSWStatus = MSD_CSW_COMMAND_FAILED; + isCommandComplete = 1; + } + else if (status == MSDD_STATUS_RW) { + + csw->bCSWStatus = MSD_CSW_COMMAND_FAILED; + isCommandComplete = 1; + } + else { + + // Update sense data + SBC_UpdateSenseData(&(lun->requestSenseData), + SBC_SENSE_KEY_NO_SENSE, + 0, + 0); + + // Is command complete ? + if (status == MSDD_STATUS_SUCCESS) { + + isCommandComplete = 1; + } + } + + // Check if command has been completed + if (isCommandComplete) { + + TRACE_INFO_WP("Cplt "); + + // Adjust data residue + if (commandState->length != 0) { + + csw->dCSWDataResidue += commandState->length; + + // STALL the endpoint waiting for data + if ((cbw->bmCBWFlags & MSD_CBW_DEVICE_TO_HOST) == 0) { + + // Stall the OUT endpoint : host to device + // MSDD_Halt(MSDD_CASE_STALL_OUT); + commandState->postprocess = MSDD_CASE_STALL_OUT; + TRACE_INFO_WP("StaOUT "); + } + else { + + // Stall the IN endpoint : device to host + // MSDD_Halt(MSDD_CASE_STALL_IN); + commandState->postprocess = MSDD_CASE_STALL_IN; + TRACE_INFO_WP("StaIN "); + } + } + + // Reset command state + commandState->state = 0; + } + + return isCommandComplete; +} + +//----------------------------------------------------------------------------- +/// State machine for the MSD %device driver +/// \param pMsdDriver Pointer to a MSDDriver instance +//----------------------------------------------------------------------------- +void MSDD_StateMachine(MSDDriver * pMsdDriver) +{ + MSDCommandState *commandState = &(pMsdDriver->commandState); + MSCbw *cbw = &(commandState->cbw); + MSCsw *csw = &(commandState->csw); + MSDTransfer *transfer = &(commandState->transfer); + unsigned char status; + + // Identify current driver state + switch (pMsdDriver->state) { + //---------------------- + case MSDD_STATE_READ_CBW: + //---------------------- + // Start the CBW read operation + transfer->semaphore = 0; + status = MSDD_Read(cbw, + MSD_CBW_SIZE, + (TransferCallback) MSDDriver_Callback, + (void *) transfer); + + // Check operation result code + if (status == USBD_STATUS_SUCCESS) { + + // If the command was successful, wait for transfer + pMsdDriver->state = MSDD_STATE_WAIT_CBW; + } + break; + + //---------------------- + case MSDD_STATE_WAIT_CBW: + //---------------------- + // Check transfer semaphore + if (transfer->semaphore > 0) { + + // Take semaphore and terminate transfer + transfer->semaphore--; + + // Check if transfer was successful + if (transfer->status == USBD_STATUS_SUCCESS) { + + TRACE_INFO_WP("------------------------------\n\r"); + + // Process received command + pMsdDriver->state = MSDD_STATE_PROCESS_CBW; + } + else if (transfer->status == USBD_STATUS_RESET) { + + TRACE_INFO("MSDD_StateMachine: EP resetted\n\r"); + pMsdDriver->state = MSDD_STATE_READ_CBW; + } + else { + + TRACE_WARNING( + "MSDD_StateMachine: Failed to read CBW\n\r"); + pMsdDriver->state = MSDD_STATE_READ_CBW; + } + } + break; + + //------------------------- + case MSDD_STATE_PROCESS_CBW: + //------------------------- + // Check if this is a new command + if (commandState->state == 0) { + + // Copy the CBW tag + csw->dCSWTag = cbw->dCBWTag; + + // Check that the CBW is 31 bytes long + if ((transfer->transferred != MSD_CBW_SIZE) || + (transfer->remaining != 0)) { + + TRACE_WARNING( + "MSDD_StateMachine: Invalid CBW (len %d)\n\r", + (int)transfer->transferred); + + // Wait for a reset recovery + pMsdDriver->waitResetRecovery = 1; + + // Halt the Bulk-IN and Bulk-OUT pipes + MSDD_Halt(MSDD_CASE_STALL_OUT | MSDD_CASE_STALL_IN); + + csw->bCSWStatus = MSD_CSW_COMMAND_FAILED; + pMsdDriver->state = MSDD_STATE_READ_CBW; + + } + // Check the CBW Signature + else if (cbw->dCBWSignature != MSD_CBW_SIGNATURE) { + + TRACE_WARNING( + "MSD_BOTStateMachine: Invalid CBW (Bad signature)\n\r"); + + // Wait for a reset recovery + pMsdDriver->waitResetRecovery = 1; + + // Halt the Bulk-IN and Bulk-OUT pipes + MSDD_Halt(MSDD_CASE_STALL_OUT | MSDD_CASE_STALL_IN); + + csw->bCSWStatus = MSD_CSW_COMMAND_FAILED; + pMsdDriver->state = MSDD_STATE_READ_CBW; + } + else { + + // Pre-process command + MSDD_PreProcessCommand(pMsdDriver); + } + } + + // Process command + if (csw->bCSWStatus == MSDD_STATUS_SUCCESS) { + + if (MSDD_ProcessCommand(pMsdDriver)) { + + // Post-process command if it is finished + if (MSDD_PostProcessCommand(pMsdDriver)) { + + TRACE_INFO_WP("WaitHALT "); + pMsdDriver->state = MSDD_STATE_WAIT_HALT; + } + else { + + pMsdDriver->state = MSDD_STATE_SEND_CSW; + } + } + TRACE_INFO_WP("\n\r"); + } + + break; + + //---------------------- + case MSDD_STATE_SEND_CSW: + //---------------------- + // Set signature + csw->dCSWSignature = MSD_CSW_SIGNATURE; + + // Start the CSW write operation + status = MSDD_Write(csw, + MSD_CSW_SIZE, + (TransferCallback) MSDDriver_Callback, + (void *) transfer); + + // Check operation result code + if (status == USBD_STATUS_SUCCESS) { + + TRACE_INFO_WP("SendCSW "); + + // Wait for end of transfer + pMsdDriver->state = MSDD_STATE_WAIT_CSW; + } + break; + + //---------------------- + case MSDD_STATE_WAIT_CSW: + //---------------------- + // Check transfer semaphore + if (transfer->semaphore > 0) { + + // Take semaphore and terminate transfer + transfer->semaphore--; + + // Check if transfer was successful + if (transfer->status == USBD_STATUS_RESET) { + + TRACE_INFO("MSDD_StateMachine: EP resetted\n\r"); + } + else if (transfer->status == USBD_STATUS_ABORTED) { + + TRACE_WARNING( + "MSDD_StateMachine: Failed to send CSW\n\r"); + } + else { + + TRACE_INFO_WP("ok"); + } + + // Read new CBW + pMsdDriver->state = MSDD_STATE_READ_CBW; + } + break; + + //---------------------- + case MSDD_STATE_WAIT_HALT: + //---------------------- + if (MSDD_IsHalted() == 0) { + + pMsdDriver->state = MSDD_STATE_SEND_CSW; + } + break; + } +} diff --git a/usb/device/massstorage/MSDDStateMachine.h b/usb/device/massstorage/MSDDStateMachine.h new file mode 100644 index 0000000..77e5cc8 --- /dev/null +++ b/usb/device/massstorage/MSDDStateMachine.h @@ -0,0 +1,264 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//----------------------------------------------------------------------------- +/// \unit +/// !Purpose +/// +/// Definitions, structs, functions required by a Mass Storage device driver +/// state machine.. +/// +/// !Usage +/// +/// - For a USB device: +/// -# MSDD_Write, MSDD_Read, MSDD_Halt should be defined for +/// usage in the state machine procedure. +/// +/// -# MSDD_StateMachine is invoked to run the MSD state machine. +/// +//----------------------------------------------------------------------------- + +#ifndef MSDDSTATEMACHINE_H +#define MSDDSTATEMACHINE_H + +//----------------------------------------------------------------------------- +// Headers +//----------------------------------------------------------------------------- + +#include "MSD.h" +#include "MSDLun.h" +#include + +//----------------------------------------------------------------------------- +// Definitions +//----------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +/// \page "MSD Driver Possible states" +/// ... +/// +/// !States +/// - MSDD_STATE_READ_CBW +/// - MSDD_STATE_WAIT_CBW +/// - MSDD_STATE_PROCESS_CBW +/// - MSDD_STATE_WAIT_HALT +/// - MSDD_STATE_SEND_CSW +/// - MSDD_STATE_WAIT_CSW +/// - MSDD_STATE_WAIT_RESET + +//! \brief Driver is expecting a command block wrapper +#define MSDD_STATE_READ_CBW (1 << 0) + +//! \brief Driver is waiting for the transfer to finish +#define MSDD_STATE_WAIT_CBW (1 << 1) + +//! \brief Driver is processing the received command +#define MSDD_STATE_PROCESS_CBW (1 << 2) + +//! \brief Driver is halted because pipe halt or wait reset +#define MSDD_STATE_WAIT_HALT (1 << 3) + +//! \brief Driver is starting the transmission of a command status wrapper +#define MSDD_STATE_SEND_CSW (1 << 4) + +//! \brief Driver is waiting for the CSW transmission to finish +#define MSDD_STATE_WAIT_CSW (1 << 5) + +//! \brief Driver is waiting for the MassStorageReset +#define MSDD_STATE_WAIT_RESET (1 << 6) +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "MSD Driver Result Codes" +/// This page lists result codes for MSD functions. +/// +/// !Codes +/// - MSDD_STATUS_SUCCESS +/// - MSDD_STATUS_ERROR +/// - MSDD_STATUS_INCOMPLETE +/// - MSDD_STATUS_PARAMETER +/// - MSDD_STATUS_RW + +//! \brief Method was successful +#define MSDD_STATUS_SUCCESS 0x00 + +//! \brief There was an error when trying to perform a method +#define MSDD_STATUS_ERROR 0x01 + +//! \brief No error was encountered but the application should call the +//! method again to continue the operation +#define MSDD_STATUS_INCOMPLETE 0x02 + +//! \brief A wrong parameter has been passed to the method +#define MSDD_STATUS_PARAMETER 0x03 + +//! \brief An error when reading/writing disk (protected or not present) +#define MSDD_STATUS_RW 0x04 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "MSD Driver Action Cases" +/// This page lists actions to perform during the post-processing phase of a +/// command. +/// +/// !Actions +/// - MSDD_CASE_PHASE_ERROR +/// - MSDD_CASE_STALL_IN +/// - MSDD_CASE_STALL_OUT + +//! \brief Indicates that the CSW should report a phase error +#define MSDD_CASE_PHASE_ERROR (1 << 0) + +//! \brief The driver should halt the Bulk IN pipe after the transfer +#define MSDD_CASE_STALL_IN (1 << 1) + +//! \brief The driver should halt the Bulk OUT pipe after the transfer +#define MSDD_CASE_STALL_OUT (1 << 2) + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "MSD Driver Xfr Directions" +/// This page lists possible direction values for a data transfer +/// +/// !Directions +/// - MSDD_DEVICE_TO_HOST +/// - MSDD_HOST_TO_DEVICE +/// - MSDD_NO_TRANSFER + +#define MSDD_DEVICE_TO_HOST 0 +#define MSDD_HOST_TO_DEVICE 1 +#define MSDD_NO_TRANSFER 2 +//------------------------------------------------------------------------------ + +//----------------------------------------------------------------------------- +// Types +//----------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +//! \brief Structure for holding the result of a USB transfer +//! \see MSDDriver_Callback +//------------------------------------------------------------------------------ +typedef struct { + + volatile unsigned int transferred; /// Number of bytes transferred + volatile unsigned int remaining; /// Number of bytes not transferred + volatile unsigned short semaphore; /// Semaphore to indicate transfer completion + volatile unsigned short status; /// Operation result code + +} MSDTransfer; + +//------------------------------------------------------------------------------ +//! \brief Status of an executing command +//! \see MSDCbw +//! \see MSDCsw +//! \see MSDTransfer +//------------------------------------------------------------------------------ +typedef struct { + + MSDTransfer transfer; /// Current transfer status (USB) + MSDTransfer disktransfer;/// Current transfer status (Disk) + unsigned int length; /// Remaining length of command + MSCbw cbw; /// Received CBW (31 bytes) + unsigned char state; /// Current command state + MSCsw csw; /// CSW to send (13 bytes) + unsigned char postprocess; /// Actions to perform when command is complete + +} MSDCommandState; + +//------------------------------------------------------------------------------ +/// \brief MSD driver state variables +/// \see MSDCommandState +/// \see MSDLun +//------------------------------------------------------------------------------ +typedef struct { + + /// LUN list for the %device. + MSDLun *luns; + /// State of the currently executing command + MSDCommandState commandState; + /// Maximum LUN index + unsigned char maxLun; + /// Current state of the driver + unsigned char state; + /// Indicates if the driver is waiting for a reset recovery + unsigned char waitResetRecovery; + +} MSDDriver; + +//----------------------------------------------------------------------------- +// Inline functions +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +/// This function is to be used as a callback for USB or LUN transfers. +/// \param transfer Pointer to the transfer structure to update +/// \param status Operation result code +/// \param transferred Number of bytes transferred by the command +/// \param remaining Number of bytes not transferred +//----------------------------------------------------------------------------- +static inline void MSDDriver_Callback(MSDTransfer *transfer, + unsigned char status, + unsigned int transferred, + unsigned int remaining) +{ + TRACE_DEBUG("Cbk "); + transfer->semaphore++; + transfer->status = status; + transfer->transferred = transferred; + transfer->remaining = remaining; +} + +//----------------------------------------------------------------------------- +// Driver functions +//----------------------------------------------------------------------------- +//- MSD General support function +extern char MSDD_Read( + void* pData, + unsigned int dLength, + TransferCallback fCallback, + void* pArgument); + +extern char MSDD_Write( + void* pData, + unsigned int dLength, + TransferCallback fCallback, + void* pArgument); + +extern void MSDD_Halt(unsigned int stallCase); + +extern unsigned int MSDD_IsHalted(void); + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +extern void MSDD_StateMachine(MSDDriver * pMsdDriver); + +#endif // #define MSDDSTATEMACHINE_H + diff --git a/usb/device/massstorage/MSDDriver.c b/usb/device/massstorage/MSDDriver.c new file mode 100644 index 0000000..fbaebb0 --- /dev/null +++ b/usb/device/massstorage/MSDDriver.c @@ -0,0 +1,343 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Includes +//------------------------------------------------------------------------------ + +#include +#include "MSDDriver.h" +#include "MSDDriverDescriptors.h" +#include "SBCMethods.h" +#include +#include +#include +#include +#include +#include +#include + +//----------------------------------------------------------------------------- +// Internal variables +//----------------------------------------------------------------------------- + +/// Mass storage device driver instance. +static MSDDriver msdDriver; + +/// Standard device driver instance. +static USBDDriver usbdDriver; + +//----------------------------------------------------------------------------- +// Internal functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Resets the state of the MSD driver +//----------------------------------------------------------------------------- +static void MSDDriver_Reset(void) +{ + TRACE_INFO_WP("MSDReset "); + + msdDriver.state = MSDD_STATE_READ_CBW; + msdDriver.waitResetRecovery = 0; + msdDriver.commandState.state = 0; +} + +//----------------------------------------------------------------------------- +// Callback re-implementation +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +/// Invoked when a new SETUP request is received from the host. Forwards the +/// request to the Mass Storage device driver handler function. +/// \param request Pointer to a USBGenericRequest instance. +//----------------------------------------------------------------------------- +void USBDCallbacks_RequestReceived(const USBGenericRequest *request) +{ + MSDDriver_RequestHandler(request); +} + +//----------------------------------------------------------------------------- +/// Invoked when the configuration of the device changes. Resets the mass +/// storage driver. +/// \param cfgnum New configuration number. +//----------------------------------------------------------------------------- +void USBDDriverCallbacks_ConfigurationChanged(unsigned char cfgnum) +{ + if (cfgnum > 0) { + + MSDDriver_Reset(); + } +} + +//----------------------------------------------------------------------------- +// Driver functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Reads from host through MSD defined bulk OUT pipe. Act as USBD_Read but by +/// a fixed OUT endpoint. +/// \param data Pointer to the data buffer that contains data read from host. +/// \param size The number of bytes should be read (buffer size). +/// \param callback Pointer to the function invoked on end of reading. +/// \param argument Pointer to additional argument data struct. +//----------------------------------------------------------------------------- +char MSDD_Read(void *data, + unsigned int size, + TransferCallback callback, + void *argument) + +{ + return USBD_Read(MSDDriverDescriptors_BULKOUT, + data, + size, + callback, + argument); +} + +//----------------------------------------------------------------------------- +/// Writes to host through MSD defined bulk IN pipe. Act as USBD_Write but by +/// a fixed IN endpoint. +/// \param data Pointer to the data that writes to the host. +/// \param size The number of bytes should be write. +/// \param callback Pointer to the function invoked on end of writing. +/// \param argument Pointer to additional argument data struct. +//----------------------------------------------------------------------------- +char MSDD_Write(void *data, + unsigned int size, + TransferCallback callback, + void *argument) +{ + return USBD_Write(MSDDriverDescriptors_BULKIN, + data, + size, + callback, + argument); +} + +//----------------------------------------------------------------------------- +/// HALT Specified USB pipe. +/// \param stallCASE Case of the stall condition (Bulk In/Out/Both). +//----------------------------------------------------------------------------- +void MSDD_Halt(unsigned int stallCASE) +{ + if (stallCASE & MSDD_CASE_STALL_OUT) { + + USBD_Halt(MSDDriverDescriptors_BULKOUT); + } + + if (stallCASE & MSDD_CASE_STALL_IN) { + + USBD_Halt(MSDDriverDescriptors_BULKIN); + } +} + +//----------------------------------------------------------------------------- +/// Return halted status +/// \return stallCASE bitmap, case of the stall condition +/// (bit: MSDD_CASE_STALL_OUT or MSDD_CASE_STALL_IN) +//----------------------------------------------------------------------------- +unsigned int MSDD_IsHalted(void) +{ + unsigned int stallCASE = 0; + if (USBD_IsHalted(MSDDriverDescriptors_BULKOUT)) { + + stallCASE |= MSDD_CASE_STALL_OUT; + } + if (USBD_IsHalted(MSDDriverDescriptors_BULKIN)) { + + stallCASE |= MSDD_CASE_STALL_IN; + } + return stallCASE; +} + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +/// Initializes the MSD driver and the associated USB driver. +/// \param luns Pointer to a list of LUNs +/// \param numLuns Number of LUN in list +/// \see MSDLun +//----------------------------------------------------------------------------- +void MSDDriver_Initialize(MSDLun *defLuns, unsigned char numLuns) +{ + + TRACE_INFO("MSD init\n\r"); + + // Command state initialization + msdDriver.commandState.state = 0; + msdDriver.commandState.postprocess = 0; + msdDriver.commandState.length = 0; + msdDriver.commandState.transfer.semaphore = 0; + + // LUNs + msdDriver.luns = defLuns; + msdDriver.maxLun = (unsigned char) (numLuns - 1); + + // Reset BOT driver + MSDDriver_Reset(); + + // Init the USB driver + USBDDriver_Initialize(&usbdDriver, &msdDriverDescriptors, 0); + USBD_Init(); +} + +//----------------------------------------------------------------------------- +/// Handler for incoming SETUP requests on default Control endpoint 0. +/// +/// Standard requests are forwarded to the USBDDriver_RequestHandler +/// method. +/// \param request Pointer to a USBGenericRequest instance +//----------------------------------------------------------------------------- +void MSDDriver_RequestHandler(const USBGenericRequest *request) +{ + TRACE_INFO_WP("NewReq "); + + // Handle requests + switch (USBGenericRequest_GetRequest(request)) { + //--------------------- + case USBGenericRequest_CLEARFEATURE: + //--------------------- + TRACE_INFO_WP("ClrFeat "); + + switch (USBFeatureRequest_GetFeatureSelector(request)) { + + //--------------------- + case USBFeatureRequest_ENDPOINTHALT: + //--------------------- + TRACE_INFO_WP("Hlt "); + + // Do not clear the endpoint halt status if the device is waiting + // for a reset recovery sequence + if (!msdDriver.waitResetRecovery) { + + // Forward the request to the standard handler + USBDDriver_RequestHandler(&usbdDriver, request); + } + else { + + TRACE_INFO_WP("No "); + } + + USBD_Write(0, 0, 0, 0, 0); + break; + + //------ + default: + //------ + // Forward the request to the standard handler + USBDDriver_RequestHandler(&usbdDriver, request); + } + break; + + //------------------- + case MSD_GET_MAX_LUN: + //------------------- + TRACE_INFO_WP("gMaxLun "); + + // Check request parameters + if ((request->wValue == 0) + && (request->wIndex == 0) + && (request->wLength == 1)) { + + USBD_Write(0, &(msdDriver.maxLun), 1, 0, 0); + + } + else { + + TRACE_WARNING( + "MSDDriver_RequestHandler: GetMaxLUN(%d,%d,%d)\n\r", + request->wValue, request->wIndex, request->wLength); + USBD_Stall(0); + } + break; + + //----------------------- + case MSD_BULK_ONLY_RESET: + //----------------------- + TRACE_INFO_WP("Rst "); + + // Check parameters + if ((request->wValue == 0) + && (request->wIndex == 0) + && (request->wLength == 0)) { + + // Reset the MSD driver + MSDDriver_Reset(); + USBD_Write(0, 0, 0, 0, 0); + } + else { + + TRACE_WARNING( + "MSDDriver_RequestHandler: Reset(%d,%d,%d)\n\r", + request->wValue, request->wIndex, request->wLength); + USBD_Stall(0); + } + break; + + //------ + default: + //------ + // Forward request to standard handler + USBDDriver_RequestHandler(&usbdDriver, request); + + break; + } +} + +//----------------------------------------------------------------------------- +/// State machine for the MSD driver +//----------------------------------------------------------------------------- +void MSDDriver_StateMachine(void) +{ + if (USBD_GetState() < USBD_STATE_CONFIGURED){} + else MSDD_StateMachine(&msdDriver); + +} + +//----------------------------------------------------------------------------- +/// Starts a remote wake-up sequence if the host has explicitely enabled it +/// by sending the appropriate SET_FEATURE request. +//----------------------------------------------------------------------------- +void MSDDriver_RemoteWakeUp(void) +{ + // Remote wake-up has been enabled + if (USBDDriver_IsRemoteWakeUpEnabled(&usbdDriver)) { + + USBD_RemoteWakeUp(); + } + // Remote wake-up NOT enabled + else { + + TRACE_WARNING( + "MSD..RemoteWakeUp: Host has not enabled remote wake-up\n\r"); + } +} + diff --git a/usb/device/massstorage/MSDDriver.h b/usb/device/massstorage/MSDDriver.h new file mode 100644 index 0000000..0a8738a --- /dev/null +++ b/usb/device/massstorage/MSDDriver.h @@ -0,0 +1,75 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// !Purpose +/// +/// Mass storage %device driver implementation. +/// +/// !Usage +/// +/// -# Enable and setup USB related pins (see pio & board.h). +/// -# Configure the memory interfaces used for Mass Storage LUNs +/// (see memories, MSDLun.h). +/// -# Configure the USB MSD %driver using MSDDriver_Initialize. +/// -# Invoke MSDDriver_StateMachine in main loop to handle all Mass Storage +/// operations. +//------------------------------------------------------------------------------ + +#ifndef MSDDRIVER_H +#define MSDDRIVER_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "MSD.h" +#include "MSDLun.h" +#include + +//------------------------------------------------------------------------------ +// Global functions +//------------------------------------------------------------------------------ + +extern void MSDDriver_Initialize(MSDLun *luns, unsigned char numLuns); + +extern void MSDDriver_RequestHandler(const USBGenericRequest *request); + +extern void MSDDriver_StateMachine(void); + +extern void MSDDriver_RemoteWakeUp(void); + +extern void MSDDriver_DataCallback(unsigned char isRead, + unsigned int dataLength, + unsigned int nullCnt, + unsigned int fullCnt); + +#endif // #ifndef MSDDRIVER_H + diff --git a/usb/device/massstorage/MSDDriverArch.png b/usb/device/massstorage/MSDDriverArch.png new file mode 100644 index 0000000..4063440 Binary files /dev/null and b/usb/device/massstorage/MSDDriverArch.png differ diff --git a/usb/device/massstorage/MSDDriverClasses.png b/usb/device/massstorage/MSDDriverClasses.png new file mode 100644 index 0000000..3fd68d1 Binary files /dev/null and b/usb/device/massstorage/MSDDriverClasses.png differ diff --git a/usb/device/massstorage/MSDDriverDescriptors.c b/usb/device/massstorage/MSDDriverDescriptors.c new file mode 100644 index 0000000..1d8a073 --- /dev/null +++ b/usb/device/massstorage/MSDDriverDescriptors.c @@ -0,0 +1,475 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "MSDDriverDescriptors.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Internal definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "MSD Device Descriptor IDs" +/// ... +/// !IDs +/// - MSDDriverDescriptors_VENDORID +/// - MSDDriverDescriptors_PRODUCTID +/// - MSDDriverDescriptors_RELEASE + +/// Vendor ID for the Mass Storage device driver. +#define MSDDriverDescriptors_VENDORID 0x03EB +/// Product ID for the Mass Storage device driver. +#define MSDDriverDescriptors_PRODUCTID 0x6129 +/// Device release number for the Mass Storage device driver. +#define MSDDriverDescriptors_RELEASE 0x0100 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Macros +//------------------------------------------------------------------------------ + +/// Returns the minimum between two values. +#define MIN(a, b) ((a < b) ? a : b) + +//------------------------------------------------------------------------------ +// Internal types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// List of configuration descriptors used by a Mass Storage device driver. +//------------------------------------------------------------------------------ +typedef struct { + + /// Standard configuration descriptor. + USBConfigurationDescriptor configuration; +#if defined(CHIP_USB_OTGHS) + // OTG descriptor + USBOtgDescriptor otgDescriptor; +#endif + /// Mass storage interface descriptor. + USBInterfaceDescriptor interface; + /// Bulk-out endpoint descriptor. + USBEndpointDescriptor bulkOut; + /// Bulk-in endpoint descriptor. + USBEndpointDescriptor bulkIn; + +} __attribute__ ((packed)) MSDConfigurationDescriptors; + +//------------------------------------------------------------------------------ +// Local variables +//------------------------------------------------------------------------------ + +/// Mass storage driver device descriptor. +static const USBDeviceDescriptor deviceDescriptor = { + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + MSDeviceDescriptor_CLASS, + MSDeviceDescriptor_SUBCLASS, + MSDeviceDescriptor_PROTOCOL, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + MSDDriverDescriptors_VENDORID, + MSDDriverDescriptors_PRODUCTID, + MSDDriverDescriptors_RELEASE, + 1, // Manufacturer string descriptor index. + 2, // Product string descriptor index. + 3, // Serial number string descriptor index. + 1 // Device has one possible configuration. +}; + +#if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) +/// Device qualifier descriptor. +static const USBDeviceQualifierDescriptor qualifierDescriptor = { + + sizeof(USBDeviceQualifierDescriptor), + USBGenericDescriptor_DEVICEQUALIFIER, + USBDeviceDescriptor_USB2_00, + MSDeviceDescriptor_CLASS, + MSDeviceDescriptor_SUBCLASS, + MSDeviceDescriptor_PROTOCOL, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + 1, // Device has one possible configuration. + 0x00 +}; +#endif + +/// Full-speed configuration descriptor. +static const MSDConfigurationDescriptors configurationDescriptorsFS = { + + // Standard configuration descriptor. + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(MSDConfigurationDescriptors), + 1, // Configuration has one interface. + 1, // This is configuration #1. + 0, // No string descriptor for configuration. + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, +#if defined(CHIP_USB_OTGHS) + // OTG descriptor + { + sizeof(USBOtgDescriptor), + USBGenericDescriptor_OTG, + USBOTGDescriptor_HNP_SRP + }, +#endif + // Mass Storage interface descriptor. + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0. + 0, // This is alternate setting #0. + 2, // Interface uses two endpoints. + MSInterfaceDescriptor_CLASS, + MSInterfaceDescriptor_SCSI, + MSInterfaceDescriptor_BULKONLY, + 0 // No string descriptor for interface. + }, + // Bulk-OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + MSDDriverDescriptors_BULKOUT), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(MSDDriverDescriptors_BULKOUT), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed Bulk endpoints. + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + MSDDriverDescriptors_BULKIN), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(MSDDriverDescriptors_BULKIN), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // Must be 0 for full-speed Bulk endpoints. + } +}; + +#if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) +/// Full-speed other speed configuration descriptor. +static const MSDConfigurationDescriptors otherSpeedDescriptorsFS = { + + // Standard configuration descriptor. + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_OTHERSPEEDCONFIGURATION, + sizeof(MSDConfigurationDescriptors), + 1, // Configuration has one interface. + 1, // This is configuration #1. + 0, // No string descriptor for configuration. + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, +#if defined(CHIP_USB_OTGHS) + // OTG descriptor + { + sizeof(USBOtgDescriptor), + USBGenericDescriptor_OTG, + USBOTGDescriptor_HNP_SRP + }, +#endif + // Mass Storage interface descriptor. + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0. + 0, // This is alternate setting #0. + 2, // Interface uses two endpoints. + MSInterfaceDescriptor_CLASS, + MSInterfaceDescriptor_SCSI, + MSInterfaceDescriptor_BULKONLY, + 0 // No string descriptor for interface. + }, + // Bulk-OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + MSDDriverDescriptors_BULKOUT), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(MSDDriverDescriptors_BULKOUT), + USBEndpointDescriptor_MAXBULKSIZE_HS), + 0 // No string descriptor for endpoint. + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + MSDDriverDescriptors_BULKIN), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(MSDDriverDescriptors_BULKIN), + USBEndpointDescriptor_MAXBULKSIZE_HS), + 0 // No string descriptor for endpoint. + } +}; + +/// High-speed configuration descriptor. +static const MSDConfigurationDescriptors configurationDescriptorsHS = { + + // Standard configuration descriptor. + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(MSDConfigurationDescriptors), + 1, // Configuration has one interface. + 1, // This is configuration #1. + 0, // No string descriptor for configuration. + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, +#if defined(CHIP_USB_OTGHS) + // OTG descriptor + { + sizeof(USBOtgDescriptor), + USBGenericDescriptor_OTG, + USBOTGDescriptor_HNP_SRP + }, +#endif + // Mass Storage interface descriptor. + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0. + 0, // This is alternate setting #0. + 2, // Interface uses two endpoints. + MSInterfaceDescriptor_CLASS, + MSInterfaceDescriptor_SCSI, + MSInterfaceDescriptor_BULKONLY, + 0 // No string descriptor for interface. + }, + // Bulk-OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + MSDDriverDescriptors_BULKOUT), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(MSDDriverDescriptors_BULKOUT), + USBEndpointDescriptor_MAXBULKSIZE_HS), + 0 // No string descriptor for endpoint. + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + MSDDriverDescriptors_BULKIN), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(MSDDriverDescriptors_BULKIN), + USBEndpointDescriptor_MAXBULKSIZE_HS), + 0 // No string descriptor for endpoint. + } +}; + +/// High-speed other speed configuration descriptor. +static const MSDConfigurationDescriptors otherSpeedDescriptorsHS = { + + // Standard configuration descriptor. + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_OTHERSPEEDCONFIGURATION, + sizeof(MSDConfigurationDescriptors), + 1, // Configuration has one interface. + 1, // This is configuration #1. + 0, // No string descriptor for configuration. + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, +#if defined(CHIP_USB_OTGHS) + // OTG descriptor + { + sizeof(USBOtgDescriptor), + USBGenericDescriptor_OTG, + USBOTGDescriptor_HNP_SRP + }, +#endif + // Mass Storage interface descriptor. + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0. + 0, // This is alternate setting #0. + 2, // Interface uses two endpoints. + MSInterfaceDescriptor_CLASS, + MSInterfaceDescriptor_SCSI, + MSInterfaceDescriptor_BULKONLY, + 0 // No string descriptor for interface. + }, + // Bulk-OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + MSDDriverDescriptors_BULKOUT), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(MSDDriverDescriptors_BULKOUT), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // No string descriptor for endpoint. + }, + // Bulk-IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + MSDDriverDescriptors_BULKIN), + USBEndpointDescriptor_BULK, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE(MSDDriverDescriptors_BULKIN), + USBEndpointDescriptor_MAXBULKSIZE_FS), + 0 // No string descriptor for endpoint. + } +}; +#endif + +/// Language ID string descriptor. +static const unsigned char languageIdDescriptor[] = { + + USBStringDescriptor_LENGTH(1), + USBGenericDescriptor_STRING, + USBStringDescriptor_ENGLISH_US +}; + +/// Manufacturer string descriptor. +static const unsigned char manufacturerDescriptor[] = { + + USBStringDescriptor_LENGTH(5), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('M'), + USBStringDescriptor_UNICODE('E'), + USBStringDescriptor_UNICODE('L') +}; + +/// Product string descriptor. +static const unsigned char productDescriptor[] = { + + USBStringDescriptor_LENGTH(14), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('M'), + USBStringDescriptor_UNICODE('E'), + USBStringDescriptor_UNICODE('L'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('9'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('M'), + USBStringDescriptor_UNICODE('S'), + USBStringDescriptor_UNICODE('D') +}; + +/// Serial number string descriptor. The serial number must be at least 12 +/// characters long and made up of only letters & numbers to be compliant with +/// the MSD specification. +static const unsigned char serialNumberDescriptor[] = { + + USBStringDescriptor_LENGTH(12), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('0'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE('2'), + USBStringDescriptor_UNICODE('3'), + USBStringDescriptor_UNICODE('4'), + USBStringDescriptor_UNICODE('5'), + USBStringDescriptor_UNICODE('6'), + USBStringDescriptor_UNICODE('7'), + USBStringDescriptor_UNICODE('8'), + USBStringDescriptor_UNICODE('9'), + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('B') +}; + +/// List of all string descriptors used. +static const unsigned char *stringDescriptors[] = { + + languageIdDescriptor, + manufacturerDescriptor, + productDescriptor, + serialNumberDescriptor +}; + +//------------------------------------------------------------------------------ +// Global variables +//------------------------------------------------------------------------------ + +/// List of the standard descriptors used by the Mass Storage driver. +const USBDDriverDescriptors msdDriverDescriptors = { + + &deviceDescriptor, + (USBConfigurationDescriptor *) &configurationDescriptorsFS, +#if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + &qualifierDescriptor, + (USBConfigurationDescriptor *) &otherSpeedDescriptorsFS, + &deviceDescriptor, + (USBConfigurationDescriptor *) &configurationDescriptorsHS, + &qualifierDescriptor, + (USBConfigurationDescriptor *) &otherSpeedDescriptorsHS, +#else + 0, // No full-speed device qualifier descriptor + 0, // No full-speed other speed configuration + 0, // No high-speed device descriptor + 0, // No high-speed configuration descriptor + 0, // No high-speed device qualifier descriptor + 0, // No high-speed other speed configuration descriptor +#endif + stringDescriptors, + 4 // Four string descriptors in array +}; + diff --git a/usb/device/massstorage/MSDDriverDescriptors.h b/usb/device/massstorage/MSDDriverDescriptors.h new file mode 100644 index 0000000..be046a9 --- /dev/null +++ b/usb/device/massstorage/MSDDriverDescriptors.h @@ -0,0 +1,83 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// !Purpose +/// +/// Definitions of the descriptors required by a Mass Storage device driver. +/// +/// !Usage +/// +/// - For a USB %device: +/// -# When initializing a USBDDriver instance, use msdDriverDescriptors as +/// the list of standard descriptors. +//------------------------------------------------------------------------------ + +#ifndef MSDDRIVERDESCRIPTORS_H +#define MSDDRIVERDESCRIPTORS_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "MSD endpoint addresses" +/// This page lists the addresses used by the Mass Storage driver %endpoints. +/// +/// !Addresses +/// +/// - MSDDriverDescriptors_BULKOUT +/// - MSDDriverDescriptors_BULKIN + +/// Address of the Mass Storage bulk-out endpoint. +#define MSDDriverDescriptors_BULKOUT 1 + +/// Address of the Mass Storage bulk-in endpoint. +#if defined(at91sam9m10) + #define MSDDriverDescriptors_BULKIN 6 +#else + #define MSDDriverDescriptors_BULKIN 2 +#endif +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +extern const USBDDriverDescriptors msdDriverDescriptors; + +#endif //#ifndef MSDDRIVERDESCRIPTORS_H + diff --git a/usb/device/massstorage/MSDDriverStates.png b/usb/device/massstorage/MSDDriverStates.png new file mode 100644 index 0000000..a0c55c8 Binary files /dev/null and b/usb/device/massstorage/MSDDriverStates.png differ diff --git a/usb/device/massstorage/MSDIOFifo.c b/usb/device/massstorage/MSDIOFifo.c new file mode 100644 index 0000000..03f09a6 --- /dev/null +++ b/usb/device/massstorage/MSDIOFifo.c @@ -0,0 +1,68 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "MSDIOFifo.h" + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +//! \brief Initializes a MSDIOFifo instance. +//! \param pFifo Pointer to the MSDIOFifo instance to initialize +//! \param pBuffer Pointer to a buffer used for read/write operation and +//! which must be blockSize bytes aligned. +//! \param bufferSize Total size of the buffer in bytes +//------------------------------------------------------------------------------ +void MSDIOFifo_Init(MSDIOFifo *pFifo, + void * pBuffer, unsigned short bufferSize) +{ + pFifo->pBuffer = pBuffer; + pFifo->bufferSize = bufferSize; + + pFifo->inputNdx = 0; + pFifo->outputNdx = 0; + pFifo->inputTotal = 0; + pFifo->outputTotal = 0; + + pFifo->inputState = MSDIO_IDLE; + pFifo->outputState = MSDIO_IDLE; + + pFifo->fullCnt = 0; + pFifo->nullCnt = 0; +} diff --git a/usb/device/massstorage/MSDIOFifo.h b/usb/device/massstorage/MSDIOFifo.h new file mode 100644 index 0000000..efe204d --- /dev/null +++ b/usb/device/massstorage/MSDIOFifo.h @@ -0,0 +1,133 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef _MSDIOFIFO_H +#define _MSDIOFIFO_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +/// Idle state, do nothing +#define MSDIO_IDLE 0 +/// Start, to start IO operation +#define MSDIO_START 1 +/// Wait, waiting for IO operation done +#define MSDIO_WAIT 2 +/// Next, to check if the next block can be performed +#define MSDIO_NEXT 3 +/// Pause, to pause the process for buffer full or null +#define MSDIO_PAUSE 4 +/// Abort, to abort the process +#define MSDIO_ABORT 5 +/// Done, finish without error +#define MSDIO_DONE 6 +/// Error, any error happens +#define MSDIO_ERROR 7 + +/// FIFO offset before USB transmit start +//#define MSDIO_FIFO_OFFSET (4*512) + +/// FIFO trunk size (in each transfer, large amount of data) +#define MSDIO_READ10_CHUNK_SIZE (4*512) +#define MSDIO_WRITE10_CHUNK_SIZE (4*512) + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +/// FIFO buffer for READ/WRITE (disk) operation of a mass storage device +typedef struct _MSDIOFifo { + + /// Pointer to the ring buffer allocated for read/write + unsigned char * pBuffer; + /// The size of the buffer allocated + unsigned int bufferSize; +#ifdef MSDIO_FIFO_OFFSET + /// The offset to start USB transfer (READ10) + unsigned int bufferOffset; +#endif + /// The index of input data (loaded to fifo buffer) + unsigned int inputNdx; + /// The total size of the loaded data + unsigned int inputTotal; + /// The index of output data (sent from the fifo buffer) + unsigned int outputNdx; + /// The total size of the output data + unsigned int outputTotal; + + /// The total size of the data + unsigned int dataTotal; + /// The size of the block in bytes + unsigned short blockSize; +#if defined(MSDIO_READ10_CHUNK_SIZE) || defined(MSDIO_WRITE10_CHUNK_SIZE) + /// The size of one chunk + /// (1 block, or several blocks for large amount data R/W) + unsigned int chunkSize; +#endif + /// State of input & output + unsigned char inputState; + unsigned char outputState; + + //- Statistics + /// Times when fifo has no data to send + unsigned short nullCnt; + /// Times when fifo can not load more input data + unsigned short fullCnt; +} MSDIOFifo, *PMSDIOFifo; + +//------------------------------------------------------------------------------ +// MACROS +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Increase the index, by defined block size, in the ring buffer +/// \param ndx The index to be increased +/// \param sectSize The defined block size +/// \param bufSize The ring buffer size +//------------------------------------------------------------------------------ +#define MSDIOFifo_IncNdx(ndx, sectSize, bufSize) \ + if ((ndx) >= (bufSize) - (sectSize)) (ndx) = 0; \ + else (ndx) += (sectSize) + + +//------------------------------------------------------------------------------ +// Exported Functions +//------------------------------------------------------------------------------ + + +extern void MSDIOFifo_Init(MSDIOFifo *pFifo, + void * pBuffer, unsigned short bufferSize); + +#endif // _MSDIOFIFO_H + diff --git a/usb/device/massstorage/MSDLun.c b/usb/device/massstorage/MSDLun.c new file mode 100644 index 0000000..42999d7 --- /dev/null +++ b/usb/device/massstorage/MSDLun.c @@ -0,0 +1,366 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + + +#include "MSDLun.h" +#include +#include + +//------------------------------------------------------------------------------ +// Constants +//------------------------------------------------------------------------------ + +/// Default LUN block size in bytes +#define DEFAULT_LUN_BLOCK_SIZE 512 + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +/// Inquiry data to return to the host for the Lun. +static SBCInquiryData inquiryData = { + + SBC_DIRECT_ACCESS_BLOCK_DEVICE, // Direct-access block device + SBC_PERIPHERAL_DEVICE_CONNECTED,// Peripheral device is connected + 0x00, // Reserved bits + 0x01, // Media is removable + SBC_SPC_VERSION_4, // SPC-4 supported + 0x2, // Response data format, must be 0x2 + 0, // Hierarchical addressing not supported + 0, // ACA not supported + 0x0, // Obsolete bits + sizeof(SBCInquiryData) - 5, // Additional length + 0, // No embedded SCC + 0, // No access control coordinator + SBC_TPGS_NONE, // No target port support group + 0, // Third-party copy not supported + 0x0, // Reserved bits + 0, // Protection information not supported + 0x0, // Obsolete bit + 0, // No embedded enclosure service component + 0x0, // ??? + 0, // Device is not multi-port + 0x0, // Obsolete bits + 0x0, // Unused feature + 0x0, // Unused features + 0, // Task management model not supported + 0x0, // ??? + {'A','T','M','E','L',' ',' ',' '}, + {'M','a','s','s',' ', + 'S','t','o','r','a','g','e',' ', + 'M','S','D'}, + {'0','.','0','1'}, + {'M','a','s','s',' ', + 'S','t','o','r','a','g','e',' ', + 'E','x','a','m','p','l','e'}, + 0x00, // Unused features + 0x00, // Reserved bits + {SBC_VERSION_DESCRIPTOR_SBC_3}, // SBC-3 compliant device + {0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0} // Reserved +}; + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +//! \brief Initializes a LUN instance. Must be invoked at least once even no +//! Media is linked. +//! \param lun Pointer to the MSDLun instance to initialize +//! \param media Media on which the LUN is constructed, set to 0 to +//! disconnect the Media or initialize an ejected LUN. +//! \param ioBuffer Pointer to a buffer used for read/write operation and +//! which must be blockSize bytes long. +//! \param ioBufferSize Size of the allocated IO buffer. +//! \param baseAddress Base address of the LUN in number of media blocks +//! \param size Total size of the LUN in number of media blocks +//! \param blockSize One block of the LUN in number of media blocks +//! \param protected The LUN area is forced to readonly even the media +//! is writable +//! \param dataMonitor Pointer to a Monitor Function to analyze the flow of +//! this LUN. +//------------------------------------------------------------------------------ +void LUN_Init(MSDLun *lun, + Media *media, + unsigned char *ioBuffer, + unsigned int ioBufferSize, + unsigned int baseAddress, + unsigned int size, + unsigned short blockSize, + unsigned char protected, + void (*dataMonitor)(unsigned char flowDirection, + unsigned int dataLength, + unsigned int fifoNullCount, + unsigned int fifoFullCount)) +{ + unsigned int logicalBlockAddress; + TRACE_INFO("LUN init\n\r"); + + // Initialize inquiry data + lun->inquiryData = &inquiryData; + + // Initialize request sense data + lun->requestSenseData.bResponseCode = SBC_SENSE_DATA_FIXED_CURRENT; + lun->requestSenseData.isValid = 1; + lun->requestSenseData.bObsolete1 = 0; + lun->requestSenseData.bSenseKey = SBC_SENSE_KEY_NO_SENSE; + lun->requestSenseData.bReserved1 = 0; + lun->requestSenseData.isILI = 0; + lun->requestSenseData.isEOM = 0; + lun->requestSenseData.isFilemark = 0; + lun->requestSenseData.pInformation[0] = 0; + lun->requestSenseData.pInformation[1] = 0; + lun->requestSenseData.pInformation[2] = 0; + lun->requestSenseData.pInformation[3] = 0; + lun->requestSenseData.bAdditionalSenseLength + = sizeof(SBCRequestSenseData) - 8; + lun->requestSenseData.bAdditionalSenseCode = 0; + lun->requestSenseData.bAdditionalSenseCodeQualifier = 0; + lun->requestSenseData.bFieldReplaceableUnitCode = 0; + lun->requestSenseData.bSenseKeySpecific = 0; + lun->requestSenseData.pSenseKeySpecific[0] = 0; + lun->requestSenseData.pSenseKeySpecific[0] = 0; + lun->requestSenseData.isSKSV = 0; + + STORE_DWORDB(0, lun->readCapacityData.pLogicalBlockAddress); + STORE_DWORDB(0, lun->readCapacityData.pLogicalBlockLength); + + // Initialize LUN + lun->media = media; + if (media == 0) { + lun->status = LUN_NOT_PRESENT; + return; + } + + lun->baseAddress = baseAddress; + + // Customized block size + if (blockSize) { + lun->blockSize = blockSize; + } + else { + if (media->blockSize < DEFAULT_LUN_BLOCK_SIZE) + lun->blockSize = DEFAULT_LUN_BLOCK_SIZE / media->blockSize; + else + lun->blockSize = 1; + } + + if (size) { + lun->size = size; + } + else { + lun->size = media->size; + //if (blockSize) + // lun->size = media->size / blockSize; + //else { + // if (media->blockSize < DEFAULT_LUN_BLOCK_SIZE) + // lun->size = media->size / lun->blockSize; + // else + // lun->size = media->size; + //} + } + + TRACE_INFO("LUN: blkSize %d, size %d\n\r", (int)lun->blockSize, (int)lun->size); + if (protected) lun->protected = 1; + else lun->protected = media->protected; + + lun->ioFifo.pBuffer = ioBuffer; + lun->ioFifo.bufferSize = ioBufferSize; + + lun->dataMonitor = dataMonitor; + + // Initialize read capacity data + logicalBlockAddress = lun->size / lun->blockSize - 1; + STORE_DWORDB(logicalBlockAddress, + lun->readCapacityData.pLogicalBlockAddress); + STORE_DWORDB(lun->blockSize * media->blockSize, + lun->readCapacityData.pLogicalBlockLength); + + // Indicate media change + lun->status = LUN_CHANGED; +} + +//------------------------------------------------------------------------------ +//! \brief Eject the media from a LUN +//! \param lun Pointer to the MSDLun instance to initialize +//! \return Operation result code +//------------------------------------------------------------------------------ +unsigned char LUN_Eject(MSDLun *lun) +{ + if (lun->media) { + + // Avoid any LUN R/W in progress + if (lun->media->state == MED_STATE_BUSY) { + + return USBD_STATUS_LOCKED; + } + + // Remove the link of the media + lun->media = 0; + } + // LUN is removed + lun->status = LUN_NOT_PRESENT; + + return USBD_STATUS_SUCCESS; +} + +//------------------------------------------------------------------------------ +//! \brief Writes data on the a LUN starting at the specified block address. +//! \param lun Pointer to a MSDLun instance +//! \param blockAddress First block address to write +//! \param data Pointer to the data to write +//! \param length Number of blocks to write +//! \param callback Optional callback to invoke when the write finishes +//! \return Operation result code +//------------------------------------------------------------------------------ +unsigned char LUN_Write(MSDLun *lun, + unsigned int blockAddress, + void *data, + unsigned int length, + TransferCallback callback, + void *argument) +{ + unsigned int medBlk, medLen; + unsigned char status; + + TRACE_INFO_WP("LUNWrite(%u) ", blockAddress); + + // Check that the data is not too big + if ((length + blockAddress) * lun->blockSize > lun->size) { + + TRACE_WARNING("LUN_Write: Data too big\n\r"); + status = USBD_STATUS_ABORTED; + } + else if (lun->media == 0 || lun->status != LUN_READY) { + + TRACE_WARNING("LUN_Write: Media not ready\n\r"); + status = USBD_STATUS_ABORTED; + } + else if (lun->protected) { + TRACE_WARNING("LUN_Write: LUN is readonly\n\r"); + status = USBD_STATUS_ABORTED; + } + else { + + // Compute write start address + medBlk = lun->baseAddress + blockAddress * lun->blockSize; + medLen = length * lun->blockSize; + + // Start write operation + status = MED_Write(lun->media, + medBlk, + data, + medLen, + (MediaCallback) callback, + argument); + + // Check operation result code + if (status == MED_STATUS_SUCCESS) { + + status = USBD_STATUS_SUCCESS; + } + else { + + TRACE_WARNING("LUN_Write: Cannot write media\n\r"); + status = USBD_STATUS_ABORTED; + } + } + + return status; +} + +//------------------------------------------------------------------------------ +//! \brief Reads data from a LUN, starting at the specified block address. +//! \param lun Pointer to a MSDLun instance +//! \param blockAddress First block address to read +//! \param data Pointer to a data buffer in which to store the data +//! \param length Number of blocks to read +//! \param callback Optional callback to invoke when the read finishes +//! \return Operation result code +//------------------------------------------------------------------------------ +unsigned char LUN_Read(MSDLun *lun, + unsigned int blockAddress, + void *data, + unsigned int length, + TransferCallback callback, + void *argument) +{ + unsigned int medBlk, medLen; + unsigned char status; + + // Check that the data is not too big + if ((length + blockAddress) * lun->blockSize > lun->size) { + + TRACE_WARNING("LUN_Read: Area: (%d + %d)*%d > %d\n\r", + (int)length, (int)blockAddress, (int)lun->blockSize, (int)lun->size); + status = USBD_STATUS_ABORTED; + } + else if (lun->media == 0 || lun->status != LUN_READY) { + + TRACE_WARNING("LUN_Read: Media not present\n\r"); + status = USBD_STATUS_ABORTED; + } + else { + + TRACE_INFO_WP("LUNRead(%u) ", blockAddress); + + // Compute read start address + medBlk = lun->baseAddress + (blockAddress * lun->blockSize); + medLen = length * lun->blockSize; + + // Start write operation + status = MED_Read(lun->media, + medBlk, + data, + medLen, + (MediaCallback) callback, + argument); + + // Check result code + if (status == MED_STATUS_SUCCESS) { + + status = USBD_STATUS_SUCCESS; + } + else { + + TRACE_WARNING("LUN_Read: Cannot read media\n\r"); + status = USBD_STATUS_ABORTED; + } + } + + return status; +} diff --git a/usb/device/massstorage/MSDLun.h b/usb/device/massstorage/MSDLun.h new file mode 100644 index 0000000..52eea4c --- /dev/null +++ b/usb/device/massstorage/MSDLun.h @@ -0,0 +1,152 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// !Purpose +/// +/// Logical Unit Number (LUN) used by the Mass Storage driver and the SCSI +/// protocol. Represents a logical hard-drive. +/// +/// !Usage +/// -# Initialize Memory related pins (see pio & board.h). +/// -# Initialize a Media instance for the LUN (see memories). +/// -# Initlalize the LUN with LUN_Init, and link to the initialized Media. +/// -# To read data from the LUN linked media, uses LUN_Read. +/// -# To write data to the LUN linked media, uses LUN_Write. +/// -# To unlink the media, uses LUN_Eject. +//------------------------------------------------------------------------------ + +#ifndef MSDLUN_H +#define MSDLUN_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "SBC.h" +#include +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +/// LUN RC: success +#define LUN_STATUS_SUCCESS 0x00 +/// LUN RC: error +#define LUN_STATUS_ERROR 0x02 + +/// Media of LUN is removed +#define LUN_NOT_PRESENT 0x00 +/// LUN is ejected by host +#define LUN_EJECTED 0x01 +/// Media of LUN is changed +#define LUN_CHANGED 0x10 +/// LUN Not Ready to Ready transition +#define LUN_TRANS_READY LUN_CHANGED +/// Media of LUN is ready +#define LUN_READY 0x11 + +//------------------------------------------------------------------------------ +// Structures +//------------------------------------------------------------------------------ + +/// LUN structure +typedef struct { + + /// Pointer to a SBCInquiryData instance. + SBCInquiryData *inquiryData; + /// Fifo for USB transfer, must be assigned. + MSDIOFifo ioFifo; + /// Pointer to Media instance for the LUN. + Media *media; + /// Pointer to a Monitor Function to analyze the flow of LUN. + /// \param flowDirection 1 - device to host (READ10) + /// 0 - host to device (WRITE10) + /// \param dataLength Length of data transferred in bytes. + /// \param fifoNullCount Times that FIFO is NULL to wait + /// \param fifoFullCount Times that FIFO is filled to wait + void (*dataMonitor)(unsigned char flowDirection, + unsigned int dataLength, + unsigned int fifoNullCount, + unsigned int fifoFullCount); + /// The start position of the media (blocks) allocated to the LUN. + unsigned int baseAddress; + /// The size of the media (blocks) allocated to the LUN. + unsigned int size; + /// Sector size of the media in number of media blocks + unsigned short blockSize; + /// The LUN can be readonly even the media is writable + unsigned char protected; + /// The LUN status (Ejected/Changed/) + unsigned char status; + + /// Data for the RequestSense command. + SBCRequestSenseData requestSenseData; + /// Data for the ReadCapacity command. + SBCReadCapacity10Data readCapacityData; + +} MSDLun; + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ +extern void LUN_Init(MSDLun *lun, + Media *media, + unsigned char *ioBuffer, + unsigned int ioBufferSize, + unsigned int baseAddress, + unsigned int size, + unsigned short blockSize, + unsigned char protected, + void (*dataMonitor)(unsigned char flowDirection, + unsigned int dataLength, + unsigned int fifoNullCount, + unsigned int fifoFullCount)); + +extern unsigned char LUN_Eject(MSDLun *lun); + +extern unsigned char LUN_Write(MSDLun *lun, + unsigned int blockAddress, + void *data, + unsigned int length, + TransferCallback callback, + void *argument); + +extern unsigned char LUN_Read(MSDLun *lun, + unsigned int blockAddress, + void *data, + unsigned int length, + TransferCallback callback, + void *argument); + +#endif //#ifndef MSDLUN_H + diff --git a/usb/device/massstorage/MSDMediaArch.png b/usb/device/massstorage/MSDMediaArch.png new file mode 100644 index 0000000..b641e97 Binary files /dev/null and b/usb/device/massstorage/MSDMediaArch.png differ diff --git a/usb/device/massstorage/SBC.h b/usb/device/massstorage/SBC.h new file mode 100644 index 0000000..7c64844 --- /dev/null +++ b/usb/device/massstorage/SBC.h @@ -0,0 +1,653 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// !Purpose +/// +/// SCSI definitions. +/// +/// !Usage +/// +/// -# After command block received, Access and decode the SCSI command block +/// with SBCCommand structure. +//------------------------------------------------------------------------------ + +#ifndef SBC_H +#define SBC_H + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "SBC Operation Codes" +/// This page lists operation codes of commands described in the SBC-3 +/// standard. +/// +/// \note That most commands are actually defined in other standards, +/// like SPC-4. Optional commands are not included here. +/// +/// \see sbc3r07.pdf - Section 5.1 - Table 12 +/// \see spc4r06.pdf +/// \see SBCCommand +/// +/// !Codes +/// - SBC_INQUIRY +/// - SBC_READ_10 +/// - SBC_READ_CAPACITY_10 +/// - SBC_REQUEST_SENSE +/// - SBC_TEST_UNIT_READY +/// - SBC_WRITE_10 +/// +/// !Optional Codes but required by Windows +/// - SBC_PREVENT_ALLOW_MEDIUM_REMOVAL +/// - SBC_MODE_SENSE_6 +/// - SBC_VERIFY_10 +/// - SBC_READ_FORMAT_CAPACITIES + +/// Request information regarding parameters of the target and Logical Unit. +#define SBC_INQUIRY 0x12 +/// Request the transfer data to the host. +#define SBC_READ_10 0x28 +/// Request capacities of the currently installed medium. +#define SBC_READ_CAPACITY_10 0x25 +/// Request that the device server transfer sense data. +#define SBC_REQUEST_SENSE 0x03 +/// Check if the LUN is ready +#define SBC_TEST_UNIT_READY 0x00 +/// Request that the device write the data transferred by the host. +#define SBC_WRITE_10 0x2A + +/// Request that the target enable or disable the removal of the medium in +/// the Logical Unit. +#define SBC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E +/// Report parameters. +#define SBC_MODE_SENSE_6 0x1A +/// Request that the %device verify the data on the medium. +#define SBC_VERIFY_10 0x2F +/// Request a list of the possible capacities that can be formatted on medium +#define SBC_READ_FORMAT_CAPACITIES 0x23 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "SBC Periph. Qualifiers" +/// This page lists the peripheral qualifier values specified in the INQUIRY +/// data +/// \see spc4r06.pdf - Section 6.4.2 - Table 83 +/// \see SBCInquiryData +/// +/// !Qualifiers +/// - SBC_PERIPHERAL_DEVICE_CONNECTED +/// - SBC_PERIPHERAL_DEVICE_NOT_CONNECTED +/// - SBC_PERIPHERAL_DEVICE_NOT_SUPPORTED + +#define SBC_PERIPHERAL_DEVICE_CONNECTED 0x00 +#define SBC_PERIPHERAL_DEVICE_NOT_CONNECTED 0x01 +#define SBC_PERIPHERAL_DEVICE_NOT_SUPPORTED 0x03 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "SBC Periph. Types" +/// This page lists peripheral device types specified in the INQUIRY data +/// \see spc4r06.pdf - Section 6.4.2 - Table 84 +/// \see SBCInquiryData +/// +/// !Types +/// - SBC_DIRECT_ACCESS_BLOCK_DEVICE +/// - SBC_SEQUENTIAL_ACCESS_DEVICE +/// - SBC_PRINTER_DEVICE +/// - SBC_PROCESSOR_DEVICE +/// - SBC_WRITE_ONCE_DEVICE +/// - SBC_CD_DVD_DEVICE +/// - SBC_SCANNER_DEVICE +/// - SBC_OPTICAL_MEMORY_DEVICE +/// - SBC_MEDIA_CHANGER_DEVICE +/// - SBC_COMMUNICATION_DEVICE +/// - SBC_STORAGE_ARRAY_CONTROLLER_DEVICE +/// - SBC_ENCLOSURE_SERVICES_DEVICE +/// - SBC_SIMPLIFIED_DIRECT_ACCESS_DEVICE +/// - SBC_OPTICAL_CARD_READER_WRITER_DEVICE +/// - SBC_BRIDGE_CONTROLLER_COMMANDS +/// - SBC_OBJECT_BASED_STORAGE_DEVICE + +#define SBC_DIRECT_ACCESS_BLOCK_DEVICE 0x00 +#define SBC_SEQUENTIAL_ACCESS_DEVICE 0x01 +#define SBC_PRINTER_DEVICE 0x02 +#define SBC_PROCESSOR_DEVICE 0x03 +#define SBC_WRITE_ONCE_DEVICE 0x04 +#define SBC_CD_DVD_DEVICE 0x05 +#define SBC_SCANNER_DEVICE 0x06 +#define SBC_OPTICAL_MEMORY_DEVICE 0x07 +#define SBC_MEDIA_CHANGER_DEVICE 0x08 +#define SBC_COMMUNICATION_DEVICE 0x09 +#define SBC_STORAGE_ARRAY_CONTROLLER_DEVICE 0x0C +#define SBC_ENCLOSURE_SERVICES_DEVICE 0x0D +#define SBC_SIMPLIFIED_DIRECT_ACCESS_DEVICE 0x0E +#define SBC_OPTICAL_CARD_READER_WRITER_DEVICE 0x0F +#define SBC_BRIDGE_CONTROLLER_COMMANDS 0x10 +#define SBC_OBJECT_BASED_STORAGE_DEVICE 0x11 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \brief Version value for the SBC-3 specification +/// \see spc4r06.pdf - Section 6.4.2 - Table 85 +#define SBC_SPC_VERSION_4 0x06 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \brief Values for the TPGS field returned in INQUIRY data +/// \see spc4r06.pdf - Section 6.4.2 - Table 86 +#define SBC_TPGS_NONE 0x0 +#define SBC_TPGS_ASYMMETRIC 0x1 +#define SBC_TPGS_SYMMETRIC 0x2 +#define SBC_TPGS_BOTH 0x3 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \brief Version descriptor value for the SBC-3 specification +/// \see spc4r06.pdf - Section 6.4.2 - Table 87 +#define SBC_VERSION_DESCRIPTOR_SBC_3 0x04C0 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "SBC Sense Response Codes" +/// This page lists sense data response codes returned in REQUEST SENSE data +/// \see spc4r06.pdf - Section 4.5.1 - Table 12 +/// +/// !Codes +/// - SBC_SENSE_DATA_FIXED_CURRENT +/// - SBC_SENSE_DATA_FIXED_DEFERRED +/// - SBC_SENSE_DATA_DESCRIPTOR_CURRENT +/// - SBC_SENSE_DATA_DESCRIPTOR_DEFERRED + +#define SBC_SENSE_DATA_FIXED_CURRENT 0x70 +#define SBC_SENSE_DATA_FIXED_DEFERRED 0x71 +#define SBC_SENSE_DATA_DESCRIPTOR_CURRENT 0x72 +#define SBC_SENSE_DATA_DESCRIPTOR_DEFERRED 0x73 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "SBC Sense Keys" +/// This page lists sense key values returned in the REQUEST SENSE data +/// \see spc4r06.pdf - Section 4.5.6 - Table 27 +/// +/// !Keys +/// - SBC_SENSE_KEY_NO_SENSE +/// - SBC_SENSE_KEY_RECOVERED_ERROR +/// - SBC_SENSE_KEY_NOT_READY +/// - SBC_SENSE_KEY_MEDIUM_ERROR +/// - SBC_SENSE_KEY_HARDWARE_ERROR +/// - SBC_SENSE_KEY_ILLEGAL_REQUEST +/// - SBC_SENSE_KEY_UNIT_ATTENTION +/// - SBC_SENSE_KEY_DATA_PROTECT +/// - SBC_SENSE_KEY_BLANK_CHECK +/// - SBC_SENSE_KEY_VENDOR_SPECIFIC +/// - SBC_SENSE_KEY_COPY_ABORTED +/// - SBC_SENSE_KEY_ABORTED_COMMAND +/// - SBC_SENSE_KEY_VOLUME_OVERFLOW +/// - SBC_SENSE_KEY_MISCOMPARE + +/// No specific sense key. Successful command. +#define SBC_SENSE_KEY_NO_SENSE 0x00 +/// Command completed succesfully with some recovery action by the %device. +#define SBC_SENSE_KEY_RECOVERED_ERROR 0x01 +/// The device can not be accessed. +#define SBC_SENSE_KEY_NOT_READY 0x02 +/// Command terminated with a error condition that was probably caused by a +/// flaw in the medium or an error in the recorded data. +#define SBC_SENSE_KEY_MEDIUM_ERROR 0x03 +/// Hardware failure while performing the command or during a self test. +#define SBC_SENSE_KEY_HARDWARE_ERROR 0x04 +/// Illegal parameter found in the command or additional parameters. +#define SBC_SENSE_KEY_ILLEGAL_REQUEST 0x05 +/// Removable medium may have been changed or the %device has been reset. +#define SBC_SENSE_KEY_UNIT_ATTENTION 0x06 +/// Write on a block that is protected. +#define SBC_SENSE_KEY_DATA_PROTECT 0x07 +/// Indicates that a write-once device or a sequential-access device +/// encountered blank medium or format-defined end-of-data indication while +/// reading or a write-once device encountered a non-blank medium while writing. +#define SBC_SENSE_KEY_BLANK_CHECK 0x08 +/// Reporting vendor specific conditions. +#define SBC_SENSE_KEY_VENDOR_SPECIFIC 0x09 +/// EXTENDED COPY command was aborted. +#define SBC_SENSE_KEY_COPY_ABORTED 0x0A +/// Device aborted the command. +#define SBC_SENSE_KEY_ABORTED_COMMAND 0x0B +/// A buffered peripheral device is overflow. +#define SBC_SENSE_KEY_VOLUME_OVERFLOW 0x0D +/// The source data did not match the data read from the medium. +#define SBC_SENSE_KEY_MISCOMPARE 0x0E +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "SBC Sense Additionals" +/// This page lists additional sense code values returned in REQUEST SENSE data +/// \see spc4r06.pdf - Section 4.5.6 - Table 28 +/// +/// !Additional Codes +/// - SBC_ASC_LOGICAL_UNIT_NOT_READY +/// - SBC_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE +/// - SBC_ASC_INVALID_FIELD_IN_CDB +/// - SBC_ASC_WRITE_PROTECTED +/// - SBC_ASC_FORMAT_CORRUPTED +/// - SBC_ASC_INVALID_COMMAND_OPERATION_CODE +/// - SBC_ASC_TOO_MUCH_WRITE_DATA +/// - SBC_ASC_NOT_READY_TO_READY_CHANGE +/// - SBC_ASC_MEDIUM_NOT_PRESENT + +#define SBC_ASC_LOGICAL_UNIT_NOT_READY 0x04 +#define SBC_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21 +#define SBC_ASC_INVALID_FIELD_IN_CDB 0x24 +#define SBC_ASC_WRITE_PROTECTED 0x27 +#define SBC_ASC_FORMAT_CORRUPTED 0x31 +#define SBC_ASC_INVALID_COMMAND_OPERATION_CODE 0x20 +#define SBC_ASC_TOO_MUCH_WRITE_DATA 0x26 +#define SBC_ASC_NOT_READY_TO_READY_CHANGE 0x28 +#define SBC_ASC_MEDIUM_NOT_PRESENT 0x3A +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \brief MEDIUM TYPE field value for direct-access block devices +/// \see sbc3r06.pdf - Section 6.3.1 +#define SBC_MEDIUM_TYPE_DIRECT_ACCESS_BLOCK_DEVICE 0x00 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \brief MRIE field values +/// \see sbc3r06.pdf - Section 7.4.11 - Table 286 +#define SBC_MRIE_NO_REPORTING 0x00 +#define SBC_MRIE_ASYNCHRONOUS 0x01 +#define SBC_MRIE_GENERATE_UNIT_ATTENTION 0x02 +#define SBC_MRIE_COND_GENERATE_RECOVERED_ERROR 0x03 +#define SBC_MRIE_UNCOND_GENERATE_RECOVERED_ERROR 0x04 +#define SBC_MRIE_GENERATE_NO_SENSE 0x05 +#define SBC_MRIE_ON_REQUEST 0x06 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \brief Supported mode pages +/// \see sbc3r06.pdf - Section 6.3.1 - Table 115 +#define SBC_PAGE_READ_WRITE_ERROR_RECOVERY 0x01 +#define SBC_PAGE_INFORMATIONAL_EXCEPTIONS_CONTROL 0x1C +#define SBC_PAGE_RETURN_ALL 0x3F +#define SBC_PAGE_VENDOR_SPECIFIC 0x00 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "MSD Endian Macros" +/// This page lists the macros for endianness conversion. +/// +/// !Macros +/// - WORDB +/// - DWORDB +/// - STORE_DWORDB +/// - STORE_WORDB +/// \brief Converts a byte array to a word value using the big endian format +#define WORDB(bytes) ((unsigned short) ((bytes[0] << 8) | bytes[1])) + +/// \brief Converts a byte array to a dword value using the big endian format +#define DWORDB(bytes) ((unsigned int) ((bytes[0] << 24) | (bytes[1] << 16) \ + | (bytes[2] << 8) | bytes[3])) + +/// \brief Stores a dword value in a byte array, in big endian format +#define STORE_DWORDB(dword, bytes) \ + bytes[0] = (unsigned char) (((dword) >> 24) & 0xFF); \ + bytes[1] = (unsigned char) (((dword) >> 16) & 0xFF); \ + bytes[2] = (unsigned char) (((dword) >> 8) & 0xFF); \ + bytes[3] = (unsigned char) ((dword) & 0xFF); + +/// \brief Stores a word value in a byte array, in big endian format +#define STORE_WORDB(word, bytes) \ + bytes[0] = (unsigned char) (((word) >> 8) & 0xFF); \ + bytes[1] = (unsigned char) ((word) & 0xFF); +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Structures +//------------------------------------------------------------------------------ + +#ifdef __ICCARM__ // IAR +#pragma pack(1) // IAR +#define __attribute__(...) // IAR +#endif // IAR + +//------------------------------------------------------------------------------ +/// \brief Structure for the INQUIRY command +/// \see spc4r06.pdf - Section 6.4.1 - Table 81 +//------------------------------------------------------------------------------ +typedef struct { + + unsigned char bOperationCode; //!< 0x12 : SBC_INQUIRY + unsigned char isEVPD:1, //!< Type of requested data + bReserved1:7; //!< Reserved bits + unsigned char bPageCode; //!< Specifies the VPD to return + unsigned char pAllocationLength[2]; //!< Size of host buffer + unsigned char bControl; //!< 0x00 + +} __attribute__ ((packed)) SBCInquiry; // GCC + +//------------------------------------------------------------------------------ +/// \brief Standard INQUIRY data format returned by the device +/// \see spc4r06.pdf - Section 6.4.2 - Table 82 +//------------------------------------------------------------------------------ +typedef struct { + + unsigned char bPeripheralDeviceType:5, //!< Peripheral device type + bPeripheralQualifier :3; //!< Peripheral qualifier + unsigned char bReserved1:7, //!< Reserved bits + isRMB :1; //!< Is media removable ? + unsigned char bVersion; //!< SPC version used + unsigned char bResponseDataFormat:4, //!< Must be 0x2 + isHIGHSUP :1, //!< Hierarchical addressing used ? + isNORMACA :1, //!< ACA attribute supported ? + bObsolete1 :2; //!< Obsolete bits + unsigned char bAdditionalLength; //!< Length of remaining INQUIRY data + unsigned char isSCCS :1, //!< Embedded SCC ? + isACC :1, //!< Access control coordinator ? + bTPGS :2, //!< Target port support group + is3PC :1, //!< Third-party copy supported ? + bReserved2:2, //!< Reserved bits + isProtect :1; //!< Protection info supported ? + unsigned char bObsolete2:1, //!< Obsolete bit + isEncServ :1, //!< Embedded enclosure service comp? + isVS :1, //!< ??? + isMultiP :1, //!< Multi-port device ? + bObsolete3:3, //!< Obsolete bits + bUnused1 :1; //!< Unused feature + unsigned char bUnused2:6, //!< Unused features + isCmdQue:1, //!< Task management model supported ? + isVS2 :1; //!< ??? + unsigned char pVendorID[8]; //!< T10 vendor identification + unsigned char pProductID[16]; //!< Vendor-defined product ID + unsigned char pProductRevisionLevel[4];//!< Vendor-defined product revision + unsigned char pVendorSpecific[20]; //!< Vendor-specific data + unsigned char bUnused3; //!< Unused features + unsigned char bReserved3; //!< Reserved bits + unsigned short pVersionDescriptors[8]; //!< Standards the device complies to + unsigned char pReserved4[22]; //!< Reserved bytes + +} __attribute__ ((packed)) SBCInquiryData; // GCC + +//------------------------------------------------------------------------------ +/// \brief Data structure for the READ (10) command +/// \see sbc3r07.pdf - Section 5.7 - Table 34 +//------------------------------------------------------------------------------ +typedef struct { + + unsigned char bOperationCode; //!< 0x28 : SBC_READ_10 + unsigned char bObsolete1:1, //!< Obsolete bit + isFUA_NV:1, //!< Cache control bit + bReserved1:1, //!< Reserved bit + isFUA:1, //!< Cache control bit + isDPO:1, //!< Cache control bit + bRdProtect:3; //!< Protection information to send + unsigned char pLogicalBlockAddress[4]; //!< Index of first block to read + unsigned char bGroupNumber:5, //!< Information grouping + bReserved2:3; //!< Reserved bits + unsigned char pTransferLength[2]; //!< Number of blocks to transmit + unsigned char bControl; //!< 0x00 + +} __attribute__ ((packed)) SBCRead10; // GCC + +//------------------------------------------------------------------------------ +/// \brief Structure for the READ CAPACITY (10) command +/// \see sbc3r07.pdf - Section 5.11.1 - Table 40 +//------------------------------------------------------------------------------ +typedef struct { + + unsigned char bOperationCode; //!< 0x25 : RBC_READ_CAPACITY + unsigned char bObsolete1:1, //!< Obsolete bit + bReserved1:7; //!< Reserved bits + unsigned char pLogicalBlockAddress[4]; //!< Block to evaluate if PMI is set + unsigned char pReserved2[2]; //!< Reserved bytes + unsigned char isPMI:1, //!< Partial medium indicator bit + bReserved3:7; //!< Reserved bits + unsigned char bControl; //!< 0x00 + +} SBCReadCapacity10; + +//------------------------------------------------------------------------------ +/// \brief Data returned by the device after a READ CAPACITY (10) command +/// \see sbc3r07.pdf - Section 5.11.2 - Table 41 +//------------------------------------------------------------------------------ +typedef struct { + + unsigned char pLogicalBlockAddress[4]; //!< Address of last logical block + unsigned char pLogicalBlockLength[4]; //!< Length of each logical block + +} SBCReadCapacity10Data; + +//------------------------------------------------------------------------------ +/// \brief Structure for the REQUEST SENSE command +/// \see spc4r06.pdf - Section 6.26 - Table 170 +//------------------------------------------------------------------------------ +typedef struct { + + unsigned char bOperationCode; //!< 0x03 : SBC_REQUEST_SENSE + unsigned char isDesc :1, //!< Type of information expected + bReserved1:7; //!< Reserved bits + unsigned char pReserved2[2]; //!< Reserved bytes + unsigned char bAllocationLength; //!< Size of host buffer + unsigned char bControl; //!< 0x00 + +} SBCRequestSense; + +//------------------------------------------------------------------------------ +/// \brief Fixed format sense data returned after a REQUEST SENSE command has +/// been received with a DESC bit cleared. +/// \see spc4r06.pdf - Section 4.5.3 - Table 26 +//------------------------------------------------------------------------------ +typedef struct { + + unsigned char bResponseCode:7, //!< Sense data format + isValid :1; //!< Information field is standard + unsigned char bObsolete1; //!< Obsolete byte + unsigned char bSenseKey :4, //!< Generic error information + bReserved1:1, //!< Reserved bit + isILI :1, //!< SSC + isEOM :1, //!< SSC + isFilemark:1; //!< SSC + unsigned char pInformation[4]; //!< Command-specific + unsigned char bAdditionalSenseLength; //!< sizeof(SBCRequestSense_data)-8 + unsigned char pCommandSpecificInformation[4]; //!< Command-specific + unsigned char bAdditionalSenseCode; //!< Additional error information + unsigned char bAdditionalSenseCodeQualifier; //!< Further error information + unsigned char bFieldReplaceableUnitCode; //!< Specific component code + unsigned char bSenseKeySpecific:7, //!< Additional exception info + isSKSV :1; //!< Is sense key specific valid? + unsigned char pSenseKeySpecific[2]; //!< Additional exception info + +} SBCRequestSenseData; + +//------------------------------------------------------------------------------ +/// \brief Data structure for the TEST UNIT READY command +/// \see spc4r06.pdf - Section 6.34 - Table 192 +//------------------------------------------------------------------------------ +typedef struct { + + unsigned char bOperationCode; //!< 0x00 : SBC_TEST_UNIT_READY + unsigned char pReserved1[4]; //!< Reserved bits + unsigned char bControl; //!< 0x00 + +} __attribute__ ((packed)) SBCTestUnitReady; // GCC + +//------------------------------------------------------------------------------ +/// \brief Structure for the WRITE (10) command +/// \see sbc3r07.pdf - Section 5.26 - Table 70 +//------------------------------------------------------------------------------ +typedef struct { + + unsigned char bOperationCode; //!< 0x2A : SBC_WRITE_10 + unsigned char bObsolete1:1, //!< Obsolete bit + isFUA_NV:1, //!< Cache control bit + bReserved1:1, //!< Reserved bit + isFUA:1, //!< Cache control bit + isDPO:1, //!< Cache control bit + bWrProtect:3; //!< Protection information to send + unsigned char pLogicalBlockAddress[4]; //!< First block to write + unsigned char bGroupNumber:5, //!< Information grouping + bReserved2:3; //!< Reserved bits + unsigned char pTransferLength[2]; //!< Number of blocks to write + unsigned char bControl; //!< 0x00 + +} SBCWrite10; + +//------------------------------------------------------------------------------ +/// \brief Structure for the PREVENT/ALLOW MEDIUM REMOVAL command +/// \see sbc3r07.pdf - Section 5.5 - Table 30 +//------------------------------------------------------------------------------ +typedef struct { + + unsigned char bOperationCode; //!< 0x1E : SBC_PREVENT_ALLOW_MEDIUM_REMOVAL + unsigned char pReserved1[3]; //!< Reserved bytes + unsigned char bPrevent:2, //!< Accept/prohibit removal + bReserved2:6; //!< Reserved bits + unsigned char bControl; //!< 0x00 + +} __attribute__ ((packed)) SBCMediumRemoval; // GCC + +//------------------------------------------------------------------------------ +/// \brief Structure for the MODE SENSE (6) command +/// \see spc4r06 - Section 6.9.1 - Table 98 +//------------------------------------------------------------------------------ +typedef struct { + + unsigned char bOperationCode; //!< 0x1A : SBC_MODE_SENSE_6 + unsigned char bReserved1:3, //!< Reserved bits + isDBD:1, //!< Disable block descriptors bit + bReserved2:4; //!< Reserved bits + unsigned char bPageCode:6, //!< Mode page to return + bPC:2; //!< Type of parameter values to return + unsigned char bSubpageCode; //!< Mode subpage to return + unsigned char bAllocationLength; //!< Host buffer allocated size + unsigned char bControl; //!< 0x00 + +} __attribute__ ((packed)) SBCModeSense6; // GCC + +//------------------------------------------------------------------------------ +/// \brief Header for the data returned after a MODE SENSE (6) command +/// \see spc4r06.pdf - Section 7.4.3 - Table 268 +//------------------------------------------------------------------------------ +typedef struct { + + unsigned char bModeDataLength; //!< Length of mode data to follow + unsigned char bMediumType; //!< Type of medium (SBC_MEDIUM_TYPE_DIRECT_ACCESS_BLOCK_DEVICE) + unsigned char bReserved1:4, //!< Reserved bits + isDPOFUA:1, //!< DPO/FUA bits supported ? + bReserved2:2, //!< Reserved bits + isWP:1; //!< Is medium write-protected ? + unsigned char bBlockDescriptorLength; //!< Length of all block descriptors + +} __attribute__ ((packed)) SBCModeParameterHeader6; // GCC + +//------------------------------------------------------------------------------ +/// \brief Informational exceptions control mode page +/// \see spc4r06.pdf - Section 7.4.11 - Table 285 +//------------------------------------------------------------------------------ +typedef struct { + + unsigned char bPageCode:6, //!< 0x1C : SBC_PAGE_INFORMATIONAL_EXCEPTIONS_CONTROL + isSPF:1, //!< Page or subpage data format + isPS:1; //!< Parameters saveable ? + unsigned char bPageLength; //!< Length of page data (0x0A) + unsigned char isLogErr:1, //!< Should informational exceptions be logged ? + isEBackErr:1, //!< Enable background error bit + isTest:1, //!< Create a device test failure ? + isDExcpt:1, //!< Disable exception control bit + isEWasc:1, //!< Report warnings ? + isEBF:1, //!< Enable background function bit + bReserved1:1, //!< Reserved bit + isPerf:1; //!< Delay acceptable when treating exceptions ? + unsigned char bMRIE:4, //!< Method of reporting informational exceptions + bReserved2:4; //!< Reserved bits + unsigned char pIntervalTimer[4]; //!< Error reporting period + unsigned char pReportCount[4]; //!< Maximum number of time a report can be issued + +} __attribute__ ((packed)) SBCInformationalExceptionsControl; // GCC + +//------------------------------------------------------------------------------ +/// \brief Read/write error recovery mode page +/// \see sbc3r07.pdf - Section 6.3.5 - Table 122 +//------------------------------------------------------------------------------ +typedef struct { + + unsigned char bPageCode:6, //!< 0x01 : SBC_PAGE_READ_WRITE_ERROR_RECOVERY + isSPF:1, //!< Page or subpage data format + isPS:1; //!< Parameters saveable ? + unsigned char bPageLength; //!< Length of page data (0x0A) + unsigned char isDCR:1, //!< Disable correction bit + isDTE:1, //!< Data terminate on error bit + isPER:1, //!< Post error bit + isEER:1, //!< Enable early recovery bit + isRC:1, //!< Read continuous bit + isTB:1, //!< Transfer block bit + isARRE:1, //!< Automatic read reallocation enabled bit + isAWRE:1; //!< Automatic write reallocation enabled bit + unsigned char bReadRetryCount; //!< Number of retries when reading + unsigned char pObsolete1[3]; //!< Obsolete bytes + unsigned char bReserved1; //!< Reserved byte + unsigned char bWriteRetryCount; //!< Number of retries when writing + unsigned char bReserved2; //!< Reserved byte + unsigned char pRecoveryTimeLimit[2]; //!< Maximum time duration for error recovery + +} __attribute__ ((packed)) SBCReadWriteErrorRecovery; // GCC + +//------------------------------------------------------------------------------ +/// \brief Generic structure for holding information about SBC commands +/// \see SBCInquiry +/// \see SBCRead10 +/// \see SBCReadCapacity10 +/// \see SBCRequestSense +/// \see SBCTestUnitReady +/// \see SBCWrite10 +/// \see SBCMediumRemoval +/// \see SBCModeSense6 +//------------------------------------------------------------------------------ +typedef union { + + unsigned char bOperationCode; //!< Operation code of the command + SBCInquiry inquiry; //!< INQUIRY command + SBCRead10 read10; //!< READ (10) command + SBCReadCapacity10 readCapacity10; //!< READ CAPACITY (10) command + SBCRequestSense requestSense; //!< REQUEST SENSE command + SBCTestUnitReady testUnitReady; //!< TEST UNIT READY command + SBCWrite10 write10; //!< WRITE (10) command + SBCMediumRemoval mediumRemoval; //!< PREVENT/ALLOW MEDIUM REMOVAL command + SBCModeSense6 modeSense6; //!< MODE SENSE (6) command + +} SBCCommand; + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + +#endif //#ifndef SBC_H + diff --git a/usb/device/massstorage/SBCMethods.c b/usb/device/massstorage/SBCMethods.c new file mode 100644 index 0000000..cd7a87a --- /dev/null +++ b/usb/device/massstorage/SBCMethods.c @@ -0,0 +1,1611 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "SBCMethods.h" +#include "MSDDStateMachine.h" +#include + +#include "MSDIOFifo.h" + +//------------------------------------------------------------------------------ +// Global variables +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Macros +//------------------------------------------------------------------------------ + +#ifdef MSDIO_READ10_CHUNK_SIZE +/// READ10 - Read data from specific LUN to FIFO +#define SBC_READ_CHUNK(pLun, lba, pFifo, pCb, pArg) \ + LUN_Read((pLun), (lba), \ + &(pFifo)->pBuffer[(pFifo)->inputNdx], \ + ((pFifo)->chunkSize/(pFifo)->blockSize), \ + (TransferCallback)(pCb), (void*)pArg) +/// READ10 - Transfer data from FIFO to USB +#define SBC_TX_CHUNK(pFifo, pCb, pArg) \ + MSDD_Write(&(pFifo)->pBuffer[(pFifo)->outputNdx], \ + (pFifo)->chunkSize, \ + (TransferCallback)(pCb), (void*)(pArg)) +#endif + +#ifdef MSDIO_WRITE10_CHUNK_SIZE +/// WRITE10 - Read data from USB to FIFO +#define SBC_RX_CHUNK(pFifo,pCb,pArg) \ + MSDD_Read(&(pFifo)->pBuffer[(pFifo)->inputNdx], \ + (pFifo)->chunkSize, \ + (TransferCallback)(pCb), (void*)(pArg)) +/// WRITE10 - Write data from FIFO to LUN +#define SBC_WRITE_CHUNK(pLun, lba, pFifo, pCb, pArg) \ + LUN_Write((pLun), (lba), \ + &(pFifo)->pBuffer[(pFifo)->outputNdx], \ + ((pFifo)->chunkSize/(pFifo)->blockSize), \ + (TransferCallback)(pCb), (void*)(pArg)) +#endif + + +//------------------------------------------------------------------------------ +//! \brief Header for the mode pages data +//! \see SBCModeParameterHeader6 +//------------------------------------------------------------------------------ +static const SBCModeParameterHeader6 modeParameterHeader6 = { + + sizeof(SBCModeParameterHeader6) - 1, //! Length is 0x03 + SBC_MEDIUM_TYPE_DIRECT_ACCESS_BLOCK_DEVICE, //! Direct-access block device + 0, //! Reserved bits + 0, //! DPO/FUA not supported + 0, //! Reserved bits + 0, //! not write-protected + 0 //! No block descriptor +}; + +//------------------------------------------------------------------------------ +// Internal functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +//! \brief Check if the LUN is ready. +//! \param lun Pointer to the LUN affected by the command +//! \return 1 if the LUN is ready to be written +//! \see MSDLun +//------------------------------------------------------------------------------ +static unsigned char SBCLunIsReady(MSDLun *lun) +{ + unsigned char lunIsReady = 0; + + if (lun->media == 0 || lun->status < LUN_CHANGED) { + TRACE_INFO("SBCLunIsReady: Not Present!\n\r"); + SBC_UpdateSenseData(&(lun->requestSenseData), + SBC_SENSE_KEY_NOT_READY, + SBC_ASC_MEDIUM_NOT_PRESENT, + 0); + + } + else if (lun->status < LUN_READY) { + TRACE_INFO("SBCLunIsReady: Changing!\n\r"); + SBC_UpdateSenseData(&(lun->requestSenseData), + SBC_SENSE_KEY_UNIT_ATTENTION, + SBC_ASC_NOT_READY_TO_READY_CHANGE, + 0); + lun->status = LUN_READY; + } + else { + + lunIsReady = 1; + } + + return lunIsReady; +} +//------------------------------------------------------------------------------ +//! \brief Check if the LUN can write. +//! \param lun Pointer to the LUN affected by the command +//! \return 1 if the LUN is ready to be written +//! \see MSDLun +//------------------------------------------------------------------------------ +static unsigned char SBCLunCanBeWritten(MSDLun *lun) +{ + unsigned char canBeWritten = 0; + + if (!SBCLunIsReady(lun)) { + + TRACE_WARNING("SBCLunCanBeWritten: Not Ready!\n\r"); + } + else if (lun->protected) { + + TRACE_WARNING("SBCLunCanBeWritten: Protected!\n\r"); + SBC_UpdateSenseData(&(lun->requestSenseData), + SBC_SENSE_KEY_DATA_PROTECT, + SBC_ASC_WRITE_PROTECTED, + 0); + } + else { + + canBeWritten = 1; + } + + return canBeWritten; +} + +//------------------------------------------------------------------------------ +//! \brief Performs a WRITE (10) command on the specified LUN. +//! +//! The data to write is first received from the USB host and then +//! actually written on the media. +//! This function operates asynchronously and must be called multiple +//! times to complete. A result code of MSDDriver_STATUS_INCOMPLETE +//! indicates that at least another call of the method is necessary. +//! \param lun Pointer to the LUN affected by the command +//! \param commandState Current state of the command +//! \return Operation result code (SUCCESS, ERROR, INCOMPLETE or PARAMETER) +//! \see MSDLun +//! \see MSDCommandState +//------------------------------------------------------------------------------ +static unsigned char SBC_Write10(MSDLun *lun, + MSDCommandState *commandState) +{ + unsigned char status; + unsigned char result = MSDD_STATUS_INCOMPLETE; + SBCRead10 *command = (SBCRead10 *) commandState->cbw.pCommand; + MSDTransfer *transfer = &(commandState->transfer); + MSDTransfer *disktransfer = &(commandState->disktransfer); + MSDIOFifo *fifo = &lun->ioFifo; + + // Init command state + if (commandState->state == 0) { + + commandState->state = SBC_STATE_WRITE; + + // The command should not be proceeded if READONLY + if (!SBCLunCanBeWritten(lun)) { + + return MSDD_STATUS_RW; + } + else { + + + // Initialize FIFO + fifo->dataTotal = commandState->length; + fifo->blockSize = lun->blockSize * lun->media->blockSize; + #ifdef MSDIO_WRITE10_CHUNK_SIZE + if ( fifo->dataTotal >= 64 * 1024 + && fifo->blockSize < MSDIO_WRITE10_CHUNK_SIZE) + fifo->chunkSize = MSDIO_WRITE10_CHUNK_SIZE; + else + fifo->chunkSize = fifo->blockSize; + #endif + fifo->fullCnt = 0; + fifo->nullCnt = 0; + + // Initialize FIFO output (Disk) + fifo->outputNdx = 0; + fifo->outputTotal = 0; + fifo->outputState = MSDIO_IDLE; + transfer->semaphore = 0; + + // Initialize FIFO input (USB) + fifo->inputNdx = 0; + fifo->inputTotal = 0; + fifo->inputState = MSDIO_START; + disktransfer->semaphore = 0; + } + + } + + if (commandState->length == 0) { + + // Perform the callback! + if (lun->dataMonitor) { + + lun->dataMonitor(0, fifo->dataTotal, fifo->nullCnt, fifo->fullCnt); + } + return MSDD_STATUS_SUCCESS; + } + + // USB receive task + switch(fifo->inputState) { + + //------------------ + case MSDIO_IDLE: + //------------------ + if (fifo->inputTotal < fifo->dataTotal && + fifo->inputTotal - fifo->outputTotal < fifo->bufferSize) { + + fifo->inputState = MSDIO_START; + } + break; + + //------------------ + case MSDIO_START: + //------------------ + // Should not start if there is any disk error + if (fifo->outputState == MSDIO_ERROR) { + + TRACE_INFO_WP("udErr "); + fifo->inputState = MSDIO_ERROR; + break; + } + + // Read one block of data sent by the host + if (lun->media->mappedWR) { + + // Directly read to memory + status = MSDD_Read((void*) + ((lun->media->baseAddress + + (lun->baseAddress + + DWORDB(command->pLogicalBlockAddress) + * lun->blockSize + ) + ) * lun->media->blockSize + ), + fifo->dataTotal, + (TransferCallback) MSDDriver_Callback, + (void *) transfer); + } + else { + #ifdef MSDIO_WRITE10_CHUNK_SIZE + status = SBC_RX_CHUNK(fifo, MSDDriver_Callback, transfer); + #else + // Read block to buffer + status = MSDD_Read((void*)&fifo->pBuffer[fifo->inputNdx], + fifo->blockSize, + (TransferCallback) MSDDriver_Callback, + (void *) transfer); + #endif + } + + // Check operation result code + if (status != USBD_STATUS_SUCCESS) { + + TRACE_WARNING( + "RBC_Write10: Failed to start receiving\n\r"); + SBC_UpdateSenseData(&(lun->requestSenseData), + SBC_SENSE_KEY_HARDWARE_ERROR, + 0, + 0); + result = MSDD_STATUS_ERROR; + } + else { + + TRACE_INFO_WP("uRx "); + + // Prepare next device state + fifo->inputState = MSDIO_WAIT; + } + break; // MSDIO_START + + //------------------ + case MSDIO_WAIT: + //------------------ + TRACE_INFO_WP("uWait "); + + // Check semaphore + if (transfer->semaphore > 0) { + + transfer->semaphore--; + fifo->inputState = MSDIO_NEXT; + } + break; + + //------------------ + case MSDIO_NEXT: + //------------------ + // Check the result code of the read operation + if (transfer->status != USBD_STATUS_SUCCESS) { + + TRACE_WARNING( + "RBC_Write10: Failed to received\n\r"); + SBC_UpdateSenseData(&(lun->requestSenseData), + SBC_SENSE_KEY_HARDWARE_ERROR, + 0, + 0); + result = MSDD_STATUS_ERROR; + } + else { + + TRACE_INFO_WP("uNxt "); + + // Mapped read, all data done + if (lun->media->mappedWR) { + + fifo->inputTotal = fifo->dataTotal; + fifo->inputState = MSDIO_IDLE; + } + else { + + // Update input index + #ifdef MSDIO_WRITE10_CHUNK_SIZE + MSDIOFifo_IncNdx(fifo->inputNdx, + fifo->chunkSize, + fifo->bufferSize); + fifo->inputTotal += fifo->chunkSize; + #else + MSDIOFifo_IncNdx(fifo->inputNdx, + fifo->blockSize, + fifo->bufferSize); + fifo->inputTotal += fifo->blockSize; + #endif + + // Start Next block + // - All Data done? + if (fifo->inputTotal >= fifo->dataTotal) { + + fifo->inputState = MSDIO_IDLE; + } + // - Buffer full? + else if (fifo->inputNdx == fifo->outputNdx) { + fifo->inputState = MSDIO_IDLE; + fifo->fullCnt ++; + + TRACE_DEBUG_WP("ufFull%d ", fifo->inputNdx); + } + // - More data to transfer? + else if (fifo->inputTotal < fifo->dataTotal) { + fifo->inputState = MSDIO_START; + + TRACE_INFO_WP("uStart "); + } + // never executed ! + //else { + // fifo->inputState = MSDIO_IDLE; + // TRACE_INFO_WP("uDone "); + //} + } + + } + break; // MSDIO_NEXT + + //------------------ + case MSDIO_ERROR: + //------------------ + + TRACE_WARNING_WP("uErr "); + commandState->length -= fifo->inputTotal; + return MSDD_STATUS_RW; + + } + + // Disk write task + switch(fifo->outputState) { + + //------------------ + case MSDIO_IDLE: + //------------------ + if (fifo->outputTotal < fifo->inputTotal) { + + fifo->outputState = MSDIO_START; + } + break; + + //------------------ + case MSDIO_START: + //------------------ + + // Write the block to the media + if (lun->media->mappedWR) { + + MSDDriver_Callback(disktransfer, MED_STATUS_SUCCESS, 0, 0); + status = LUN_STATUS_SUCCESS; + } + else { + #ifdef MSDIO_WRITE10_CHUNK_SIZE + status = SBC_WRITE_CHUNK(lun, DWORDB(command->pLogicalBlockAddress), + fifo, MSDDriver_Callback, disktransfer); + #else + status = LUN_Write(lun, + DWORDB(command->pLogicalBlockAddress), + &fifo->pBuffer[fifo->outputNdx], + 1, + (TransferCallback) MSDDriver_Callback, + (void *) disktransfer); + #endif + } + + // Check operation result code + if (status != USBD_STATUS_SUCCESS) { + + TRACE_WARNING( + "RBC_Write10: Failed to start write - "); + + if (!SBCLunCanBeWritten(lun)) { + + TRACE_WARNING("?\n\r"); + SBC_UpdateSenseData(&(lun->requestSenseData), + SBC_SENSE_KEY_NOT_READY, + 0, + 0); + } + + fifo->outputState = MSDIO_ERROR; + } + else { + + // Prepare next state + fifo->outputState = MSDIO_WAIT; + } + break; // MSDIO_START + + //------------------ + case MSDIO_WAIT: + //------------------ + TRACE_INFO_WP("dWait "); + + // Check semaphore value + if (disktransfer->semaphore > 0) { + + // Take semaphore and move to next state + disktransfer->semaphore--; + fifo->outputState = MSDIO_NEXT; + } + break; + + //------------------ + case MSDIO_NEXT: + //------------------ + // Check operation result code + if (transfer->status != USBD_STATUS_SUCCESS) { + + TRACE_WARNING( + "RBC_Write10: Failed to write\n\r"); + SBC_UpdateSenseData(&(lun->requestSenseData), + SBC_SENSE_KEY_RECOVERED_ERROR, + SBC_ASC_TOO_MUCH_WRITE_DATA, + 0); + result = MSDD_STATUS_ERROR; + } + else { + + TRACE_INFO_WP("dNxt "); + + // Update transfer length and block address + + // Mapped memory, done + if (lun->media->mappedWR) { + + commandState->length = 0; + fifo->outputState = MSDIO_IDLE; + } + else { + + // Update output index + #ifdef MSDIO_WRITE10_CHUNK_SIZE + STORE_DWORDB(DWORDB(command->pLogicalBlockAddress) + + fifo->chunkSize/fifo->blockSize, + command->pLogicalBlockAddress); + MSDIOFifo_IncNdx(fifo->outputNdx, + fifo->chunkSize, + fifo->bufferSize); + fifo->outputTotal += fifo->chunkSize; + #else + STORE_DWORDB(DWORDB(command->pLogicalBlockAddress) + 1, + command->pLogicalBlockAddress); + MSDIOFifo_IncNdx(fifo->outputNdx, + fifo->blockSize, + fifo->bufferSize); + fifo->outputTotal += fifo->blockSize; + #endif + + // Start Next block + // - All data done? + if (fifo->outputTotal >= fifo->dataTotal) { + + fifo->outputState = MSDIO_IDLE; + commandState->length = 0; + TRACE_INFO_WP("dDone "); + } + // - Send next? + else if (fifo->outputTotal < fifo->inputTotal) { + + fifo->outputState = MSDIO_START; + TRACE_INFO_WP("dStart "); + } + // - Buffer Null? + else { + fifo->outputState = MSDIO_IDLE; + fifo->nullCnt ++; + + TRACE_DEBUG_WP("dfNull%d ", fifo->outputNdx); + } + } + } + break; // MSDIO_NEXT + + //------------------ + case MSDIO_ERROR: + //------------------ + break; + } + + return result; +} + +//------------------------------------------------------------------------------ +//! \brief Performs a READ (10) command on specified LUN. +//! +//! The data is first read from the media and then sent to the USB host. +//! This function operates asynchronously and must be called multiple +//! times to complete. A result code of MSDDriver_STATUS_INCOMPLETE +//! indicates that at least another call of the method is necessary. +//! \param lun Pointer to the LUN affected by the command +//! \param commandState Current state of the command +//! \return Operation result code (SUCCESS, ERROR, INCOMPLETE or PARAMETER) +//! \see MSDLun +//! \see MSDCommandState +//------------------------------------------------------------------------------ +static unsigned char SBC_Read10(MSDLun *lun, + MSDCommandState *commandState) +{ + unsigned char status; + unsigned char result = MSDD_STATUS_INCOMPLETE; + SBCRead10 *command = (SBCRead10 *) commandState->cbw.pCommand; + MSDTransfer *transfer = &(commandState->transfer); + MSDTransfer *disktransfer = &(commandState->disktransfer); + MSDIOFifo *fifo = &lun->ioFifo; + + // Init command state + if (commandState->state == 0) { + + commandState->state = SBC_STATE_READ; + + if (!SBCLunIsReady(lun)) { + + return MSDD_STATUS_RW; + } + else { + + // Initialize FIFO + fifo->dataTotal = commandState->length; + fifo->blockSize = lun->blockSize * lun->media->blockSize; + #ifdef MSDIO_READ10_CHUNK_SIZE + if ( fifo->dataTotal >= 64*1024 + && fifo->blockSize < MSDIO_READ10_CHUNK_SIZE) + fifo->chunkSize = MSDIO_READ10_CHUNK_SIZE; + else + fifo->chunkSize = fifo->blockSize; + #endif + fifo->fullCnt = 0; + fifo->nullCnt = 0; + + #ifdef MSDIO_FIFO_OFFSET + // Enable offset if total size >= 2*bufferSize + if (fifo->dataTotal / fifo->bufferSize >= 2) + fifo->bufferOffset = MSDIO_FIFO_OFFSET; + else + fifo->bufferOffset = 0; + #endif + + // Initialize FIFO output (USB) + fifo->outputNdx = 0; + fifo->outputTotal = 0; + fifo->outputState = MSDIO_IDLE; + transfer->semaphore = 0; + + // Initialize FIFO input (Disk) + fifo->inputNdx = 0; + fifo->inputTotal = 0; + fifo->inputState = MSDIO_START; + disktransfer->semaphore = 0; + } + } + + // Check length + if (commandState->length == 0) { + + // Perform the callback! + if (lun->dataMonitor) { + + lun->dataMonitor(1, fifo->dataTotal, fifo->nullCnt, fifo->fullCnt); + } + return MSDD_STATUS_SUCCESS; + } + + // Disk reading task + switch(fifo->inputState) { + + //------------------ + case MSDIO_IDLE: + //------------------ + if (fifo->inputTotal < fifo->dataTotal && + fifo->inputTotal - fifo->outputTotal < fifo->bufferSize) { + + fifo->inputState = MSDIO_START; + } + break; + + //------------------ + case MSDIO_START: + //------------------ + // Read one block of data from the media + if (lun->media->mappedRD) { + + // Directly write, no read needed + MSDDriver_Callback(disktransfer, MED_STATUS_SUCCESS, 0, 0); + status = LUN_STATUS_SUCCESS; + } + else { + #ifdef MSDIO_READ10_CHUNK_SIZE + status = SBC_READ_CHUNK(lun, DWORDB(command->pLogicalBlockAddress), + fifo, MSDDriver_Callback, disktransfer); + #else + status = LUN_Read(lun, + DWORDB(command->pLogicalBlockAddress), + &fifo->pBuffer[fifo->inputNdx], + 1, + (TransferCallback) MSDDriver_Callback, + (void *)disktransfer); + #endif + } + + // Check operation result code + if (status != LUN_STATUS_SUCCESS) { + + TRACE_WARNING("RBC_Read10: Failed to start reading\n\r"); + + if (SBCLunIsReady(lun)) { + + SBC_UpdateSenseData(&(lun->requestSenseData), + SBC_SENSE_KEY_NOT_READY, + SBC_ASC_LOGICAL_UNIT_NOT_READY, + 0); + } + + fifo->inputState = MSDIO_ERROR; + } + else { + + TRACE_INFO_WP("dRd "); + + // Move to next command state + fifo->inputState = MSDIO_WAIT; + } + break; // MSDIO_START + + //------------------ + case MSDIO_WAIT: + //------------------ + // Check semaphore value + if (disktransfer->semaphore > 0) { + + TRACE_INFO_WP("dOk "); + + // Take semaphore and move to next state + disktransfer->semaphore--; + fifo->inputState = MSDIO_NEXT; + } + break; + + //------------------ + case MSDIO_NEXT: + //------------------ + // Check the operation result code + if (disktransfer->status != USBD_STATUS_SUCCESS) { + + TRACE_WARNING( + "RBC_Read10: Failed to read media\n\r"); + SBC_UpdateSenseData(&(lun->requestSenseData), + SBC_SENSE_KEY_RECOVERED_ERROR, + SBC_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE, + 0); + result = MSDD_STATUS_ERROR; + } + else { + + TRACE_INFO_WP("dNxt "); + + if (lun->media->mappedRD) { + + // All data is ready + fifo->inputState = MSDIO_IDLE; + fifo->inputTotal = fifo->dataTotal; + } + else { + + // Update block address + #ifdef MSDIO_READ10_CHUNK_SIZE + STORE_DWORDB(DWORDB(command->pLogicalBlockAddress) + + fifo->chunkSize/fifo->blockSize, + command->pLogicalBlockAddress); + + // Update input index + MSDIOFifo_IncNdx(fifo->inputNdx, + fifo->chunkSize, + fifo->bufferSize); + fifo->inputTotal += fifo->chunkSize; + #else + // Update block address + STORE_DWORDB(DWORDB(command->pLogicalBlockAddress) + 1, + command->pLogicalBlockAddress); + + // Update input index + MSDIOFifo_IncNdx(fifo->inputNdx, + fifo->blockSize, + fifo->bufferSize); + fifo->inputTotal += fifo->blockSize; + #endif + + // Start Next block + // - All Data done? + if (fifo->inputTotal >= fifo->dataTotal) { + + TRACE_INFO_WP("dDone "); + fifo->inputState = MSDIO_IDLE; + } + // - Buffer full? + else if (fifo->inputNdx == fifo->outputNdx) { + + TRACE_INFO_WP("dfFull%d ", (int)fifo->inputNdx); + fifo->inputState = MSDIO_IDLE; + fifo->fullCnt ++; + } + // - More data to transfer? + else if (fifo->inputTotal < fifo->dataTotal) { + + TRACE_DEBUG_WP("dStart "); + fifo->inputState = MSDIO_START; + } + } + + } + + break; + + //------------------ + case MSDIO_ERROR: + //------------------ + break; + } + + // USB sending task + switch(fifo->outputState) { + + //------------------ + case MSDIO_IDLE: + //------------------ + if (fifo->outputTotal < fifo->inputTotal) { + + #ifdef MSDIO_FIFO_OFFSET + // Offset buffer the input data + if (fifo->bufferOffset) { + if (fifo->inputTotal < fifo->bufferOffset) { + break; + } + fifo->bufferOffset = 0; + } + #endif + fifo->outputState = MSDIO_START; + } + break; + + //------------------ + case MSDIO_START: + //------------------ + // Should not start if there is any disk error + if (fifo->outputState == MSDIO_ERROR) { + + fifo->inputState = MSDIO_ERROR; + break; + } + + // Send the block to the host + if (lun->media->mappedRD) { + + status = MSDD_Write((void*) + ((lun->media->baseAddress + + (lun->baseAddress + + DWORDB(command->pLogicalBlockAddress) + * lun->blockSize + ) + ) * lun->media->blockSize + ), + commandState->length, + (TransferCallback) MSDDriver_Callback, + (void *) transfer); + } + else { + #ifdef MSDIO_READ10_CHUNK_SIZE + status = SBC_TX_CHUNK(fifo, MSDDriver_Callback, transfer); + #else + status = MSDD_Write(&fifo->pBuffer[fifo->outputNdx], + fifo->blockSize, + (TransferCallback) MSDDriver_Callback, + (void *) transfer); + #endif + } + // Check operation result code + if (status != USBD_STATUS_SUCCESS) { + + TRACE_WARNING( + "RBC_Read10: Failed to start to send\n\r"); + SBC_UpdateSenseData(&(lun->requestSenseData), + SBC_SENSE_KEY_HARDWARE_ERROR, + 0, + 0); + result = MSDD_STATUS_ERROR; + } + else { + + TRACE_INFO_WP("uTx "); + + // Move to next command state + fifo->outputState = MSDIO_WAIT; + } + break; // MSDIO_START + + //------------------ + case MSDIO_WAIT: + //------------------ + // Check semaphore value + if (transfer->semaphore > 0) { + + TRACE_INFO_WP("uOk "); + + // Take semaphore and move to next state + transfer->semaphore--; + fifo->outputState = MSDIO_NEXT; + } + break; + + //------------------ + case MSDIO_NEXT: + //------------------ + // Check operation result code + if (transfer->status != USBD_STATUS_SUCCESS) { + + TRACE_WARNING( + "RBC_Read10: Failed to send data\n\r"); + SBC_UpdateSenseData(&(lun->requestSenseData), + SBC_SENSE_KEY_HARDWARE_ERROR, + 0, + 0); + result = MSDD_STATUS_ERROR; + } + else { + + TRACE_INFO_WP("uNxt "); + + if (lun->media->mappedRD) { + + commandState->length = 0; + } + else { + + // Update output index + #ifdef MSDIO_READ10_CHUNK_SIZE + MSDIOFifo_IncNdx(fifo->outputNdx, + fifo->chunkSize, + fifo->bufferSize); + fifo->outputTotal += fifo->chunkSize; + #else + MSDIOFifo_IncNdx(fifo->outputNdx, + fifo->blockSize, + fifo->bufferSize); + fifo->outputTotal += fifo->blockSize; + #endif + + // Start Next block + // - All data done? + if (fifo->outputTotal >= fifo->dataTotal) { + + fifo->outputState = MSDIO_IDLE; + commandState->length = 0; + TRACE_INFO_WP("uDone "); + } + // - Buffer Null? + else if (fifo->inputNdx == fifo->outputNdx) { + + TRACE_INFO_WP("ufNull%d ", (int)fifo->outputNdx); + fifo->outputState = MSDIO_IDLE; + fifo->nullCnt ++; + } + // - Send next? + else if (fifo->outputTotal < fifo->inputTotal) { + + TRACE_DEBUG_WP("uStart "); + fifo->outputState = MSDIO_START; + } + } + + } + break; + + //------------------ + case MSDIO_ERROR: + //------------------ + break; + } + + return result; +} + +//------------------------------------------------------------------------------ +//! \brief Performs a READ CAPACITY (10) command. +//! +//! This function operates asynchronously and must be called multiple +//! times to complete. A result code of MSDD_STATUS_INCOMPLETE +//! indicates that at least another call of the method is necessary. +//! \param lun Pointer to the LUN affected by the command +//! \param commandState Current state of the command +//! \return Operation result code (SUCCESS, ERROR, INCOMPLETE or PARAMETER) +//! \see MSDLun +//! \see MSDCommandState +//------------------------------------------------------------------------------ +static unsigned char SBC_ReadCapacity10(MSDLun *lun, + MSDCommandState *commandState) +{ + unsigned char result = MSDD_STATUS_INCOMPLETE; + unsigned char status; + MSDTransfer *transfer = &(commandState->transfer); + + if (!SBCLunIsReady(lun)) { + + TRACE_INFO("SBC_ReadCapacity10: Not Ready!\n\r"); + return MSDD_STATUS_RW; + } + + // Initialize command state if needed + if (commandState->state == 0) { + + commandState->state = SBC_STATE_WRITE; + } + + // Identify current command state + switch (commandState->state) { + //------------------- + case SBC_STATE_WRITE: + //------------------- + // Start the write operation + status = MSDD_Write(&(lun->readCapacityData), + commandState->length, + (TransferCallback) MSDDriver_Callback, + (void *) transfer); + + // Check operation result code + if (status != USBD_STATUS_SUCCESS) { + + TRACE_WARNING( + "RBC_ReadCapacity: Cannot start sending data\n\r"); + result = MSDD_STATUS_ERROR; + } + else { + + // Proceed to next command state + TRACE_INFO_WP("Sending "); + commandState->state = SBC_STATE_WAIT_WRITE; + } + break; + + //------------------------ + case SBC_STATE_WAIT_WRITE: + //------------------------ + // Check semaphore value + if (transfer->semaphore > 0) { + + // Take semaphore and terminate command + transfer->semaphore--; + + if (transfer->status != USBD_STATUS_SUCCESS) { + + TRACE_WARNING("RBC_ReadCapacity: Cannot send data\n\r"); + result = MSDD_STATUS_ERROR; + } + else { + + TRACE_INFO_WP("Sent "); + result = MSDD_STATUS_SUCCESS; + } + commandState->length -= transfer->transferred; + } + break; + } + + return result; +} + +//------------------------------------------------------------------------------ +//! \brief Handles an INQUIRY command. +//! +//! This function operates asynchronously and must be called multiple +//! times to complete. A result code of MSDDriver_STATUS_INCOMPLETE +//! indicates that at least another call of the method is necessary. +//! \param lun Pointer to the LUN affected by the command +//! \param commandState Current state of the command +//! \return Operation result code (SUCCESS, ERROR, INCOMPLETE or PARAMETER) +//! \see MSDLun +//! \see MSDCommandState +//------------------------------------------------------------------------------ +static unsigned char SBC_Inquiry(MSDLun *lun, + MSDCommandState *commandState) +{ + unsigned char result = MSDD_STATUS_INCOMPLETE; + unsigned char status; + MSDTransfer *transfer = &(commandState->transfer); + + // Check if required length is 0 + if (commandState->length == 0) { + + // Nothing to do + result = MSDD_STATUS_SUCCESS; + } + // Initialize command state if needed + else if (commandState->state == 0) { + + commandState->state = SBC_STATE_WRITE; + + // Change additional length field of inquiry data + lun->inquiryData->bAdditionalLength + = (unsigned char) (commandState->length - 5); + } + + // Identify current command state + switch (commandState->state) { + //------------------- + case SBC_STATE_WRITE: + //------------------- + // Start write operation + status = MSDD_Write((void *) lun->inquiryData, + commandState->length, + (TransferCallback) MSDDriver_Callback, + (void *) transfer); + + // Check operation result code + if (status != USBD_STATUS_SUCCESS) { + + TRACE_WARNING( + "SPC_Inquiry: Cannot start sending data\n\r"); + result = MSDD_STATUS_ERROR; + } + else { + + // Proceed to next state + TRACE_INFO_WP("Sending "); + commandState->state = SBC_STATE_WAIT_WRITE; + } + break; + + //------------------------ + case SBC_STATE_WAIT_WRITE: + //------------------------ + // Check the semaphore value + if (transfer->semaphore > 0) { + + // Take semaphore and terminate command + transfer->semaphore--; + + if (transfer->status != USBD_STATUS_SUCCESS) { + + TRACE_WARNING( + "SPC_Inquiry: Data transfer failed\n\r"); + result = MSDD_STATUS_ERROR; + } + else { + + TRACE_INFO_WP("Sent "); + result = MSDD_STATUS_SUCCESS; + } + + // Update length field + commandState->length -= transfer->transferred; + } + break; + } + + return result; +} + +//------------------------------------------------------------------------------ +//! \brief Performs a REQUEST SENSE command. +//! +//! This function operates asynchronously and must be called multiple +//! times to complete. A result code of MSDDriver_STATUS_INCOMPLETE +//! indicates that at least another call of the method is necessary. +//! \param lun Pointer to the LUN affected by the command +//! \param commandState Current state of the command +//! \return Operation result code (SUCCESS, ERROR, INCOMPLETE or PARAMETER) +//! \see MSDLun +//! \see MSDCommandState +//------------------------------------------------------------------------------ +static unsigned char SBC_RequestSense(MSDLun *lun, + MSDCommandState *commandState) +{ + unsigned char result = MSDD_STATUS_INCOMPLETE; + unsigned char status; + MSDTransfer *transfer = &(commandState->transfer); + + // Check if requested length is zero + if (commandState->length == 0) { + + // Nothing to do + result = MSDD_STATUS_SUCCESS; + } + // Initialize command state if needed + else if (commandState->state == 0) { + + commandState->state = SBC_STATE_WRITE; + } + + // Identify current command state + switch (commandState->state) { + //------------------- + case SBC_STATE_WRITE: + //------------------- + // Start transfer + status = MSDD_Write(&(lun->requestSenseData), + commandState->length, + (TransferCallback) MSDDriver_Callback, + (void *) transfer); + + // Check result code + if (status != USBD_STATUS_SUCCESS) { + + TRACE_WARNING( + "RBC_RequestSense: Cannot start sending data\n\r"); + result = MSDD_STATUS_ERROR; + } + else { + + // Change state + commandState->state = SBC_STATE_WAIT_WRITE; + } + break; + + //------------------------ + case SBC_STATE_WAIT_WRITE: + //------------------------ + // Check the transfer semaphore + if (transfer->semaphore > 0) { + + // Take semaphore and finish command + transfer->semaphore--; + + if (transfer->status != USBD_STATUS_SUCCESS) { + + result = MSDD_STATUS_ERROR; + } + else { + + result = MSDD_STATUS_SUCCESS; + } + + // Update length + commandState->length -= transfer->transferred; + } + break; + } + + return result; +} + +//------------------------------------------------------------------------------ +//! \brief Performs a MODE SENSE (6) command. +//! +//! This function operates asynchronously and must be called multiple +//! times to complete. A result code of MSDDriver_STATUS_INCOMPLETE +//! indicates that at least another call of the method is necessary. +//! \param lun Pointer to the LUN affected by the command +//! \param commandState Current state of the command +//! \return Operation result code (SUCCESS, ERROR, INCOMPLETE or PARAMETER) +//! \see MSDLun +//! \see MSDCommandState +//------------------------------------------------------------------------------ +static unsigned char SBC_ModeSense6(MSDLun *lun, MSDCommandState *commandState) +{ + unsigned char result = MSDD_STATUS_INCOMPLETE; + unsigned char status; + MSDTransfer *transfer = &(commandState->transfer); + + if (!SBCLunIsReady(lun)) { + + TRACE_INFO("SBC_ModeSense6: Not Ready!\n\r"); + return MSDD_STATUS_RW; + } + + // Check if mode page is supported + if (((SBCCommand *) commandState->cbw.pCommand)->modeSense6.bPageCode + != SBC_PAGE_RETURN_ALL) { + + return MSDD_STATUS_PARAMETER; + } + + // Initialize command state if needed + if (commandState->state == 0) { + + commandState->state = SBC_STATE_WRITE; + } + + // Check current command state + switch (commandState->state) { + //------------------- + case SBC_STATE_WRITE: + //------------------- + // Start transfer + status = MSDD_Write((void *) &modeParameterHeader6, + commandState->length, + (TransferCallback) MSDDriver_Callback, + (void *) transfer); + + // Check operation result code + if (status != USBD_STATUS_SUCCESS) { + + TRACE_WARNING( + "SPC_ModeSense6: Cannot start data transfer\n\r"); + result = MSDD_STATUS_ERROR; + } + else { + + // Proceed to next state + commandState->state = SBC_STATE_WAIT_WRITE; + } + break; + + //------------------------ + case SBC_STATE_WAIT_WRITE: + //------------------------ + TRACE_INFO_WP("Wait "); + + // Check semaphore value + if (transfer->semaphore > 0) { + + // Take semaphore and terminate command + transfer->semaphore--; + + if (transfer->status != USBD_STATUS_SUCCESS) { + + TRACE_WARNING( + "SPC_ModeSense6: Data transfer failed\n\r"); + result = MSDD_STATUS_ERROR; + } + else { + + result = MSDD_STATUS_SUCCESS; + } + + // Update length field + commandState->length -= transfer->transferred; + + } + break; + } + + return result; +} + +//------------------------------------------------------------------------------ +//! \brief Performs a TEST UNIT READY COMMAND command. +//! \param lun Pointer to the LUN affected by the command +//! \return Operation result code (SUCCESS, ERROR, INCOMPLETE or PARAMETER) +//! \see MSDLun +//------------------------------------------------------------------------------ +static unsigned char SBC_TestUnitReady(MSDLun *lun) +{ + unsigned char result = MSDD_STATUS_RW; + unsigned char senseKey = SBC_SENSE_KEY_NO_SENSE, + addSenseCode = 0, + addSenseCodeQual = 0; + + // Check current media state + if (lun->status < LUN_CHANGED) { + + TRACE_INFO_WP("Ejc "); + senseKey = SBC_SENSE_KEY_NOT_READY; + addSenseCode = SBC_ASC_MEDIUM_NOT_PRESENT; + } + else if (lun->status == LUN_CHANGED) { + + TRACE_INFO_WP("Chg "); + senseKey = SBC_SENSE_KEY_UNIT_ATTENTION; + addSenseCode = SBC_ASC_NOT_READY_TO_READY_CHANGE; + lun->status = LUN_READY; + } + else { + + switch(lun->media->state) { + //------------------- + case MED_STATE_READY: + //------------------- + // Nothing to do + TRACE_INFO_WP("Rdy "); + result = MSDD_STATUS_SUCCESS; + break; + + //------------------ + case MED_STATE_BUSY: + //------------------ + TRACE_INFO_WP("Bsy "); + senseKey = SBC_SENSE_KEY_NOT_READY; + break; + + //------ + default: + //------ + TRACE_INFO_WP("? "); + senseKey = SBC_SENSE_KEY_NOT_READY; + addSenseCode = SBC_ASC_MEDIUM_NOT_PRESENT; + break; + } + } + SBC_UpdateSenseData(&(lun->requestSenseData), + senseKey, + addSenseCode, + addSenseCodeQual); + + return result; +} + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//! \brief Updates the sense data of a LUN with the given key and codes +//! \param requestSenseData Pointer to the sense data to update +//! \param senseKey Sense key +//! \param additionalSenseCode Additional sense code +//! \param additionalSenseCodeQualifier Additional sense code qualifier +//------------------------------------------------------------------------------ +void SBC_UpdateSenseData(SBCRequestSenseData *requestSenseData, + unsigned char senseKey, + unsigned char additionalSenseCode, + unsigned char additionalSenseCodeQualifier) +{ + requestSenseData->bSenseKey = senseKey; + requestSenseData->bAdditionalSenseCode = additionalSenseCode; + requestSenseData->bAdditionalSenseCodeQualifier + = additionalSenseCodeQualifier; +} + +//------------------------------------------------------------------------------ +//! \brief Return information about the transfer length and direction expected +//! by the device for a particular command. +//! \param command Pointer to a buffer holding the command to evaluate +//! \param length Expected length of the data transfer +//! \param type Expected direction of data transfer +//! \param lun Pointer to the LUN affected by the command +//------------------------------------------------------------------------------ +unsigned char SBC_GetCommandInformation(void *command, + unsigned int *length, + unsigned char *type, + MSDLun *lun) +{ + SBCCommand *sbcCommand = (SBCCommand *) command; + unsigned char isCommandSupported = 1; + + // Identify command + switch (sbcCommand->bOperationCode) { + //--------------- + case SBC_INQUIRY: + //--------------- + (*type) = MSDD_DEVICE_TO_HOST; + + // Allocation length is stored in big-endian format + (*length) = WORDB(sbcCommand->inquiry.pAllocationLength); + break; + + //-------------------- + case SBC_MODE_SENSE_6: + //-------------------- + (*type) = MSDD_DEVICE_TO_HOST; + if (sbcCommand->modeSense6.bAllocationLength > + sizeof(SBCModeParameterHeader6)) { + + *length = sizeof(SBCModeParameterHeader6); + } + else { + + *length = sbcCommand->modeSense6.bAllocationLength; + } + break; + + //------------------------------------ + case SBC_PREVENT_ALLOW_MEDIUM_REMOVAL: + //------------------------------------ + (*type) = MSDD_NO_TRANSFER; + break; + + //--------------------- + case SBC_REQUEST_SENSE: + //--------------------- + (*type) = MSDD_DEVICE_TO_HOST; + (*length) = sbcCommand->requestSense.bAllocationLength; + break; + + //----------------------- + case SBC_TEST_UNIT_READY: + //----------------------- + (*type) = MSDD_NO_TRANSFER; + break; + + //--------------------- + case SBC_READ_CAPACITY_10: + //--------------------- + (*type) = MSDD_DEVICE_TO_HOST; + (*length) = sizeof(SBCReadCapacity10Data); + break; + + //--------------- + case SBC_READ_10: + //--------------- + (*type) = MSDD_DEVICE_TO_HOST; + (*length) = WORDB(sbcCommand->read10.pTransferLength) + * lun->blockSize * lun->media->blockSize; + break; + + //---------------- + case SBC_WRITE_10: + //---------------- + (*type) = MSDD_HOST_TO_DEVICE; + (*length) = WORDB(sbcCommand->write10.pTransferLength) + * lun->blockSize * lun->media->blockSize; + break; + + //----------------- + case SBC_VERIFY_10: + //----------------- + (*type) = MSDD_NO_TRANSFER; + break; + #if 0 + //--------------------- + case SBC_READ_FORMAT_CAPACITIES: + //--------------------- + (*type) = MSDD_DEVICE_TO_HOST; + (*length) = 1; + break; + #endif + //------ + default: + //------ + isCommandSupported = 0; + } + + // If length is 0, no transfer is expected + if ((*length) == 0) { + + (*type) = MSDD_NO_TRANSFER; + } + + return isCommandSupported; +} + +//------------------------------------------------------------------------------ +//! \brief Processes a SBC command by dispatching it to a subfunction. +//! \param lun Pointer to the affected LUN +//! \param commandState Pointer to the current command state +//! \return Operation result code +//------------------------------------------------------------------------------ +unsigned char SBC_ProcessCommand(MSDLun *lun, + MSDCommandState *commandState) +{ + unsigned char result = MSDD_STATUS_INCOMPLETE; + SBCCommand *command = (SBCCommand *) commandState->cbw.pCommand; + + // Identify command + switch (command->bOperationCode) { + //--------------- + case SBC_READ_10: + //--------------- + TRACE_DEBUG_WP("Read(10) "); + + // Perform the Read10 command + result = SBC_Read10(lun, commandState); + break; + + //---------------- + case SBC_WRITE_10: + //---------------- + TRACE_DEBUG_WP("Write(10) "); + + // Perform the Write10 command + result = SBC_Write10(lun, commandState); + break; + + //--------------------- + case SBC_READ_CAPACITY_10: + //--------------------- + TRACE_INFO_WP("RdCapacity(10) "); + + // Perform the ReadCapacity command + result = SBC_ReadCapacity10(lun, commandState); + break; + + //--------------------- + case SBC_VERIFY_10: + //--------------------- + TRACE_INFO_WP("Verify(10) "); + + // Flush media + MED_Flush(lun->media); + result = MSDD_STATUS_SUCCESS; + break; + + //--------------- + case SBC_INQUIRY: + //--------------- + TRACE_INFO_WP("Inquiry "); + + // Process Inquiry command + result = SBC_Inquiry(lun, commandState); + break; + + //-------------------- + case SBC_MODE_SENSE_6: + //-------------------- + TRACE_INFO_WP("ModeSense(6) "); + + // Process ModeSense6 command + result = SBC_ModeSense6(lun, commandState); + break; + + //----------------------- + case SBC_TEST_UNIT_READY: + //----------------------- + TRACE_INFO_WP("TstUnitRdy "); + + // Process TestUnitReady command + //MED_Flush(lun->media); + result = SBC_TestUnitReady(lun); + break; + + //--------------------- + case SBC_REQUEST_SENSE: + //--------------------- + TRACE_INFO_WP("ReqSense "); + + // Perform the RequestSense command + result = SBC_RequestSense(lun, commandState); + break; + + //------------------------------------ + case SBC_PREVENT_ALLOW_MEDIUM_REMOVAL: + //------------------------------------ + TRACE_INFO_WP("PrevAllowRem "); + + // Check parameter + result = command->mediumRemoval.bPrevent ? + MSDD_STATUS_PARAMETER : MSDD_STATUS_SUCCESS; + break; + #if 0 + //------------------------------------ + case SBC_READ_FORMAT_CAPACITIES: + //------------------------------------ + TRACE_INFO_WP("RdFmtCap "); + if (!SBCLunIsReady(lun)) { + + result = MSDD_STATUS_RW; + break; + } + #endif + //------ + default: + //------ + result = MSDD_STATUS_PARAMETER; + } + + return result; +} diff --git a/usb/device/massstorage/SBCMethods.h b/usb/device/massstorage/SBCMethods.h new file mode 100644 index 0000000..1ef199e --- /dev/null +++ b/usb/device/massstorage/SBCMethods.h @@ -0,0 +1,111 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// !Purpose +/// +/// SCSI commands implementation. +/// +/// !Usage +/// +/// -# After a CBW is received from host, use SBC_GetCommandInformation to check +/// if the command is supported, and get the command length and type +/// information before processing it. +/// -# Then SBC_ProcessCommand can be used to handle a valid command, to +/// perform the command operations. +/// -# SBC_UpdateSenseData is used to update the sense data that will be sent +/// to host. +//------------------------------------------------------------------------------ + +#ifndef SBCMETHODS_H +#define SBCMETHODS_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "SBC.h" +#include "MSDLun.h" +#include "MSDDStateMachine.h" + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "SBC Command States" +/// This page lists the possible states of a SBC command. +/// +/// !States +/// - SBC_STATE_READ +/// - SBC_STATE_WAIT_READ +/// - SBC_STATE_WRITE +/// - SBC_STATE_WAIT_WRITE +/// - SBC_STATE_NEXT_BLOCK + +/// Start of reading bulk data +#define SBC_STATE_READ 0x01 +/// Waiting for the bulk data reading complete +#define SBC_STATE_WAIT_READ 0x02 +/// Read error state +#define SBC_STATE_READ_ERROR 0x03 +/// Start next read block +#define SBC_STATE_NEXT_READ 0x04 +/// Start writing bulk data to host +#define SBC_STATE_WRITE 0x05 +/// Waiting for the bulk data sending complete +#define SBC_STATE_WAIT_WRITE 0x06 +/// Write error state +#define SBC_STATE_WRITE_ERROR 0x07 +/// Start next write block +#define SBC_STATE_NEXT_WRITE 0x08 +/// Start next command block +#define SBC_STATE_NEXT_BLOCK 0x09 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +void SBC_UpdateSenseData(SBCRequestSenseData *requestSenseData, + unsigned char senseKey, + unsigned char additionalSenseCode, + unsigned char additionalSenseCodeQualifier); + +unsigned char SBC_GetCommandInformation(void *command, + unsigned int *length, + unsigned char *type, + MSDLun *lun); + +unsigned char SBC_ProcessCommand(MSDLun *lun, + MSDCommandState *commandState); + +#endif //#ifndef SBCMETHODS_H + diff --git a/usb/device/massstorage/massstorage.dir b/usb/device/massstorage/massstorage.dir new file mode 100644 index 0000000..bc793c5 --- /dev/null +++ b/usb/device/massstorage/massstorage.dir @@ -0,0 +1,1005 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// +/// !!!Purpose +/// +/// This directory provides definitions, structs and functions for a USB Mass +/// Storage %device (MSD) - USB Mass Storage demo. +/// +/// !!!Contents +/// +/// There are four things for the implement of the USB MSD driver: +/// - Implement the MSD driver structs and functions for the %device, +/// to initialize, to handle MSD-specific requests and dispach +/// standard requests in USBD callbacks, to read/write through assigned USB +/// %endpoints, +/// - Create the MSD device's descriptors that should be passed to +/// the USBDDriver instance on initialization, so that the host can +/// recognize the %device as a USB Mass Storage %device. +/// - Implement state machine for MSD command/data/status handling. +/// - Implement storage media interface for MSD disk accessing. +/// +/// For more information about what a particular group contains, please refer to +/// "USB MSD Driver". +//------------------------------------------------------------------------------ + +/** + \page "USB MSD Driver" + This page describes how to use the USB framework to produce a USB MSD driver, + which appears as a USB Disk on host. + + !!!References + - "AT91 USB device framework" + - "USB Device Enumeration" + - + Universal Serial Bus Revision 2.0 specification + (.zip file format, size 9.80 MB) + - + Mass Storage Overview 1.2 + - + Mass Storage Bulk Only 1.0 + - SCSI Standards + - SCSI Block Commands - 3 (SBC-3) + - SCSI Primary Commands - 4 (SPC-4) + + !!!Mass Storage Class Basic + This section gives generic details on the MSD class. + + See "USB MSD Basic". + + !!!Mass Storage SCSI Disk + + This section describes how to implement a USB disk by using the MSD class with + the SCSI transparent command set and the AT91 USB Framework. For more + information about the framework, please refer to the "AT91 USB device + framework" application note; details about the USB and the Mass Storage class + can be found in the USB specification 2.0 and the MSC Bulk-Only Transport + specification 1.0 documents, respectively. + + The software example provided with this document uses the ram disk of the chip + as its storage medium, but has been designed in a modular way to allow easy + modification for any medium, e.g. internal flash, DataFlash, SD card, external + Flash chip. + + !!Architecture + The MSD driver is based on framework, See "USB Device Framework Architecture". + + The internal architecture of the Application layer is extended for the + following factors: + - The Command/Data/Status flow described in "USB MSD Basic" requires the use + of a #state machine# for non-blocking operation. + - The example software has been designed to be easily extended with support + for other media. + - The example software has been designed to support multiple LUNs on one or + more media. + + \image MSDAppArch.png "Application Layer Architecture" + + !!Descriptors + There are no class-specific descriptors for a device using the MSD class with + the Bulk-only transport protocol. This section thus only details the values + which must be set in the standard descriptors. + + !Device Descriptor +\code +static const USBDeviceDescriptor deviceDescriptor = { + + sizeof(USBDeviceDescriptor), // bLength: Size of descriptor (18 bytes) + USBGenericDescriptor_DEVICE, // bDescriptorType: Device descriptor + USBDeviceDescriptor_USB2_00, // bcdUSB: USB 2.00 + MSDeviceDescriptor_CLASS, // bDeviceClass: 0 + MSDeviceDescriptor_SUBCLASS, // bDeviceSubClass: 0 + MSDeviceDescriptor_PROTOCOL, // bDeviceProtocol: 0 + BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0), // bMaxPacketSize0: Max Size EP0 + MSDDriverDescriptors_VENDORID, // idVendor: Vendor ID ATMEL (0x03eb) + MSDDriverDescriptors_PRODUCTID,// idProduct: Product ID (0x6202) + MSDDriverDescriptors_RELEASE, // bcdDevice: 0x0001, Version 0.01 + 1, // iManufacturer: Manufacturer string (manufacturerDescriptor) index. + 2, // iProduct: Product string (productDescriptor) index. + 3, // iSerialNumber: Serial number string (serialNumberDescriptor) index. + 1 // bNumConfigurations: Device has one possible configuration. +}; +\endcode + Note that the Vendor ID is a special value attributed by the USB-IF + organization. The product ID can be chosen freely by the vendor. + + !Configuration Descriptor + The descriptors are defined as: +\code +const MSDConfigurationDescriptors configurationDescriptorsFS; +\endcode + + Configuration descriptor +\code +// Standard configuration descriptor. +{ + sizeof(USBConfigurationDescriptor), // bLength: 9 bytes + USBGenericDescriptor_CONFIGURATION, // bDescriptorType: Configuration + sizeof(MSDConfigurationDescriptors),// wTotalLength: Length of all + 1, // bNumInterface: Configuration has one interface. + 1, // bConfigurationValue: This is configuration #1. + 0, // iConfiguration: No string descriptor for configuration. + BOARD_USB_BMATTRIBUTES, // bmAttributes: Power and remote wakeup + USBConfigurationDescriptor_POWER(100) // 100mA max power +}, +\endcode + + !Interface Descriptor + The interface descriptor must indicate several features: + - #Mass Storage Device# class code (08h) in the }bInterfaceClass} field + - #Data Transport Protocol# code in the }bInterfaceSubclass} field + - #Bulk-Only Transport# protocol code (50h) in the }bInterfaceProtocol} field + This example uses the SCSI transparent command set (code 06h). This is the + most appropriate setting for a Flash %device, given that the RBC command set + is not supported by Microsoft Windows. +\code +// Mass Storage interface descriptor. +{ + sizeof(USBInterfaceDescriptor), // bLength: Size of descriptor(9 bytes) + USBGenericDescriptor_INTERFACE, // bDescriptorType: Interface descriptor + 0, // bInterfaceNumber: This is interface #0. + 0, // bAlternateSetting: This is alternate setting #0. + 2, // bNumEndpoints: Interface uses two endpoints. + MSInterfaceDescriptor_CLASS, // bInterfaceClass: Mass Storage Device Class + MSInterfaceDescriptor_SCSI, // bInterfaceSubClass: SCSI transparent command + MSInterfaceDescriptor_BULKONLY,// bInterfaceProtocol: Bulk-Only transport + 0 // iInterface: No string descriptor for interface. +}, +\endcode + + !Endpoint Descriptors + No special requirements on these apart from being Bulk-IN and Bulk-OUT. +\code +// Bulk-OUT endpoint descriptor +{ + sizeof(USBEndpointDescriptor), // bLength: 7 bytes + USBGenericDescriptor_ENDPOINT, // bDescriptorType: Endpoint descriptor + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + MSDDriverDescriptors_BULKOUT), // bEndpointAddress: OUT 0x01 + USBEndpointDescriptor_BULK, // bmAttributes: Bulk endpoint + MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(MSDDriverDescriptors_BULKOUT), + USBEndpointDescriptor_MAXBULKSIZE_FS), // wMaxPacketSize: 64 bytes + 0 // bInterval: Must be 0 for full-speed Bulk endpoints. +}, +// Bulk-IN endpoint descriptor +{ + sizeof(USBEndpointDescriptor), // bLength: 7 bytes + USBGenericDescriptor_ENDPOINT, // bDescriptorType: Endpoint descriptor + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + MSDDriverDescriptors_BULKIN), // bEndpointAddress: IN 0x82 + USBEndpointDescriptor_BULK, // bmAttributes: Bulk endpoint + MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(MSDDriverDescriptors_BULKIN), + USBEndpointDescriptor_MAXBULKSIZE_FS), // wMaxPacketSize: 64 + 0 // bInterval: Must be 0 for full-speed Bulk endpoints. +} +\endcode + + !String descriptors + Several descriptors can be commented with a String descriptor. The latter are + completely optional and do not influence the detection of the device by the + operating system. Whether or not to include them is entirely up to the + programmer. + + There is one exception to this rule when using the MSD class. According to the + specification, there must be a Serial Number string. It must contains at least + 12 characters, and these characters must only be either letters (a-z, A-Z) or + numbers (0-9). This cause no problem for the driver in practice, but this is a + strict requirement for certification. Also remember that string descriptors + use the Unicode format. + + See manufacturerDescriptor, productDescriptor, serialNumberDescriptor. + + !!Class-specific Requests + There are two Mass Storage-specific requests: + - GetMaxLUN + - Bulk-Only Mass Storage Reset + + Standard requests can be forwarded to the USBDDriver_RequestHandler, with one + exception: #CLEAR_FEATURE#. This is necessary for Reset Recovery sequence. + + !ClearFeature + As previously stated, the CLEAR_FEATURE request must be handled in a + particular way, depending on whether or not the device is waiting for a Reset + Recovery sequence. If it is, then CLEAR_FEATURE requests to unhalt a Bulk + endpoint must be discarded. + + In the example software, this behavior is indicated by a boolean field in the + driver structure, named waitResetRecovery. The handler only has to check this + field value to decide whether to forward the request to the standard handler + or to discard it. +\code +// Handle requests +switch (USBGenericRequest_GetRequest(request)) { +//--------------------- +case USBGenericRequest_CLEARFEATURE: +//--------------------- + + switch (USBFeatureRequest_GetFeatureSelector(request)) { + + //--------------------- + case USBFeatureRequest_ENDPOINTHALT: + //--------------------- + + // Do not clear the endpoint halt status if the device is waiting + // for a reset recovery sequence + if (!msdDriver.waitResetRecovery) { + + // Forward the request to the standard handler + USBDDriver_RequestHandler(&usbdDriver, request); + } + + USBD_Write(0, 0, 0, 0, 0); + break; + + //------ + default: + //------ + // Forward the request to the standard handler + USBDDriver_RequestHandler(&usbdDriver, request); + } + break; +} +\endcode + + !GetMaxLUN + Usually, the first request issued by the host right after the enumeration + phase will be a GET_MAX_LUN request. It enables it to discover how many + different logical units the device has; each of these LUNs can then be queried + in turn by the host when needed. + + After the request is received by the device, it should return one byte of data + indicating the maximum Logical Unit Number (LUN). It is equal to the number of + LUNs used by the device minus one. For example, a device with three LUNs shall + return a GET_MAX_LUN value of two. + + Sending this byte is done by calling the USBD_Write method on Control endpoint + 0. Note that the data must be held in a permanent buffer (since the transfer + is asynchronous); in the software provided with this application note, a + dedicated field is used in the driver structure (MSDDriver) to store this + value. + + In addition due to the }Mass Storage Bulk-Only Transport} specification the + }wValue} should be 0, }wLength} should be 1, }wIndex} should be the interface + number also 0. A request which does not comply to these requirements must be + STALLed. +\code +//------------------- +case MSD_GET_MAX_LUN: +//------------------- + // Check request parameters + if ((request->wValue == 0) + && (request->wIndex == 0) + && (request->wLength == 1)) { + USBD_Write(0, &(msdDriver.maxLun), 1, 0, 0); + } + else { + USBD_Stall(0); + } + break; +\endcode + + !Bulk-Only Mass Storage Reset + The host issues #RESET# requests to return the MSD driver of the device to its + initial state, i.e., ready to receive a new command. However, this request + does not impact the USB controller state; in particular, endpoints must not be + reset. This means the data toggle bit must not be altered, and Halted endpoint + must not be returned to a normal state. After processing the reset, the device + must return a Zero-Length Packet (ZLP) to acknowledge the SETUP transfer. + + Like GET_MAX_LUN, this request must be issued with specific parameters - + wValue, wIndex and wLength should be zero. A request which does not have valid + values in its field must be acknowledged with a STALL handshake from the + %device. + + The handler for this request must return the state machine to its initial state. +\code +//----------------------- +case MSD_BULK_ONLY_RESET: +//----------------------- + // Check parameters + if ((request->wValue == 0) + && (request->wIndex == 0) + && (request->wLength == 0)) { + + // Reset the MSD driver + MSDDriver_Reset(); + USBD_Write(0, 0, 0, 0, 0); + } + else { + USBD_Stall(0); + } + break; +\endcode + + !!State Machine + ... + + !Rationale + A state machine is necessary for #non-blocking# operation of the driver. As + previously stated, there are three steps when processing a command: + - Reception of the CBW + - Processing of the command (with data transfers if required) + - Emission of the CSW + + Without a state machine, the program execution would be stopped at each step + to wait for transfers completion or command processing. For example, reception + of a CBW does not always happen immediately (the host does not have to issue + commands regularly) and can block the system for a long time. + + Developing an asynchronous design based on a state machine is made easier when + using Atmel "AT91 USB device framework", as most methods are asynchronous. For + example, a write operation (using the USBD_Write function) returns + immediately; a callback function can then be invoked when the transfer + actually completes. + + !States + Apart from the three states corresponding to the command processing flow (CBW, + command processing and CSW), two more can be identified. The + reception/emission of CBW/CSW will be broken down into two different states: + the first state is used to issue the read/write operation, while the second + one waits for the transfer to finish. This can be done by monitoring a + "transfer complete" flag which is set using a callback function. + + In addition, some commands can be quite complicated to process: they may + require several consecutive data transfers mixed with media access. Each + command thus has its own second-tier state machine. During execution of a + command, the main state machine remains in the "processing" state, and + proceeds to the next one (CSW emission) only when the command is complete. + + Here is the states list: + - MSDDriver_STATE_READ_CBW: Start of CBW reception + (initial state after reset) + - MSDDriver_STATE_WAIT_CBW: Waiting for CBW reception + - MSDDriver_STATE_PROCESS_CBW: Command processing + - MSDDriver_STATE_SEND_CSW: Start of CSW emission + - MSDDriver_STATE_WAIT_CSW: Waiting for CSW emission + + A single function, named MSDDriver_StateMachine, is provided by the driver. It + must be called regularly during the program execution. The following + subsections describe the actions that must be performed during each state. + + \image MSDDriverStates.png "MSD Driver State Machine" + + #MSDDriver_STATE_READ_CBW# + + As said previously, this state is used to start the reception of a new Command + Block Wrapper. This is done using the USB_Read method of the USB framework. + The result code of the function is checked for any error; the + USB_STATUS_SUCCESS code indicates that the transfer has been successfully + started. +\code +//---------------------- +case MSDDriver_STATE_READ_CBW: +//---------------------- + // Start the CBW read operation + transfer->semaphore = 0; + status = USBD_Read(MSDDriverDescriptors_BULKOUT, + cbw, + MSD_CBW_SIZE, + (TransferCallback) MSDDriver_Callback, + (void *) transfer); + + // Check operation result code + if (status == USBD_STATUS_SUCCESS) { + + // If the command was successful, wait for transfer + msdDriver.state = MSDDriver_STATE_WAIT_CBW; + } + break; +\endcode + A callback function to invoke when the transfer is complete is provided to the + USBD_Read method, to update a MSDTransfer structure. This structure + indicates the transfer completion, the returned result code and the number of + transferred and remaining bytes. +\code +typedef struct { + unsigned int transferred; //!< Number of bytes transferred + unsigned int remaining; //!< Number of bytes not transferred + unsigned char semaphore; //!< Semaphore to indicate transfer completion + unsigned char status; //!< Operation result code +} MSDTransfer; +\endcode + The callback function is trivial and thus not listed here. + + #MSDDriver_STATE_WAIT_CBW# + + The first step here is to monitor the }semaphore} field of the MSDTransfer + structure (see above); this will enable detection of the transfer end. Please + note that this field must be declared as volatile in C, or accesses to it + might get optimized by the compiler; this can result in endless loops. + + If the transfer is complete, then the result code must be checked to see if + there was an error. If the operation is successful, the state machine can + proceed to command processing. Otherwise, it returns to the READ_CBW state. +\code +//---------------------- +case MSDDriver_STATE_WAIT_CBW: +//---------------------- + // Check transfer semaphore + if (transfer->semaphore > 0) { + + // Take semaphore and terminate transfer + transfer->semaphore--; + + // Check if transfer was successful + if (transfer->status == USBD_STATUS_SUCCESS) { + + // Process received command + msdDriver.state = MSDDriver_STATE_PROCESS_CBW; + } + else if (transfer->status == USBD_STATUS_RESET) { + + msdDriver.state = MSDDriver_STATE_READ_CBW; + } + else { + + msdDriver.state = MSDDriver_STATE_READ_CBW; + } + } + break; +\endcode + + #MSDDriver_STATE_PROCESS_CBW# + + Once the CBW has been received, its validity must be checked. A CBW is not + valid if: + - it has not been received right after a CSW was sent or a reset occured or + - it is not exactly 31 bytes long or + - its signature field is not equal to 43425355h + + The state machine prevents the first case from happening, so only the two + other cases have to be verified. + + The number of bytes transferred during a USBD_Read operation is passed as an + argument to the callback function, if one has been specified. As stated + previously, such a function is used to fill a MSDTransfer structure. + Therefore, it is trivial to check that the CBW is indeed 31 bytes by verifying + that the number of bytes transferred is 31, and that there are no remaining + bytes. The following table illustrates the three cases which may happen: +||Number of bytes transferred||Number of bytes remaining||Meaning +|transferred<31|remaining==0|CBW is too short +|transferred==31|remaining>0|CBW is too long +|transferred==31|remaining==0|CBW length is correct + + Checking the signature is simply done by comparing the dCBWSignature field + with the expected value (43425355h). + + If the CBW is not valid, then the device must immediately halt both Bulk + endpoints, to STALL further traffic from the host. In addition, it should stay + in this state until a Reset Recovery is performed by the host. This is done by + setting the waitResetRecovery flag in the MSDDriver structure. Finally, the + CSW status is set to report an error, and the state machine is returned to + MSDDriver_STATE_READ_CBW. + + Otherwise, if the CBW is correct, then the command can be processed. Remember + the CBW tag must be copied regardless of the validity of the CBW. + + Note that these steps are only necessary for a new command (remember commands + are asynchronous and are carried out in several calls, so a check can be + performed to avoid useless processing. A value of zero for the internal + command state indicates a new command. +\code +//------------------------- +case MSDDriver_STATE_PROCESS_CBW: +//------------------------- + // Check if this is a new command + if (commandState->state == 0) { + + // Copy the CBW tag + csw->dCSWTag = cbw->dCBWTag; + + // Check that the CBW is 31 bytes long + if ((transfer->transferred != MSD_CBW_SIZE) || + (transfer->remaining != 0)) { + + // Wait for a reset recovery + msdDriver.waitResetRecovery = 1; + + // Halt the Bulk-IN and Bulk-OUT pipes + USBD_Halt(MSDDriverDescriptors_BULKOUT); + USBD_Halt(MSDDriverDescriptors_BULKIN); + + csw->bCSWStatus = MSD_CSW_COMMAND_FAILED; + msdDriver.state = MSDDriver_STATE_READ_CBW; + + } + // Check the CBW Signature + else if (cbw->dCBWSignature != MSD_CBW_SIGNATURE) { + + // Wait for a reset recovery + msdDriver.waitResetRecovery = 1; + + // Halt the Bulk-IN and Bulk-OUT pipes + USBD_Halt(MSDDriverDescriptors_BULKOUT); + USBD_Halt(MSDDriverDescriptors_BULKIN); + + csw->bCSWStatus = MSD_CSW_COMMAND_FAILED; + msdDriver.state = MSDDriver_STATE_READ_CBW; + } + else { + + // Pre-process command + MSDDriver_PreProcessCommand(); + } + } + + // Process command + if (csw->bCSWStatus == MSDDriver_STATUS_SUCCESS) { + + if (MSDDriver_ProcessCommand()) { + + // Post-process command if it is finished + MSDDriver_PostProcessCommand(); + msdDriver.state = MSDDriver_STATE_SEND_CSW; + } + } + + break; +\endcode + + #MSDDriver_STATE_SEND_CSW# + + This state is similar to MSDDriver_STATE_READ_CBW, except that a write + operation is performed instead of a read and the CSW is sent, not the CBW. The + same callback function is used to fill the transfer structure, which is + checked in the next state: +\code +//---------------------- +case MSDDriver_STATE_SEND_CSW: +//---------------------- + // Set signature + csw->dCSWSignature = MSD_CSW_SIGNATURE; + + // Start the CSW write operation + status = USBD_Write(MSDDriverDescriptors_BULKIN, + csw, + MSD_CSW_SIZE, + (TransferCallback) MSDDriver_Callback, + (void *) transfer); + + // Check operation result code + if (status == USBD_STATUS_SUCCESS) { + + // Wait for end of transfer + msdDriver.state = MSDDriver_STATE_WAIT_CSW; + } + break; +\endcode + + #MSDDriver_STATE_WAIT_CSW# + + Again, this state is very similar to MSDDriver_STATE_WAIT_CBW. The only + difference is that the state machine is set to MSDDriver_STATE_READ_CBW + regardless of the operation result code: +\code +//---------------------- +case MSDDriver_STATE_WAIT_CSW: +//---------------------- + // Check transfer semaphore + if (transfer->semaphore > 0) { + + // Take semaphore and terminate transfer + transfer->semaphore--; + + // Read new CBW + msdDriver.state = MSDDriver_STATE_READ_CBW; + } + break; +\endcode + + !!Media + + USB MSD Media access is three-level abstraction. + + \image MSDMediaArch.png "Media Architecture" + + The bottom level is the specific driver for each media type (See memories). + + In the middle, a structure Media is used to hide which specific driver a media + instance is using. This enables transparent use of any media driver once it + has been initialized (See _Media). + + Finally, a LUN abstraction is made over the media structure to allow multiple + partitions over one media. This also makes it possible to place the LUN at any + address and use any block size. When performing a write or read operation on a + LUN, it forwards the operation to the underlying media while translating it to + the correct address and length. + + !Media Drivers + A media driver must provide several functions for: + - Reading data from the media + - Writing data on the media + - Handling interrupts on the media + The last function may be empty if the media does not require interrupts for + asynchronous operation, or if synchronous operation produces an acceptable + delay. + + In addition, it should also define a function for initializing a Media + structure with the correct values, as well as perform the necessary step for + the media to be useable. + + For the drivers see: + - MEDSdram.h: }Internal Flash Driver} + - MEDFlash.h: }SDRAM disk driver} + + !!SCSI Commands + + The example software described in this application note uses SCSI commands + with the MSD class, since this is the most appropriate setting for a Flash + device. This section details how SCSI commands are processed. + + !Documents + + There are several documents covering SCSI commands. In this application note, + the reference document used is SCSI Block Commands - 3 (SBC-3). However, it + makes many references to another SCSI document, SCSI Primary Commands - 4 + (SPC-4). Both are needed for full details on required commands. + + !Endianness + + SCSI commands use the big-endian format for storing word- and double word- + sized data. This means the Most Significant Bit (MSB) is stored at the + lowest address, and the Least Significant Bit (LSB) at the highest one. + + On ARM Thumb microcontrollers, the endianness of the core is selectable. + However, the little-endian mode is most often used. Therefore, SCSI command + data must be converted before being usable. This is done by declaring + word- and dword-sized fields as byte arrays, and then using a macro for + loading or storing data. Several of them are available in the provided + software: + - Load + - WORDB: Converts a big-endian word value to little-endian + - DWORDB: Converts a big-endian double-word value to little-endian + - Store + - STORE_WORDB: Stores a little-endian word value in big-endian format + - STORE_DWORDB: Stores a little-endian double-word value in big-endian format + + !Sense Data + + When an error happens during the execution of a command, it is recorded by the + device. The host may then issue a Request Sense command to retrieve + #Sense Data#, i.e., information about previous errors. + + While the sense data structure has many fields, only three are really + important. The first one is the Sense Key. It indicates the result of the last + command performed: success, media not ready, hardware error, etc. Two other + fields can then be specified to give a more accurate description of the + problem. They are named }Additional Sense Code} and }Additional Sense Code + Qualifier}. + + In the example application, each LUN has its own sense data. It is updated + during command execution if there is any error. + + !Commands + + The SBC-3 specification gives a list of mandatory and optional commands that + are relevant for a block device (like a Flash drive). In practice, only a + subset of the mandatory commands is effectively used by operating systems; + conversely, several commands which are supposed to be optional are required. + The software provided with this application note implements the following list + of commands: + - SBC-3 + - Prevent/Allow Medium Removal + - Read (10) + - Read Capacity (10) + - Verify (10) + - Write (10) + - SPC-4 + - Inquiry + - Mode Sense (6) + - Request Sense + - Test Unit Ready + The commands are actually processed in SBC_ProcessCommand. + + }Internal State Machine} + + As previously stated, most commands have an internal state machine to prevent + blocking the whole system during a data transfer (on the USB or when accessing + a media). A result code is used to indicate that the corresponding function + must be called again for the command to complete (MSDDriver_STATUS_SUCCESS). + + A command state structure is used by the driver to record several parameters + during command processing: +\code +typedef struct { + + MSDTransfer transfer; //!< Current transfer status + MSCbw cbw; //!< Received CBW + MSCsw csw; //!< CSW to send + unsigned char state; //!< Current command state + unsigned char postprocess; //!< Actions to perform when command is complete + unsigned int length; //!< Remaining length of command + +} MSDCommandState; +\endcode + + Note that the }state} field must be initialized when the command is first + called. A value of 0 means that no command is currently being executed. + + For the commands descriptions and implementation, please reffer to the SCSI + spec. and source code. + + Functions to handle SCSI commands: + - SBC_Inquiry + - SBC_Read10 + - SBC_ReadCapacity10 + - SBC_RequestSense + - SBC_TestUnitReady + - SBC_Write10 + - SBC_ModeSense6 + + !Command Processing + + }Flow} + + Command processing is actually divided into three phases in the example + software: + - Pre-processing: MSDDriver_PreProcessCommand + - Processing: MSDDriver_ProcessCommand + - Post-processing: MSDDriver_PostProcessCommand + + }The Thirteen Cases} + + There are basically three actions that should be performed depending on the + case: + - STALL the Bulk-IN endpoint + - STALL the Bulk-OUT endpoint + - Report a Phase Error in the CSW + + The table below lists all cases along with the actions which must be taken + after the command, including the correct length/direction of the transfer. The + following notation is used to characterize host and %device expectations: + + Data %Transfer Characterization +||Notation||Meaning||Notation||Meaning +|Hn|Host expects no data transfer|Dn|Device expects no data transfer +|Hi|Host expects to #receive# data|Di|Device expects to #send# data +|Ho|Host expects to #send# data|Do|Device expects to #receive# data +|Lh|Length of data expected by the host|Ld|Length of data expected by the %device + +|Hx=Dx|Host and %device agree on transfer length and direction (x is either n, i or o) +|Hx>Dx|Host and %device agree on transfer direction, host expects a larger transfer than %device +|HxDx|Host and %device disagree on transfer direction + + The Thirteen Cases +||\#||Case||Length||Residue||Direction||STALL IN?||STALL OUT?||Phase Error? +|1|Hn = Dn|0|0|Irrelevant| | | +|2|Hn < Di|0|Ld - Lh|Irrelevant| | |X +|3|Hn < Do|0|Ld - Lh|Irrelevant| | |X +|4|Hi > Dn|0|Lh|Irrelevant|X| | +|5|Hi > Di|Ld|Lh - Ld|In|X| | +|6|Hi = Di|Ld|0|In| | | +|7|Hi < Di|Lh|Ld - Lh|In| | |X +|8|Hi <> Do|0|0|Irrelevant|X| |X +|9|Ho > Dn|0|Lh|Irrelevant| |X| +|10|Ho <> Di|0|0|Irrelevant| |X|X +|11|Ho > Do|Ld|Lh - Ld|Out| |X| +|12|Ho = Do|Ld|0|Out| | | +|13|Ho < Do|Lh|Lh - Ld|Out| | |X + + !!Main Application + After the MSD driver and the media have been initialized using the + corresponding functions, the only requirement for the main application is to + regularly call the state machine function. This is necessary for processing + received commands in a fully asynchronous way. + + The application is otherwise free of doing any other task; for example, it + could implement a filesystem and a serial port interface to be accessed with a + standard terminal. An MP3 player could also continue playing a song while its + memory is accessed like an external hard disk. + + \image MSDDriverClasses.png "Driver Class Diagram" + +*/ +/** + \page "USB MSD Basic" + + This page gives generic details on the MSD class. + + !!!Purpose + + The MSD class defines how devices such as a hard disk, a USB floppy disk drive + or a disk-on-key shall operate on the USB. These devices are referred to as + mass storage devices, since they usually offer a high storage capacity. When + plugged to a PC, a %device complying to the MSD specification is accessed like + any other disk on the system. + + In practice, the specification only defines a way to wrap existing data + transfer protocols, such as SCSI or the Reduced Block Commands (RBC) set. A + list of the supported protocols and their uses will be given in the following + section. + + !!!Data Transfer Protocols + + The }Mass Storagae Class Specification Overview 1.2} supports the following + set of %devices: + + Protocols for MSD %devices +||Subclass Code||Command Block Spec.||Used by +|01h|Reduced Block Commands(RBC)|Flash %devices +|02h|SFF-8020i, MMC-2|CD & DVD %devices +|03h|QIC-157|Tape %devices +|04h|UFI|Floppy disk drives +|05h|SFF-8070i|Floppy disk drives +|06h|SCSI transparent command set|Any + + The SCSI transparent command set comprises all SCSI-related specifications, + such as SCSI Primary Commands (SPC), SCSI Block Commands (SBC), and so on. A + command will be issued by the host to determine exactly with which standard + the %device is compliant. + + The protocol used by the %device is specified in its Interface descriptor, in + the }bInterfaceSubclass} field. + + !!!Transfer Protocols + + There are actually two different transport protocols for the MSD class: + - Control/Bulk/Interface (CBI) transport + - Bulk-Only Transport (BOT) + + These two methods are described in two separate stand-alone documents. CBI can + be considered obsolete and is being completely replaced by BOT. It was + originally targeted at full-speed floppy disk drives. Therefore, the rest of + this document will talk about Bulk-Only Transport exclusively. + + Transport Protocol Codes +||bInterfaceProtocol||Protocol Implementation +|00h|Control/Bulk/Interrupt protocol (with command completion interrupt) +|01h|Control/Bulk/Interrupt protocol (without command completion interrupt) +|50h|Bulk-only transport + + !!!Architecture + ... + + !!Interfaces & Endpoints + + An MSD %device only needs one single interface. The bInterfaceClass field of + the interface descriptor should be set to MSD class code (0x08), the + corresponding data transfer protocol code in the }bInterfaceSubclass} field + and transport protocol code in the }bInterfaceProtocol} field can be found in + the tables on above. + + Exactly three %endpoints (when using the Bulk-Only Transport protocol) are + necessary for MSD %devices. + + The first one is the Control endpoint 0, and is used for class-specific + requests and for clearing Halt conditions on the other two %endpoints. + Endpoints are halted in response to errors and host bad behavior during data + transfers, and the CLEAR_FEATURE request is consequently used to return them + to a functional state. + + The other two %endpoints, which are of type Bulk, are used for transferring + commands and data over the bus. There must be one Bulk-IN and one Bulk-OUT + endpoint. + + \image MSDDriverArch.png "Mass Storage Device Driver Architecture" + + !!Class-Specific Descriptors + No class-specific descriptors for an MSD %device using the Bulk-only transfport + protocol. + + !!Class-Specific Requests + Two class specific requests should be handled. + + !GetMaxLUN + A %device can feature one or more Logical Unit (LU). Each of these units will + be treated as a separate disk when plugged to a computer. A %device can have up + to 15 logical units. + + The GET_MAX_LUN request is issued by the host to determine the maximum Logical + Unit Number (LUN) supported by the %device. This is not equivalent to the + number of LU on the %device; since units are numbered starting from 0, a %device + with 5 LUs should report a value of 4, which will be the index of the fifth + unit. + + Optionally, a %device with only one LUN may STALL this request instead of + returning a value of zero. + + !Bulk-Only Mass Storage Reset + This request is used to reset the state of the %device and prepare it to + receive commands and data. Note that the data toggle bits must not be altered + by a RESET command; same for the Halt state of %endpoints, i.e., halted + %endpoints must not be reset to a normal state. + + !!Command/Data/Status + Each MSD transaction is divided into three steps: + - Command stage + - Data stage (optional) + - Status stage + + During the command stage, a Command Block Wrapper (CBW) is transmitted by the + host to the %device. The CBW describes several parameters of the transaction + (direction, length, LUN) and carries a variable-length command block. The + command block contains data in the format defined by the transfer protocol + used by the %device. + + Command Block Wrapper Data Format +||Offset||Field Name||Length||Comment +|0|dCBWSignature|4 bytes|Signature to identify CBW, must be 43425355h +|4|dCBWTag|4 bytes|Tag sent by the host, echoed in the CSW +|8|dCBWTransferLength|4 bytes|Length of transfer during the data stage +|12|bmCBWFlags|1 byte|Bits 0-6: Reserved/obsolete\n + Bit 7: Transfer direction (0 = OUT, 1 = IN) +|13|bCBWLUN|1 byte|Bits 0-3: LUN to which the command is sent\n + Bits 4-7: Reserved +|14|bCBWCBLength|1 byte|Bits 0-5: Length of command block in bytes\n + Bits 6-7: Reserved +|15|CBWCB|0-16 bytes|Command block to be executed by the %device + + After the %device has received and interpreted the command, an optional data + stage may take place if the command requires it. During this step, data is + transferred either to or from the %device depending on the command, in several + IN/OUT transfers. + + Once the data stage is complete, the host issues a final IN request on the + Bulk-IN endpoint of the %device to request the Command Status Wrapper (CSW). + The CSW is used to report correct or incorrect execution of the command, as + well as indicating the length of remaining data that has not been transferred. + + Command Status Wrapper +||Offset||Field Name||Length||Comment +|0|dCSWSignature|4 bytes|Signature to identify CSW, must be 53425355h +|4|dCSWTag|4 bytes|Copy of previous CBW tag +|8|dCSWDataResidue|4 bytes|Difference between expected and real transfer length +|12|bCSWStatus|1 byte|Indicates the success or failure of the command + + These steps are all performed on the two Bulk %endpoints, and do not involve + Control endpoint 0 at all. + + !!Reset Recovery + When severe errors occur during command or data transfers (as defined in the + }Mass Storage Bulk-only Transport 1.0} document), the %device must halt both + Bulk %endpoints and wait for a #Reset Recovery# procedure. The Reset Recovery + sequence goes as follows: + - The host issues a Bulk-Only Mass Storage Reset request + - The host issues two #CLEAR_FEATURE# requests to unhalt each endpoint + + A %device waiting for a Reset Recovery must not carry out CLEAR_FEATURE + requests trying to unhalt either Bulk endpoint until after a Reset request has + been received. This enables the host to distinguish between severe and minor + errors. + + The only major error defined by the Bulk-Only Transport standard is when a CBW + is not valid. This means one or more of the following: + - The CBW is not received after a CSW has been sent or a reset. + - The CBW is not exactly 31 bytes in length. + - The dCBWSignature field of the CBW is not equal to 43425355h. + + !!!Host Drivers + Almost all operating systems now provide a generic driver for the MSD class. + However, the set of supported data transfer protocols may vary. For example, + Microsoft Windows does not currently support the Reduced Block Command set. + +*/ diff --git a/usb/host/core/USBH.h b/usb/host/core/USBH.h new file mode 100644 index 0000000..7836619 --- /dev/null +++ b/usb/host/core/USBH.h @@ -0,0 +1,73 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !!!Purpose +/// +/// Collection of methods for using the USB device controller on AT91 +/// microcontrollers. +/// +/// !!!Usage +/// +/// Please refer to the corresponding application note. +/// - "AT91 USB device framework" +/// - "USBD API" . "USBD API Methods" +//------------------------------------------------------------------------------ + +#ifndef USBH_H +#define USBH_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +//#include +//#include +#include +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern void USBH_Init(OHCI_HCCA* pHCCA); +extern void USBH_ResetPort(unsigned char portNumber); +extern unsigned char USBH_IsDeviceConnectedOnPort(unsigned char portNumber); +extern void USBH_program(unsigned int* pBHED, unsigned int* pBCED, OHCI_HCCA* pHCCA); +extern void USBH_enablingPort(void); + + +#endif //#ifndef USBD_H + diff --git a/usb/host/core/USB_UHP.c b/usb/host/core/USB_UHP.c new file mode 100644 index 0000000..59c3b4c --- /dev/null +++ b/usb/host/core/USB_UHP.c @@ -0,0 +1,223 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include +#include +#include +#include "USBH.h" +#include + + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +/// HcFmInterval Register: +/// FrameInterval specifies the interval between 2 consecutive SOFs in bit times +/// 1/12 = 0,08333333 +/// 1(ms) / 0,0833333 = 12 +/// FrameInterval = 12x1000 = 12000 +#define FRAMEINTERVAL 12000 +/// FSLargestDataPacket +/// This field specifies a value which is loaded into the Largest +/// Data Packet Counter at the beginning of each frame. + +/// overhead. +/// The value of MAXIMUM_OVERHEAD below is 210 bit times. +#define MAXIMUM_OVERHEAD 210 +/// FSLargestDataPacket initializes a counter within the Host Controller that is +/// used to determine if a transaction on USB can be completed before EOF +/// processing must start. +/// It is a function of the new FrameInterval and is calculated by subtracting +/// from FrameInterval the maximum number of bit times for transaction overhead +/// on USB and the number of bit times needed for EOF processing, then +/// multiplying the result by 6/7 to account for the worst case bit stuffing +#define FSLARGESTDATAPACKET (((FRAMEINTERVAL-MAXIMUM_OVERHEAD) * 6) / 7) +#define OHCI_FMINTERVAL ((FSLARGESTDATAPACKET << 16) | FRAMEINTERVAL) + +/// HcPeriodicStart Register +// The HcPeriodicStart register has a 14-bit programmable value which +// determines when is the earliest time HC should start processing the +// periodic list. +/// Set HcPeriodicStart to a value that is 90% of the value in FrameInterval +/// field of the HcFmInterval register. +#define OHCI_PRDSTRT (FRAMEINTERVAL*90/100) + + +//------------------------------------------------------------------------------ +// Internal Functions +//------------------------------------------------------------------------------ + +#ifdef AT91C_BASE_UHPHS_OHCI +#define AT91C_ID_UHP AT91C_ID_UHPHS +#define AT91C_BASE_UHP AT91C_BASE_UHPHS_OHCI +#define UHP_HcRhPortStatus UHPHS_OHCI_HcRhPortStatus +#define UHP_HcControlHeadED UHPHS_OHCI_HcControlHeadED +#define UHP_HcControlCurrentED UHPHS_OHCI_HcControlCurrentED +#define UHP_HcBulkDoneHead UHPHS_OHCI_HcBulkDoneHead +#define UHP_HcControl UHPHS_OHCI_HcControl +#define UHP_HcRhStatus UHPHS_OHCI_HcRhStatus +#define UHP_HcHCCA UHPHS_OHCI_HcHCCA +#define UHP_HcFmInterval UHPHS_OHCI_HcFmInterval +#define UHP_HcPeriodicStart UHPHS_OHCI_HcPeriodicStart +#endif + +//------------------------------------------------------------------------------ +/// Enable UHP clock +//------------------------------------------------------------------------------ +static inline void UHP_EnablePeripheralClock(void) +{ + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UHP); +} + +//------------------------------------------------------------------------------ +/// Disable UHP clock +//------------------------------------------------------------------------------ +static inline void UHP_DisablePeripheralClock( void ) +{ + AT91C_BASE_PMC->PMC_PCDR = (1 << AT91C_ID_UHP); +} + +//------------------------------------------------------------------------------ +/// Enables the 48MHz USB clock. +//------------------------------------------------------------------------------ +static inline void UHP_EnableUsbClock(void) +{ +#ifdef AT91C_PMC_USBS_USB_UPLL + AT91C_BASE_PMC->PMC_USB = AT91C_PMC_USBS_USB_UPLL | AT91C_PMC_USBDIV_10; +#endif +#ifdef AT91C_CKGR_UPLLEN_ENABLED + AT91C_BASE_PMC->PMC_UCKR = AT91C_CKGR_UPLLEN_ENABLED; +#endif + AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UHP; +} + +//------------------------------------------------------------------------------ +/// Disables the 48MHz USB clock. +//------------------------------------------------------------------------------ +static inline void UHP_DisableUsbClock(void) +{ + AT91C_BASE_PMC->PMC_SCDR = AT91C_PMC_UHP; +#ifdef AT91C_CKGR_UPLLEN_ENABLED + AT91C_BASE_PMC->PMC_UCKR = AT91C_CKGR_UPLLEN_ENABLED; +#endif +} + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Detect a connected device +//------------------------------------------------------------------------------ +unsigned char USBH_IsDeviceConnectedOnPort(unsigned char portNumber) +{ + return (AT91C_BASE_UHP->UHP_HcRhPortStatus[portNumber] & 0x01); +} + +//------------------------------------------------------------------------------ +/// Reset the port number +//------------------------------------------------------------------------------ +void USBH_ResetPort(unsigned char portNumber) +{ + // SetPortReset + AT91C_BASE_UHP->UHP_HcRhPortStatus[portNumber] = (1 << 4); + // Wait for the end of reset + while (AT91C_BASE_UHP->UHP_HcRhPortStatus[portNumber] & (1 << 4)); + // SetPortEnable + AT91C_BASE_UHP->UHP_HcRhPortStatus[portNumber] = (1 << 1); +} + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +void USBH_program(unsigned int* pBHED, unsigned int* pBCED, OHCI_HCCA* pHCCA) +{ + // Programming the BHED + // The HcBulkHeadED register contains the physical address of the first + // Endpoint Descriptor of the Bulk list. + AT91C_BASE_UHP->UHP_HcControlHeadED = (unsigned int) pBHED; + + // Programming the BCED + // The HcBulkCurrentED register contains the physical address of the current + // endpoint of the Bulk list. + AT91C_BASE_UHP->UHP_HcControlCurrentED = (unsigned int) pBCED; + + // Initializing the UHP_HcDoneHead + AT91C_BASE_UHP->UHP_HcBulkDoneHead = 0x00; + pHCCA->UHP_HccaDoneHead = 0x0000; + + // Forcing UHP_Hc to Operational State + AT91C_BASE_UHP->UHP_HcControl = 0x80; +} + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +void USBH_enablingPort(void) +{ + // Enabling port power + AT91C_BASE_UHP->UHP_HcRhPortStatus[0] = 0x00000100; + AT91C_BASE_UHP->UHP_HcRhPortStatus[1] = 0x00000100; + AT91C_BASE_UHP->UHP_HcRhStatus = 0x00010000; +} + +//------------------------------------------------------------------------------ +/// Initializes the specified USB driver +/// This function initializes the current FIFO bank of endpoints, +/// configures the pull-up and VBus lines, disconnects the pull-up and +/// then trigger the Init callback. +//------------------------------------------------------------------------------ +void USBH_Init(OHCI_HCCA* pHCCA) +{ + TRACE_DEBUG_WP("USBH Init()\n\r"); + + UHP_EnablePeripheralClock(); + UHP_EnableUsbClock(); + + // Forcing UHP_Hc to reset + AT91C_BASE_UHP->UHP_HcControl = 0; + + // Writing the UHP_HCCA + AT91C_BASE_UHP->UHP_HcHCCA = (unsigned int) &pHCCA; + + // Enabling list processing + AT91C_BASE_UHP->UHP_HcControl = 0; + + // HcFmInterval register is used to control the length of USB frames + AT91C_BASE_UHP->UHP_HcFmInterval = OHCI_FMINTERVAL; + // The HcPeriodicStart register has a 14-bit programmable value which + // determines when is the earliest time HC should start processing the + // periodic list. + AT91C_BASE_UHP->UHP_HcPeriodicStart = OHCI_PRDSTRT; +} + diff --git a/usb/host/ohci/ohci.c b/usb/host/ohci/ohci.c new file mode 100644 index 0000000..d125559 --- /dev/null +++ b/usb/host/ohci/ohci.c @@ -0,0 +1,124 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/// OHCI ED, TD HCCA definitions + inlined functions + + +#include "ohci.h" + + +//------------------------------------------------------------------------------ +/// Init a pre-allocated endpoint descriptor +/// TD must be aligned on a 16 bytes boundary +//------------------------------------------------------------------------------ +void OHCI_CreateEd( unsigned int EDAddr, + unsigned int MaxPacket, + unsigned int TDFormat, + unsigned int Skip, + unsigned int Speed, + unsigned int Direction, + unsigned int EndPt, + unsigned int FuncAddress, + unsigned int TDQTailPntr, + unsigned int TDQHeadPntr, + unsigned int ToggleCarry, + unsigned int NextED ) +{ + OHCIEndpointDescriptor *pED = (OHCIEndpointDescriptor*) EDAddr; + + pED->Control = (MaxPacket << 16) | (TDFormat << 15) | + (Skip << 14) | (Speed << 13) | (Direction << 11) | + (EndPt << 7) | FuncAddress; + pED->TailP = (TDQTailPntr & 0xFFFFFFF0); + pED->HeadP = (TDQHeadPntr & 0xFFFFFFF0) | (ToggleCarry << 1); + pED->NextEd = (NextED & 0xFFFFFFF0); +} + +//------------------------------------------------------------------------------ +/// Init a pre-allocated transfer descriptor +/// TD must be aligned on a 16 bytes boundary +//------------------------------------------------------------------------------ +void OHCI_CreateGenTd( unsigned int GenTdAddr, + unsigned int DataToggle, + unsigned int DelayInterrupt, + unsigned int Direction, + unsigned int BufRnding, + unsigned int CurBufPtr, + unsigned int NextTD, + unsigned int BuffLen) +{ + OHCITransferDescriptor *pTD = (OHCITransferDescriptor*) GenTdAddr; + + pTD->Control = (DataToggle << 24) | (DelayInterrupt << 21) + | (Direction << 19) | (BufRnding << 18); + pTD->CBP = CurBufPtr; + pTD->NextTD = (NextTD & 0xFFFFFFF0); + pTD->BE = (BuffLen) ? (CurBufPtr + BuffLen - 1) : CurBufPtr; +} + +//------------------------------------------------------------------------------ +/// Init a pre-allocated periodic transfer descriptor +/// TD must be aligned on a 16 bytes boundary +//------------------------------------------------------------------------------ +void OHCI_CreateGenITd( unsigned int GenTdAddr, + unsigned int CondCode, + unsigned int FrameCount, + unsigned int DelayInterrupt, + unsigned int StartFrame, + unsigned int BuffPage0, + unsigned int NextTD, + unsigned int BufEnd, + unsigned int PswOffset0, + unsigned int PswOffset1, + unsigned int PswOffset2, + unsigned int PswOffset3, + unsigned int PswOffset4, + unsigned int PswOffset5, + unsigned int PswOffset6, + unsigned int PswOffset7) +{ + OHCIPeriodicTransferDescriptor *pITD = (OHCIPeriodicTransferDescriptor*) GenTdAddr; + + pITD->Control = (CondCode << 28) | (FrameCount << 24) + | (DelayInterrupt << 21) | StartFrame; + pITD->BP0 = (BuffPage0 << 12); + pITD->NextTD = (NextTD << 4); + pITD->BE = BufEnd; + pITD->PSW0 = PswOffset0; + pITD->PSW1 = PswOffset1; + pITD->PSW2 = PswOffset2; + pITD->PSW3 = PswOffset3; + pITD->PSW4 = PswOffset4; + pITD->PSW5 = PswOffset5; + pITD->PSW6 = PswOffset6; + pITD->PSW7 = PswOffset7; + +} + + diff --git a/usb/host/ohci/ohci.h b/usb/host/ohci/ohci.h new file mode 100644 index 0000000..804d75b --- /dev/null +++ b/usb/host/ohci/ohci.h @@ -0,0 +1,139 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/// OHCI ED, TD HCCA definitions + inlined functions + +#ifndef _OHCI_H +#define _OHCI_H + +#ifdef __ICCARM__ // IAR +#pragma pack(8) +#define __attribute__(...) // IAR +#endif // IAR +// Endpoint Descriptor Field Definitions +typedef struct { + // FunctionAddress | EndpointNumber | Direction | Speed | sKip | Format + // MaximumPacketSize + volatile unsigned int Control; + // TailP: TDQueueTailPointer + // If TailP and HeadP are the same, then the list contains no TD that the HC + // can process. If TailP and HeadP are different, then the list contains a TD to be + // processed. + volatile unsigned int TailP; + // HeadP: TDQueueHeadPointer Points to the next TD to be processed for this + // endpoint. + volatile unsigned int HeadP; + // NextED: If nonzero, then this entry points to the next ED on the list + volatile unsigned int NextEd; +} __attribute__((aligned(16))) OHCIEndpointDescriptor; + +/// General Transfer Descriptor Format +typedef struct { + volatile unsigned int Control; // bufferRounding | Direction/PID | DelayInterrupt + // DataToggle | ErrorCount | ConditionCode + volatile unsigned int CBP; // Current Buffer Pointer + volatile unsigned int NextTD; // Next TD + volatile unsigned int BE; // Buffer End +} __attribute__((aligned(16))) OHCITransferDescriptor; + +typedef struct { + volatile unsigned int Control; // StartingFrame | DelayInterrupt | FrameCount + // ConditionCode + volatile unsigned int BP0; // Buffer Page 0 + volatile unsigned int NextTD; // NextTD + volatile unsigned int BE; // Buffer End + volatile unsigned int PSW0; // Offset0/PSW0 + volatile unsigned int PSW1; // Offset1/PSW1 + volatile unsigned int PSW2; // Offset2/PSW2 + volatile unsigned int PSW3; // Offset3/PSW3 + volatile unsigned int PSW4; // Offset4/PSW4 + volatile unsigned int PSW5; // Offset5/PSW5 + volatile unsigned int PSW6; // Offset6/PSW6 + volatile unsigned int PSW7; // Offset7/PSW7 +} __attribute__((aligned(8))) OHCIPeriodicTransferDescriptor; + +//Host Controller Communications Area Description +typedef struct { + // pointers to an Interrupt List each of which is a list of EDs + volatile unsigned int UHP_HccaInterruptTable[32]; + // This 16-bit value is updated by the Host Controller on each frame. + volatile unsigned short UHP_HccaFrameNumber; // current frame number + // When the HC updates HccaFrameNumber, it sets this word to 0. + volatile unsigned short UHP_HccaPad1; + // When a TD is complete (with or without an error) it is unlinked from the + // queue that it is on and linked to the Done Queue + volatile unsigned int UHP_HccaDoneHead; + // Reserved for use by HC + volatile unsigned char reserved[116]; +} __attribute__((aligned(8))) OHCI_HCCA; + +#ifdef __ICCARM__ // IAR +#pragma pack() // IAR +#endif // IAR + + +extern void OHCI_CreateEd( unsigned int EDAddr, + unsigned int MaxPacket, + unsigned int TDFormat, + unsigned int Skip, + unsigned int Speed, + unsigned int Direction, + unsigned int EndPt, + unsigned int FuncAddress, + unsigned int TDQTailPntr, + unsigned int TDQHeadPntr, + unsigned int ToggleCarry, + unsigned int NextED ); +extern void OHCI_CreateGenTd( unsigned int GenTdAddr, + unsigned int DataToggle, + unsigned int DelayInterrupt, + unsigned int Direction, + unsigned int BufRnding, + unsigned int CurBufPtr, + unsigned int NextTD, + unsigned int BuffLen); +extern void OHCI_CreateGenITd( unsigned int GenTdAddr, + unsigned int CondCode, + unsigned int FrameCount, + unsigned int DelayInterrupt, + unsigned int StartFrame, + unsigned int BuffPage0, + unsigned int NextTD, + unsigned int BufEnd, + unsigned int PswOffset0, + unsigned int PswOffset1, + unsigned int PswOffset2, + unsigned int PswOffset3, + unsigned int PswOffset4, + unsigned int PswOffset5, + unsigned int PswOffset6, + unsigned int PswOffset7); +#endif //_OHCI_H + + diff --git a/usb/otg/compiler.h b/usb/otg/compiler.h new file mode 100644 index 0000000..b85521b --- /dev/null +++ b/usb/otg/compiler.h @@ -0,0 +1,65 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef _COMPILER_H_ +#define _COMPILER_H_ + +typedef float Float16; +typedef unsigned char U8 ; +typedef unsigned short U16; +typedef unsigned long U32; +typedef unsigned char Bool; + +typedef unsigned char Byte; + +typedef char bit; + +#define MSB0(u32) (((U8* )&u32)[3]) +#define MSB1(u32) (((U8* )&u32)[2]) +#define MSB2(u32) (((U8* )&u32)[1]) +#define MSB3(u32) (((U8* )&u32)[0]) +#define LSB0(u32) MSB3(u32) +#define LSB1(u32) MSB2(u32) +#define LSB2(u32) MSB1(u32) +#define LSB3(u32) MSB0(u32) +#define MSB(u16) (((U8* )&u16)[1]) +#define LSB(u16) (((U8* )&u16)[0]) +#define MSW(u32) (((U16*)&u32)[1]) +#define LSW(u32) (((U16*)&u32)[0]) + + +// Constants +#define DISABLE 0 +#define ENABLE 1 + +#define TRUE (1 == 1) +#define FALSE (0 == 1) + +#endif /* _COMPILER_H_ */ + diff --git a/usb/otg/usb_drv.c b/usb/otg/usb_drv.c new file mode 100644 index 0000000..c29689c --- /dev/null +++ b/usb/otg/usb_drv.c @@ -0,0 +1,246 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include "usb_drv.h" +#include + +U8 global_pipe_nb=0; +U8 global_endpoint_nb=0; +unsigned char dBytes=0; +char* pFifo; + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//! This function configures an endpoint with the selected type. +U8 dev_configure_endpoint(U8 ept, U8 type, U8 dir, U8 size, U8 bank, U8 nyet) +{ + unsigned char status=0; + + // Enable endpoint + AT91C_BASE_OTGHS->OTGHS_DEVEPT |= (1<OTGHS_DEVEPTCFG[ept] = (bank<<2)|(size<<4)|(dir<<8) + |AT91C_OTGHS_AUTOSW |(type<<11); + + AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[ept] |= AT91C_OTGHS_ALLOC; + if(!(AT91C_BASE_OTGHS->OTGHS_DEVEPTISR[ept]&AT91C_OTGHS_CFGOK)) { + TRACE_ERROR("Bad endpoint configuration\n\r"); + status = 1; + } + if(nyet == NYET_ENABLED) { + AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[ept] = AT91C_OTGHS_NYETDIS; + } + else { + AT91C_BASE_OTGHS->OTGHS_DEVEPTIER[ept] = AT91C_OTGHS_NYETDIS; + } + return status; +} + + + + +//------------------------------------------------------------------------------ +// HOST +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +//! This function configures a pipe with the selected type. +//! @param config0 +//! @param config1 +//! @return Is_endpoint_configured. +//------------------------------------------------------------------------------ +U8 host_config_pipe(U8 config0, U8 config1) +{ + TRACE_DEBUG("host_config_pipe\n\r"); + Host_enable_pipe(); +// UPCFG0X = config0; +// UPCFG1X = config1; + Host_allocate_memory(); + return (Is_pipe_configured()); +} + +//------------------------------------------------------------------------------ +//! This function returns the size configuration register value according +//! to the endpint size detected inthe device enumeration process. +//! @return pipe size register value. +//------------------------------------------------------------------------------ +U8 host_determine_pipe_size(U16 size) +{ + //TRACE_DEBUG("host_determine_pipe_size\n\r"); + if(size <= 8 ) {return (SIZE_8 );} + else if(size <= 16 ) {return (SIZE_16 );} + else if(size <= 32 ) {return (SIZE_32 );} + else if(size <= 64 ) {return (SIZE_64 );} + else if(size <= 128) {return (SIZE_128 );} + else if(size <= 256) {return (SIZE_256 );} + else if(size <= 512) {return (SIZE_512 );} + else {return (SIZE_1024);} +} + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +U16 host_get_pipe_length(void) +{ + unsigned int size; + + size = (AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[global_pipe_nb]&AT91C_OTGHS_PSIZE)>>4; + //TRACE_DEBUG("host_get_pipe_length = %d\n\r", (int)size); + + if(size == SIZE_8 ) {return (8 );} + else if(size == SIZE_16 ) {return (16 );} + else if(size == SIZE_32 ) {return (32 );} + else if(size == SIZE_64 ) {return (64 );} + else if(size == SIZE_128) {return (128);} + else if(size == SIZE_256) {return (256);} + else if(size == SIZE_512) {return (512);} + else if(size == SIZE_1024){return (1024);} + else {TRACE_ERROR("Error size\n\r");return 0;} +} + + +//------------------------------------------------------------------------------ +//! host_disable_all_pipe. +//! +//! This function disable all pipes for the host controller +//! Usefull to execute upon device disconnection. +//! +//! @return none. +//------------------------------------------------------------------------------ +void host_disable_all_pipe(void) +{ + U8 i; + + TRACE_DEBUG("host_disable_all_pipe\n\r"); + for (i=0; i<7; i++) { + Host_reset_pipe(i); + Host_select_pipe(i); + Host_unallocate_memory(); + Host_disable_pipe(); + } +} + +//------------------------------------------------------------------------------ +//! @brief Returns the pipe number that generates a USB communication interrupt +//! +//! This function sould be called only when an interrupt has been detected. Otherwize +//! the return value is incorect +//! +//! @param none +//! +//! @return pipe_number +//------------------------------------------------------------------------------ +U8 host_get_nb_pipe_interrupt(void) +{ + U8 interrupt_flags; + U8 i; + + TRACE_DEBUG("host_get_nb_pipe_interrupt\n\r"); + interrupt_flags = Host_get_pipe_interrupt(); + for(i=0; iOTGHS_HSTADDR1 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P0; + AT91C_BASE_OTGHS->OTGHS_HSTADDR1 |= ((addr<<0) & AT91C_OTGHS_UHADDR_P0); + } + else if( pipe == 1 ) { + AT91C_BASE_OTGHS->OTGHS_HSTADDR1 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P1; + AT91C_BASE_OTGHS->OTGHS_HSTADDR1 |= ((addr<<8) & AT91C_OTGHS_UHADDR_P1); + } + else if( pipe == 2 ) { + AT91C_BASE_OTGHS->OTGHS_HSTADDR1 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P2; + AT91C_BASE_OTGHS->OTGHS_HSTADDR1 |= ((addr<<16) & AT91C_OTGHS_UHADDR_P2); + } + else if( pipe == 3 ) { + AT91C_BASE_OTGHS->OTGHS_HSTADDR1 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P3; + AT91C_BASE_OTGHS->OTGHS_HSTADDR1 |= ((addr<<24) & AT91C_OTGHS_UHADDR_P3); + } + else if( pipe == 4 ) { + AT91C_BASE_OTGHS->OTGHS_HSTADDR2 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P4; + AT91C_BASE_OTGHS->OTGHS_HSTADDR2 |= ((addr<<0) & AT91C_OTGHS_UHADDR_P4); + } + else if( pipe == 5 ) { + AT91C_BASE_OTGHS->OTGHS_HSTADDR2 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P5; + AT91C_BASE_OTGHS->OTGHS_HSTADDR2 |= ((addr<<8) & AT91C_OTGHS_UHADDR_P5); + } + else if( pipe == 6 ) { + AT91C_BASE_OTGHS->OTGHS_HSTADDR2 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P6; + AT91C_BASE_OTGHS->OTGHS_HSTADDR2 |= ((addr<<16) & AT91C_OTGHS_UHADDR_P6); + } + else if( pipe == 7 ) { + AT91C_BASE_OTGHS->OTGHS_HSTADDR2 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P7; + AT91C_BASE_OTGHS->OTGHS_HSTADDR2 |= ((addr<<24) & AT91C_OTGHS_UHADDR_P7); + } + else if( pipe == 8 ) { + AT91C_BASE_OTGHS->OTGHS_HSTADDR3 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P8; + AT91C_BASE_OTGHS->OTGHS_HSTADDR3 |= ((addr<<0) & AT91C_OTGHS_UHADDR_P8); + } + else if( pipe == 9 ) { + AT91C_BASE_OTGHS->OTGHS_HSTADDR3 &= ~(unsigned int)AT91C_OTGHS_UHADDR_P9; + AT91C_BASE_OTGHS->OTGHS_HSTADDR3 |= ((addr<<8) & AT91C_OTGHS_UHADDR_P9); + } + else { + TRACE_ERROR("pipe not defined\n\r"); + } +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +void host_configure_pipe(U8 pip, U8 type, U8 token, U8 ep_num, U8 size, U8 bank, U8 freq) +{ + AT91C_BASE_OTGHS->OTGHS_HSTPIP |= (1<OTGHS_HSTPIPCFG[pip] = (bank<< 2) | (size << 4) | (token<< 8) + | (type<<12) |(ep_num<<16)| (freq <<24); + AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[pip] |= AT91C_OTGHS_ALLOC; +} + + diff --git a/usb/otg/usb_drv.h b/usb/otg/usb_drv.h new file mode 100644 index 0000000..c9276fe --- /dev/null +++ b/usb/otg/usb_drv.h @@ -0,0 +1,859 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/// This file contains the USB low level driver definition + + +#ifndef _USB_DRV_H +#define _USB_DRV_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ +#include "board.h" + +extern unsigned char dBytes; +extern char* pFifo_ctrl; +extern char* pFifo; + +//#define Address_fifo_endpoint(ep) (char*)&(AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0[EPT_VIRTUAL_SIZE*ep]) +#define Address_fifochar_endpoint(ep) pFifo = (char*)((unsigned int *)AT91C_BASE_OTGHS_EPTFIFO + (EPT_VIRTUAL_SIZE * ep));dBytes=0 +//#define Address_fifochar_endpoint(ep) (char*)((unsigned int *)AT91C_BASE_OTGHS_EPTFIFO + (EPT_VIRTUAL_SIZE * ep)) +#define Address_fifo_endpoint(ep) (int*) ((int)(AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0) + (EPT_VIRTUAL_SIZE*(ep))) + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +/// USB_low_level_drivers USB low level drivers module + +#define MAX_EP_NB 7 + +#define EPT_VIRTUAL_SIZE 8192 + +#define EP_CONTROL 0 +#define PIPE_CONTROL 0 + +// USB EndPoint +#define MSK_EP_DIR 0x7F + +// Parameters for endpoint configuration +// These define are the values used to enable and configure an endpoint. +#define TYPE_CONTROL 0 +#define TYPE_ISOCHRONOUS 1 +#define TYPE_BULK 2 +#define TYPE_INTERRUPT 3 + +#define DIRECTION_OUT 0 +#define DIRECTION_IN 1 + +#define SIZE_8 0 +#define SIZE_16 1 +#define SIZE_32 2 +#define SIZE_64 3 +#define SIZE_128 4 +#define SIZE_256 5 +#define SIZE_512 6 +#define SIZE_1024 7 + +#define ONE_BANK 0 +#define TWO_BANKS 1 +#define TREE_BANKS 2 + +#define NYET_ENABLED 0 +#define NYET_DISABLED 1 + +#define TOKEN_SETUP 0 +#define TOKEN_IN 1 +#define TOKEN_OUT 2 + +#define Is_ep_addr_in(x) (x & 0x80) + +//Set_bits(AVR32_USB_uatst1,AVR32_USB_UATST1_LOADCNTA_MASK); +#define Usb_load_tsta1_countMask() AT91C_BASE_OTGHS->OTGHS_TSTA1 &= ~(unsigned int)AT91C_OTGHS_COUNTERA + +//#define AVR32_USB_UATST1_LOADCNTA_MASK_NONZERO 0x00008001 +#define Usb_load_tsta1_counta() AT91C_BASE_OTGHS->OTGHS_TSTA1 = AT91C_OTGHS_LOADCNTA | (AT91C_OTGHS_COUNTERA&0x01) + +//#define AVR32_USB_UATST2_FORCE_51MS_RESETHS_MASK 0x00000080 +#define USb_ForceHSRst_50ms() AT91C_BASE_OTGHS->OTGHS_TSTA2 |= AT91C_OTGHS_FORCHSRST + +//#define AVR32_USB_UATST2_FORCE_RESET_UTMI 0x00000100 +#define Usb_SetForceResetUTMI() AT91C_BASE_OTGHS->OTGHS_TSTA2 |= AT91C_OTGHS_UTMIRESET +#define Usb_ClrForceResetUTMI() AT91C_BASE_OTGHS->OTGHS_TSTA2 &= ~(unsigned int)AT91C_OTGHS_UTMIRESET + +//#define AVR32_USB_UATST2_HOSTHSDISCONNECTDISABLE_MASK +#define Usb_SetHSTDiconnectDisableMask() AT91C_BASE_OTGHS->OTGHS_TSTA2 |= AT91C_OTGHS_HSTHSDISCDIS +#define Usb_ClrHSTDiconnectDisableMask() AT91C_BASE_OTGHS->OTGHS_TSTA2 &= ~(unsigned int)AT91C_OTGHS_HSTHSDISCDIS + +#define Usb_enable_vbus_error_interrupt() AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_VBERR + +#define Is_Usb_InHighSpeed() (AT91C_BASE_OTGHS->OTGHS_SR&AT91C_OTGHS_SPEED_SR) == AT91C_OTGHS_SPEED_SR_HS + +/// OTG Timers customizing +// HOST : Minimum delay after Vbus requested to get it > Va_vbus_valid (otherwise => error) +//#define VBUSRISE_20MS 0x00 +//#define VBUSRISE_50MS 0x01 +#define VBUSRISE_70MS 0x02 +//#define VBUSRISE_100MS 0x03 +// DEVICE : Duration of Vbus pulse during SRP protocol +//#define VBUSPULSE_15MS 0x20 +//#define VBUSPULSE_23MS 0x21 +//#define VBUSPULSE_31MS 0x22 +#define VBUSPULSE_40MS 0x23 +// DEVICE : Minimum delay after Vbus < Vb_sess_end to enable SRP +//#define VFALLTMOUT_93MS 0x40 +//#define VFALLTMOUT_105MS 0x41 +//#define VFALLTMOUT_118MS 0x42 +#define VFALLTMOUT_131MS 0x43 +// HOST : Minimum pulse duration accepted as SRP pulse +//#define SRPMINDET_10US 0x60 +#define SRPMINDET_100US 0x61 +//#define SRPMINDET_1MS 0x62 +//#define SRPMINDET_11MS 0x63 + +//------------------------------------------------------------------------------ +// A R B I T R E R +//------------------------------------------------------------------------------ + +/// gen_usb USB common management drivers +/// These macros manage the USB controller + +/// Enable external UID pin +//#define Usb_enable_uid_pin() (UHWCON |= (1<OTGHS_CTRL |= AT91C_OTGHS_UIDE +/// Disable external UID pin +//#define Usb_disable_uid_pin() AT91C_BASE_OTGHS->OTGHS_CTRL &= ~AT91C_OTGHS_UIDE +/// Disable external UID pin and force device mode +//#define Usb_force_device_mode() //{AT91C_BASE_OTGHS->OTGHS_CTRL &= ~AT91C_OTGHS_UIDE; + // AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_UIMOD;} +/// Disable external UID pin and force host mode +//#define Usb_force_host_mode() //{AT91C_BASE_OTGHS->OTGHS_CTRL &= ~AT91C_OTGHS_UIDE; + // AT91C_BASE_OTGHS->OTGHS_CTRL &= ~AT91C_OTGHS_UIMOD;} +/// Enable external UVCON pin +//#define Usb_enable_uvcon_pin() // (UHWCON |= (1<OTGHS_DEVCTRL |= AT91C_OTGHS_LS + +#define Usb_enable() AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_USBECTRL +#define Usb_disable() AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_USBECTRL + +/// Enable VBUS pad +//#define Usb_enable_vbus_pad() (USBCON |= (1<OTGHS_CTRL |= AT91C_OTGHS_USBECTRL;\ + AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_OTGPADE;\ + AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_FRZCLKCTRL;} +/// Disable VBUS pad +//#define Usb_disable_vbus_pad() (USBCON &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_OTGPADE + +#define Usb_select_device() Usb_enable_uid_pin() +#define Usb_select_host() Usb_enable_uid_pin() +#define Is_usb_device_enabled() (AT91C_BASE_OTGHS->OTGHS_SR & AT91C_OTGHS_ID) +#define Is_usb_host_enabled() !Is_usb_device_enabled() +/// Stop internal USB clock in interface (freeze the interface register) +//#define Usb_freeze_clock() (USBCON |= (1<OTGHS_CTRL |= AT91C_OTGHS_FRZCLKCTRL +//jcb +//#define Usb_unfreeze_clock() (USBCON &= ~(1<OTGHS_CTRL &= ~AT91C_OTGHS_FRZCLKCTRL +//#define Is_usb_clock_freezed() ((USBCON & (1<OTGHS_CTRL & AT91C_OTGHS_FRZCLKCTRL) + +//#define Usb_enable_id_interrupt() (USBCON |= (1<OTGHS_CTRL |= AT91C_OTGHS_IDT +//#define Usb_disable_id_interrupt() (USBCON &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_IDT +//#define Is_usb_id_interrupt_enabled() ((USBCON & (1<OTGHS_CTRL & AT91C_OTGHS_IDT) +//#define Is_usb_id_device() ((USBSTA & (1<OTGHS_SR & AT91C_OTGHS_ID) +//#define Is_usb_id_host() ((USBSTA & (1<OTGHS_SCR = AT91C_OTGHS_IDT +//#define Is_usb_id_transition() ((USBINT & (1<OTGHS_SR & AT91C_OTGHS_IDT) + +//#define Usb_enable_vbus_interrupt() (USBCON |= (1<OTGHS_CTRL |= AT91C_OTGHS_VBUSTI +//#define Usb_disable_vbus_interrupt() (USBCON &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_VBUSTI +//#define Is_usb_vbus_interrupt_enabled() ((USBCON & (1<OTGHS_CTRL & AT91C_OTGHS_VBUSTI) +//#define Is_usb_vbus_high() ((USBSTA & (1<OTGHS_SR&AT91C_OTGHS_VBUSSR)==AT91C_OTGHS_VBUSSR) +//#define Is_usb_vbus_low() ((USBSTA & (1<OTGHS_SR&AT91C_OTGHS_VBUSSR)!=AT91C_OTGHS_VBUSSR) +//#define Usb_ack_vbus_transition() (USBINT = ~(1<OTGHS_SCR = AT91C_OTGHS_VBUSTI +//#define Is_usb_vbus_transition() ((USBINT & (1<OTGHS_CTRL & AT91C_OTGHS_VBUSTI) + +/// requests for VBus activation +//#define Usb_enable_vbus() (OTGCON |= (1<OTGHS_SFR = AT91C_OTGHS_VBUSRQ //JCB +/// requests for VBus desactivation +#define Usb_disable_vbus() AT91C_BASE_OTGHS->OTGHS_SCR = AT91C_OTGHS_VBUSRQ //JCB +/// Manually request VBUS without UVCON signal from USB interface +//#define Usb_disable_uvcon_pin() (UHWCON &= ~(1<OTGHS_SFR = AT91C_OTGHS_VBUSRQ //JCB +/// Manually request VBUS OFF without UVCON signal from USB interface +//#define Usb_disable_manual_vbus() (PORTE&=~0x80,DDRE|=0x80,Usb_enable_uvcon_pin()) +#define Usb_disable_manual_vbus() AT91C_BASE_OTGHS->OTGHS_SCR = AT91C_OTGHS_VBUSRQ //JCB + +/// initiates a Host Negociation Protocol +//#define Usb_device_initiate_hnp() (OTGCON |= (1<OTGHS_CTRL |= AT91C_OTGHS_HNPREQ +/// stops a Host Negociation Protocol +//#define Usb_device_stop_hnp() (OTGCON &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_HNPREQ +/// accepts a Host Negociation Protocol +//#define Usb_host_accept_hnp() (OTGCON |= (1<OTGHS_CTRL |= AT91C_OTGHS_HNPREQ +/// rejects a Host Negociation Protocol +//#define Usb_host_reject_hnp() (OTGCON &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_HNPREQ +/// initiates a Session Request Protocol +//#define Usb_device_initiate_srp() (OTGCON |= (1<OTGHS_CTRL |= AT91C_OTGHS_SRPREQ +/// selects VBus as SRP method +//#define Usb_select_vbus_srp_method() (OTGCON |= (1<OTGHS_CTRL |= AT91C_OTGHS_SRPSEL +/// selects data line as SRP method +//#define Usb_select_data_srp_method() (OTGCON &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_SRPSEL + + +/// enables hardware control on VBus +#define Usb_enable_vbus_hw_control() // AT91C_BASE_OTGHS->OTGHS_CTRL &= ~AT91C_OTGHS_VBUSHWC +/// disables hardware control on VBus +#define Usb_disable_vbus_hw_control() AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_VBUSHWC +/// tests if VBus has been requested +//#define Is_usb_vbus_enabled() ((OTGCON & (1<OTGHS_SR&AT91C_OTGHS_ROLEEX) == AT91C_OTGHS_ROLEEX) +/// tests if a SRP from device occurs +//#define Is_usb_device_srp() ((OTGCON & (1<OTGHS_CTRL&AT91C_OTGHS_SRPREQ) + +/// acks suspend time out interrupt +//#define Usb_ack_suspend_time_out_interrupt() (OTGINT &= ~(1<OTGHS_SCR = AT91C_OTGHS_STO +/// enables suspend time out interrupt +//#define Usb_enable_suspend_time_out_interrupt() (OTGIEN |= (1<OTGHS_CTRL |= AT91C_OTGHS_STO +/// disables suspend time out interrupt +//#define Usb_disable_suspend_time_out_interrupt() (OTGIEN &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_STO +//#define Is_suspend_time_out_interrupt_enabled() ((OTGIEN & (1<OTGHS_CTRL&AT91C_OTGHS_STO)==AT91C_OTGHS_STO) +/// tests if a suspend time out occurs +//#define Is_usb_suspend_time_out_interrupt() ((OTGINT & (1<OTGHS_SR&AT91C_OTGHS_STO)==AT91C_OTGHS_STO) + +/// enables HNP error interrupt +//#define Usb_enable_hnp_error_interrupt() (OTGIEN |= (1<OTGHS_CTRL |= AT91C_OTGHS_HNPERR +/// disables HNP error interrupt +//#define Usb_disable_hnp_error_interrupt() (OTGIEN &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_HNPERR +//#define Is_hnp_error_interrupt_enabled() ((OTGIEN & (1<OTGHS_CTRL&AT91C_OTGHS_HNPERR)==AT91C_OTGHS_HNPERR) +/// acks HNP error interrupt +//#define Usb_ack_hnp_error_interrupt() (OTGINT &= ~(1<OTGHS_SCR |= AT91C_OTGHS_HNPERR +/// tests if a HNP error occurs +//#define Is_usb_hnp_error_interrupt() ((OTGINT & (1<OTGHS_SR&AT91C_OTGHS_HNPERR) == AT91C_OTGHS_HNPERR) + +/// enables role exchange interrupt +//#define Usb_enable_role_exchange_interrupt() (OTGIEN |= (1<OTGHS_CTRL |= AT91C_OTGHS_ROLEEX +/// disables role exchange interrupt +//#define Usb_disable_role_exchange_interrupt() (OTGIEN &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_ROLEEX +//#define Is_role_exchange_interrupt_enabled() ((OTGIEN & (1<OTGHS_CTRL&AT91C_OTGHS_ROLEEX)==AT91C_OTGHS_ROLEEX) +/// acks role exchange interrupt +//#define Usb_ack_role_exchange_interrupt() (OTGINT &= ~(1<OTGHS_SCR |= AT91C_OTGHS_ROLEEX +/// tests if a role exchange occurs +//#define Is_usb_role_exchange_interrupt() ((OTGINT & (1<OTGHS_SR&AT91C_OTGHS_ROLEEX)==AT91C_OTGHS_ROLEEX) + +/// enables B device connection error interrupt +//#define Usb_enable_bconnection_error_interrupt() (OTGIEN |= (1<OTGHS_CTRL |= AT91C_OTGHS_BCERR +/// disables B device connection error interrupt +//#define Usb_disable_bconnection_error_interrupt() (OTGIEN &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_BCERR +//#define Is_bconnection_error_interrupt_enabled() ((OTGIEN & (1<OTGHS_SCR = AT91C_OTGHS_BCERR +/// tests if a B device connection error occurs +#define Is_usb_bconnection_error_interrupt() FALSE//jcb (AT91C_BASE_OTGHS->OTGHS_SR & AT91C_OTGHS_BCERR) + +/// enables VBus error interrupt +//#define Usb_enable_vbus_error_interrupt() (OTGIEN |= (1<OTGHS_SCR = AT91C_OTGHS_VBERR +/// tests if a VBus error occurs +#define Is_usb_vbus_error_interrupt() ((AT91C_BASE_OTGHS->OTGHS_SR&AT91C_OTGHS_VBERR)==AT91C_OTGHS_VBERR) + +/// enables SRP interrupt +//#define Usb_enable_srp_interrupt() (OTGIEN |= (1<OTGHS_CTRL |= AT91C_OTGHS_SRP +/// disables SRP interrupt +//#define Usb_disable_srp_interrupt() (OTGIEN &= ~(1<OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_SRP +//#define Is_srp_interrupt_enabled() ((OTGIEN & (1<OTGHS_CTRL&AT91C_OTGHS_SRP)==AT91C_OTGHS_SRP) +/// acks SRP interrupt +#define Usb_ack_srp_interrupt() AT91C_BASE_OTGHS->OTGHS_SCR = AT91C_OTGHS_SRP +/// tests if a SRP occurs +#define Is_usb_srp_interrupt() ((AT91C_BASE_OTGHS->OTGHS_SR&AT91C_OTGHS_SRP)==AT91C_OTGHS_SRP) + + +//------------------------------------------------------------------------------ +// D E V I C E +//------------------------------------------------------------------------------ + +/// USB_device_driver USB device controller drivers +/// These macros manage the USB Device controller. + +/// test if remote wake-up still running +//#define Is_usb_pending_remote_wake_up() ((UDCON & (1<OTGHS_DEVCTRL | AT91C_OTGHS_RMWKUP) +/// acks remote wake-up +//#define Usb_ack_remote_wake_up_start() (UDINT = ~(1<OTGHS_DEVICR = AT91C_OTGHS_UPRSM + +/// enables resume interrupt +//#define Usb_enable_resume_interrupt() (UDIEN |= (1<OTGHS_DEVIDR = AT91C_OTGHS_EORSM +#define Is_resume_interrupt_enabled() (AT91C_BASE_OTGHS->OTGHS_DEVISR & AT91C_OTGHS_EORSM) +/// acks resume +#define Usb_ack_resume() AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_EORSM +/// tests if resume occurs +#define Is_usb_resume() (AT91C_BASE_OTGHS->OTGHS_DEVISR & AT91C_OTGHS_EORSM) + +/// enables wake-up interrupt +#define Usb_enable_wake_up_interrupt() AT91C_BASE_OTGHS->OTGHS_DEVIER = AT91C_OTGHS_WAKEUP +/// disables wake-up interrupt +#define Usb_disable_wake_up_interrupt() AT91C_BASE_OTGHS->OTGHS_DEVIDR = AT91C_OTGHS_WAKEUP +#define Is_swake_up_interrupt_enabled() (AT91C_BASE_OTGHS->OTGHS_DEVIMR & AT91C_OTGHS_WAKEUP) +/// acks wake-up +#define Usb_ack_wake_up() AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_WAKEUP +/// tests if wake-up occurs +#define Is_usb_wake_up() (AT91C_BASE_OTGHS->OTGHS_DEVISR & AT91C_OTGHS_WAKEUP) + +/// enables USB reset interrupt +#define Usb_enable_reset_interrupt() AT91C_BASE_OTGHS->OTGHS_DEVIER = AT91C_OTGHS_EORST +/// disables USB reset interrupt +//#define Usb_disable_reset_interrupt() (UDIEN &= ~(1<OTGHS_DEVIMR & AT91C_OTGHS_EORST) +/// acks USB reset +#define Usb_ack_reset() AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_EORST +/// tests if USB reset occurs +#define Is_usb_reset() (AT91C_BASE_OTGHS->OTGHS_DEVISR & AT91C_OTGHS_EORST) + +/// enables Start Of Frame Interrupt +#define Usb_enable_sof_interrupt() AT91C_BASE_OTGHS->OTGHS_DEVIER = AT91C_OTGHS_SOF +/// disables Start Of Frame Interrupt +//#define Usb_disable_sof_interrupt() (UDIEN &= ~(1<OTGHS_DEVIDR = AT91C_OTGHS_SOF +#define Is_sof_interrupt_enabled() (AT91C_BASE_OTGHS->OTGHS_DEVIMR & AT91C_OTGHS_SOF) +/// acks Start Of Frame +#define Usb_ack_sof() AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_SOF +/// tests if Start Of Frame occurs +#define Is_usb_sof() (AT91C_BASE_OTGHS->OTGHS_DEVISR & AT91C_OTGHS_SOF) + +/// enables suspend state interrupt +#define Usb_enable_suspend_interrupt() AT91C_BASE_OTGHS->OTGHS_DEVIER = AT91C_OTGHS_SUSP +/// disables suspend state interrupt +//#define Usb_disable_suspend_interrupt() (UDIEN &= ~(1<OTGHS_DEVIDR = AT91C_OTGHS_SUSP +#define Is_suspend_interrupt_enabled() (AT91C_BASE_OTGHS->OTGHS_DEVIMR & AT91C_OTGHS_SUSP) +/// acks Suspend +#define Usb_ack_suspend() AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_SUSP +/// tests if Suspend state detected +#define Is_usb_suspend() (AT91C_BASE_OTGHS->OTGHS_DEVISR & AT91C_OTGHS_SUSP) + +/// returns the last frame number +//#define Usb_frame_number() ((unsigned short)((((unsigned short)UDFNUMH) << 8) | ((unsigned short)UDFNUML))) +/// tests if a crc error occurs in frame number +//#define Is_usb_frame_number_crc_error() ((UDMFN & (1<OTGHS_DEVFNUM&AT91C_OTGHS_FRAME_NUMBER)>>3) + + +// **************************************************************************** +// **************************************************************************** +// H O S T +// **************************************************************************** +// **************************************************************************** + +/// @defgroup host_management USB host controller drivers +/// These macros manage the USB Host controller. +/// @{ +/// allocates the current configuration in DPRAM memory +//#define Host_allocate_memory() (UPCFG1X |= (1<OTGHS_HSTPIPISR[pip] & AT91C_OTGHS_CFGOK))?FALSE:TRUE) + +/// enables SOF generation +//#define Host_enable_sof() (UHCON |= (1<OTGHS_HSTCTRL |= AT91C_OTGHS_SOFHST + +/// disables SOF generation +#define Host_disable_sof() AT91C_BASE_OTGHS->OTGHS_HSTCTRL &= ~(unsigned int)AT91C_OTGHS_SOFHST + +/// sends a USB Reset to the device +#define Host_send_reset() AT91C_BASE_OTGHS->OTGHS_HSTCTRL |= AT91C_OTGHS_RESET +// *AT91C_OTGHS_TSTA2 |= AT91C_OTGHS_FORCHSRST; +// *AT91C_OTGHS_TSTA2 |= AT91C_OTGHS_UTMIRESET; +// *AT91C_OTGHS_TSTA2 &= ~AT91C_OTGHS_UTMIRESET + +/// tests if USB Reset running +#define Is_host_sending_reset() (AT91C_BASE_OTGHS->OTGHS_HSTCTRL&AT91C_OTGHS_RESET) +//#define Host_is_reset() ((UHCON & (1<OTGHS_HSTCTRL&AT91C_OTGHS_RESET) +#define Is_host_reset() (AT91C_BASE_OTGHS->OTGHS_HSTCTRL&AT91C_OTGHS_RESET) + +/// sends a USB Resume to the device +#define Host_send_resume() AT91C_BASE_OTGHS->OTGHS_HSTCTRL |= AT91C_OTGHS_RESUME +/// tests if USB Resume running +//#define Host_is_resume() ((UHCON & (1<OTGHS_HSTCTRL&AT91C_OTGHS_RESUME) + +/// enables host start of frame interrupt +//#define Host_enable_sof_interrupt() (UHIEN |= (1<OTGHS_HSTIER = AT91C_OTGHS_HSOFI +/// enables host start of frame interrupt +#define Host_disable_sof_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIDR = AT91C_OTGHS_HSOFI +#define Is_host_sof_interrupt_enabled() (AT91C_BASE_OTGHS->OTGHS_HSTIMR&AT91C_OTGHS_HSOFI) +/// tests if SOF detected +//#define Host_is_sof() ((UHINT & (1<OTGHS_HSTISR&AT91C_OTGHS_HSOFI) +#define Host_ack_sof() AT91C_BASE_OTGHS->OTGHS_HSTICR = AT91C_OTGHS_HSOFI + +/// enables host wake up interrupt detection +#define Host_enable_hwup_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIER = AT91C_OTGHS_HWUPI +/// disables host wake up interrupt detection +#define Host_disable_hwup_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIDR = AT91C_OTGHS_HWUPI +#define Is_host_hwup_interrupt_enabled() (AT91C_BASE_OTGHS->OTGHS_HSTIMR&AT91C_OTGHS_HWUPI) +/// tests if host wake up detected +//#define Host_is_hwup() ((UHINT & (1<OTGHS_HSTISR&AT91C_OTGHS_HWUPI) +#define Host_ack_hwup() AT91C_BASE_OTGHS->OTGHS_HSTICR = AT91C_OTGHS_HWUPI + + +/// enables host down stream rsm sent interrupt detection +#define Host_enable_down_stream_resume_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIER = AT91C_OTGHS_RSMEDI +/// disables host down stream rsm sent interrupt detection +#define Host_disable_down_stream_resume_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIDR = AT91C_OTGHS_RSMEDI +//#define Is_host_down_stream_resume_interrupt_enabled() ((UHIEN & (1<OTGHS_HSTISR&AT91C_OTGHS_RSMEDI) +//#define Host_ack_down_stream_resume() (UHINT &= ~(1<OTGHS_HSTICR = AT91C_OTGHS_RSMEDI + +/// enables host remote wake up interrupt detection +//#define Host_enable_remote_wakeup_interrupt() (UHIEN |= (1<OTGHS_HSTIER = AT91C_OTGHS_RXRSMI +/// disables host remote wake up interrupt detection +//#define Host_disable_remote_wakeup_interrupt() (UHIEN &= ~(1<OTGHS_HSTIDR = AT91C_OTGHS_RXRSMI +//#define Is_host_remote_wakeup_interrupt_enabled() ((UHIEN & (1<OTGHS_HSTISR&AT91C_OTGHS_RXRSMI) +/// tests if host wake up detected +//#define Host_is_remote_wakeup() ((UHINT & (1<OTGHS_HSTISR&AT91C_OTGHS_RXRSMI) == AT91C_OTGHS_RXRSMI) +#define Host_ack_remote_wakeup() AT91C_BASE_OTGHS->OTGHS_HSTICR = AT91C_OTGHS_RXRSMI + +#define Host_disable_device_connection_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIDR = AT91C_OTGHS_DCONN +/// enables host device connection interrupt +//#define Host_enable_device_connection_interrupt() (UHIEN |= (1<OTGHS_HSTIER = AT91C_OTGHS_DCONN +/// disables USB device connection interrupt +//#define Host_disable_device_connection_interrupt() (UHIEN &= ~(1<OTGHS_HSTIMR & AT91C_OTGHS_DCONN) +/// tests if a USB device has been detected +//#define Is_device_connection() (UHINT & (1<OTGHS_HSTISR & AT91C_OTGHS_DCONN) +#define Is_host_device_connection() (AT91C_BASE_OTGHS->OTGHS_HSTISR & AT91C_OTGHS_DCONN) +/// acks device connection +//#define Host_ack_device_connection() (UHINT = ~(1<OTGHS_HSTICR = AT91C_OTGHS_DCONN + +/// tests if a USB device has been removed +//#define Is_device_disconnection() (UHINT & (1<OTGHS_HSTISR & AT91C_OTGHS_DDIS) +/// enables host device disconnection interrupt +//#define Host_enable_device_disconnection_interrupt() (UHIEN |= (1<OTGHS_HSTIER = AT91C_OTGHS_DDIS +/// disables USB device connection interrupt +//#define Host_disable_device_disconnection_interrupt() (UHIEN &= ~(1<OTGHS_HSTIDR = AT91C_OTGHS_DDIS +//#define Is_host_device_disconnection_interrupt_enabled() ((UHIEN & (1<OTGHS_HSTIMR & AT91C_OTGHS_DDIS) +/// tests if a USB device has been removed +//#define Is_device_disconnection() (UHINT & (1<OTGHS_HSTISR & AT91C_OTGHS_DDIS) +/// acks device disconnection +//#define Host_ack_device_disconnection() (UHINT = ~(1<OTGHS_HSTICR = AT91C_OTGHS_DDIS + +#define host_get_device_descriptor_incomplete() (usb_request.uncomplete_read == TRUE) +#define Host_enable_reset_sent_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIER = AT91C_OTGHS_RSTI + + +#define Host_disable_reset_sent_interrupt() AT91C_BASE_OTGHS->OTGHS_HSTIDR = AT91C_OTGHS_RSTI +/// enables host USB reset interrupt +//#define Host_enable_reset_interrupt() (UHIEN |= (1<OTGHS_HSTIDR = AT91C_OTGHS_RSTI) +//#define Is_host_reset_interrupt_enabled() ((UHIEN & (1<OTGHS_HSTICR = AT91C_OTGHS_RSTI +/// tests if USB reset has been sent + + +/// switches on VBus +//#define Host_vbus_request() (OTGCON |= (1<OTGHS_SCR = AT91C_OTGHS_VBUSRQ //JCB +/// configures the address to use for the device +//#define Host_configure_address(addr) (UHADDR = addr & MSK_HADDR) +//#define Host_configure_address(addr) AT91C_BASE_OTGHS->OTGHS_HSTCTRL |= addr & 0x3F +//#define Host_configure_address(addr) AT91C_BASE_OTGHS->OTGHS_HSTADDR1 &= ~AT91C_OTGHS_UHADDR_P0; +// AT91C_BASE_OTGHS->OTGHS_HSTADDR1 |= (addr & AT91C_OTGHS_UHADDR_P0) + +/// Get connected device speed, returns TRUE when in full speed mode +#define Is_host_full_speed() (AT91C_BASE_OTGHS->OTGHS_SR&AT91C_OTGHS_SPEED) +/// @} + +#define Usb_disable_otg_pad() AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_OTGPADE + + + +/// @defgroup general_pipe USB pipe drivers +/// These macros manage the common features of the pipes. +/// @{ +/// selects pipe for CPU interface +//#define Host_select_pipe(p) (UPNUM = (unsigned char)p) +#define Host_select_pipe(p) global_pipe_nb = p + +/// get the currently selected pipe number +//#define Host_get_selected_pipe() (UPNUM ) +#define Host_get_selected_pipe() (global_pipe_nb) + +/// enables pipe +//#define Host_enable_pipe() (UPCONX |= (1<OTGHS_HSTPIP |= (1<OTGHS_HSTPIP &= ~(unsigned int)(1<OTGHS_HSTPIPCFG[global_pipe_nb] &= ~(unsigned int)AT91C_OTGHS_PTOKEN;\ + AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[global_pipe_nb] |= AT91C_OTGHS_PTOKEN_SETUP +/// sets IN token +//#define Host_set_token_in() (UPCFG0X = (UPCFG0X & ~MSK_TOKEN_SETUP) | MSK_TOKEN_IN) +#define Host_set_token_in() AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[global_pipe_nb] &= ~(unsigned int)AT91C_OTGHS_PTOKEN;\ + AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[global_pipe_nb] |= AT91C_OTGHS_PTOKEN_IN +/// sets OUT token +//#define Host_set_token_out() (UPCFG0X = (UPCFG0X & ~MSK_TOKEN_SETUP) | MSK_TOKEN_OUT) +#define Host_set_token_out() AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[global_pipe_nb] &= ~(unsigned int)AT91C_OTGHS_PTOKEN;\ + AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[global_pipe_nb] |= AT91C_OTGHS_PTOKEN_OUT + +/// returns the number of the endpoint associated to the current pipe +//#define Host_get_endpoint_number() (UPCFG0X & (1<OTGHS_HSTPIPCFG[global_pipe_nb]&AT91C_OTGHS_PEPNUM)>>16) + +/// returns pipe interrupt register +#define Host_get_pipe_interrupt() ((AT91C_BASE_OTGHS->OTGHS_HSTISR>>8)&0x7F) + +/// sets the interrupt frequency +//#define Host_set_interrupt_frequency(pip, frq) (AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[pip]|=AT91C_OTGHS_INTFRQ&(frq<<24)) + +/// tests if current pipe is configured +#define Is_pipe_configured() (AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[global_pipe_nb]&AT91C_OTGHS_CFGOK) +/// tests if at least one bank is busy +//#define Is_host_one_bank_busy() ((UPSTAX & (1<OTGHS_HSTPIPISR[pip]&AT91C_OTGHS_NBUSYBK)!=0) +/// returns the number of busy banks +//#define Host_number_of_busy_bank() (UPSTAX & (1<OTGHS_HSTPIP|=(1<<16<OTGHS_HSTPIP&=~(unsigned int)(1<<16<OTGHS_READEPT0[global_pipe_nb << 14]=data +//#define Host_write_byte(data) (((char*)((unsigned int *)AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0))[dBytes++])=data +#define Host_write_byte(data) pFifo[dBytes++]=data + +#define Host_write_32(data) AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0[0]=data +/// reads a byte from the pipe FIFO +//#define Host_read_byte() (UPDATX) +//#define Host_read_byte() (U8)(((char*)((unsigned int *)AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0))[dBytes++]) +#define Host_read_byte() pFifo[dBytes++] +//#define Host_read_byte_index(pip, index) pfifo[index] = pEndpoint->pData[index++]; +//#define Host_read_32(pip) AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0[pip << 14] + +/// freezes the pipe +//#define Host_freeze_pipe() (UPCONX |= (1<OTGHS_HSTPIPIER[global_pipe_nb] = AT91C_OTGHS_FREEZE +#define Host_freeze_pipe() AT91C_BASE_OTGHS->OTGHS_HSTPIPIER[global_pipe_nb] = AT91C_OTGHS_FREEZE +/// un-freezees the pipe +//#define Host_unfreeze_pipe() (UPCONX &= ~(1<OTGHS_HSTPIPIMR[global_pipe_nb] & AT91C_OTGHS_FREEZE)); +// AT91C_BASE_OTGHS->OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_FREEZE +#define Host_unfreeze_pipe() while(!(AT91C_BASE_OTGHS->OTGHS_HSTPIPIMR[global_pipe_nb] & AT91C_OTGHS_FREEZE));\ + AT91C_BASE_OTGHS->OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_FREEZE +/// tests if the current pipe is frozen +//#define Is_host_pipe_freeze() (UPCONX & (1<OTGHS_HSTPIPIMR[global_pipe_nb] & AT91C_OTGHS_FREEZE) + +/// resets data toggle +#define Host_reset_pipe_data_toggle(pip) AT91C_BASE_OTGHS->OTGHS_HSTPIPIER[pip] = AT91C_OTGHS_RSTDT + +/// tests if SETUP has been sent +#define Is_host_setup_sent() (AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[0] & AT91C_OTGHS_TXSTPI) +/// tests if control IN has been received +#define Is_host_control_in_received() (AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[0] & AT91C_OTGHS_RXINI) +/// tests if control OUT has been sent +//#define Is_host_control_out_sent() ((UPINTX & (1<OTGHS_HSTPIPISR[0] & AT91C_OTGHS_TXOUT) +/// tests if a STALL has been received +//#define Is_host_stall() ((UPINTX & (1<OTGHS_HSTPIPISR[global_pipe_nb] & AT91C_OTGHS_RXSTALL) +/// tests if an error occurs on current pipe +//#define Is_host_pipe_error() ((UPINTX & (1<OTGHS_HSTPIPISR[global_pipe_nb] & AT91C_OTGHS_PERR) + +/// sends a setup +//#define Host_send_setup() (UPINTX &= ~(1<OTGHS_HSTPIPIDR[0] = AT91C_OTGHS_FIFOCON +/// sends a control IN +//#define Host_send_control_in() (UPINTX &= ~(1<OTGHS_HSTPIPIDR[0] = AT91C_OTGHS_FIFOCON +#define Host_send_control() AT91C_BASE_OTGHS->OTGHS_HSTPIPIDR[0] = AT91C_OTGHS_FIFOCON +/// sends a control OUT +//#define Host_send_control_out() (UPINTX &= ~(1<OTGHS_HSTPIPIDR[0] = AT91C_OTGHS_FIFOCON + +/// acks control OUT +//#define Host_ack_control_out() (UPINTX &= ~(1<OTGHS_HSTPIPICR[0] = AT91C_OTGHS_TXOUT +/// acks control IN +//#define Host_ack_control_in() (UPINTX &= ~(1<OTGHS_HSTPIPICR[0] = AT91C_OTGHS_RXINI +/// acks setup +//#define Host_ack_setup() (UPINTX &= ~(1<OTGHS_HSTPIPICR[0] = AT91C_OTGHS_TXSTPI +/// acks STALL reception +//#define Host_ack_stall() (UPINTX &= ~(1<OTGHS_HSTPIPICR[global_pipe_nb] = AT91C_OTGHS_RXSTALL + +/// sends a OUT +//#define Host_send_out() (UPINTX &= ~(1<OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_FIFOCON +/// tests if OUT has been sent +//#define Is_host_out_sent() ((UPINTX & (1<OTGHS_HSTPIPISR[global_pipe_nb] & AT91C_OTGHS_TXOUT) +/// acks OUT sent +//#define Host_ack_out_sent() (UPINTX &= ~(1<OTGHS_HSTPIPICR[global_pipe_nb] = AT91C_OTGHS_TXOUT + +/// tests if IN received +//#define Is_host_in_received() ((UPINTX & (1<OTGHS_HSTPIPISR[global_pipe_nb] & AT91C_OTGHS_RXINI) +/// acks IN reception +//#define Host_ack_in_received() (UPINTX &= ~(1<OTGHS_HSTPIPICR[global_pipe_nb] = AT91C_OTGHS_RXINI +/// sends a IN +//#define Host_send_in() (UPINTX &= ~(1<OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_FIFOCON +/// tests if nak handshake has been received +//#define Is_host_nak_received() ((UPINTX & (1<OTGHS_HSTPIPISR[global_pipe_nb] & AT91C_OTGHS_NAKEDI) +/// acks NAk received sent +//#define Host_ack_nak_received() (UPINTX &= ~(1<OTGHS_HSTPIPICR[global_pipe_nb] = AT91C_OTGHS_NAKEDI + +/// tests if endpoint read allowed +//#define Is_host_read_enabled() (UPINTX&(1<OTGHS_HSTPIPISR[global_pipe_nb] & AT91C_OTGHS_RWALL) +/// tests if endpoint read allowed +//#define Is_host_write_enabled() (UPINTX&(1<OTGHS_HSTPIPINRQ[global_pipe_nb] &= ~(unsigned int)AT91C_OTGHS_INMOD +/// sets IN in continuous mode +//#define Host_continuous_in_mode() (UPCONX |= (1<OTGHS_HSTPIPINRQ[global_pipe_nb] |= AT91C_OTGHS_INMOD + +/// sets number of IN requests to perform before freeze +//#define Host_in_request_number(in_num) (UPINRQX = (unsigned char)in_num) +#define Host_in_request_number(pip, in_num) AT91C_BASE_OTGHS->OTGHS_HSTPIPINRQ[pip] &= ~(unsigned int)AT91C_OTGHS_INMOD;\ + AT91C_BASE_OTGHS->OTGHS_HSTPIPINRQ[pip] &= ~(unsigned int)AT91C_OTGHS_INRQ;\ + AT91C_BASE_OTGHS->OTGHS_HSTPIPINRQ[pip] |= in_num +/// returns number of remaining IN requests +//#define Host_get_in_request_number() (UPINRQX) + +/// returns number of bytes (8 bits) +//#define Host_data_length_U8() (UPBCLX) +#define Host_data_length_U8() (unsigned short)((AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[global_pipe_nb]&AT91C_OTGHS_PBYCT)>>20) +#define UPBCLX (unsigned short)((AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[global_pipe_nb]&AT91C_OTGHS_PBYCT)>>20) + +/// returns number of bytes (16 bits) +//#define Host_data_length_U16() ((((unsigned short)UPBCHX)<<8) | UPBCLX) +#define Host_data_length_U16() (unsigned short)((AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[global_pipe_nb]&AT91C_OTGHS_PBYCT)>>20) +/// for device compatibility +//#define Host_byte_counter() Host_data_length_U16() +#define Host_byte_counter() Host_data_length_U16() +/// for device compatibility +//#define Host_byte_counter_8() Host_data_length_U8() + +/// returns the size of the current pipe +//#define Host_get_pipe_length() ((unsigned short)0x08 << ((UPCFG1X & MSK_PSIZE)>>4)) +//#define Host_get_pipe_length() (unsigned short)(((AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[global_pipe_nb]&AT91C_OTGHS_PSIZE)>>4)? +// (8<<((AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[global_pipe_nb]&AT91C_OTGHS_PSIZE)>>4)):8) + +/// returns the type of the current pipe +//#define Host_get_pipe_type() (UPCFG0X>>6) +#define Host_get_pipe_type() ((AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[global_pipe_nb]&AT91C_OTGHS_PTYPE)>>12) + +/// tests if error occurs on pipe +//#define Host_error_status() (UPERRX & MSK_ERROR) +#define Host_error_status() (unsigned long)(AT91C_BASE_OTGHS->OTGHS_HSTPIPERR[global_pipe_nb]) +/// acks all pipe error +//#define Host_ack_all_errors() (UPERRX = 0x00) +#define Host_ack_all_errors() AT91C_BASE_OTGHS->OTGHS_HSTPIPERR[global_pipe_nb] = 0 + +/// Enable pipe end transmission interrupt +//#define Host_enable_transmit_interrupt() (UPIENX |= (1<OTGHS_HSTPIPIER[global_pipe_nb] = AT91C_OTGHS_TXOUT +/// Disable pipe end transmission interrupt +//#define Host_disable_transmit_interrupt() (UPIENX &= ~(1<OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_TXOUT + +/// Enable pipe reception interrupt +//#define Host_enable_receive_interrupt() (UPIENX |= (1<OTGHS_HSTPIPIER[global_pipe_nb] = AT91C_OTGHS_RXINI +/// Disable pipe recption interrupt +//#define Host_disable_receive_interrupt() (UPIENX &= ~(1<OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_RXINI + +/// Enable pipe stall interrupt +//#define Host_enable_stall_interrupt() (UPIENX |= (1<OTGHS_HSTPIPIER[global_pipe_nb] = AT91C_OTGHS_RXSTALL +/// Disable pipe stall interrupt +//#define Host_disable_stall_interrupt() (UPIENX &= ~(1<OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_RXSTALL + +/// Enable pipe error interrupt +//#define Host_enable_error_interrupt() (UPIENX |= (1<OTGHS_HSTPIPIER[global_pipe_nb] = AT91C_OTGHS_PERR +/// Disable pipe error interrupt +//#define Host_disable_error_interrupt() (UPIENX &= ~(1<OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_PERR + +/// Enable pipe NAK interrupt +//#define Host_enable_nak_interrupt() (UPIENX |= (1<OTGHS_HSTPIPIER[global_pipe_nb] = AT91C_OTGHS_NAKEDI +/// Disable pipe NAK interrupt +//#define Host_disable_nak_interrupt() (UPIENX &= ~(1<OTGHS_HSTPIPIDR[global_pipe_nb] = AT91C_OTGHS_NAKEDI + +//#define Get_pipe_token(x) ((x & (0x80)) ? TOKEN_IN : TOKEN_OUT) +#define Get_pipe_token(x) ((x & (0x80)) ? TOKEN_IN : TOKEN_OUT) + + +//_____ D E C L A R A T I O N ______________________________________________ + +extern unsigned char dev_configure_endpoint(unsigned char ept, + unsigned char type, + unsigned char dir, + unsigned char size, + unsigned char bank, + unsigned char nyet); + + +extern unsigned char usb_select_enpoint_interrupt (void); +extern unsigned char usb_send_packet(unsigned char, unsigned char*, unsigned char); +extern unsigned char usb_read_packet(unsigned char, unsigned char*, unsigned char); + +extern unsigned char host_config_pipe(unsigned char, unsigned char); +extern unsigned char host_determine_pipe_size(unsigned short); +extern void host_disable_all_pipe(void); +extern unsigned char host_get_nb_pipe_interrupt(void); +extern U16 host_get_pipe_length(void); +extern void host_configure_address( unsigned char pipe, unsigned char addr); + +#endif // _USB_DRV_H + diff --git a/usb/otg/usb_host_enum.c b/usb/otg/usb_host_enum.c new file mode 100644 index 0000000..69c9ba5 --- /dev/null +++ b/usb/otg/usb_host_enum.c @@ -0,0 +1,670 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/// This file manages the host enumeration process + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ +#include +#include "usb/otg/usb_drv.h" +#include "usb_host_enum.h" +#include "usb/otg/usb_task.h" +#include "usb_host_task.h" +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ +#if (MAX_INTERFACE_SUPPORTED<1) +#error MAX_INTERFACE_SUPPORTED<1 : The host controller should support at least one interface... +#endif + +#ifndef VID_PID_TABLE + #error VID_PID_TABLE should be defined somewhere (conf_usb.h) + // VID_PID_TABLE format definition: + // #define VID_PID_TABLE {VID1, number_of_pid_for_this_VID1, PID11_value,..., PID1X_Value + // ... + // ,VIDz, number_of_pid_for_this_VIDz, PIDz1_value,..., PIDzX_Value} +#endif + +#ifndef CLASS_SUBCLASS_PROTOCOL + #error CLASS_SUBCLASS_PROTOCOL shoud be defined somewhere (conf_usb.h) + // CLASS_SUBCLASS_PROTOCOL format definition: + // #define CLASS_SUBCLASS_PROTOCOL {CLASS1, SUB_CLASS1,PROTOCOL1, + // ... + // CLASSz, SUB_CLASSz,PROTOCOLz} +#endif + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +//! Const table of known devices (see conf_usb.h for table content) +U16 registered_VID_PID[] = VID_PID_TABLE; + +//! Const table of known class (see conf_usb.h for table content) +U8 registered_class[] = CLASS_SUBCLASS_PROTOCOL; + +//! Physical EP to address device endpoints look-up table +// This table is dynamically built with the "host_configure_endpoint_class" function +U8 ep_table[MAX_EP_NB]={0,0,0,0,0,0,0}; + +//! The number of interface the host is able to support in the device connected +U8 nb_interface_supported=0; + +S_interface interface_supported[MAX_INTERFACE_SUPPORTED]; + +//! PID of device connected +U16 device_PID; +//! VID of device connected +U16 device_VID; +//! bmAttributes byte of the connected device +U8 bmattributes; +//! maxpower byte of the connected device (Caution, unit is 2mA) +U8 maxpower; + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// checks if the VID and the PID are supported +/// (if the VID/PID belongs to the VID_PID table) +//------------------------------------------------------------------------------ +U8 host_check_VID_PID(void) +{ + U8 nb_of_vid; + U8 nb_of_pid; + + TRACE_DEBUG("host_check_VID_PID\n\r"); + // Rebuild VID PID from data stage + LSB(device_VID) = data_stage[OFFSET_FIELD_LSB_VID]; + MSB(device_VID) = data_stage[OFFSET_FIELD_MSB_VID]; + LSB(device_PID) = data_stage[OFFSET_FIELD_LSB_PID]; + MSB(device_PID) = data_stage[OFFSET_FIELD_MSB_PID]; + + // Compare detected VID PID with supported table + nb_of_vid=0; + while (nb_of_vid< sizeof(registered_VID_PID)/2) // /2 because registered_VID_PID table is U16... + { + TRACE_DEBUG("registered_VID_PID[%d]: 0x%X\n\r", nb_of_vid, registered_VID_PID[nb_of_vid]); + TRACE_DEBUG("device_VID: 0x%X\n\r", device_VID); + if (registered_VID_PID[nb_of_vid] == device_VID) // VID is correct + { + TRACE_DEBUG("Good VID\n\r"); + nb_of_pid = (U8)registered_VID_PID[nb_of_vid+1]; // store nb of PID for this VID + while (nb_of_pid != 0) + { + TRACE_DEBUG("registered_VID_PID[%d]: 0x%X\n\r", nb_of_vid+nb_of_pid+1, registered_VID_PID[nb_of_vid+nb_of_pid+1]); + TRACE_DEBUG("device_PID: 0x%X\n\r", device_PID); + if (registered_VID_PID[nb_of_vid+nb_of_pid+1] == device_PID) + { + TRACE_DEBUG("Good PID\n\r"); + return HOST_TRUE; + } + nb_of_pid--; + } + } + nb_of_vid+=registered_VID_PID[nb_of_vid+1]+2; + } + return HOST_FALSE; +} + + +//------------------------------------------------------------------------------ +/// checks if the device class is supported. +/// The function looks in all interface declared in the received dewcriptors, if +/// one of them match with the CLASS/SUB_CLASS/PROTOCOL table +//------------------------------------------------------------------------------ +U8 host_check_class(void) +{ + U8 class_table; + T_DESC_OFFSET descriptor_offset; + T_DESC_OFFSET conf_offset_end; + U16 config_size; + U8 device_class; + U8 device_subclass; + U8 device_protocol; + + TRACE_DEBUG("host_check_class\n\r"); + nb_interface_supported=0; //First asumes ,no interface is supported! + if (data_stage[OFFSET_FIELD_DESCRIPTOR_TYPE] != USBGenericDescriptor_CONFIGURATION) // check if configuration descriptor + { + TRACE_DEBUG("host_check_class problem\n\r"); + return HOST_FALSE; + } + LSB(config_size) = data_stage[OFFSET_FIELD_TOTAL_LENGHT]; + MSB(config_size) = data_stage[OFFSET_FIELD_TOTAL_LENGHT+1]; + bmattributes = data_stage[OFFSET_FIELD_BMATTRIBUTES]; + maxpower = data_stage[OFFSET_FIELD_MAXPOWER]; + descriptor_offset = 0; + conf_offset_end = descriptor_offset + config_size; + + // Look in all interfaces declared in the configuration + while(descriptor_offset < conf_offset_end) + { + // Find next interface descriptor + while (data_stage[descriptor_offset+OFFSET_FIELD_DESCRIPTOR_TYPE] != USBGenericDescriptor_INTERFACE) + { + descriptor_offset += data_stage[descriptor_offset]; + if(descriptor_offset >= conf_offset_end) + { + if(nb_interface_supported) + { + TRACE_DEBUG("host_check_class ok\n\r"); + return HOST_TRUE; + } + else + { + TRACE_DEBUG("host_check_class problem2\n\r"); + return HOST_FALSE; + } + } + } + // Found an interface descriptor + // Get charateristics of this interface + device_class = data_stage[descriptor_offset + OFFSET_FIELD_CLASS]; + device_subclass = data_stage[descriptor_offset + OFFSET_FIELD_SUB_CLASS]; + device_protocol = data_stage[descriptor_offset + OFFSET_FIELD_PROTOCOL]; + // Look in registered class table for match + class_table=0; + while (class_table< sizeof(registered_class)) + { + if (registered_class[class_table] == device_class) // class is correct! + { + if (registered_class[class_table+1] == device_subclass) // sub class is correct! + { + if (registered_class[class_table+2] == device_protocol) // protocol is correct! + { + // Prepare for another item CLASS/SUB_CLASS/PROTOCOL in table + class_table+=3; + // Store this interface as supported interface + // Memorize its interface nb + interface_supported[nb_interface_supported].interface_nb=data_stage[descriptor_offset+OFFSET_FIELD_INTERFACE_NB]; + // its alternate setting + interface_supported[nb_interface_supported].altset_nb=data_stage[descriptor_offset+OFFSET_FIELD_ALT]; + // its USB class + interface_supported[nb_interface_supported].class=device_class; + // its USB subclass + interface_supported[nb_interface_supported].subclass=device_subclass; + // its USB protocol + interface_supported[nb_interface_supported].protocol=device_protocol; + // the number of endpoints associated to this interface + // Note: The associated endpoints addresses are stored during pipe attribution... + interface_supported[nb_interface_supported].nb_ep=data_stage[descriptor_offset+OFFSET_FIELS_NB_OF_EP]; + // Update the number of interface supported + nb_interface_supported++; + // Check the maximum number of interfaces we can support + if(nb_interface_supported>=MAX_INTERFACE_SUPPORTED) + { + TRACE_DEBUG("host_check_class ok1\n\r"); + return HOST_TRUE; + } + } + } + } + class_table+=3; // Check other item CLASS/SUB_CLASS/PROTOCOL in table + } + descriptor_offset += data_stage[descriptor_offset]; // Next descriptor + if(descriptor_offset > SIZEOF_DATA_STAGE) // Check overflow + { + if(nb_interface_supported) + { + TRACE_DEBUG("host_check_class ok3\n\r"); + return HOST_TRUE; + } + else + { + TRACE_DEBUG("host_check_class problem3\n\r"); + return HOST_FALSE; + } + } + } + if(nb_interface_supported) + { + TRACE_DEBUG("host_check_class ok4\n\r"); + return HOST_TRUE; + } + else + { + TRACE_DEBUG("host_check_class problem4\n\r"); + return HOST_FALSE; + } +} + +//------------------------------------------------------------------------------ +/// configures the pipe according to the device class of the +//------------------------------------------------------------------------------ +U8 host_auto_configure_endpoint(void) +{ + U8 nb_endpoint_to_configure; + T_DESC_OFFSET descriptor_offset; + U8 physical_pipe=1; // =1 cause lookup table assumes that physiacl pipe 0 is reserved for control + U8 i; + U8 ep_index; + + TRACE_DEBUG("host_auto_configure_endpoint\n\r"); + // For all interfaces to configure... + for(i=0;i SIZEOF_DATA_STAGE) // No more endpoint descriptor found -> Errror ! + { + TRACE_DEBUG("PB\n\r"); + return HOST_FALSE; + } + } + + // Select the new physical pipe to configure and get ride of any previous configuration for this physical pipe + Host_select_pipe(physical_pipe); + Host_disable_pipe(); + Host_enable_pipe(); + + // Build the pipe configuration according to the endpoint descriptors fields received + // + // host_configure_pipe( + // physical_pipe, // pipe nb in USB interface + // data_stage[descriptor_offset+OFFSET_FIELD_EP_TYPE], // pipe type (interrupt/BULK/ISO) + // Get_pipe_token(data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR]), // pipe addr + // (data_stage[descriptor_offset+2] & MSK_EP_DIR), // pipe dir (IN/OUT) + // host_determine_pipe_size((U16)data_stage[descriptor_offset+OFFSET_FIELD_EP_SIZE]),// pipe size + // ONE_BANK, // bumber of bank to allocate for pipe + // data_stage[descriptor_offset+OFFSET_FIELD_EP_INTERVAL] // interrupt period (for interrupt pipe) + // ); + + host_configure_pipe( + physical_pipe, + data_stage[descriptor_offset+OFFSET_FIELD_EP_TYPE], + Get_pipe_token(data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR]), + (data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR] & MSK_EP_DIR), + host_determine_pipe_size( + (U16)data_stage[descriptor_offset+OFFSET_FIELD_EP_SIZE_LOW] + + (((U16)data_stage[descriptor_offset+OFFSET_FIELD_EP_SIZE_HIGH])<<8)), + ONE_BANK, + data_stage[descriptor_offset+OFFSET_FIELD_EP_INTERVAL] ); + + host_configure_address(physical_pipe, DEVICE_ADDRESS); + + // Update Physical Pipe lookup table with device enpoint address + ep_table[physical_pipe]=data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR]; + physical_pipe++; + // Update endpoint addr table in supported interface structure + interface_supported[i].ep_addr[ep_index++]=data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR]; + descriptor_offset += data_stage[descriptor_offset]; // pointing on next descriptor + + // All target endpoints configured ? + nb_endpoint_to_configure--; + } //for(i=0;i SIZEOF_DATA_STAGE) + { + return HOST_FALSE; + } + } + if (data_stage[descriptor_offset+OFFSET_FIELD_INTERFACE_NB]==interface + && data_stage[descriptor_offset+OFFSET_FIELD_ALT]==alt) + { + return descriptor_offset; + } + descriptor_offset += data_stage[descriptor_offset]; + } + return descriptor_offset; +} + +//------------------------------------------------------------------------------ +/// returns the physical pipe number linked to a logical endpoint address. +//------------------------------------------------------------------------------ +U8 host_get_hwd_pipe_nb(U8 ep_addr) +{ + U8 i; + + for(i=0; iOTGHS_HSTPIPISR[0] & AT91C_OTGHS_TXSTPI) != 0); + // Freeze the pipe + Host_freeze_pipe(); + + status=(CONTROL_GOOD); + goto host_send_control_end; + } + + // OUT request management --------------------------------------------- + else // Data stage OUT (bmRequestType==0) + { + Host_set_token_out(); + Host_ack_control_out(); + while(data_length != 0) + { + Host_unfreeze_pipe(); + status = host_get_pipe_length(); + if ( (U16)status > data_length) + { + status = (U8)data_length; + data_length = 0; + } + else + { + data_length -= status; + } + Address_fifochar_endpoint(global_pipe_nb); + while (status!=0) + { + Host_write_byte(*data_pointer); + data_pointer++; + status--; + } + Host_send_control_out(); + while (!Is_host_control_out_sent()) + { + if (Is_host_emergency_exit()) + { + status=CONTROL_TIMEOUT; + Host_freeze_pipe(); + Host_reset_pipe(0); + goto host_send_control_end; + } + if(Is_host_pipe_error()) + { + status = Host_error_status(); + Host_ack_all_errors(); + goto host_send_control_end; + } + if(Is_host_stall()) + { + status=CONTROL_STALL; + Host_ack_stall(); + goto host_send_control_end; + } + } + Host_ack_control_out(); + } // end of OUT data stage + Host_freeze_pipe(); + Host_set_token_in(); + Host_unfreeze_pipe(); + while(!Is_host_control_in_received()) + { + if (Is_host_emergency_exit()) + { + status=CONTROL_TIMEOUT; + Host_freeze_pipe(); + Host_reset_pipe(0); + goto host_send_control_end; + } + if(Is_host_pipe_error()) + { + status = Host_error_status(); + Host_ack_all_errors(); + goto host_send_control_end; + } + if(Is_host_stall()) + { + status=CONTROL_STALL; + Host_ack_stall(); + goto host_send_control_end; + } + } + Host_ack_control_in(); + Host_freeze_pipe(); + Host_send_control_in(); + status=(CONTROL_GOOD); + goto host_send_control_end; + } + +host_send_control_end: + return ((U8)status); +} + + diff --git a/usb/otg/usb_host_enum.h b/usb/otg/usb_host_enum.h new file mode 100644 index 0000000..959cb52 --- /dev/null +++ b/usb/otg/usb_host_enum.h @@ -0,0 +1,329 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +#ifndef _USB_HOST_ENUM_H_ +#define _USB_HOST_ENUM_H_ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ +#ifndef SIZEOF_DATA_STAGE + #error SIZEOF_DATA_STAGE should be defined in conf_usb.h +#endif + +#if (SIZEOF_DATA_STAGE<0xFF) //! Optimize descriptor offset index according to data_stage[] size + #define T_DESC_OFFSET U8 //! U8 is enought and faster +#else + #define T_DESC_OFFSET U16 //! U16 required ! +#endif + +#ifndef MAX_EP_PER_INTERFACE + #define MAX_EP_PER_INTERFACE 4 +#endif + + + + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ +typedef struct +{ + U8 bmRequestType; //!< Characteristics of the request + U8 bRequest; //!< Specific request + U16 wValue; //!< field that varies according to request + U16 wIndex; //!< field that varies according to request + U16 wLength; //!< Number of bytes to transfer if Data + U8 uncomplete_read; //!< 1 = only one read +} S_usb_setup_data; + + +typedef struct +{ + U8 interface_nb; + U8 altset_nb; + U16 class; + U16 subclass; + U16 protocol; + U8 nb_ep; + U8 ep_addr[MAX_EP_PER_INTERFACE]; +} S_interface; + +#define CONTROL_GOOD 0 +#define CONTROL_TIMEOUT 0x08 +#define CONTROL_STALL 0x20 + + +//!< Set of defines for offset in data stage +#define OFFSET_FIELD_MAXPACKETSIZE 7 +#define OFFSET_FIELD_MSB_VID 9 +#define OFFSET_FIELD_LSB_VID 8 +#define OFFSET_FIELD_MSB_PID 11 +#define OFFSET_FIELD_LSB_PID 10 + +#define OFFSET_DESCRIPTOR_LENGHT 0 +#define OFFSET_FIELD_DESCRIPTOR_TYPE 1 +#define OFFSET_FIELD_TOTAL_LENGHT 2 +#define OFFSET_FIELD_BMATTRIBUTES 7 +#define OFFSET_FIELD_MAXPOWER 8 + +#define OFFSET_FIELD_OTG_FEATURES 2 +#define OTG_DESCRIPTOR_bLength 0x03 + +//! OFFSET for INTERFACE DESCRIPTORS +#define OFFSET_FIELD_INTERFACE_NB 2 +#define OFFSET_FIELD_ALT 3 +#define OFFSET_FIELS_NB_OF_EP 4 +#define OFFSET_FIELD_NB_INTERFACE 4 // Nb of endpoint used by this interface +#define OFFSET_FIELD_CLASS 5 +#define OFFSET_FIELD_SUB_CLASS 6 +#define OFFSET_FIELD_PROTOCOL 7 + + +#define OFFSET_FIELD_EP_ADDR 2 +#define OFFSET_FIELD_EP_TYPE 3 +#define OFFSET_FIELD_EP_SIZE_LOW 4 +#define OFFSET_FIELD_EP_SIZE_HIGH 5 +#define OFFSET_FIELD_EP_INTERVAL 6 + +//! defines for Hub detection +#define OFFSET_DEV_DESC_CLASS 4 // offset for the CLASS field in the Device Descriptor +#define HUB_CLASS_CODE 9 // value of Hub CLASS + + +#define HOST_FALSE 0 +#define HOST_TRUE 1 + + +//----------------------------------------------------------------------------- +// Exported macro +//----------------------------------------------------------------------------- + +/// send a clear endpoint request +#define host_clear_endpoint_feature(ep) (usb_request.bmRequestType = 0x02,\ + usb_request.bRequest = USBGenericRequest_CLEARFEATURE,\ + usb_request.wValue = USBFeatureRequest_ENDPOINTHALT << 8,\ + usb_request.wIndex = ep,\ + usb_request.wLength = 0,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) +/// send a get configuration request +#define host_get_configuration() (usb_request.bmRequestType = 0x80,\ + usb_request.bRequest = USBGenericRequest_GETCONFIGURATION,\ + usb_request.wValue = 0,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 1,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) +/// send a set configuration request +#define host_set_configuration(cfg_nb) (usb_request.bmRequestType = 0x00,\ + usb_request.bRequest = USBGenericRequest_SETCONFIGURATION,\ + usb_request.wValue = cfg_nb,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 0,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) +/// send a set interface request to specify a specific alt setting for an +/// interface +#define host_set_interface(interface_nb,alt_setting) \ + (usb_request.bmRequestType = 0x00,\ + usb_request.bRequest = USBGenericRequest_SETINTERFACE,\ + usb_request.wValue = alt_setting,\ + usb_request.wIndex = interface_nb,\ + usb_request.wLength = 0,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) + +/// send a get device desriptor request. +/// The descriptor table received is stored in data_stage array. +/// The received descriptors is limited to the control pipe lenght +#define host_get_device_descriptor_uncomplete() \ + (usb_request.bmRequestType = 0x80,\ + usb_request.bRequest = USBGenericRequest_GETDESCRIPTOR,\ + usb_request.wValue = USBGenericDescriptor_DEVICE << 8,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 64,\ + usb_request.uncomplete_read = TRUE,\ + host_send_control(data_stage)) + +/// send a get device desriptor request. +/// The descriptor table received is stored in data_stage array. +#define host_get_device_descriptor() (usb_request.bmRequestType = 0x80,\ + usb_request.bRequest = USBGenericRequest_GETDESCRIPTOR,\ + usb_request.wValue = USBGenericDescriptor_DEVICE << 8,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 18,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) +/// send a get device configuration request. +/// The configuration descriptor table received is stored in data_stage array. +#define host_get_configuration_descriptor()(usb_request.bmRequestType = 0x80,\ + usb_request.bRequest = USBGenericRequest_GETDESCRIPTOR,\ + usb_request.wValue = USBGenericDescriptor_CONFIGURATION << 8,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 255,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) + +#define host_get_descriptor_uncomplete() (usb_request.bmRequestType = 0x80,\ + usb_request.bRequest = USBGenericRequest_GETDESCRIPTOR,\ + usb_request.wValue = 0,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 64,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) +/// send a set address request. +#define host_set_address(addr) (usb_request.bmRequestType = 0x00,\ + usb_request.bRequest = USBGenericRequest_SETADDRESS,\ + usb_request.wValue = (U16)addr,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 0,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) + +/// send a set feature device remote wakeup +#define host_set_feature_remote_wakeup() (usb_request.bmRequestType = 0x00,\ + usb_request.bRequest = USBGenericRequest_SETFEATURE,\ + usb_request.wValue = 1,\ + usb_request.wIndex = 1,\ + usb_request.wLength = 0,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) + +/// send a set feature "a_hnp_support" to tell to B-Device that A-Device support HNP +#define host_set_feature_a_hnp_support() (usb_request.bmRequestType = 0x00,\ + usb_request.bRequest = USBGenericRequest_SETFEATURE,\ + usb_request.wValue = 4,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 0,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) + +/// send a set feature "b_hnp_enable" to make B-Device initiating a HNP +#define host_set_feature_b_hnp_enable() (usb_request.bmRequestType = 0x00,\ + usb_request.bRequest = USBGenericRequest_SETFEATURE,\ + usb_request.wValue = 3,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 0,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) + +/// send the mass storage specific request "get max lun" +#define host_ms_get_max_lun() (usb_request.bmRequestType = 0xA1,\ + usb_request.bRequest = MS_GET_MAX_LUN,\ + usb_request.wValue = 0,\ + usb_request.wIndex = 0,\ + usb_request.wLength = 1,\ + usb_request.uncomplete_read = FALSE,\ + host_send_control(data_stage)) +/// returns the VID of the device connected +#define Get_VID() (device_VID) + +/// returns the PID of the device connected +#define Get_PID() (device_PID) + +/// returns the maximum power consumption ot hte connected device (unit is 2mA) +#define Get_maxpower() (maxpower) + +/// returns the USB class associated to the specified interface +#define Get_class(s_interface) (interface_supported[s_interface].class) + +/// returns the USB subclass associated to the specified interface +#define Get_subclass(s_interface) (interface_supported[s_interface].subclass) + +/// returns the USB protocol associated to the specified interface +#define Get_protocol(s_interface) (interface_supported[s_interface].protocol) + +/// returns endpoint address associated to the specified interface and +/// endpoint number in this interface. +#define Get_ep_addr(s_interface,n_ep) (interface_supported[s_interface].ep_addr[n_ep]) + +/// returns number of endpoints associated to +#define Get_nb_ep(s_interface) (interface_supported[s_interface].nb_ep) + +/// returns number of the alternate setting field associated to +#define Get_alts_s(s_interface) (interface_supported[s_interface].altset_nb) + +/// returns number of the interface number associated to +#define Get_interface_number(s_interface) (interface_supported[s_interface].interface_nb) + +/// returns the number of interface supported in the device connected +#define Get_nb_supported_interface() (nb_interface_supported) + +#define BIT_SELF_POWERED 6 // offset +/// returns true if the device connected is self powered +#define Is_device_self_powered() ((bmattributes & (1< +#include "usb/otg/usb_drv.h" +#include "usb_host_enum.h" +#include "usb/otg/usb_task.h" +#include "usb_host_task.h" +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ +#if (MAX_INTERFACE_SUPPORTED<1) +#error MAX_INTERFACE_SUPPORTED<1 : The host controller should support at least one interface... +#endif + +#ifndef VID_PID_TABLE + #error VID_PID_TABLE should be defined somewhere (conf_usb.h) + // VID_PID_TABLE format definition: + // #define VID_PID_TABLE {VID1, number_of_pid_for_this_VID1, PID11_value,..., PID1X_Value + // ... + // ,VIDz, number_of_pid_for_this_VIDz, PIDz1_value,..., PIDzX_Value} +#endif + +#ifndef CLASS_SUBCLASS_PROTOCOL + #error CLASS_SUBCLASS_PROTOCOL shoud be defined somewhere (conf_usb.h) + // CLASS_SUBCLASS_PROTOCOL format definition: + // #define CLASS_SUBCLASS_PROTOCOL {CLASS1, SUB_CLASS1,PROTOCOL1, + // ... + // CLASSz, SUB_CLASSz,PROTOCOLz} +#endif + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +//! Const table of known devices (see conf_usb.h for table content) +U16 registered_VID_PID[] = VID_PID_TABLE; + +//! Const table of known class (see conf_usb.h for table content) +U8 registered_class[] = CLASS_SUBCLASS_PROTOCOL; + +//! Physical EP to address device endpoints look-up table +// This table is dynamically built with the "host_configure_endpoint_class" function +U8 ep_table[MAX_EP_NB]={0,0,0,0,0,0,0}; + +//! The number of interface the host is able to support in the device connected +U8 nb_interface_supported=0; + +S_interface interface_supported[MAX_INTERFACE_SUPPORTED]; + +//! PID of device connected +U16 device_PID; +//! VID of device connected +U16 device_VID; +//! bmAttributes byte of the connected device +U8 bmattributes; +//! maxpower byte of the connected device (Caution, unit is 2mA) +U8 maxpower; + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// checks if the VID and the PID are supported +/// (if the VID/PID belongs to the VID_PID table) +//------------------------------------------------------------------------------ +U8 host_check_VID_PID(void) +{ + U8 nb_of_vid; + U8 nb_of_pid; + + TRACE_DEBUG("host_check_VID_PID\n\r"); + // Rebuild VID PID from data stage + LSB(device_VID) = data_stage[OFFSET_FIELD_LSB_VID]; + MSB(device_VID) = data_stage[OFFSET_FIELD_MSB_VID]; + LSB(device_PID) = data_stage[OFFSET_FIELD_LSB_PID]; + MSB(device_PID) = data_stage[OFFSET_FIELD_MSB_PID]; + + // Compare detected VID PID with supported table + nb_of_vid=0; + while (nb_of_vid< sizeof(registered_VID_PID)/2) // /2 because registered_VID_PID table is U16... + { + TRACE_DEBUG("registered_VID_PID[%d]: 0x%X\n\r", nb_of_vid, registered_VID_PID[nb_of_vid]); + TRACE_DEBUG("device_VID: 0x%X\n\r", device_VID); + if (registered_VID_PID[nb_of_vid] == device_VID) // VID is correct + { + TRACE_DEBUG("Good VID\n\r"); + nb_of_pid = (U8)registered_VID_PID[nb_of_vid+1]; // store nb of PID for this VID + while (nb_of_pid != 0) + { + TRACE_DEBUG("registered_VID_PID[%d]: 0x%X\n\r", nb_of_vid+nb_of_pid+1, registered_VID_PID[nb_of_vid+nb_of_pid+1]); + TRACE_DEBUG("device_PID: 0x%X\n\r", device_PID); + if (registered_VID_PID[nb_of_vid+nb_of_pid+1] == device_PID) + { + TRACE_DEBUG("Good PID\n\r"); + return HOST_TRUE; + } + nb_of_pid--; + } + } + nb_of_vid+=registered_VID_PID[nb_of_vid+1]+2; + } + return HOST_FALSE; +} + +//------------------------------------------------------------------------------ +/// checks if the OTG descriptor has been received and +/// indicates which features are supported +//------------------------------------------------------------------------------ +U8 host_check_OTG_features(void) +{ + U8 index; // variable offset used to search the OTG descriptor + U8 nb_bytes; // number of bytes of the config descriptor + + TRACE_DEBUG("host_check_OTG_features\n\r"); + Peripheral_is_not_otg_device(); // init + otg_features_supported = 0; + + nb_bytes = data_stage[OFFSET_FIELD_TOTAL_LENGHT]; + index = 0; + if (nb_bytes > 0x09) // check this is not a reduced/uncomplete config descriptor + { + while (index < nb_bytes) // search in the descriptors + { + if (data_stage[index+OFFSET_FIELD_DESCRIPTOR_TYPE] != USBGenericDescriptor_OTG) // IS the pointed descriptor THE OTG DESCRIPTOR ? + { + index += data_stage[index+OFFSET_DESCRIPTOR_LENGHT]; // NO, skip to next descriptor + } + else + { + if (data_stage[index+OFFSET_DESCRIPTOR_LENGHT] == OTG_DESCRIPTOR_bLength) // YES, check descriptor length + { + Peripheral_is_otg_device(); // an OTG descriptor has been found + otg_features_supported = data_stage[index+OFFSET_FIELD_OTG_FEATURES]; // load otg features supported + TRACE_DEBUG("OK\n\r"); + return HOST_TRUE; + } + else + { + TRACE_DEBUG("PB\n\r"); + return HOST_FALSE; // bad descriptor length + } + } + } + } + else + { + TRACE_DEBUG("PB1\n\r"); + return HOST_FALSE; // this was only a reduced/uncomplete configuration descriptor + } + TRACE_DEBUG("OK1\n\r"); + return HOST_TRUE; +} + + +//------------------------------------------------------------------------------ +/// checks if the device class is supported. +/// The function looks in all interface declared in the received dewcriptors, if +/// one of them match with the CLASS/SUB_CLASS/PROTOCOL table +//------------------------------------------------------------------------------ +U8 host_check_class(void) +{ + U8 class_table; + T_DESC_OFFSET descriptor_offset; + T_DESC_OFFSET conf_offset_end; + U16 config_size; + U8 device_class; + U8 device_subclass; + U8 device_protocol; + + TRACE_DEBUG("host_check_class\n\r"); + nb_interface_supported=0; //First asumes ,no interface is supported! + if (data_stage[OFFSET_FIELD_DESCRIPTOR_TYPE] != USBGenericDescriptor_CONFIGURATION) // check if configuration descriptor + { + TRACE_DEBUG("host_check_class problem\n\r"); + return HOST_FALSE; + } + LSB(config_size) = data_stage[OFFSET_FIELD_TOTAL_LENGHT]; + MSB(config_size) = data_stage[OFFSET_FIELD_TOTAL_LENGHT+1]; + bmattributes = data_stage[OFFSET_FIELD_BMATTRIBUTES]; + maxpower = data_stage[OFFSET_FIELD_MAXPOWER]; + descriptor_offset = 0; + conf_offset_end = descriptor_offset + config_size; + + // Look in all interfaces declared in the configuration + while(descriptor_offset < conf_offset_end) + { + // Find next interface descriptor + while (data_stage[descriptor_offset+OFFSET_FIELD_DESCRIPTOR_TYPE] != USBGenericDescriptor_INTERFACE) + { + descriptor_offset += data_stage[descriptor_offset]; + if(descriptor_offset >= conf_offset_end) + { + if(nb_interface_supported) + { + TRACE_DEBUG("host_check_class ok\n\r"); + return HOST_TRUE; + } + else + { + TRACE_DEBUG("host_check_class problem2\n\r"); + return HOST_FALSE; + } + } + } + // Found an interface descriptor + // Get charateristics of this interface + device_class = data_stage[descriptor_offset + OFFSET_FIELD_CLASS]; + device_subclass = data_stage[descriptor_offset + OFFSET_FIELD_SUB_CLASS]; + device_protocol = data_stage[descriptor_offset + OFFSET_FIELD_PROTOCOL]; + // Look in registered class table for match + class_table=0; + while (class_table< sizeof(registered_class)) + { + if (registered_class[class_table] == device_class) // class is correct! + { + if (registered_class[class_table+1] == device_subclass) // sub class is correct! + { + if (registered_class[class_table+2] == device_protocol) // protocol is correct! + { + // Prepare for another item CLASS/SUB_CLASS/PROTOCOL in table + class_table+=3; + // Store this interface as supported interface + // Memorize its interface nb + interface_supported[nb_interface_supported].interface_nb=data_stage[descriptor_offset+OFFSET_FIELD_INTERFACE_NB]; + // its alternate setting + interface_supported[nb_interface_supported].altset_nb=data_stage[descriptor_offset+OFFSET_FIELD_ALT]; + // its USB class + interface_supported[nb_interface_supported].class=device_class; + // its USB subclass + interface_supported[nb_interface_supported].subclass=device_subclass; + // its USB protocol + interface_supported[nb_interface_supported].protocol=device_protocol; + // the number of endpoints associated to this interface + // Note: The associated endpoints addresses are stored during pipe attribution... + interface_supported[nb_interface_supported].nb_ep=data_stage[descriptor_offset+OFFSET_FIELS_NB_OF_EP]; + // Update the number of interface supported + nb_interface_supported++; + // Check the maximum number of interfaces we can support + if(nb_interface_supported>=MAX_INTERFACE_SUPPORTED) + { + TRACE_DEBUG("host_check_class ok1\n\r"); + return HOST_TRUE; + } + } + } + } + class_table+=3; // Check other item CLASS/SUB_CLASS/PROTOCOL in table + } + descriptor_offset += data_stage[descriptor_offset]; // Next descriptor + if(descriptor_offset > SIZEOF_DATA_STAGE) // Check overflow + { + if(nb_interface_supported) + { + TRACE_DEBUG("host_check_class ok3\n\r"); + return HOST_TRUE; + } + else + { + TRACE_DEBUG("host_check_class problem3\n\r"); + return HOST_FALSE; + } + } + } + if(nb_interface_supported) + { + TRACE_DEBUG("host_check_class ok4\n\r"); + return HOST_TRUE; + } + else + { + TRACE_DEBUG("host_check_class problem4\n\r"); + return HOST_FALSE; + } +} + +//------------------------------------------------------------------------------ +/// configures the pipe according to the device class of the +//------------------------------------------------------------------------------ +U8 host_auto_configure_endpoint(void) +{ + U8 nb_endpoint_to_configure; + T_DESC_OFFSET descriptor_offset; + U8 physical_pipe=1; // =1 cause lookup table assumes that physiacl pipe 0 is reserved for control + U8 i; + U8 ep_index; + + TRACE_DEBUG("host_auto_configure_endpoint\n\r"); + // For all interfaces to configure... + for(i=0;i SIZEOF_DATA_STAGE) // No more endpoint descriptor found -> Errror ! + { + TRACE_DEBUG("PB\n\r"); + return HOST_FALSE; + } + } + + // Select the new physical pipe to configure and get ride of any previous configuration for this physical pipe + Host_select_pipe(physical_pipe); + Host_disable_pipe(); + Host_enable_pipe(); + + // Build the pipe configuration according to the endpoint descriptors fields received + // + // host_configure_pipe( + // physical_pipe, // pipe nb in USB interface + // data_stage[descriptor_offset+OFFSET_FIELD_EP_TYPE], // pipe type (interrupt/BULK/ISO) + // Get_pipe_token(data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR]), // pipe addr + // (data_stage[descriptor_offset+2] & MSK_EP_DIR), // pipe dir (IN/OUT) + // host_determine_pipe_size((U16)data_stage[descriptor_offset+OFFSET_FIELD_EP_SIZE]),// pipe size + // ONE_BANK, // bumber of bank to allocate for pipe + // data_stage[descriptor_offset+OFFSET_FIELD_EP_INTERVAL] // interrupt period (for interrupt pipe) + // ); + + host_configure_pipe( + physical_pipe, + data_stage[descriptor_offset+OFFSET_FIELD_EP_TYPE], + Get_pipe_token(data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR]), + (data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR] & MSK_EP_DIR), + host_determine_pipe_size( + (U16)data_stage[descriptor_offset+OFFSET_FIELD_EP_SIZE_LOW] + + (((U16)data_stage[descriptor_offset+OFFSET_FIELD_EP_SIZE_HIGH])<<8)), + ONE_BANK, + data_stage[descriptor_offset+OFFSET_FIELD_EP_INTERVAL] ); + + host_configure_address(physical_pipe, DEVICE_ADDRESS); + + // Update Physical Pipe lookup table with device enpoint address + ep_table[physical_pipe]=data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR]; + physical_pipe++; + // Update endpoint addr table in supported interface structure + interface_supported[i].ep_addr[ep_index++]=data_stage[descriptor_offset+OFFSET_FIELD_EP_ADDR]; + descriptor_offset += data_stage[descriptor_offset]; // pointing on next descriptor + + // All target endpoints configured ? + nb_endpoint_to_configure--; + } //for(i=0;i SIZEOF_DATA_STAGE) + { + return HOST_FALSE; + } + } + if (data_stage[descriptor_offset+OFFSET_FIELD_INTERFACE_NB]==interface + && data_stage[descriptor_offset+OFFSET_FIELD_ALT]==alt) + { + return descriptor_offset; + } + descriptor_offset += data_stage[descriptor_offset]; + } + return descriptor_offset; +} + +//------------------------------------------------------------------------------ +/// returns the physical pipe number linked to a logical endpoint address. +//------------------------------------------------------------------------------ +U8 host_get_hwd_pipe_nb(U8 ep_addr) +{ + U8 i; + + for(i=0; iOTGHS_HSTPIPISR[0] & AT91C_OTGHS_TXSTPI) != 0); + // Freeze the pipe + Host_freeze_pipe(); + + status=(CONTROL_GOOD); + goto host_send_control_end; + } + + // OUT request management --------------------------------------------- + else // Data stage OUT (bmRequestType==0) + { + Host_set_token_out(); + Host_ack_control_out(); + while(data_length != 0) + { + Host_unfreeze_pipe(); + status = host_get_pipe_length(); + if ( (U16)status > data_length) + { + status = (U8)data_length; + data_length = 0; + } + else + { + data_length -= status; + } + Address_fifochar_endpoint(global_pipe_nb); + while (status!=0) + { + Host_write_byte(*data_pointer); + data_pointer++; + status--; + } + Host_send_control_out(); + while (!Is_host_control_out_sent()) + { + if (Is_host_emergency_exit()) + { + status=CONTROL_TIMEOUT; + Host_freeze_pipe(); + Host_reset_pipe(0); + goto host_send_control_end; + } + if (Is_timeout_bdev_response_overflow()) + { + Otg_print_new_failure_message(OTGMSG_DEVICE_NO_RESP,OTG_TEMPO_4SEC); + status=CONTROL_TIMEOUT; + Host_freeze_pipe(); + Host_reset_pipe(0); + goto host_send_control_end; + } + if(Is_host_pipe_error()) + { + status = Host_error_status(); + Host_ack_all_errors(); + goto host_send_control_end; + } + if(Is_host_stall()) + { + status=CONTROL_STALL; + Host_ack_stall(); + goto host_send_control_end; + } + } + Host_ack_control_out(); + } // end of OUT data stage + Host_freeze_pipe(); + Host_set_token_in(); + Host_unfreeze_pipe(); + while(!Is_host_control_in_received()) + { + if (Is_host_emergency_exit()) + { + status=CONTROL_TIMEOUT; + Host_freeze_pipe(); + Host_reset_pipe(0); + goto host_send_control_end; + } + if (Is_timeout_bdev_response_overflow()) + { + Otg_print_new_failure_message(OTGMSG_DEVICE_NO_RESP,OTG_TEMPO_4SEC); + status=CONTROL_TIMEOUT; + Host_freeze_pipe(); + Host_reset_pipe(0); + goto host_send_control_end; + } + if(Is_host_pipe_error()) + { + status = Host_error_status(); + Host_ack_all_errors(); + goto host_send_control_end; + } + if(Is_host_stall()) + { + status=CONTROL_STALL; + Host_ack_stall(); + goto host_send_control_end; + } + } + Host_ack_control_in(); + Host_freeze_pipe(); + Host_send_control_in(); + status=(CONTROL_GOOD); + goto host_send_control_end; + } + +host_send_control_end: + return ((U8)status); +} + + diff --git a/usb/otg/usb_host_task.c b/usb/otg/usb_host_task.c new file mode 100644 index 0000000..6d38400 --- /dev/null +++ b/usb/otg/usb_host_task.c @@ -0,0 +1,1260 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include "conf_usb.h" +#include +#include +#include +#include "usb/otg/usb_task.h" +#include "usb_host_task.h" +#include "usb/otg/usb_drv.h" +#include "usb/otg/usb_host_enum.h" +#include +#include "main.h" + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ +//jcb #define WAIT_100MS 100 +// Wait 100 x 125 us = 12,5 ms before USB reset +//#define WAIT_100MS 800 +#define WAIT_100MS 100 + +#ifndef DEVICE_ADDRESS +#error DEVICE_ADDRESS should be defined somewhere in config files (conf_usb.h) +#endif + +#ifndef SIZEOF_DATA_STAGE +#error SIZEOF_DATA_STAGE should be defined in conf_usb.h +#endif + +#ifndef HOST_CONTINUOUS_SOF_INTERRUPT +#error HOST_CONTINUOUS_SOF_INTERRUPT should be defined as ENABLE or DISABLE in conf_usb.h +#endif + +#ifndef Usb_id_transition_action +#define Usb_id_transition_action() +#endif +#ifndef Host_device_disconnection_action +#define Host_device_disconnection_action() +#endif +#ifndef Host_device_connection_action +#define Host_device_connection_action() +#endif +#ifndef Host_sof_action +#define Host_sof_action() +#endif +#ifndef Host_suspend_action +#define Host_suspend_action() +#endif +#ifndef Host_hwup_action +#define Host_hwup_action() +#endif +#ifndef Host_device_not_supported_action +#define Host_device_not_supported_action() +#endif +#ifndef Host_device_class_not_supported_action +#define Host_device_class_not_supported_action() +#endif +#ifndef Host_device_supported_action +#define Host_device_supported_action() +#endif +#ifndef Host_device_error_action +#define Host_device_error_action() +#endif + +extern U8 id_changed_to_host_event; + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +volatile S_pipe_int it_pipe_str[MAX_EP_NB]; +volatile U8 pipe_nb_save; +U8 g_sav_int_sof_enable; + +//! Its value represent the current state of the +//! device connected to the usb host controller +//! Value can be: +//! - DEVICE_ATTACHED +//! - DEVICE_POWERED +//! - DEVICE_SUSPENDED +//! - DEVICE_DEFAULT +//! - DEVICE_ADDRESSED +//! - DEVICE_CONFIGURED +//! - DEVICE_ERROR +//! - DEVICE_UNATTACHED +//! - DEVICE_READY +//! - DEVICE_WAIT_RESUME +//! - DEVICE_DISCONNECTED +//! - DEVICE_DISCONNECTED_ACK +//! - and these have been added for OTG : +//! - A_PERIPHERAL +//! - A_INIT_HNP +//! - A_SUSPEND +//! - A_END_HNP_WAIT_VFALL +U8 device_state; + +//! For control requests management over pipe 0 +S_usb_setup_data usb_request; + +//! Internal RAM buffer for USB data stage content +//! This buffer is required to setup host enumeration process +//! Its contains the device descriptors received. +//! Depending on the device descriptors lenght, its size can be optimized +//! with the SIZEOF_DATA_STAGE define of conf_usb.h file +U8 data_stage[SIZEOF_DATA_STAGE]; + +U8 device_status; +U8 request_resume; + + +U8 new_device_connected=0; + +//------------------------------------------------------------------------------ +// Local Variables +//------------------------------------------------------------------------------ +static U16 hostSOFCounter; // As internal host start of frame counter + + +//------------------------------------------------------------------------------ +// Internal Functions +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// This function initializes the USB controller in host mode and the associated +/// variables. +/// This function enables the USB controller for host mode operation. +//------------------------------------------------------------------------------ +void usb_host_task_init(void) +{ + unsigned int i; + + TRACE_DEBUG("usb_host_task_init\n\r"); + + for( i=0; ibOTGSoftwareVbusCtrl == ENABLE) { + if( Is_usb_bconnection_error_interrupt()||Is_usb_vbus_error_interrupt()) + { + Usb_ack_bconnection_error_interrupt(); + Usb_ack_vbus_error_interrupt(); + Host_clear_vbus_request(); + } + if (Is_usb_id_host()) { + Host_ack_device_connection(); + // Usb_enable_manual_vbus(); + Usb_ack_bconnection_error_interrupt(); + Usb_enable_vbus_pad(); + Usb_enable_vbus(); + Host_vbus_action(); + } + + Usb_disable_vbus_pad(); + Usb_enable_manual_vbus(); + + if(Is_usb_srp_interrupt()) { + Usb_ack_srp_interrupt(); + // if Vbus was not already delivered, it is really an SRP (OTG B-Device) + device_state=DEVICE_ATTACHED; + Usb_ack_bconnection_error_interrupt(); + Usb_enable_vbus_pad(); + Usb_enable_vbus(); + Host_vbus_action(); + } + } + else { + Usb_enable_vbus(); // Give at least device power supply!!! + Host_vbus_action(); + if(Is_usb_vbus_high()) { + device_state=DEVICE_ATTACHED; + } // If VBUS ok goto to device connection expectation + } + } + break; + + case DEVICE_ATTACHED : + // DEVICE_ATTACHED state + // - Vbus is on + // - Try to detect device connection + if (Is_device_connection()) { // Device pull-up detected + //TRACE_DEBUG("Is_device_connection\n\r"); + Host_ack_device_connection(); + // Now device is connected, enable disconnection interrupt + Host_enable_device_disconnection_interrupt(); + // Reset device status + Host_clear_device_supported(); + Host_clear_configured(); + Host_clear_device_ready(); + Host_ack_sof(); + + TRACE_DEBUG("begin timer\n\r"); + gSystemTick = 0; + DelayMS(200); + TRACE_DEBUG("end timer\n\r"); + // Clear bad VBUS error + Usb_ack_vbus_error_interrupt(); + Host_disable_device_disconnection_interrupt(); + + Host_send_reset(); // First USB reset + Host_enable_sof(); // Start Start Of Frame generation + Host_enable_sof_interrupt(); // SOF will be detected under interrupt + + Usb_ack_event(EVT_HOST_SOF); + while (Is_host_reset()) { + } // Active wait of end of reset send + Host_ack_reset(); + //Workaround for some bugly devices with powerless pull up + //usually low speed where data line rise slowly and can be interpretaded as disconnection + for(hostSOFCounter=0;hostSOFCounter!=0xFFFF;hostSOFCounter++) { // Basic Timeout counter + if(Is_usb_event(EVT_HOST_SOF)) { //If we detect SOF, device is still alive and connected, just clear false disconnect flag + if(Is_device_disconnection()) { + Host_ack_device_connection(); + Host_ack_device_disconnection(); + break; + } + } + } + Host_enable_device_disconnection_interrupt(); + hostSOFCounter = 0; + while (hostSOFCounter Retry the connection process from the begining + if( Is_usb_bconnection_error_interrupt()||Is_usb_vbus_error_interrupt()||Is_usb_vbus_low()) { + TRACE_DEBUG("HOST device_attached_error\n\r"); + TRACE_DEBUG("Is_usb_bconnection_error_interrupt: 0x%X\n\r", Is_usb_bconnection_error_interrupt()); + TRACE_DEBUG("Is_usb_vbus_error_interrupt: 0x%X\n\r", Is_usb_vbus_error_interrupt()); + TRACE_DEBUG("Is_usb_vbus_low: 0x%X\n\r", Is_usb_vbus_low()); + //while(1); //JCB for test, to be removed. + if (Is_usb_id_host()) { + Usb_ack_bconnection_error_interrupt(); + Usb_enable_vbus_hw_control(); + device_state=DEVICE_UNATTACHED; + Usb_disable_vbus(); + Usb_disable_vbus_pad(); + Usb_enable_vbus_pad(); + Usb_ack_vbus_error_interrupt(); + Usb_enable_vbus(); + Usb_disable_vbus_hw_control(); + Host_disable_sof(); + Host_vbus_action(); + } + else { + device_state = DEVICE_UNATTACHED; + } + } + break; + + case DEVICE_POWERED : + // DEVICE_POWERED state + // + // - Device connection (attach) as been detected, + // - Wait 100ms and configure default control pipe + // + //TRACE_INFO("Device Connection\n\r"); + Host_device_connection_action(); + if (Is_usb_event(EVT_HOST_SOF)) { + Usb_ack_event(EVT_HOST_SOF); + if (hostSOFCounter++ >= WAIT_100MS) { + device_state = DEVICE_DEFAULT; + Host_select_pipe(PIPE_CONTROL); + Host_enable_pipe(); + host_configure_pipe(PIPE_CONTROL, + TYPE_CONTROL, + TOKEN_SETUP, + EP_CONTROL, + SIZE_64, + ONE_BANK, + 0 ); + device_state = DEVICE_DEFAULT; + } + } + break; + + case DEVICE_DEFAULT : + // DEVICE_DEFAULT state + // - Get device descriptor + // - Reconfigure Pipe 0 according to Device EP0 + // - Attribute device address + TRACE_DEBUG("DEVICE_DEFAULT\n\r"); + // Get first device descriptor + + if( CONTROL_GOOD == host_get_device_descriptor_uncomplete()) { + hostSOFCounter = 0; + while(hostSOFCounter<20) { // wait 20ms before USB reset (special buggly devices...) + if (Is_usb_event(EVT_HOST_SOF)) { + Usb_ack_event(EVT_HOST_SOF); + hostSOFCounter++; + } + if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) { + break; + } + } + Host_disable_device_disconnection_interrupt(); + Host_send_reset(); // First USB reset + Usb_ack_event(EVT_HOST_SOF); + while (Is_host_reset()); // Active wait of end of reset send + Host_ack_reset(); + + + //Workaround for some bugly devices with powerless pull up + //usually low speed where data line rise slowly and can be interpretaded as disconnection + for(hostSOFCounter=0;hostSOFCounter!=0xFFFF;hostSOFCounter++) { // Basic Timeout counter + if(Is_usb_event(EVT_HOST_SOF)) { //If we detect SOF, device is still alive and connected, just clear false disconnect flag + if(Is_device_disconnection()) { + Host_ack_device_connection(); + Host_ack_device_disconnection(); + break; + } + } + } + Host_enable_device_disconnection_interrupt(); + hostSOFCounter = 0; + while(hostSOFCounter<200) { // wait 200ms after USB reset + if (Is_usb_event(EVT_HOST_SOF)) { + Usb_ack_event(EVT_HOST_SOF); + hostSOFCounter++; + } + if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) { + break; + } + } + + Host_select_pipe(PIPE_CONTROL); + Host_disable_pipe(); + Host_unallocate_memory(); + Host_enable_pipe(); + // Re-Configure the Ctrl Pipe according to the device ctrl EP + + TRACE_DEBUG("Size: 0x%X\n\r", (U16)data_stage[OFFSET_FIELD_MAXPACKETSIZE]); + TRACE_DEBUG("Size Pipe: 0x%X\n\r", host_determine_pipe_size((U16)data_stage[OFFSET_FIELD_MAXPACKETSIZE])); + + host_configure_pipe(PIPE_CONTROL, + TYPE_CONTROL, + TOKEN_SETUP, + EP_CONTROL, + host_determine_pipe_size((U16)data_stage[OFFSET_FIELD_MAXPACKETSIZE]), + ONE_BANK, + 0 ); + // Give an absolute device address + host_set_address(DEVICE_ADDRESS); + host_configure_address(PIPE_CONTROL, DEVICE_ADDRESS); + device_state = DEVICE_ADDRESSED; + } + else { + device_state = DEVICE_ERROR; + } + break; + + case DEVICE_ADDRESSED : + // DEVICE_ADDRESSED state + // - Check if VID PID is in supported list + TRACE_DEBUG("DEVICE_ADDRESSED\n\r"); + if (CONTROL_GOOD == host_get_device_descriptor()) { + // Detect if the device connected belongs to the supported devices table + if (HOST_TRUE == host_check_VID_PID()) { + Host_set_device_supported(); + Host_device_supported_action(); + device_state = DEVICE_CONFIGURED; + } + else + { + } + + } + else {// Can not get device descriptor + device_state = DEVICE_ERROR; + } + break; + + case DEVICE_CONFIGURED : + // DEVICE_CONFIGURED state + // - Configure pipes for the supported interface + // - Send Set_configuration() request + // - Goto full operating mode (device ready) + TRACE_DEBUG("DEVICE_CONFIGURED\n\r"); + if (CONTROL_GOOD == host_get_configuration_descriptor()) { + if (HOST_FALSE != host_check_class()) { // Class support OK? + host_auto_configure_endpoint(); + + if (Is_host_configured()) { + if (CONTROL_GOOD== host_set_configuration(1)) { // Send Set_configuration + // host_set_interface(interface_bound,interface_bound_alt_set); + // device and host are now fully configured + // goto DEVICE READY normal operation + device_state = DEVICE_READY; + // monitor device disconnection under interrupt + Host_enable_device_disconnection_interrupt(); + // If user host application requires SOF interrupt event + // Keep SOF interrupt enable otherwize, disable this interrupt +#if (HOST_CONTINUOUS_SOF_INTERRUPT==DISABLE) + Host_disable_sof_interrupt(); +#endif + new_device_connected=TRUE; + TRACE_INFO("Device Enumerated\n\r"); + } + else { // Problem during Set_configuration request... + device_state = DEVICE_ERROR; + } + } + } + else { // device class not supported... + device_state = DEVICE_ERROR; + TRACE_INFO("Unsupported Device\n\r"); + Host_device_class_not_supported_action(); + } + } + else { // Can not get configuration descriptors... + device_state = DEVICE_ERROR; + } + break; + + case DEVICE_READY : + // DEVICE_READY state + // - Full standard operating mode + // - Nothing to do... + // Host full std operating mode! + new_device_connected=FALSE; + + // Handles user requests : "stop Vbus" and "suspend" + break; + + case DEVICE_ERROR : + //------------------------------------------------------ + // DEVICE_ERROR state + // - Error state + // - Do custom action call (probably go to default mode...) + TRACE_DEBUG("DEVICE_ERROR\n\r"); + Host_device_error_action(); + break; + + case DEVICE_SUSPENDED : + // DEVICE_SUSPENDED state + // - Host application request to suspend the device activity + // - State machine comes here thanks to Host_request_suspend() + TRACE_DEBUG("DEVICE_SUSPENDED\n\r"); + device_state=DEVICE_WAIT_RESUME; // wait for device resume event + if(Is_device_supports_remote_wakeup()) { // If the connected device supports remote wake up + if (CONTROL_GOOD != host_set_feature_remote_wakeup()) { + device_state = DEVICE_DISCONNECTED; // stop connexion because device has not accepted the feature + } + } + TRACE_INFO("Usb suspend\n\r"); + hostSOFCounter = Is_host_sof_interrupt_enabled(); //Save current sof interrupt enable state + Host_disable_sof_interrupt(); + Host_ack_sof(); + Host_disable_sof(); // Stop start of frame generation, this generates the suspend state + Host_ack_remote_wakeup(); + Host_enable_remote_wakeup_interrupt(); + Host_ack_hwup(); + Host_enable_hwup_interrupt(); // Enable host wake-up interrupt + // (this is the unique USB interrupt able to wake up the CPU core from power-down mode) + Usb_freeze_clock(); + Host_suspend_action(); // Custom action here! (for example go to power-save mode...) + } + break; + + case DEVICE_WAIT_RESUME : + // DEVICE_WAIT_RESUME state + // - Wait in this state till the host receives an upstream resume from the device + // - or the host software request the device to resume + TRACE_DEBUG("DEVICE_WAIT_RESUME\n\r"); + if(Is_usb_event(EVT_HOST_REMOTE_WAKEUP)|| Is_host_request_resume()) { // Remote wake up has been detected + // or Local resume request has been received + if(Is_host_request_resume()) { // Not a remote wakeup, but an host application request + Host_disable_hwup_interrupt(); // Wake up interrupt should be disable host is now wake up ! + // CAUTION HWUP can be cleared only when USB clock is active + // Pll_start_auto(); // First Restart the PLL for USB operation + // Wait_pll_ready(); // Get sure pll is lock + Usb_unfreeze_clock(); // Enable clock on USB interface + } + Host_ack_hwup(); // Clear HWUP interrupt flag + Host_enable_sof(); + + if (Is_usb_event(EVT_HOST_REMOTE_WAKEUP)) { + Usb_ack_event(EVT_HOST_REMOTE_WAKEUP); // Ack software event + Host_disable_sof_interrupt(); + Host_ack_device_disconnection(); + Host_disable_device_disconnection_interrupt(); + + Host_send_resume(); // this other downstream resume is done to ensure min. 20ms of HOST DRIVING RESUME (not Device) + while (!Is_device_disconnection() && Host_is_resume()); + hostSOFCounter = 0; + Host_ack_sof(); + while (!Is_device_disconnection() && (hostSOFCounter != 12)) { // wait for min. 10ms of device recovery time + if (Is_host_sof()) { + Host_ack_sof(); + hostSOFCounter++; + } + } + if (Is_device_disconnection()) { + usb_host_task_init(); + device_state = DEVICE_DISCONNECTED; + Host_ack_remote_wakeup(); // Ack remote wake-up reception + Host_ack_request_resume(); // Ack software request + Host_ack_down_stream_resume(); // Ack down stream resume sent + } + else { + device_state = DEVICE_READY; + Host_ack_remote_wakeup(); // Ack remote wake-up reception + Host_ack_request_resume(); // Ack software request + Host_ack_down_stream_resume(); // Ack down stream resume sent + } + Host_enable_device_disconnection_interrupt(); + Host_ack_sof(); + } + else { + Host_send_resume(); // Send down stream resume + //----------------------- + // Work-around for case of Device disconnection during Suspend + // The disconnection is never detected and the Resume bit remains high (and RSMEDI flag never set) + // If the timeout elapses, it implies that the device has disconnected => macro is reset (to reset the Resume bit) + dec = 0; + while (dec < 0x4FFFF) { // several hundreds of ms + if (Is_host_down_stream_resume()) { // Wait Down stream resume sent + Host_ack_remote_wakeup(); // Ack remote wake-up reception + Host_ack_request_resume(); // Ack software request + Host_ack_down_stream_resume(); // Ack down stream resume sent + if(hostSOFCounter) { + Host_enable_sof_interrupt(); + } // Restore SOF interrupt enable state before suspend + device_state=DEVICE_READY; // Come back to full operating mode + TRACE_INFO("Usb resumed\n\r"); + dec = 0x3FFFFE; // will cause a loop end + } + dec++; + } + if (dec != 0x3FFFFF) { // if resume failed + usb_host_task_init(); + device_state = DEVICE_DISCONNECTED; + } + else + { + hostSOFCounter = 0; + Host_ack_sof(); + while (!Is_device_disconnection() && (hostSOFCounter != 12)) { // wait for min. 10ms of device recovery time + if (Is_host_sof()) { + Host_ack_sof(); + hostSOFCounter++; + } + } + } + //-----------------------End of Work Around + } + } + break; + + case DEVICE_DISCONNECTED : + // DEVICE_DISCONNECTED state + // - Device disconnection has been detected + // - Run scheduler in this state at least two times to get sure event is detected by all host application tasks + // - Go to DEVICE_DISCONNECTED_ACK state before DEVICE_UNATTACHED, to get sure scheduler calls all app tasks... + TRACE_DEBUG("DEVICE_DISCONNECTED\n\r"); + device_state = DEVICE_DISCONNECTED_ACK; + break; + + case DEVICE_DISCONNECTED_ACK : + // DEVICE_DISCONNECTED_ACK state + // - Device disconnection has been detected and managed bu applicatives tasks + // - Go to DEVICE_UNATTACHED state + TRACE_DEBUG("DEVICE_DISCONNECTED_ACK\n\r"); + host_disable_all_pipe(); + device_state = DEVICE_UNATTACHED; + break; + + + default : + // default state + // - Default case: ERROR + // - Goto no device state + TRACE_DEBUG("default\n\r"); + device_state = DEVICE_UNATTACHED; + break; + } +} + +//------------------------------------------------------------------------------ +/// This function send nb_data pointed with *buf with the pipe number specified +/// This function will activate the host sof interrupt to detect timeout. The +/// interrupt enable sof will be restore. +//------------------------------------------------------------------------------ +U8 host_send_data(U8 pipe, U16 nb_data, U8 *buf) +{ + U16 length; + U8 status=PIPE_GOOD; + U8 sav_int_sof_enable; + U8 nak_timeout; +#if (NAK_TIMEOUT_ENABLE==ENABLE) + U16 cpt_nak; +#endif + U16 nb_data_loaded; + + TRACE_DEBUG("host_send_data[]%d: %d\n\r", pipe, nb_data); + + sav_int_sof_enable=Is_host_sof_interrupt_enabled(); // Save state of enable sof interrupt + Host_enable_sof_interrupt(); + Host_select_pipe(pipe); + + Host_set_token_in(); + + Host_set_token_out(); + Host_ack_out_sent(); + /* + TRACE_DEBUG("CTRL: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_CTRL); + TRACE_DEBUG("SR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_SR); + TRACE_DEBUG("DEVCTRL: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_DEVCTRL); + TRACE_DEBUG("DEVISR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_DEVISR); + TRACE_DEBUG("DEVIMR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_DEVIMR); + TRACE_DEBUG("DEVEPTISR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_DEVEPTISR[0]); + TRACE_DEBUG("HSTCTRL: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTCTRL); + TRACE_DEBUG("HSTISR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTISR); + TRACE_DEBUG("HSTIMR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTIMR); + TRACE_DEBUG("HSTPIP: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIP); + TRACE_DEBUG("HSTPIPCFG[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[0]); + TRACE_DEBUG("HSTPIPCFG[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[1]); + TRACE_DEBUG("HSTPIPCFG[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[2]); + TRACE_DEBUG("HSTPIPINRQ[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPINRQ[0]); + TRACE_DEBUG("HSTPIPINRQ[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPINRQ[1]); + TRACE_DEBUG("HSTPIPINRQ[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPINRQ[2]); + TRACE_DEBUG("HSTPIPERR[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPERR[0]); + TRACE_DEBUG("HSTPIPERR[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPERR[1]); + TRACE_DEBUG("HSTPIPERR[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPERR[2]); + TRACE_DEBUG("HSTPIPISR[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[0]); + TRACE_DEBUG("HSTPIPISR[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[1]); + TRACE_DEBUG("HSTPIPISR[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[2]); + TRACE_DEBUG("HSTPIPIMR[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPIMR[0]); + TRACE_DEBUG("HSTPIPIMR[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPIMR[1]); + TRACE_DEBUG("HSTPIPIMR[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPIMR[2]); + */ + while (nb_data != 0) { // While there is something to send... + Host_unfreeze_pipe(); + // Prepare data to be sent + length = host_get_pipe_length(); + TRACE_DEBUG("size=%d\n\r", length); + + if ( length > nb_data) { + nb_data_loaded = nb_data; + length = nb_data; + } + else { + nb_data_loaded = length; + } + Address_fifochar_endpoint(global_pipe_nb); + while (length!=0) { // Load Pipe buffer + Host_write_byte(*buf++); + //(((char*)((unsigned int *)AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0))[dBytes++])=*(buf++); + //pFifo[dBytes++] = *buf; + //buf++; + length--; + } + private_sof_counter=0; // Reset the counter in SOF detection sub-routine +#if (NAK_TIMEOUT_ENABLE==ENABLE) + cpt_nak=0; +#endif + nak_timeout=0; + Host_ack_out_sent(); + Host_send_out(); + while (!Is_host_out_sent()) { + if (Is_host_emergency_exit()) { // Async disconnection or role change detected under interrupt + TRACE_DEBUG("Emergency exit\n\r"); + status=PIPE_DELAY_TIMEOUT; + Host_reset_pipe(pipe); + goto host_send_data_end; + } + if (private_sof_counter>=250) { // Count 250ms (250sof) + TRACE_DEBUG("TimeOut Send Data\n\r"); + private_sof_counter=0; + if (nak_timeout++>=TIMEOUT_DELAY) { // Inc timeout and check for overflow + status=PIPE_DELAY_TIMEOUT; + Host_reset_pipe(pipe); + goto host_send_data_end; + } + } + if (Is_host_pipe_error()) { // Any error ? + TRACE_DEBUG("pipe error\n\r"); + status = Host_error_status(); + Host_ack_all_errors(); + goto host_send_data_end; + } + if (Is_host_stall()) { // Stall management + TRACE_DEBUG("stall\n\r"); + status =PIPE_STALL; + Host_ack_stall(); + goto host_send_data_end; + } +#if (NAK_TIMEOUT_ENABLE==ENABLE) + if(Is_host_nak_received()) { //NAK received + Host_ack_nak_received(); + if (cpt_nak++>NAK_SEND_TIMEOUT) { + TRACE_DEBUG("NAK timeout\n\r"); + status = PIPE_NAK_TIMEOUT; + Host_reset_pipe(pipe); + goto host_send_data_end; + } + } +#endif + } + // Here OUT sent + nb_data -= nb_data_loaded; + status=PIPE_GOOD; // Frame correctly sent + Host_ack_out_sent(); + } + Host_freeze_pipe(); + +host_send_data_end: + // Restore sof interrupt enable state + if (sav_int_sof_enable==FALSE) { + Host_disable_sof_interrupt(); + } + // And return... + return ((U8)status); +} + + + +//------------------------------------------------------------------------------ +/// This function receives nb_data pointed with *buf with the pipe number specified +/// The nb_data parameter is passed as a U16 pointer, thus the data pointed by this pointer +/// is updated with the final number of data byte received. +//------------------------------------------------------------------------------ +U8 host_get_data(U8 pipe, U16 *nb_data, U8 *buf) +{ + U8 status=PIPE_GOOD; + U8 sav_int_sof_enable; + U8 nak_timeout; + U16 n; + U16 i; +#if (NAK_TIMEOUT_ENABLE==ENABLE) + U16 cpt_nak; +#endif + + // TRACE_DEBUG("host_get_data[%d]\n\r", pipe); + n=*nb_data; + *nb_data=0; + + sav_int_sof_enable=Is_host_sof_interrupt_enabled(); + Host_enable_sof_interrupt(); + + Host_select_pipe(pipe); + Host_set_token_in(); + Host_continuous_in_mode(); + // Host_ack_in_received(); + + while (n) { // While missing data... + // start IN request generation + Host_unfreeze_pipe(); + Host_send_in(); + private_sof_counter=0; // Reset the counter in SOF detection sub-routine + nak_timeout=0; +#if (NAK_TIMEOUT_ENABLE==ENABLE) + cpt_nak=0; +#endif + while (!Is_host_in_received()) + { + if (Is_host_emergency_exit()) // Async disconnection or role change detected under interrupt + { + status=PIPE_DELAY_TIMEOUT; + Host_reset_pipe(pipe); + goto host_get_data_end; + } + if (private_sof_counter>=250) // Timeout management + { + private_sof_counter=0; // Done in host SOF interrupt + if (nak_timeout++>=TIMEOUT_DELAY)// Check for local timeout + { + status=PIPE_DELAY_TIMEOUT; + Host_reset_pipe(pipe); + goto host_get_data_end; + } + } + if(Is_host_pipe_error()) // Error management + { + status = Host_error_status(); + Host_ack_all_errors(); + goto host_get_data_end; + } + if(Is_host_stall()) // STALL management + { + status =PIPE_STALL; + Host_reset_pipe(pipe); + Host_ack_stall(); + goto host_get_data_end; + } +#if (NAK_TIMEOUT_ENABLE==ENABLE) + if(Is_host_nak_received()) //NAK received + { + Host_ack_nak_received(); + if (cpt_nak++>NAK_RECEIVE_TIMEOUT) + { + status = PIPE_NAK_TIMEOUT; + Host_reset_pipe(pipe); + goto host_get_data_end; + } + } +#endif + } + status=PIPE_GOOD; + Host_freeze_pipe(); + if (Host_byte_counter()<=n) + { + if ((Host_byte_counter() < n)&&(Host_byte_counter() nb_data) // Pipe size> remaining data + { + i = nb_data; + nb_data = 0; + } + else // Pipe size < remaining data + { + nb_data -= i; + } + it_pipe_str[pipe].nb_byte_on_going+=i; // Update nb data processed + Address_fifochar_endpoint(global_pipe_nb); + while (i!=0) // Load Pipe buffer + { + Host_write_byte(*ptr_buf++); + i--; + } + private_sof_counter=0; // Reset the counter in SOF detection sub-routine + it_pipe_str[pipe].timeout=0; // Refresh timeout counter + Host_ack_out_sent(); + Host_ack_stall(); + Host_ack_nak_received(); + + Host_enable_stall_interrupt(); + Host_enable_error_interrupt(); +#if (NAK_TIMEOUT_ENABLE==ENABLE) + Host_enable_nak_interrupt(); +#endif + Host_enable_transmit_interrupt(); + Host_send_out(); // Send the USB frame + return HOST_TRUE; + } +} + +//------------------------------------------------------------------------------ +//! @brief USB pipe interrupt subroutine +//! +//! @param none +//! +//! @return none +//------------------------------------------------------------------------------ +void usb_pipe_interrupt(void) +{ + U8 pipe_nb; + U8 *ptr_buf; + void (*fct_handle)(U8 status,U16 nb_byte); + U16 n; + U8 i; + U8 do_call_back=FALSE; + + TRACE_DEBUG("usb_pipe_interrupt\n\r"); + + if(Host_get_pipe_interrupt()) { + + pipe_nb_save = Host_get_selected_pipe(); // Important! Save here working pipe number + pipe_nb=host_get_nb_pipe_interrupt(); // work with the correct pipe number that generates the interrupt + Host_select_pipe(pipe_nb); // Select this pipe + fct_handle=*(it_pipe_str[pipe_nb].handle); + + // Now try to detect what event generate an interrupt... + if (Is_host_pipe_error()) // Any error ? + { + TRACE_DEBUG("host_pipe_error\n\r"); + it_pipe_str[pipe_nb].status = Host_error_status(); + it_pipe_str[pipe_nb].enable=DISABLE; + Host_stop_pipe_interrupt(pipe_nb); + Host_ack_all_errors(); + do_call_back=TRUE; + goto usb_pipe_interrupt_end; + } + + if (Is_host_stall()) // Stall handshake received ? + { + TRACE_DEBUG("host_stall\n\r"); + it_pipe_str[pipe_nb].status=PIPE_STALL; + it_pipe_str[pipe_nb].enable=DISABLE; + Host_stop_pipe_interrupt(pipe_nb); + do_call_back=TRUE; + goto usb_pipe_interrupt_end; + } + +#if (NAK_TIMEOUT_ENABLE==ENABLE) + if (Is_host_nak_received()) // NAK ? + { + Host_ack_nak_received(); + // check if number of NAK timeout error occurs (not for interrupt type pipe) + if((--it_pipe_str[pipe_nb].nak_timeout==0) && (Host_get_pipe_type()!=TYPE_INTERRUPT)) + { + it_pipe_str[pipe_nb].status=PIPE_NAK_TIMEOUT; + it_pipe_str[pipe_nb].enable=DISABLE; + Host_stop_pipe_interrupt(pipe_nb); + do_call_back=TRUE; + goto usb_pipe_interrupt_end; + } + } +#endif + + if (Is_host_in_received()) // Pipe IN reception ? + { + TRACE_DEBUG("host_in received\n\r"); + ptr_buf = it_pipe_str[pipe_nb].ptr_buf; + ptr_buf += it_pipe_str[pipe_nb].nb_byte_processed; // Build pointer to data buffer + n = it_pipe_str[pipe_nb].nb_byte_to_process; + n -= it_pipe_str[pipe_nb].nb_byte_processed; // Remaining data bytes + Host_freeze_pipe(); + if (Host_byte_counter()<=n) + { + if ((Host_byte_counter() < n)&&(Host_byte_counter()0) //still something to process + { + Host_unfreeze_pipe(); // Request another IN transfer + Host_send_in(); + private_sof_counter=0; // Reset the counter in SOF detection sub-routine + it_pipe_str[pipe_nb].timeout=0; // Reset timeout + it_pipe_str[pipe_nb].nak_timeout=NAK_RECEIVE_TIMEOUT; + } + else //end of transfer + { + it_pipe_str[pipe_nb].enable=DISABLE; + it_pipe_str[pipe_nb].status=PIPE_GOOD; + Host_stop_pipe_interrupt(pipe_nb); + do_call_back=TRUE; + } + } + + if(Is_host_out_sent()) // Pipe OUT sent ? + { + TRACE_DEBUG("host_out send\n\r"); + Host_ack_out_sent(); + it_pipe_str[pipe_nb].nb_byte_processed+=it_pipe_str[pipe_nb].nb_byte_on_going; + it_pipe_str[pipe_nb].nb_byte_on_going=0; + ptr_buf = it_pipe_str[pipe_nb].ptr_buf; + ptr_buf += it_pipe_str[pipe_nb].nb_byte_processed; // Build pointer to data buffer + n = it_pipe_str[pipe_nb].nb_byte_to_process; + n -= it_pipe_str[pipe_nb].nb_byte_processed; // Remaining data bytes + if(n>0) // Still data to process... + { + Host_unfreeze_pipe(); + // Prepare data to be sent + i = host_get_pipe_length(); + if ( i > n) // Pipe size> remaining data + { + i = n; + n = 0; + } + else // Pipe size < remaining data + { + n -= i; + } + it_pipe_str[pipe_nb].nb_byte_on_going+=i; // Update nb data processed + Address_fifochar_endpoint(global_pipe_nb); + while (i!=0) // Load Pipe buffer + { + Host_write_byte(*ptr_buf++); i--; + } + private_sof_counter=0; // Reset the counter in SOF detection sub-routine + it_pipe_str[pipe_nb].timeout=0; // Refresh timeout counter + it_pipe_str[pipe_nb].nak_timeout=NAK_SEND_TIMEOUT; + Host_send_out(); // Send the USB frame + } + else //n==0 Transfer is finished + { + it_pipe_str[pipe_nb].enable=DISABLE; // Tranfer end + it_pipe_str[pipe_nb].status=PIPE_GOOD; // Status OK + Host_stop_pipe_interrupt(pipe_nb); + do_call_back=TRUE; + } + } + +usb_pipe_interrupt_end: + Host_select_pipe(pipe_nb_save); // Restore pipe number !!!! + if (is_any_interrupt_pipe_active()==FALSE) // If no more transfer is armed + { + if (g_sav_int_sof_enable==FALSE) + { + Host_disable_sof_interrupt(); + } + } + if(do_call_back) // Any callback functions to perform ? + { + fct_handle(it_pipe_str[pipe_nb].status,it_pipe_str[pipe_nb].nb_byte_processed); + } + + } + +} + + + diff --git a/usb/otg/usb_host_task.h b/usb/otg/usb_host_task.h new file mode 100644 index 0000000..af752ec --- /dev/null +++ b/usb/otg/usb_host_task.h @@ -0,0 +1,230 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ +#ifndef _USB_HOST_TASK_H_ +#define _USB_HOST_TASK_H_ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ +#include +#include + +#include "main.h" + +//! @brief Selects the Reset Length (x11ms) +//! This value is the number of consecutives Reset sent by the Host +#define OTG_RESET_LENGTH 1 + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ +typedef struct +{ + bit enable; + U16 nb_byte_to_process; + U16 nb_byte_processed; + U16 nb_byte_on_going; + U8 *ptr_buf; + void(*handle)(U8 status, U16 nb_byte); + U8 status; + U8 timeout; + U16 nak_timeout; +} S_pipe_int; + + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ +#define PIPE_GOOD 0 +//#define PIPE_DATA_TOGGLE 0x01 +//#define PIPE_DATA_PID 0x02 +//#define PIPE_PID 0x04 +//#define PIPE_TIMEOUT 0x08 +//#define PIPE_CRC16 0x10 +#define PIPE_STALL 0x20 +#define PIPE_NAK_TIMEOUT 0x40 +#define PIPE_DELAY_TIMEOUT 0x80 + +// usb_host_task USB host task module +// Returns true when device connected and correctly enumerated. +// The host high level application should tests this before performing any applicative requests +// to the device connected +#define Is_host_ready() ((device_state==DEVICE_READY) ? TRUE : FALSE) + +/// Check if host controller is in suspend mode +#define Is_host_suspended() (((device_state==DEVICE_WAIT_RESUME) ||(device_state==DEVICE_SUSPENDED)) ? TRUE : FALSE) + +/// Check if host controller is not suspend mode +#define Is_host_not_suspended() (((device_state==DEVICE_WAIT_RESUME) ||(device_state==DEVICE_SUSPENDED)) ? FALSE : TRUE) + +/// This function should be called to make the host controller enter USB suspend mode +#define Host_request_suspend() (device_state=DEVICE_SUSPENDED) + +/// This function should be called to request the host controller to resume the USB bus +#define Host_request_resume() (request_resume=TRUE) + +/// Private ack for software event +#define Host_ack_request_resume() (request_resume=FALSE) + +/// Private check for resume sequence +#define Is_host_request_resume() ((request_resume==TRUE) ? TRUE : FALSE) + +/// Returns true when a new device is enumerated +#define Is_new_device_connection_event() (new_device_connected ? TRUE : FALSE) + +/// Returns true when the device disconnects from the host +#define Is_device_disconnection_event() ((device_state==DEVICE_DISCONNECTED_ACK || device_state==DEVICE_DISCONNECTED) ? TRUE : FALSE) + +/// Stop all interrupt attached to a pipe +#define Host_stop_pipe_interrupt(i) {Host_disable_transmit_interrupt();\ + Host_disable_receive_interrupt();\ + Host_disable_stall_interrupt();\ + Host_disable_error_interrupt();\ + Host_disable_nak_interrupt();\ + Host_reset_pipe(i); } + +/// device_state_value Host controller states +/// Defines for device state coding +#define DEVICE_UNATTACHED 0 +#define DEVICE_ATTACHED 1 +#define DEVICE_POWERED 2 +#define DEVICE_DEFAULT 3 +#define DEVICE_ADDRESSED 4 +#define DEVICE_CONFIGURED 5 +#define DEVICE_READY 6 +#define DEVICE_ERROR 7 +#define DEVICE_SUSPENDED 8 +#define DEVICE_WAIT_RESUME 9 +#define DEVICE_DISCONNECTED 10 +#define DEVICE_DISCONNECTED_ACK 11 +#define A_PERIPHERAL 12 // used for A-Device in OTG mode +#define A_INIT_HNP 13 +#define A_SUSPEND 14 +#define A_END_HNP_WAIT_VFALL 15 +#define A_TEMPO_VBUS_DISCHARGE 16 + + +#define Host_set_device_supported() (device_status |= 0x01) +#define Host_clear_device_supported() (device_status &= ~0x01) + +#define Host_set_device_ready() (device_status |= 0x02) +#define Host_clear_device_ready() (device_status &= ~0x02) + +#define Host_set_configured() (device_status |= 0x04) +#define Host_clear_configured() (device_status &= ~0x04) +#define Is_host_configured() (device_status & 0x04) + + + + +/// Has a SRP been received, and waiting for a connect of B-Device (Vbus delivered) +#define Srp_received_and_waiting_connect() (otg_a_device_srp |= 0x01) +#define Ack_srp_received_and_connect() (otg_a_device_srp &= ~0x01) +#define Is_srp_received_and_waiting_connect() (((otg_a_device_srp&0x01) != 0) ? TRUE : FALSE) +/// Is the current session has been started with SRP +#define Host_session_started_srp() (otg_a_device_srp |= 0x02) +#define Host_end_session_started_srp() (otg_a_device_srp &= ~0x02) +#define Is_host_session_started_srp() (((otg_a_device_srp&0x02) != 0) ? TRUE : FALSE) + +/// Is the current peripheral is an OTG device ? +#define Peripheral_is_not_otg_device() (otg_device_connected = 0x00) +#define Peripheral_is_otg_device() (otg_device_connected = 0x11) +#define Is_peripheral_otg_device() ((otg_device_connected != 0) ? TRUE : FALSE) + +/// Check if counter of Vbus delivery time after SRP is elapsed +// 0xDAC = 3500, 3500x2 = 7000 => 7s +#define T_VBUS_DELIV_AFTER_SRP 0xDAC // minimum time (x2ms) with Vbus ON once a SRP has been received (5s T_VBUS_DELIV_AFTER_SRP) ? TRUE : FALSE) + +/// Check if counter of A-Suspend delay is elapsed +/// Max. delay for a B-DEVICE to disconnect once the A-HOST has set suspend mode +// Min 200 ms +// 0x96 = 150 ,150x2 = 300 => 300 ms +#define TA_AIDL_BDIS 0x96 // minimum time (x2ms) in A_suspend state before stop Vbus (must be > 200ms) + // if value = 0, this is an infinite delay +#define Init_ta_aidl_bdis_counter() (otg_ta_aidl_bdis_tmr = TA_AIDL_BDIS) +#define Is_ta_aidl_bdis_counter_overflow() ((otg_ta_aidl_bdis_tmr == 0x0001) ? TRUE : FALSE) + +/// Check if counter otg_timeout_bdev_respond is elapsed +// 0xD00 = 3328, 3328x2 = 6656 => 6s +#define TM_OUT_MAX_BDEV_RESPONSE 0xD00 // maximum delay for the A-Device waiting for a response from B-Device once attached +#define Init_timeout_bdev_response() (otg_timeout_bdev_respond = TM_OUT_MAX_BDEV_RESPONSE) +#define Is_timeout_bdev_response_overflow() ((otg_timeout_bdev_respond == 0) ? TRUE : FALSE) + +/// Check if counter otg_ta_vbus_rise is elapsed +// 0x28 = 40, 40x2 = 80 => 80ms +#define TA_VBUS_RISE 0x28 // maximum delay for Vbus to reach the Va_vbus_valid threshold after being requested (must be < 100ms) +#define Init_ta_vbus_rise_counter() (otg_ta_vbus_rise = TA_VBUS_RISE) +#define Is_ta_vbus_rise_counter_overflow() ((otg_ta_vbus_rise == 0) ? TRUE : FALSE) + +/// Check if counter otg_ta_vbus_fall is elapsed +// 50x2 = 100 => 100ms +#define TA_VBUS_FALL 50 +#define Init_ta_vbus_fall_counter() (otg_end_hnp_vbus_delay = TA_VBUS_FALL) +#define Is_ta_vbus_fall_counter_overflow() ((otg_end_hnp_vbus_delay == 0) ? TRUE : FALSE) + + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ +extern U8 g_sav_int_sof_enable; +extern U8 device_state; +extern U8 request_resume; +extern U8 new_device_connected; + +// OTG Defines, Variables and Macros +// See "usb_host_task.c" file for description of variables role and use +extern U16 otg_ta_srp_wait_connect; +extern U16 otg_ta_aidl_bdis_tmr; +extern U8 otg_ta_vbus_rise; +extern U16 otg_timeout_bdev_respond; +extern U16 otg_end_hnp_vbus_delay; + +extern U8 otg_a_device_srp; +extern U8 otg_device_connected; +extern S_usb_setup_data usb_request; +extern U8 device_status; +extern U8 data_stage[SIZEOF_DATA_STAGE]; + +//----------------------------------------------------------------------------- +// Exported functions +//----------------------------------------------------------------------------- +extern void usb_host_task_init(void); +extern void usb_host_task(void); +extern U8 host_send_data(U8 pipe, U16 nb_data, U8 *buf); +extern U8 host_get_data(U8 pipe, U16 *nb_data, U8 *buf); +extern void reset_it_pipe_str(void); +extern U8 is_any_interrupt_pipe_active(void); +extern U8 host_get_data_interrupt(U8 pipe, U16 nb_data, U8 *buf, void (*handle)(U8 status, U16 nb_byte)); +extern U8 host_send_data_interrupt(U8 pipe, U16 nb_data, U8 *buf, void (*handle)(U8 status, U16 nb_byte)); +extern void usb_pipe_interrupt(void); + +#endif // _USB_HOST_TASK_H_ + diff --git a/usb/otg/usb_host_task_with_srp_hnp.c b/usb/otg/usb_host_task_with_srp_hnp.c new file mode 100644 index 0000000..4cf02b7 --- /dev/null +++ b/usb/otg/usb_host_task_with_srp_hnp.c @@ -0,0 +1,1493 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include "conf_usb.h" +#include +#include +#include +#include +#include "usb/otg/usb_task.h" +#include "usb_host_task.h" +#include "usb/otg/usb_drv.h" +#include "usb/otg/usb_host_enum.h" +#include +#include "main.h" + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ +//jcb #define WAIT_100MS 100 +// Wait 100 x 125 us = 12,5 ms before USB reset +//#define WAIT_100MS 800 +#define WAIT_100MS 100 + +#if (HOST_STRICT_VID_PID_TABLE != ENABLE) +#warning HOST_STRICT_VID_PID_TABLE must be defined to ENABLE to comply with Targeted Peripheral List requirements +#endif + + +#ifndef DEVICE_ADDRESS +#error DEVICE_ADDRESS should be defined somewhere in config files (conf_usb.h) +#endif + +#ifndef SIZEOF_DATA_STAGE +#error SIZEOF_DATA_STAGE should be defined in conf_usb.h +#endif + +#ifndef HOST_CONTINUOUS_SOF_INTERRUPT +#error HOST_CONTINUOUS_SOF_INTERRUPT should be defined as ENABLE or DISABLE in conf_usb.h +#endif + +#ifndef Usb_id_transition_action +#define Usb_id_transition_action() +#endif +#ifndef Host_device_disconnection_action +#define Host_device_disconnection_action() +#endif +#ifndef Host_device_connection_action +#define Host_device_connection_action() +#endif +#ifndef Host_sof_action +#define Host_sof_action() +#endif +#ifndef Host_suspend_action +#define Host_suspend_action() +#endif +#ifndef Host_hwup_action +#define Host_hwup_action() +#endif +#ifndef Host_device_not_supported_action +#define Host_device_not_supported_action() +#endif +#ifndef Host_device_class_not_supported_action +#define Host_device_class_not_supported_action() +#endif +#ifndef Host_device_supported_action +#define Host_device_supported_action() +#endif +#ifndef Host_device_error_action +#define Host_device_error_action() +#endif + +extern U8 id_changed_to_host_event; + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +volatile S_pipe_int it_pipe_str[MAX_EP_NB]; +volatile U8 pipe_nb_save; +U8 g_sav_int_sof_enable; + +//! Min. delay after an SRP received, with VBUS delivered ON (waiting for a B-DEV connect) +U16 otg_ta_srp_wait_connect; +//! Max. delay for a B-DEVICE to disconnect once the A-HOST has set suspend mode +U16 otg_ta_aidl_bdis_tmr; +//! Max. delay for vbus to reach Va_vbus_valid threshold +U8 otg_ta_vbus_rise; +//! Max. delay once B-Device attached to respond to the first A-Device requests +U16 otg_timeout_bdev_respond; +//! Indicates if the connected peripheral is an OTG Device or not +U8 otg_device_connected; +//! Stores special events about SRP in A-Device mode +U8 otg_a_device_srp; +//! Variable used for timing Vbus discharge to avoid bounces around vbus_valid threshold +U16 otg_end_hnp_vbus_delay; + +//! Its value represent the current state of the +//! device connected to the usb host controller +//! Value can be: +//! - DEVICE_ATTACHED +//! - DEVICE_POWERED +//! - DEVICE_SUSPENDED +//! - DEVICE_DEFAULT +//! - DEVICE_ADDRESSED +//! - DEVICE_CONFIGURED +//! - DEVICE_ERROR +//! - DEVICE_UNATTACHED +//! - DEVICE_READY +//! - DEVICE_WAIT_RESUME +//! - DEVICE_DISCONNECTED +//! - DEVICE_DISCONNECTED_ACK +//! - and these have been added for OTG : +//! - A_PERIPHERAL +//! - A_INIT_HNP +//! - A_SUSPEND +//! - A_END_HNP_WAIT_VFALL +U8 device_state; + +//! For control requests management over pipe 0 +S_usb_setup_data usb_request; + +//! Internal RAM buffer for USB data stage content +//! This buffer is required to setup host enumeration process +//! Its contains the device descriptors received. +//! Depending on the device descriptors lenght, its size can be optimized +//! with the SIZEOF_DATA_STAGE define of conf_usb.h file +U8 data_stage[SIZEOF_DATA_STAGE]; + +U8 device_status; +U8 request_resume; + + +U8 new_device_connected=0; + +//------------------------------------------------------------------------------ +// Local Variables +//------------------------------------------------------------------------------ +static U16 hostSOFCounter; // As internal host start of frame counter + + +//------------------------------------------------------------------------------ +// Internal Functions +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// This function initializes the USB controller in host mode and the associated +/// variables. +/// This function enables the USB controller for host mode operation. +//------------------------------------------------------------------------------ +void usb_host_task_init(void) +{ + unsigned int i; + + TRACE_DEBUG("usb_host_task_init\n\r"); + + for( i=0; ibOTGADevSRPReaction == VBUS_PULSE) { + Usb_select_vbus_srp_method(); + } + else { + Usb_select_data_srp_method(); + } + device_state=DEVICE_UNATTACHED; +} + +//------------------------------------------------------------------------------ +/// Entry point of the USB host management +/// The aim is to manage the device target connection and enumeration +/// depending on the device_state, the function performs the required operations +/// to get the device enumerated and configured +/// Once the device is operationnal, the device_state value is DEVICE_READY +/// This state should be tested by the host task application before performing +/// any applicative requests to the device. +//------------------------------------------------------------------------------ +void usb_host_task(void) +{ + U32 dec; + U8 desc_temp; + + //TRACE_DEBUG("host_task "); + switch (device_state) { + case DEVICE_UNATTACHED: + // DEVICE_UNATTACHED state + // - Default init state + // - Try to give device power supply + //TRACE_DEBUG("DEVICE_UNATTACHED\n\r"); + for (hostSOFCounter=0; hostSOFCounterbOTGSoftwareVbusCtrl == ENABLE) { + if( Is_usb_bconnection_error_interrupt()||Is_usb_vbus_error_interrupt()) + { + Usb_ack_bconnection_error_interrupt(); + Usb_ack_vbus_error_interrupt(); + Host_clear_vbus_request(); + } + + if(Is_usb_srp_interrupt()) { + Usb_ack_srp_interrupt(); + // if Vbus was not already delivered, it is really an SRP (OTG B-Device) + Otg_print_new_event_message(OTGMSG_SRP_RECEIVED,OTG_TEMPO_2SEC); + Host_session_started_srp(); + Init_ta_srp_counter(); + Srp_received_and_waiting_connect(); + Init_ta_vbus_rise_counter(); + device_state=DEVICE_ATTACHED; + Usb_ack_bconnection_error_interrupt(); + Usb_enable_vbus_pad(); + Usb_enable_vbus(); + Host_vbus_action(); + } + } + else { + Usb_enable_vbus(); // Give at least device power supply!!! + Host_vbus_action(); + if(Is_usb_vbus_high()) { + device_state=DEVICE_ATTACHED; + } // If VBUS ok goto to device connection expectation + } + } + else if (b_uut_device_state == B_HOST) { + device_state = DEVICE_ATTACHED; + } + break; + + case DEVICE_ATTACHED : + // DEVICE_ATTACHED state + // - Vbus is on + // - Try to detect device connection + if (Is_device_connection() || (Is_usb_id_device() && (b_uut_device_state == B_HOST))) { + //TRACE_DEBUG("Is_device_connection\n\r"); + Host_ack_device_connection(); + Ack_srp_received_and_connect(); // connection might have been requested by SRP + // Now device is connected, enable disconnection interrupt + Host_enable_device_disconnection_interrupt(); + // Reset device status + Host_clear_device_supported(); + Host_clear_configured(); + Host_clear_device_ready(); + Host_ack_sof(); + + TRACE_DEBUG("begin timer\n\r"); + gSystemTick = 0; + DelayMS(200); + TRACE_DEBUG("end timer\n\r"); + // Clear bad VBUS error + Usb_ack_vbus_error_interrupt(); + Host_disable_device_disconnection_interrupt(); + + Host_send_reset(); // First USB reset + Host_enable_sof(); // Start Start Of Frame generation + Host_enable_sof_interrupt(); // SOF will be detected under interrupt + + Usb_ack_event(EVT_HOST_SOF); + while (Is_host_reset()) { + if (Is_usb_device_enabled()) { + break; + } + } // Active wait of end of reset send + Host_ack_reset(); + // User can choose the number of consecutive resets sent + hostSOFCounter = 1; + while (hostSOFCounter != OTG_RESET_LENGTH ) { + Host_send_reset(); + Usb_ack_event(EVT_HOST_SOF); + while (Is_host_reset()) { + if (Is_usb_device_enabled()) { + break; + } + }// Active wait of end of reset send + Host_ack_reset(); + hostSOFCounter++; + } + + //Workaround for some bugly devices with powerless pull up + //usually low speed where data line rise slowly and can be interpretaded as disconnection + for(hostSOFCounter=0;hostSOFCounter!=0xFFFF;hostSOFCounter++) { // Basic Timeout counter + if(Is_usb_event(EVT_HOST_SOF)) { //If we detect SOF, device is still alive and connected, just clear false disconnect flag + if(Is_device_disconnection()) { + Host_ack_device_connection(); + Host_ack_device_disconnection(); + break; + } + } + } + Host_enable_device_disconnection_interrupt(); + hostSOFCounter = 0; + while (hostSOFCounter= WAIT_100MS) { + device_state = DEVICE_DEFAULT; + Host_select_pipe(PIPE_CONTROL); + Host_enable_pipe(); + host_configure_pipe(PIPE_CONTROL, + TYPE_CONTROL, + TOKEN_SETUP, + EP_CONTROL, + SIZE_64, + ONE_BANK, + 0 ); + device_state = DEVICE_DEFAULT; + } + } + break; + + case DEVICE_DEFAULT : + // DEVICE_DEFAULT state + // - Get device descriptor + // - Reconfigure Pipe 0 according to Device EP0 + // - Attribute device address + TRACE_DEBUG("DEVICE_DEFAULT\n\r"); + // Get first device descriptor + Peripheral_is_not_otg_device(); // init status variable + Init_timeout_bdev_response(); // init B-Device "waiting response" delay (handled by timer interrupt in usb_task.c) + + if( CONTROL_GOOD == host_get_device_descriptor_uncomplete()) { + hostSOFCounter = 0; + while(hostSOFCounter<20) { // wait 20ms before USB reset (special buggly devices...) + if (Is_usb_event(EVT_HOST_SOF)) { + Usb_ack_event(EVT_HOST_SOF); + hostSOFCounter++; + } + if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) { + break; + } + } + Host_disable_device_disconnection_interrupt(); + Host_send_reset(); // First USB reset + Usb_ack_event(EVT_HOST_SOF); + while (Is_host_reset()); // Active wait of end of reset send + Host_ack_reset(); + hostSOFCounter = 1; + while (hostSOFCounter != OTG_RESET_LENGTH) { + Host_send_reset(); + Usb_ack_event(EVT_HOST_SOF); + while (Is_host_reset()); // Active wait of end of reset send + Host_ack_reset(); + hostSOFCounter++; + } + + //Workaround for some bugly devices with powerless pull up + //usually low speed where data line rise slowly and can be interpretaded as disconnection + for(hostSOFCounter=0;hostSOFCounter!=0xFFFF;hostSOFCounter++) { // Basic Timeout counter + if(Is_usb_event(EVT_HOST_SOF)) { //If we detect SOF, device is still alive and connected, just clear false disconnect flag + if(Is_device_disconnection()) { + Host_ack_device_connection(); + Host_ack_device_disconnection(); + break; + } + } + } + Host_enable_device_disconnection_interrupt(); + hostSOFCounter = 0; + while(hostSOFCounter<200) { // wait 200ms after USB reset + if (Is_usb_event(EVT_HOST_SOF)) { + Usb_ack_event(EVT_HOST_SOF); + hostSOFCounter++; + } + if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) { + break; + } + } + + Host_select_pipe(PIPE_CONTROL); + Host_disable_pipe(); + Host_unallocate_memory(); + Host_enable_pipe(); + // Re-Configure the Ctrl Pipe according to the device ctrl EP + + TRACE_DEBUG("Size: 0x%X\n\r", (U16)data_stage[OFFSET_FIELD_MAXPACKETSIZE]); + TRACE_DEBUG("Size Pipe: 0x%X\n\r", host_determine_pipe_size((U16)data_stage[OFFSET_FIELD_MAXPACKETSIZE])); + + host_configure_pipe(PIPE_CONTROL, + TYPE_CONTROL, + TOKEN_SETUP, + EP_CONTROL, + host_determine_pipe_size((U16)data_stage[OFFSET_FIELD_MAXPACKETSIZE]), + ONE_BANK, + 0 ); + // Give an absolute device address + host_set_address(DEVICE_ADDRESS); + host_configure_address(PIPE_CONTROL, DEVICE_ADDRESS); + device_state = DEVICE_ADDRESSED; + } + else { + device_state = DEVICE_ERROR; + } + break; + + case DEVICE_ADDRESSED : + // DEVICE_ADDRESSED state + // - Check if VID PID is in supported list + TRACE_DEBUG("DEVICE_ADDRESSED\n\r"); + if (CONTROL_GOOD == host_get_device_descriptor()) { + // Detect if the device connected belongs to the supported devices table + if (HOST_TRUE == host_check_VID_PID()) { + Host_set_device_supported(); + Host_device_supported_action(); + device_state = DEVICE_CONFIGURED; + // In OTG A-HOST state, initiate a HNP if the OTG B-DEVICE has requested this session with a SRP + if ((pOTGDescriptor->bOTGEnableHNPAfterSRP == ENABLE) && Is_host_session_started_srp() && Is_usb_id_host()) { + device_state = A_INIT_HNP; + } + else { + if (Is_device_supports_hnp()) { + if (CONTROL_GOOD != host_set_feature_a_hnp_support()) { + device_state = A_END_HNP_WAIT_VFALL; // end session if Device STALLs the request + } + } + } + } + else + { + // In OTG, if the B-DEVICE VID/PID does not match the Target Peripheral List, it is seen as "Unsupported" + // - a HNP must be initiated if the device supports it + // - an error message must be displayed (and difference must be made between "Std device" and "Hub") + desc_temp = data_stage[OFFSET_DEV_DESC_CLASS]; // store the device class (for future hub check) + if (b_uut_device_state != B_HOST) { + if (Is_host_session_started_srp()) { + if (CONTROL_GOOD == host_get_configuration_descriptor()) { + host_check_OTG_features(); + if (Is_device_supports_hnp()) { + device_state = A_INIT_HNP; // unsupported (or test) device will cause a HNP request + } + else { + device_state = A_END_HNP_WAIT_VFALL; + if (desc_temp == HUB_CLASS_CODE) { + // Display "Hub unsupported" message + Otg_print_new_failure_message(OTGMSG_UNSUPPORTED_HUB,OTG_TEMPO_4SEC); + } + else { + // Display "Class unsupported" message + TRACE_DEBUG("Class unsupported\n\r"); + Otg_print_new_failure_message(OTGMSG_UNSUPPORTED,OTG_TEMPO_4SEC); + } + } + } + else { + device_state = A_END_HNP_WAIT_VFALL; + } + } + else { + device_state = A_INIT_HNP; + } + } + else + { + TRACE_DEBUG("VID/PID does not match the Target Peripheral List\n\r"); + Otg_print_new_failure_message(OTGMSG_UNSUPPORTED,OTG_TEMPO_4SEC); + Set_user_request_disc(); // ask end of session now + Set_user_request_suspend(); + } + } + + } + else {// Can not get device descriptor + device_state = DEVICE_ERROR; + } + break; + + case DEVICE_CONFIGURED : + // DEVICE_CONFIGURED state + // - Configure pipes for the supported interface + // - Send Set_configuration() request + // - Goto full operating mode (device ready) + TRACE_DEBUG("DEVICE_CONFIGURED\n\r"); + if (CONTROL_GOOD == host_get_configuration_descriptor()) { + if (HOST_FALSE != host_check_class()) { // Class support OK? + // Collect information about peripheral OTG descriptor if present + host_check_OTG_features(); + host_auto_configure_endpoint(); + + if (Is_host_configured()) { + if (CONTROL_GOOD== host_set_configuration(1)) { // Send Set_configuration + // host_set_interface(interface_bound,interface_bound_alt_set); + // device and host are now fully configured + // goto DEVICE READY normal operation + device_state = DEVICE_READY; + // monitor device disconnection under interrupt + Host_enable_device_disconnection_interrupt(); + // If user host application requires SOF interrupt event + // Keep SOF interrupt enable otherwize, disable this interrupt +#if (HOST_CONTINUOUS_SOF_INTERRUPT==DISABLE) + Host_disable_sof_interrupt(); +#endif + new_device_connected=TRUE; + TRACE_INFO("Device Enumerated\n\r"); + } + else { // Problem during Set_configuration request... + device_state = DEVICE_ERROR; + } + } + } + else { // device class not supported... + device_state = DEVICE_ERROR; + TRACE_INFO("Unsupported Device\n\r"); + Host_device_class_not_supported_action(); + } + } + else { // Can not get configuration descriptors... + device_state = DEVICE_ERROR; + } + break; + + case DEVICE_READY : + // DEVICE_READY state + // - Full standard operating mode + // - Nothing to do... + // Host full std operating mode! + new_device_connected=FALSE; + + // Handles user requests : "stop Vbus" and "suspend" + if (Is_usb_id_host()) { + if (Is_user_requested_suspend() || Is_user_requested_hnp()) { + // Before entering suspend mode, A-Host must send a SetFeature(b_hnp_enable) if supported by the B-Periph + Ack_user_request_hnp(); + Ack_user_request_suspend(); + device_state = A_INIT_HNP; + } + } + break; + + case DEVICE_ERROR : + //------------------------------------------------------ + // DEVICE_ERROR state + // - Error state + // - Do custom action call (probably go to default mode...) + TRACE_DEBUG("DEVICE_ERROR\n\r"); + device_state=DEVICE_UNATTACHED; + Host_device_error_action(); + break; + + case DEVICE_SUSPENDED : + // DEVICE_SUSPENDED state + // - Host application request to suspend the device activity + // - State machine comes here thanks to Host_request_suspend() + TRACE_DEBUG("DEVICE_SUSPENDED\n\r"); + // If OTG device, initiate a HNP process (go to specific state) + if (Is_peripheral_otg_device()) { + device_state = A_INIT_HNP; + } + else { + device_state=DEVICE_WAIT_RESUME; // wait for device resume event + if(Is_device_supports_remote_wakeup()) { // If the connected device supports remote wake up + if (CONTROL_GOOD != host_set_feature_remote_wakeup()) { + device_state = DEVICE_DISCONNECTED; // stop connexion because device has not accepted the feature + } + } + TRACE_INFO("Usb suspend\n\r"); + hostSOFCounter = Is_host_sof_interrupt_enabled(); //Save current sof interrupt enable state + Host_disable_sof_interrupt(); + Host_ack_sof(); + Host_disable_sof(); // Stop start of frame generation, this generates the suspend state + Host_ack_remote_wakeup(); + Host_enable_remote_wakeup_interrupt(); + Host_ack_hwup(); + Host_enable_hwup_interrupt(); // Enable host wake-up interrupt + // (this is the unique USB interrupt able to wake up the CPU core from power-down mode) + Usb_freeze_clock(); + Host_suspend_action(); // Custom action here! (for example go to power-save mode...) + } + break; + + case DEVICE_WAIT_RESUME : + // DEVICE_WAIT_RESUME state + // - Wait in this state till the host receives an upstream resume from the device + // - or the host software request the device to resume + TRACE_DEBUG("DEVICE_WAIT_RESUME\n\r"); + if(Is_usb_event(EVT_HOST_REMOTE_WAKEUP)|| Is_host_request_resume()) { // Remote wake up has been detected + // or Local resume request has been received + if(Is_host_request_resume()) { // Not a remote wakeup, but an host application request + Host_disable_hwup_interrupt(); // Wake up interrupt should be disable host is now wake up ! + // CAUTION HWUP can be cleared only when USB clock is active + // Pll_start_auto(); // First Restart the PLL for USB operation + // Wait_pll_ready(); // Get sure pll is lock + Usb_unfreeze_clock(); // Enable clock on USB interface + } + Host_ack_hwup(); // Clear HWUP interrupt flag + Host_enable_sof(); + + if (Is_usb_event(EVT_HOST_REMOTE_WAKEUP)) { + Usb_ack_event(EVT_HOST_REMOTE_WAKEUP); // Ack software event + Host_disable_sof_interrupt(); + Host_ack_device_disconnection(); + Host_disable_device_disconnection_interrupt(); + + Host_send_resume(); // this other downstream resume is done to ensure min. 20ms of HOST DRIVING RESUME (not Device) + while (!Is_device_disconnection() && Host_is_resume()); + hostSOFCounter = 0; + Host_ack_sof(); + while (!Is_device_disconnection() && (hostSOFCounter != 12)) { // wait for min. 10ms of device recovery time + if (Is_host_sof()) { + Host_ack_sof(); + hostSOFCounter++; + } + } + if (Is_device_disconnection()) { + usb_host_task_init(); + device_state = DEVICE_DISCONNECTED; + Host_ack_remote_wakeup(); // Ack remote wake-up reception + Host_ack_request_resume(); // Ack software request + Host_ack_down_stream_resume(); // Ack down stream resume sent + } + else { + device_state = DEVICE_READY; + Host_ack_remote_wakeup(); // Ack remote wake-up reception + Host_ack_request_resume(); // Ack software request + Host_ack_down_stream_resume(); // Ack down stream resume sent + } + Host_enable_device_disconnection_interrupt(); + Host_ack_sof(); + } + else { + Host_send_resume(); // Send down stream resume + //----------------------- + // Work-around for case of Device disconnection during Suspend + // The disconnection is never detected and the Resume bit remains high (and RSMEDI flag never set) + // If the timeout elapses, it implies that the device has disconnected => macro is reset (to reset the Resume bit) + dec = 0; + while (dec < 0x4FFFF) { // several hundreds of ms + if (Is_host_down_stream_resume()) { // Wait Down stream resume sent + Host_ack_remote_wakeup(); // Ack remote wake-up reception + Host_ack_request_resume(); // Ack software request + Host_ack_down_stream_resume(); // Ack down stream resume sent + if(hostSOFCounter) { + Host_enable_sof_interrupt(); + } // Restore SOF interrupt enable state before suspend + device_state=DEVICE_READY; // Come back to full operating mode + TRACE_INFO("Usb resumed\n\r"); + dec = 0x3FFFFE; // will cause a loop end + } + dec++; + } + if (dec != 0x3FFFFF) { // if resume failed + usb_host_task_init(); + device_state = DEVICE_DISCONNECTED; + } + else + { + hostSOFCounter = 0; + Host_ack_sof(); + while (!Is_device_disconnection() && (hostSOFCounter != 12)) { // wait for min. 10ms of device recovery time + if (Is_host_sof()) { + Host_ack_sof(); + hostSOFCounter++; + } + } + } + //-----------------------End of Work Around + } + } + break; + + case DEVICE_DISCONNECTED : + // DEVICE_DISCONNECTED state + // - Device disconnection has been detected + // - Run scheduler in this state at least two times to get sure event is detected by all host application tasks + // - Go to DEVICE_DISCONNECTED_ACK state before DEVICE_UNATTACHED, to get sure scheduler calls all app tasks... + TRACE_DEBUG("DEVICE_DISCONNECTED\n\r"); + device_state = DEVICE_DISCONNECTED_ACK; + break; + + case DEVICE_DISCONNECTED_ACK : + // DEVICE_DISCONNECTED_ACK state + // - Device disconnection has been detected and managed bu applicatives tasks + // - Go to DEVICE_UNATTACHED state + TRACE_DEBUG("DEVICE_DISCONNECTED_ACK\n\r"); + host_disable_all_pipe(); + device_state = DEVICE_UNATTACHED; + End_session_with_srp(); + Usb_ack_srp_interrupt(); + break; + + case A_PERIPHERAL: + // OTG Specific states : A_PERIPHERAL (A-Host has been turned into a Device after a HNP) + // - End session (and stop driving Vbus) when detecting suspend condition + // - Disconnect on user request + // - Call standard (non-OTG) device task to handle the Endpoint 0 requests + TRACE_DEBUG("A_PERIPHERAL\n\r"); + // End of role exchange : A_PERIPH go into DEVICE_DISCONNECTED mode : stop supplying VBUS + if (Is_usb_event(EVT_USB_SUSPEND)) { + Clear_all_user_request(); + Usb_ack_event(EVT_USB_SUSPEND); + Usb_disable_wake_up_interrupt(); + Usb_ack_role_exchange_interrupt(); + Usb_select_host(); + USBD_Connect();//Usb_attach(); + Usb_unfreeze_clock(); + b_uut_device_state = B_IDLE; + device_state = A_END_HNP_WAIT_VFALL; + Usb_ack_srp_interrupt(); + } + if (Is_user_requested_disc() || Is_user_requested_vbus()) { + Clear_all_user_request(); + Usb_disable_suspend_interrupt(); + Usb_ack_role_exchange_interrupt(); + Usb_select_host(); + Usb_unfreeze_clock(); + b_uut_device_state = B_IDLE; + device_state = A_END_HNP_WAIT_VFALL; + } + if (!Is_device_disconnection_event() && (device_state != A_END_HNP_WAIT_VFALL)) { + //usb_device_task(); + //MSDDriver_StateMachine(); + Scheduler_task_3(); + } + break; + + case A_INIT_HNP: + // OTG Specific states : A_INIT_HNP + // - Software enters this state when it has been requested to initiate a HNP + // - Handle "set feature" commands such as B_HNP_ENABLE or REMOTE_WAKE_UP + // - Handle failures + TRACE_DEBUG("A_INIT_HNP\n\r"); + Ack_user_request_hnp(); + Ack_user_request_suspend(); + if (Is_peripheral_otg_device() || !Is_host_configured()) { + device_state = A_SUSPEND; + if(Is_device_supports_remote_wakeup() && Is_host_configured()) { // If the connected device supports remote wake up + if (CONTROL_GOOD == host_set_feature_remote_wakeup()) { + Host_ack_remote_wakeup(); + Host_enable_remote_wakeup_interrupt(); + Host_ack_hwup(); + Host_enable_hwup_interrupt(); // Enable host wake-up interrupt + } + else { + device_state = A_END_HNP_WAIT_VFALL; // stop connection because device has STALLed the feature + } + } + if (Is_device_supports_hnp() || !Is_host_configured()) { + if (CONTROL_GOOD == host_set_feature_b_hnp_enable()) { + // B-Device has not STALLed the SetFeature + Usb_host_accept_hnp(); + Usb_ack_role_exchange_interrupt(); + Usb_ack_hnp_error_interrupt(); + Usb_enable_role_exchange_interrupt(); + Usb_enable_hnp_error_interrupt(); + Host_disable_device_disconnection_interrupt(); + Host_disable_device_connection_interrupt(); + } + else { + Otg_print_new_failure_message(OTGMSG_DEVICE_NO_RESP,OTG_TEMPO_4SEC); + device_state = A_END_HNP_WAIT_VFALL; + } + } + Host_ack_remote_wakeup(); + Host_enable_remote_wakeup_interrupt(); + Init_ta_aidl_bdis_counter(); + Host_disable_sof_interrupt(); + Host_ack_sof(); + Host_disable_sof(); // Stop start of frame generation, this generates the suspend state + Usb_disable_suspend_interrupt(); + } + else { + device_state = DEVICE_SUSPENDED; + } + break; + + case A_SUSPEND: + // OTG Specific states : A_SUSPEND + // - A-Host enters this state when it has requested the B-DEVICE to start HNP, and have entered Suspend mode + // - Detects device silences (with HNP time-out management) and Resume condition + TRACE_DEBUG("A_SUSPEND\n\r"); + Usb_ack_suspend(); + // HNP is managed by interrupt (HNPERRI/ROLEEXI) + if (Is_ta_aidl_bdis_counter_overflow()) { + device_state = A_END_HNP_WAIT_VFALL; // stop Vbus = end of current session + } + if (Is_usb_event(EVT_HOST_HWUP)|| Is_host_request_resume()) { + device_state = DEVICE_WAIT_RESUME; + } + break; + + case A_END_HNP_WAIT_VFALL: + // OTG Specific states : A_END_HNP_WAIT_VFALL + // - A-PERIPH enters this state when it has detected a Suspend from the B-Host + // - It stop Vbus delivery and waits line discharge (to avoid spurious SRP detection) + TRACE_DEBUG("A_END_HNP_WAIT_VFALL\n\r"); + Usb_disable_manual_vbus(); + Usb_disable_vbus(); + usb_configuration_nb = 0; + Host_vbus_action(); + Clear_all_user_request(); + device_state = DEVICE_DISCONNECTED; + usb_host_task_init(); + break; + + case A_TEMPO_VBUS_DISCHARGE: + // OTG Specific states : A_TEMPO_VBUS_DISCHARGE + // - State entered from A_END_HNP_WAIT_VFALL, when Vbus has just reached the vbus_valid threshold + // - In this state we wait long enough (50ms) to be sure that Vbus is not valid on the other device (if still connected) + // - When delay is elapsed, go to reset state + TRACE_DEBUG("A_TEMPO_VBUS_DISCHARGE\n\r"); + if (otg_end_hnp_vbus_delay == 0) { + Host_ack_device_connection(); + Host_ack_device_disconnection(); + Usb_ack_role_exchange_interrupt(); + Usb_ack_srp_interrupt(); + device_state = DEVICE_DISCONNECTED; + } + break; + + default : + // default state + // - Default case: ERROR + // - Goto no device state + TRACE_DEBUG("default\n\r"); + device_state = DEVICE_UNATTACHED; + break; + } +} + +//------------------------------------------------------------------------------ +/// This function send nb_data pointed with *buf with the pipe number specified +/// This function will activate the host sof interrupt to detect timeout. The +/// interrupt enable sof will be restore. +//------------------------------------------------------------------------------ +U8 host_send_data(U8 pipe, U16 nb_data, U8 *buf) +{ + U16 length; + U8 status=PIPE_GOOD; + U8 sav_int_sof_enable; + U8 nak_timeout; +#if (NAK_TIMEOUT_ENABLE==ENABLE) + U16 cpt_nak; +#endif + U16 nb_data_loaded; + + TRACE_DEBUG("host_send_data[]%d: %d\n\r", pipe, nb_data); + + sav_int_sof_enable=Is_host_sof_interrupt_enabled(); // Save state of enable sof interrupt + Host_enable_sof_interrupt(); + Host_select_pipe(pipe); + + Host_set_token_in(); + + Host_set_token_out(); + Host_ack_out_sent(); + /* + TRACE_DEBUG("CTRL: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_CTRL); + TRACE_DEBUG("SR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_SR); + TRACE_DEBUG("DEVCTRL: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_DEVCTRL); + TRACE_DEBUG("DEVISR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_DEVISR); + TRACE_DEBUG("DEVIMR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_DEVIMR); + TRACE_DEBUG("DEVEPTISR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_DEVEPTISR[0]); + TRACE_DEBUG("HSTCTRL: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTCTRL); + TRACE_DEBUG("HSTISR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTISR); + TRACE_DEBUG("HSTIMR: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTIMR); + TRACE_DEBUG("HSTPIP: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIP); + TRACE_DEBUG("HSTPIPCFG[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[0]); + TRACE_DEBUG("HSTPIPCFG[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[1]); + TRACE_DEBUG("HSTPIPCFG[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPCFG[2]); + TRACE_DEBUG("HSTPIPINRQ[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPINRQ[0]); + TRACE_DEBUG("HSTPIPINRQ[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPINRQ[1]); + TRACE_DEBUG("HSTPIPINRQ[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPINRQ[2]); + TRACE_DEBUG("HSTPIPERR[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPERR[0]); + TRACE_DEBUG("HSTPIPERR[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPERR[1]); + TRACE_DEBUG("HSTPIPERR[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPERR[2]); + TRACE_DEBUG("HSTPIPISR[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[0]); + TRACE_DEBUG("HSTPIPISR[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[1]); + TRACE_DEBUG("HSTPIPISR[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPISR[2]); + TRACE_DEBUG("HSTPIPIMR[0]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPIMR[0]); + TRACE_DEBUG("HSTPIPIMR[1]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPIMR[1]); + TRACE_DEBUG("HSTPIPIMR[2]: 0x%X\n\r",AT91C_BASE_OTGHS->OTGHS_HSTPIPIMR[2]); + */ + while (nb_data != 0) { // While there is something to send... + Host_unfreeze_pipe(); + // Prepare data to be sent + length = host_get_pipe_length(); + TRACE_DEBUG("size=%d\n\r", length); + + if ( length > nb_data) { + nb_data_loaded = nb_data; + length = nb_data; + } + else { + nb_data_loaded = length; + } + Address_fifochar_endpoint(global_pipe_nb); + while (length!=0) { // Load Pipe buffer + Host_write_byte(*buf++); + //(((char*)((unsigned int *)AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0))[dBytes++])=*(buf++); + //pFifo[dBytes++] = *buf; + //buf++; + length--; + } + private_sof_counter=0; // Reset the counter in SOF detection sub-routine +#if (NAK_TIMEOUT_ENABLE==ENABLE) + cpt_nak=0; +#endif + nak_timeout=0; + Host_ack_out_sent(); + Host_send_out(); + while (!Is_host_out_sent()) { + if (Is_host_emergency_exit()) { // Async disconnection or role change detected under interrupt + TRACE_DEBUG("Emergency exit\n\r"); + status=PIPE_DELAY_TIMEOUT; + Host_reset_pipe(pipe); + goto host_send_data_end; + } + if (private_sof_counter>=250) { // Count 250ms (250sof) + TRACE_DEBUG("TimeOut Send Data\n\r"); + private_sof_counter=0; + if (nak_timeout++>=TIMEOUT_DELAY) { // Inc timeout and check for overflow + status=PIPE_DELAY_TIMEOUT; + Host_reset_pipe(pipe); + goto host_send_data_end; + } + } + if (Is_host_pipe_error()) { // Any error ? + TRACE_DEBUG("pipe error\n\r"); + status = Host_error_status(); + Host_ack_all_errors(); + goto host_send_data_end; + } + if (Is_host_stall()) { // Stall management + TRACE_DEBUG("stall\n\r"); + status =PIPE_STALL; + Host_ack_stall(); + goto host_send_data_end; + } +#if (NAK_TIMEOUT_ENABLE==ENABLE) + if(Is_host_nak_received()) { //NAK received + Host_ack_nak_received(); + if (cpt_nak++>NAK_SEND_TIMEOUT) { + TRACE_DEBUG("NAK timeout\n\r"); + status = PIPE_NAK_TIMEOUT; + Host_reset_pipe(pipe); + goto host_send_data_end; + } + } +#endif + } + // Here OUT sent + nb_data -= nb_data_loaded; + status=PIPE_GOOD; // Frame correctly sent + Host_ack_out_sent(); + } + Host_freeze_pipe(); + +host_send_data_end: + // Restore sof interrupt enable state + if (sav_int_sof_enable==FALSE) { + Host_disable_sof_interrupt(); + } + // And return... + return ((U8)status); +} + + + +//------------------------------------------------------------------------------ +/// This function receives nb_data pointed with *buf with the pipe number specified +/// The nb_data parameter is passed as a U16 pointer, thus the data pointed by this pointer +/// is updated with the final number of data byte received. +//------------------------------------------------------------------------------ +U8 host_get_data(U8 pipe, U16 *nb_data, U8 *buf) +{ + U8 status=PIPE_GOOD; + U8 sav_int_sof_enable; + U8 nak_timeout; + U16 n; + U16 i; +#if (NAK_TIMEOUT_ENABLE==ENABLE) + U16 cpt_nak; +#endif + + // TRACE_DEBUG("host_get_data[%d]\n\r", pipe); + n=*nb_data; + *nb_data=0; + + sav_int_sof_enable=Is_host_sof_interrupt_enabled(); + Host_enable_sof_interrupt(); + + Host_select_pipe(pipe); + Host_set_token_in(); + Host_continuous_in_mode(); + // Host_ack_in_received(); + + while (n) { // While missing data... + // start IN request generation + Host_unfreeze_pipe(); + Host_send_in(); + private_sof_counter=0; // Reset the counter in SOF detection sub-routine + nak_timeout=0; +#if (NAK_TIMEOUT_ENABLE==ENABLE) + cpt_nak=0; +#endif + while (!Is_host_in_received()) + { + if (Is_host_emergency_exit()) // Async disconnection or role change detected under interrupt + { + status=PIPE_DELAY_TIMEOUT; + Host_reset_pipe(pipe); + goto host_get_data_end; + } + if (private_sof_counter>=250) // Timeout management + { + private_sof_counter=0; // Done in host SOF interrupt + if (nak_timeout++>=TIMEOUT_DELAY)// Check for local timeout + { + status=PIPE_DELAY_TIMEOUT; + Host_reset_pipe(pipe); + goto host_get_data_end; + } + } + if(Is_host_pipe_error()) // Error management + { + status = Host_error_status(); + Host_ack_all_errors(); + goto host_get_data_end; + } + if(Is_host_stall()) // STALL management + { + status =PIPE_STALL; + Host_reset_pipe(pipe); + Host_ack_stall(); + goto host_get_data_end; + } +#if (NAK_TIMEOUT_ENABLE==ENABLE) + if(Is_host_nak_received()) //NAK received + { + Host_ack_nak_received(); + if (cpt_nak++>NAK_RECEIVE_TIMEOUT) + { + status = PIPE_NAK_TIMEOUT; + Host_reset_pipe(pipe); + goto host_get_data_end; + } + } +#endif + } + status=PIPE_GOOD; + Host_freeze_pipe(); + if (Host_byte_counter()<=n) + { + if ((Host_byte_counter() < n)&&(Host_byte_counter() nb_data) // Pipe size> remaining data + { + i = nb_data; + nb_data = 0; + } + else // Pipe size < remaining data + { + nb_data -= i; + } + it_pipe_str[pipe].nb_byte_on_going+=i; // Update nb data processed + Address_fifochar_endpoint(global_pipe_nb); + while (i!=0) // Load Pipe buffer + { + Host_write_byte(*ptr_buf++); + i--; + } + private_sof_counter=0; // Reset the counter in SOF detection sub-routine + it_pipe_str[pipe].timeout=0; // Refresh timeout counter + Host_ack_out_sent(); + Host_ack_stall(); + Host_ack_nak_received(); + + Host_enable_stall_interrupt(); + Host_enable_error_interrupt(); +#if (NAK_TIMEOUT_ENABLE==ENABLE) + Host_enable_nak_interrupt(); +#endif + Host_enable_transmit_interrupt(); + Host_send_out(); // Send the USB frame + return HOST_TRUE; + } +} + +//------------------------------------------------------------------------------ +//! @brief USB pipe interrupt subroutine +//! +//! @param none +//! +//! @return none +//------------------------------------------------------------------------------ +void usb_pipe_interrupt(void) +{ + U8 pipe_nb; + U8 *ptr_buf; + void (*fct_handle)(U8 status,U16 nb_byte); + U16 n; + U8 i; + U8 do_call_back=FALSE; + + TRACE_DEBUG("usb_pipe_interrupt\n\r"); + + if(Host_get_pipe_interrupt()) { + + pipe_nb_save = Host_get_selected_pipe(); // Important! Save here working pipe number + pipe_nb=host_get_nb_pipe_interrupt(); // work with the correct pipe number that generates the interrupt + Host_select_pipe(pipe_nb); // Select this pipe + fct_handle=*(it_pipe_str[pipe_nb].handle); + + // Now try to detect what event generate an interrupt... + if (Is_host_pipe_error()) // Any error ? + { + TRACE_DEBUG("host_pipe_error\n\r"); + it_pipe_str[pipe_nb].status = Host_error_status(); + it_pipe_str[pipe_nb].enable=DISABLE; + Host_stop_pipe_interrupt(pipe_nb); + Host_ack_all_errors(); + do_call_back=TRUE; + goto usb_pipe_interrupt_end; + } + + if (Is_host_stall()) // Stall handshake received ? + { + TRACE_DEBUG("host_stall\n\r"); + it_pipe_str[pipe_nb].status=PIPE_STALL; + it_pipe_str[pipe_nb].enable=DISABLE; + Host_stop_pipe_interrupt(pipe_nb); + do_call_back=TRUE; + goto usb_pipe_interrupt_end; + } + +#if (NAK_TIMEOUT_ENABLE==ENABLE) + if (Is_host_nak_received()) // NAK ? + { + Host_ack_nak_received(); + // check if number of NAK timeout error occurs (not for interrupt type pipe) + if((--it_pipe_str[pipe_nb].nak_timeout==0) && (Host_get_pipe_type()!=TYPE_INTERRUPT)) + { + it_pipe_str[pipe_nb].status=PIPE_NAK_TIMEOUT; + it_pipe_str[pipe_nb].enable=DISABLE; + Host_stop_pipe_interrupt(pipe_nb); + do_call_back=TRUE; + goto usb_pipe_interrupt_end; + } + } +#endif + + if (Is_host_in_received()) // Pipe IN reception ? + { + TRACE_DEBUG("host_in received\n\r"); + ptr_buf = it_pipe_str[pipe_nb].ptr_buf; + ptr_buf += it_pipe_str[pipe_nb].nb_byte_processed; // Build pointer to data buffer + n = it_pipe_str[pipe_nb].nb_byte_to_process; + n -= it_pipe_str[pipe_nb].nb_byte_processed; // Remaining data bytes + Host_freeze_pipe(); + if (Host_byte_counter()<=n) + { + if ((Host_byte_counter() < n)&&(Host_byte_counter()0) //still something to process + { + Host_unfreeze_pipe(); // Request another IN transfer + Host_send_in(); + private_sof_counter=0; // Reset the counter in SOF detection sub-routine + it_pipe_str[pipe_nb].timeout=0; // Reset timeout + it_pipe_str[pipe_nb].nak_timeout=NAK_RECEIVE_TIMEOUT; + } + else //end of transfer + { + it_pipe_str[pipe_nb].enable=DISABLE; + it_pipe_str[pipe_nb].status=PIPE_GOOD; + Host_stop_pipe_interrupt(pipe_nb); + do_call_back=TRUE; + } + } + + if(Is_host_out_sent()) // Pipe OUT sent ? + { + TRACE_DEBUG("host_out send\n\r"); + Host_ack_out_sent(); + it_pipe_str[pipe_nb].nb_byte_processed+=it_pipe_str[pipe_nb].nb_byte_on_going; + it_pipe_str[pipe_nb].nb_byte_on_going=0; + ptr_buf = it_pipe_str[pipe_nb].ptr_buf; + ptr_buf += it_pipe_str[pipe_nb].nb_byte_processed; // Build pointer to data buffer + n = it_pipe_str[pipe_nb].nb_byte_to_process; + n -= it_pipe_str[pipe_nb].nb_byte_processed; // Remaining data bytes + if(n>0) // Still data to process... + { + Host_unfreeze_pipe(); + // Prepare data to be sent + i = host_get_pipe_length(); + if ( i > n) // Pipe size> remaining data + { + i = n; + n = 0; + } + else // Pipe size < remaining data + { + n -= i; + } + it_pipe_str[pipe_nb].nb_byte_on_going+=i; // Update nb data processed + Address_fifochar_endpoint(global_pipe_nb); + while (i!=0) // Load Pipe buffer + { + Host_write_byte(*ptr_buf++); i--; + } + private_sof_counter=0; // Reset the counter in SOF detection sub-routine + it_pipe_str[pipe_nb].timeout=0; // Refresh timeout counter + it_pipe_str[pipe_nb].nak_timeout=NAK_SEND_TIMEOUT; + Host_send_out(); // Send the USB frame + } + else //n==0 Transfer is finished + { + it_pipe_str[pipe_nb].enable=DISABLE; // Tranfer end + it_pipe_str[pipe_nb].status=PIPE_GOOD; // Status OK + Host_stop_pipe_interrupt(pipe_nb); + do_call_back=TRUE; + } + } + +usb_pipe_interrupt_end: + Host_select_pipe(pipe_nb_save); // Restore pipe number !!!! + if (is_any_interrupt_pipe_active()==FALSE) // If no more transfer is armed + { + if (g_sav_int_sof_enable==FALSE) + { + Host_disable_sof_interrupt(); + } + } + if(do_call_back) // Any callback functions to perform ? + { + fct_handle(it_pipe_str[pipe_nb].status,it_pipe_str[pipe_nb].nb_byte_processed); + } + + } + +} + + + diff --git a/usb/otg/usb_task.c b/usb/otg/usb_task.c new file mode 100644 index 0000000..043879f --- /dev/null +++ b/usb/otg/usb_task.c @@ -0,0 +1,999 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + + + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include "main.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "otg_user_task.h" +#include "usb_task.h" +#include "usb/otg/usb_drv.h" + +#if ((USB_HOST_FEATURE == ENABLE)) + #include "usb/otg/usb_host_task.h" +#endif + +#if ((USB_DEVICE_FEATURE == ENABLE)) +#include +#include +#include +#include +#include +#include +#include +#endif + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + + + +extern volatile unsigned int timer_set_counter; +#define Timer16_select(...) +#define Timer16_set_counter(value) timer_set_counter = value +#define Timer16_get_counter_low() (unsigned char)timer_set_counter + + +/// Returns the OTG features sent by the host by a SetFeature +/// Allow also to clear the features (only on a bus Reset or Session End) +#define Is_host_requested_hnp() (((otg_features_supported&USBFeatureRequest_OTG_B_HNP_ENABLE) != 0) ? TRUE : FALSE) +#define Clear_otg_features_from_host() (otg_features_supported = 0) + +#define Set_otg_custom_timer(ep) // STUB: todo + +#define USB_MODE_UNDEFINED 0x00 +#define USB_MODE_HOST 0x01 +#define USB_MODE_DEVICE 0x02 + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +U8 otg_device_sessions; +U8 b_uut_device_state; +U16 otg_tb_srp_cpt; + +/// usb_connected is used to store USB events detected upon +/// USB general interrupt subroutine +/// Its value is managed by the following macros (See usb_task.h file) +/// Usb_send_event(x) +/// Usb_ack_event(x) +/// Usb_clear_all_event() +/// Is_usb_event(x) +/// Is_not_usb_event(x) +volatile U16 g_usb_event=0; + + +#if (USB_DEVICE_FEATURE == ENABLE) +/// +/// Public : (bit) usb_connected +/// usb_connected is set to TRUE when VBUS has been detected +/// usb_connected is set to FALSE otherwise +/// Used with USB_DEVICE_FEATURE == ENABLE only +//// +bit usb_connected; + +/// +/// Public : (U8) usb_configuration_nb +/// Store the number of the USB configuration used by the USB device +/// when its value is different from zero, it means the device mode is enumerated +/// Used with USB_DEVICE_FEATURE == ENABLE only +//// +U8 usb_configuration_nb; + +/// +/// Public : (U8) remote_wakeup_feature +/// Store a host request for remote wake up (set feature received) +//// +U8 remote_wakeup_feature; +#endif + + +#if (USB_HOST_FEATURE == ENABLE) +/// +/// Private : (U8) private_sof_counter +/// Incremented by host SOF interrupt subroutime +/// This counter is used to detect timeout in host requests. +/// It must not be modified by the user application tasks. +//// +volatile U8 private_sof_counter=0; + +extern volatile S_pipe_int it_pipe_str[MAX_EP_NB]; + +#endif + +#if ((USB_DEVICE_FEATURE == ENABLE)&& (USB_HOST_FEATURE == ENABLE)) +/// +/// Public : (U8) g_usb_mode +/// Used in dual role application (both device/host) to store +/// the current mode the usb controller is operating +//// + U8 g_usb_mode=USB_MODE_UNDEFINED; + U8 g_old_usb_mode; +#endif + + +#if (USB_OTG_FEATURE == ENABLE) + /// + /// Public : (U8) otg_features_supported; + /// -> A-Device side : indicates if the B-Device supports HNP and SRP (this is the bmAttributes field of OTG Decriptor) + /// -> B-Device side : indicates if the A-Device has enabled the "a_hnp_support" and "b_hnp_enable" features + volatile U8 otg_features_supported; + + /// Public : (U8) otg_user_request; + /// Store the last request of the user (see usb_device_task.h) + U8 otg_user_request; + + /// Public : (U16) otg_msg_event_delay; + /// Contains the current display duration of the OTG event message + U16 otg_msg_event_delay; + + /// Public : (U16) otg_msg_failure_delay; + /// Contains the current display duration of the OTG failure message + U16 otg_msg_failure_delay; + + /// Public : (U16) g_otg_event; + /// Contains several bits corresponding to differents OTG events (similar to g_usb_event) + volatile U16 g_otg_event; + + /// Public : (U8) otg_device_nb_hnp_retry; + /// Counts the number of times a HNP fails, before aborting the operations + U8 otg_device_nb_hnp_retry; + + U8 id_changed_to_host_event; + + volatile U8 otg_last_sof_received; // last SOF received in SOF interrupt + volatile U8 otg_last_sof_stored; // last SOF value stored in OTG Timer interrupt + volatile U8 reset_received; // indicates if a reset has been received from B-Host after a HNP (used in A-Periph mode) + + /// @brief VBUS Overload management + /// + /// Nothing to do ! If the condition is not defined in the board driver file + /// (i.e. if the board does not support Vbus overcurrent detection), + /// the macro is defined to false for firmware compatibility +#define Is_vbus_overcurrent() (FALSE) + + /// Private function prototypes + /// Tasks for OTG Messaging features + void Otg_message_task_init(void); + void Otg_message_task(void); +#endif + + +//------------------------------------------------------------------------------ +// Local Variables +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Internal Functions +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes the USB process +/// Depending on the mode supported (HOST/DEVICE/DUAL_ROLE) the function calls +/// the coresponding USB mode initialization function +//------------------------------------------------------------------------------ +void usb_task_init(void) +{ + +// ---- DUAL ROLE DEVICE USB MODE --------------------------------------------- +#if (USB_OTG_FEATURE == ENABLE) + Otg_message_task_init(); // OTG program needs to display event messages to the user + b_uut_device_state = B_IDLE; // init state machines variables +#if (USB_HOST_FEATURE == ENABLE) + device_state = DEVICE_UNATTACHED; +#endif + otg_device_nb_hnp_retry = BDEV_HNP_NB_RETRY; + Clear_all_user_request(); +#endif + +#if (((USB_DEVICE_FEATURE == ENABLE) && (USB_HOST_FEATURE == ENABLE)) || (USB_OTG_FEATURE == ENABLE)) +#if (USB_OTG_FEATURE == ENABLE) + Usb_enable_uid_pin(); +#endif + + // delay=PORTA; + g_usb_mode=USB_MODE_UNDEFINED; + + if(Is_usb_id_device()) + { + g_usb_mode=USB_MODE_DEVICE; + //usb_device_task_init(); + MSDDriver_Initialize(luns, numMedias); + +#if (USB_OTG_FEATURE == ENABLE) + id_changed_to_host_event = DISABLE; +#endif + } + else + { + Usb_send_event(EVT_USB_HOST_FUNCTION); + g_usb_mode=USB_MODE_HOST; + Usb_ack_id_transition(); // REQUIRED !!! Startup with ID=0, Ack ID pin transistion (default hwd start up is device mode) + Usb_enable_id_interrupt(); + usb_host_task_init(); +#if (USB_OTG_FEATURE == ENABLE) + id_changed_to_host_event = ENABLE; +#endif + } +#if ((USB_DEVICE_FEATURE == ENABLE)&& (USB_HOST_FEATURE == ENABLE)) + g_old_usb_mode = g_usb_mode; // Store current usb mode, for mode change detection +#endif + // ------------------------------------------------------------------------- + + // ---- DEVICE ONLY USB MODE ----------------------------------------------- +#elif ((USB_DEVICE_FEATURE == ENABLE)&& (USB_HOST_FEATURE == DISABLE)) + //jcbUsb_force_device_mode(); + //usb_device_task_init(); + MSDDriver_Initialize(luns, numMedias); + // ------------------------------------------------------------------------- + + // ---- REDUCED HOST ONLY USB MODE ----------------------------------------- +#elif ((USB_DEVICE_FEATURE == DISABLE)&& (USB_HOST_FEATURE == ENABLE)) + //jcbUsb_force_host_mode(); + usb_host_task_init(); +#elif ((USB_DEVICE_FEATURE == DISABLE)&& (USB_HOST_FEATURE == DISABLE)) +#error at least one of USB_DEVICE_FEATURE or USB_HOST_FEATURE should be enabled +#endif + // ------------------------------------------------------------------------- + +} + + +//------------------------------------------------------------------------------ +/// Entry point of the USB mamnagement +/// Depending on the USB mode supported (HOST/DEVICE/DUAL_ROLE) the function +/// calls the coresponding USB management function +//------------------------------------------------------------------------------ +void usb_task(void) +{ + // ---- DUAL ROLE DEVICE USB MODE --------------------------------------------- +#if ((USB_DEVICE_FEATURE == ENABLE) && (USB_HOST_FEATURE == ENABLE)) + if(Is_usb_id_device()) { + g_usb_mode = USB_MODE_DEVICE; + } + else { + g_usb_mode = USB_MODE_HOST; + } + g_old_usb_mode = g_usb_mode; // Store current usb mode, for mode change detection + // Depending on current usb mode, launch the correct usb task (device or host) + +#if (USB_OTG_FEATURE == ENABLE) + // Configure OTG timers + Set_otg_custom_timer(VBUSRISE_70MS); + Set_otg_custom_timer(VBUSPULSE_40MS); + Set_otg_custom_timer(VFALLTMOUT_131MS); + Set_otg_custom_timer(SRPMINDET_100US); +#endif + + switch(g_usb_mode) { + case USB_MODE_DEVICE: + //usb_device_task(); + MSDDriver_StateMachine(); + break; + + case USB_MODE_HOST: + if( pOTGDescriptor.bOTGADevSRPReaction == VBUS_PULSE) { + Usb_select_vbus_srp_method(); + } + else { + Usb_select_data_srp_method(); + } + usb_host_task(); + // Handle Vbus overcurrent error (auto-disabled if not supported or not defined in board driver file) +#if (USB_OTG_FEATURE == ENABLE) + if (Is_vbus_overcurrent()) { + Otg_print_new_event_message(OTGMSG_VBUS_SURCHARGE,OTG_TEMPO_3SEC); + } +#endif + break; + + case USB_MODE_UNDEFINED: // No break ! + default: + break; + } + // ------------------------------------------------------------------------- + // ---- DEVICE ONLY USB MODE ----------------------------------------------- +#elif ((USB_DEVICE_FEATURE == ENABLE)&& (USB_HOST_FEATURE == DISABLE)) + //usb_device_task(); + MSDDriver_StateMachine(); + // ------------------------------------------------------------------------- + + // ---- REDUCED HOST ONLY USB MODE ----------------------------------------- +#elif ((USB_DEVICE_FEATURE == DISABLE)&& (USB_HOST_FEATURE == ENABLE)) + usb_host_task(); + // ------------------------------------------------------------------------- + + /// ---- ERROR, NO MODE ENABLE --------------------------------------------- +#elif ((USB_DEVICE_FEATURE == DISABLE)&& (USB_HOST_FEATURE == DISABLE)) +#error at least one of USB_DEVICE_FEATURE or USB_HOST_FEATURE should be enabled +#error otherwise the usb task has nothing to do ... +#endif + // ------------------------------------------------------------------------- + +#if (USB_OTG_FEATURE == ENABLE) + Otg_message_task(); +#endif +} + + + +//------------------------------------------------------------------------------ +/// USB interrupt subroutine +/// +/// This function is called each time a USB interrupt occurs. +/// The following USB DEVICE events are taken in charge: +/// - VBus On / Off +/// - Start Of Frame +/// - Suspend +/// - Wake-Up +/// - Resume +/// - Reset +/// - Start of frame +/// +/// The following USB HOST events are taken in charge: +/// - Device connection +/// - Device Disconnection +/// - Start Of Frame +/// - ID pin change +/// - SOF (or Keep alive in low speed) sent +/// - Wake up on USB line detected +/// +/// The following USB HOST events are taken in charge: +/// - HNP success (Role Exchange) +/// - HNP failure (HNP Error) +/// +/// For each event, the user can launch an action by completing +/// the associate define (See conf_usb.h file to add action upon events) +/// +/// Note: Only interrupts events that are enabled are processed +//------------------------------------------------------------------------------ +void usb_general_interrupt(void) +{ + U8 i; + U8 save_pipe_nb; + + // ---------- DEVICE events management ----------------------------------- + // ----------------------------------------------------------------------- +#if ((USB_DEVICE_FEATURE == ENABLE) || (USB_OTG_FEATURE == ENABLE)) + + //- VBUS state detection + // ----------------------------------------------------------------------- + /// Arbitrer + // ----------------------------------------------------------------------- + if (Is_usb_vbus_transition() && Is_usb_vbus_interrupt_enabled() + && Is_usb_id_device()) { + Usb_ack_vbus_transition(); + + if (Is_usb_vbus_high()) { + usb_connected = TRUE; + Usb_vbus_on_action(); + Usb_send_event(EVT_USB_POWERED); + //jcb Usb_enable_reset_interrupt(); + //usb_start_device(); + USBD_Connect();//Usb_attach(); + } + else { + TRACE_DEBUG("VBUS low\n\r"); + USBD_Disconnect(); +#if (USB_OTG_FEATURE == ENABLE) + Usb_device_stop_hnp(); + TRACE_DEBUG("Usb_select_device4\n\r"); + Usb_select_device(); + Clear_all_user_request(); +#endif + Usb_vbus_off_action(); + usb_connected = FALSE; + usb_configuration_nb = 0; + Usb_send_event(EVT_USB_UNPOWERED); + } + + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - Device start of frame received + if (Is_usb_sof() && Is_sof_interrupt_enabled()) { + // TRACE_DEBUG_WP("F"); // device + Usb_ack_sof(); + Usb_sof_action(); +#if (USB_OTG_FEATURE == ENABLE) + //sof_seen_in_session = TRUE; + otg_last_sof_received = UDFNUML; // store last frame number received +#endif + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - Device Suspend event (no more USB activity detected) + if (Is_usb_suspend()) { //&& Is_suspend_interrupt_enabled()) { + //TRACE_DEBUG_WP("D\n\r"); +#if (USB_OTG_FEATURE == ENABLE) + // 1st : B-PERIPH mode ? + if (Is_usb_id_device()) { + // HNP Handler + TRACE_DEBUG("HNP Handler\n\r"); + //TRACE_DEBUG("device_state = %d\n\r", device_state); + //TRACE_DEBUG("b_uut_device_state = %d\n\r", b_uut_device_state); + if (Is_host_requested_hnp() // "b_hnp_enable" feature received + && (Is_session_started_with_srp() || Is_user_requested_hnp() { + if (otg_device_nb_hnp_retry == 0) { + otg_features_supported &= ~USBFeatureRequest_OTG_B_HNP_ENABLE; + } + else { + Ack_user_request_hnp(); + Usb_ack_hnp_error_interrupt(); + Usb_ack_role_exchange_interrupt(); + Usb_enable_role_exchange_interrupt(); + Usb_enable_hnp_error_interrupt(); + Usb_device_initiate_hnp(); + otg_device_nb_hnp_retry--; + } + } + else + { + // Remote wake-up handler + //TRACE_DEBUG("Remote wake-up handler\n\r"); + //TRACE_DEBUG("device_state = %d\n\r", device_state); + //TRACE_DEBUG("b_uut_device_state = %d\n\r", b_uut_device_state); + if ((remote_wakeup_feature == ENABLE) && (usb_configuration_nb != 0)) + { + //TRACE_DEBUG("enabled\n\r"); + // After that user can execute "Usb_initiate_remote_wake_up()" to initiate a remote wake-up + // Note that the suspend interrupt flag SUSPI must still be set to enable upstream resume + // So the SUSPE enable bit must be cleared to avoid redundant interrupt + // **************** + // Please note also that is Vbus is lost during an upstream resume (Host disconnection), + // the RMWKUP bit (used to initiate remote wake up and that is normally cleared by hardware when sent) + // remains set after the event, so that a good way to handle this feature is : + // Usb_initiate_remote_wake_up(); + // while (Is_usb_pending_remote_wake_up()) + // { + // if (Is_usb_vbus_low()) + // { + // // Emergency action (reset macro, etc.) if Vbus lost during resuming + // break; + // } + // } + // Usb_ack_remote_wake_up_start(); + // **************** + } + else { + //TRACE_DEBUG("disabled: %d %d\n\r", usb_configuration_nb, remote_wakeup_feature); + // No remote wake-up supported + Usb_send_event(EVT_USB_SUSPEND); + } + } + } + else + { + //TRACE_DEBUG("ici\n\r"); + // A-PERIPH mode (will cause a session end, handled in usb_host_task.c) + Usb_send_event(EVT_USB_SUSPEND); + Usb_suspend_action(); + //jcb Usb_ack_suspend(); + } +#else + // Remote wake-up handler + if ((remote_wakeup_feature == ENABLE) && (usb_configuration_nb != 0)) { + TRACE_DEBUG("Remote wake-up handler\n\r"); + Usb_disable_suspend_interrupt(); + Usb_ack_wake_up(); + Usb_enable_wake_up_interrupt(); + Usb_suspend_action(); + Usb_freeze_clock(); + // After that user can execute "Usb_initiate_remote_wake_up()" to initiate a remote wake-up + // Note that the suspend interrupt flag SUSPI must still be set to enable upstream resume + // So the SUSPE enable bit must be cleared to avoid redundant interrupt + // **************** + // Please note also that is Vbus is lost during an upstream resume (Host disconnection), + // the RMWKUP bit (used to initiate remote wake up and that is normally cleared by hardware when sent) + // remains set after the event, so that a good way to handle this feature is : + // Usb_unfreeze_clock(); + // Usb_initiate_remote_wake_up(); + // while (Is_usb_pending_remote_wake_up()) + // { + // if (Is_usb_vbus_low()) + // { + // // Emergency action (reset macro, etc.) if Vbus lost during resuming + // break; + // } + // } + // Usb_ack_remote_wake_up_start(); + // **************** + } + else { + // No remote wake-up supported + Usb_send_event(EVT_USB_SUSPEND); + Usb_suspend_action(); + Usb_ack_suspend(); + Usb_ack_wake_up(); // clear wake up to detect next event + Usb_enable_wake_up_interrupt(); + Usb_freeze_clock(); + } +#endif + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - Wake up event (USB activity detected): Used to resume + if (Is_usb_wake_up() && Is_swake_up_interrupt_enabled()) { + TRACE_DEBUG("W\n\r"); + Usb_unfreeze_clock(); + Usb_send_event(EVT_USB_WAKE_UP); + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - Resume state bus detection + if (Is_usb_resume() && Is_resume_interrupt_enabled()) { + TRACE_DEBUG("Resume state bus detect\n\r"); + Usb_send_event(EVT_USB_RESUME); + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - USB bus reset detection + if (Is_usb_reset()&& Is_reset_interrupt_enabled()) { + TRACE_DEBUG_WP("B\n\r"); +#if (USB_OTG_FEATURE == ENABLE) + if (Is_usb_id_host()) { + //TRACE_DEBUG_WP("id_host\n\r"); + dev_configure_endpoint(EP_CONTROL, + TYPE_CONTROL, + DIRECTION_OUT, + SIZE_64, + ONE_BANK, + NYET_DISABLED); + } + // First initialization is important to be synchronized + // A reset must first have been received + if (device_state == A_PERIPHERAL) { + //TRACE_DEBUG_WP("r A_PERIPHERAL\n\r"); + otg_last_sof_received = UDFNUML; + otg_last_sof_stored = UDFNUML; + Usb_ack_sof(); + Usb_enable_sof_interrupt(); + reset_received = TRUE; + Timer16_set_counter(0); + } +#endif + Usb_reset_action(); + Usb_send_event(EVT_USB_RESET); + } + + // ---------- OTG events management ------------------------------------ + // --------------------------------------------------------------------- +#if (USB_OTG_FEATURE == ENABLE) && (USB_HOST_FEATURE == ENABLE) + + // ----------------------------------------------------------------------- + /// Arbitrer + // ----------------------------------------------------------------------- + // - OTG HNP Success detection + if (Is_usb_role_exchange_interrupt() && Is_role_exchange_interrupt_enabled()) { + // TRACE_DEBUG("OTG HNP detect\n\r"); + Usb_ack_role_exchange_interrupt(); + Host_ack_device_connection(); + Host_ack_device_disconnection(); + Otg_send_event(EVT_OTG_HNP_SUCCESS); + End_session_with_srp(); + Clear_otg_features_from_host(); + if (Is_usb_id_host()) { + // HOST (A- or B-) mode + if ((device_state != A_PERIPHERAL) && (device_state != A_END_HNP_WAIT_VFALL)) { + static volatile unsigned int jcb; + // Current mode is A-HOST, device will take the A-PERIPHERAL role + b_uut_device_state = B_PERIPHERAL; + device_state = A_PERIPHERAL; + usb_connected = FALSE; + usb_configuration_nb = 0; + Usb_select_device(); + USBD_Connect();//Usb_attach(); + Usb_unfreeze_clock(); + Usb_disable_role_exchange_interrupt(); + Usb_disable_hnp_error_interrupt(); + Usb_device_stop_hnp(); + Usb_ack_reset(); + Timer16_set_counter(0); + Usb_freeze_clock(); // USB clock can be freezed to slow down events and condition detection + //jcb while (Timer16_get_counter_low() != 20); + jcb=0; + while( jcb <100000){ jcb++; } + + Usb_unfreeze_clock(); + reset_received = FALSE; + Usb_disable_sof_interrupt(); // will be set in the next OTG Timer IT (mandatory) + + Usb_enable_suspend_interrupt(); + Usb_enable_reset_interrupt(); + dev_configure_endpoint(EP_CONTROL, + TYPE_CONTROL, + DIRECTION_OUT, + SIZE_64, + ONE_BANK, + NYET_DISABLED); + } + } + else { + // In B_HOST mode, the HNPREQ bit must not be cleared because it releases the bus in suspend mode (and sof can't start) + if ((b_uut_device_state != B_HOST) && (b_uut_device_state != B_END_HNP_SUSPEND)) { + static volatile unsigned int jcb2; + // Current mode is B-PERIPHERAL, device will go into B-HOST role + End_session_with_srp(); + Clear_otg_features_from_host(); + b_uut_device_state = B_HOST; + device_state = DEVICE_ATTACHED; + usb_connected = FALSE; + usb_configuration_nb = 0; + TRACE_DEBUG("Select host 3\n\r"); + Usb_select_host(); + + TRACE_DEBUG("Send reset\n\r"); + Host_send_reset(); // send the first RESET + while (Host_is_reset()); + TRACE_DEBUG("Reset passed\n\r"); + + jcb2=0; + while( jcb2 <1000000){ jcb2++; } + Host_enable_sof(); // start Host (sof) + Usb_disable_role_exchange_interrupt(); + Usb_disable_hnp_error_interrupt(); + Clear_all_user_request(); + + TRACE_DEBUG("Select host 3\n\r"); + } + } + } + + // ----------------------------------------------------------------------- + /// Arbitrer + // ----------------------------------------------------------------------- + // - OTG HNP Failure detection + if (Is_usb_hnp() && Is_usb_hnp_error_interrupt()&& Is_hnp_error_interrupt_enabled()) { + TRACE_DEBUG("OTG HNP failure\n\r"); + Usb_device_stop_hnp(); + Usb_disable_role_exchange_interrupt(); + Usb_disable_hnp_error_interrupt(); + Usb_ack_hnp_error_interrupt(); + if (Is_usb_id_device()) { + Otg_send_event(EVT_OTG_HNP_ERROR); + Clear_all_user_request(); + } + } +#endif +#endif// End DEVICE FEATURE MODE && USB_HOST_FEATURE + + // ---------- HOST events management ----------------------------------- + // --------------------------------------------------------------------- +#if (((USB_HOST_FEATURE == ENABLE) && (USB_DEVICE_FEATURE == ENABLE)) || (USB_OTG_FEATURE == ENABLE)) + // ----------------------------------------------------------------------- + /// Arbitrer + // ----------------------------------------------------------------------- + // - ID pin change detection + if(Is_usb_id_transition()&&Is_usb_id_interrupt_enabled()) { + TRACE_DEBUG("ID pin change\n\r"); + TRACE_DEBUG("device_state = %d\n\r", device_state); + TRACE_DEBUG("b_uut_device_state = %d\n\r", b_uut_device_state); + Usb_device_stop_hnp(); +#if (USB_OTG_FEATURE == ENABLE) + Clear_all_user_request(); +#endif + if(Is_usb_id_device()) { + g_usb_mode = USB_MODE_DEVICE; + } + else { + g_usb_mode = USB_MODE_HOST; + } + Usb_ack_id_transition(); + if( g_usb_mode != g_old_usb_mode) { // Basic Debounce + if(Is_usb_id_device()) { // Going into device mode + Usb_send_event(EVT_USB_DEVICE_FUNCTION); +#if (USB_OTG_FEATURE == ENABLE) + b_uut_device_state = B_IDLE; +#endif + device_state = DEVICE_UNATTACHED; +#if (USB_OTG_FEATURE == ENABLE) + id_changed_to_host_event = DISABLE; +#endif + } + else { // Going into host mode +#if (USB_OTG_FEATURE == ENABLE) + b_uut_device_state = B_IDLE; +#endif + device_state = DEVICE_UNATTACHED; + Usb_send_event(EVT_USB_HOST_FUNCTION); +#if (USB_OTG_FEATURE == ENABLE) + id_changed_to_host_event = ENABLE; +#endif + } + Usb_id_transition_action(); + TRACE_INFO("Pin Id changed\n\r"); +#if ( ID_PIN_CHANGE_GENERATE_RESET == ENABLE) + // Hot ID transition generates wdt reset +#endif + } + } + +#endif +#if ((USB_HOST_FEATURE == ENABLE) || (USB_OTG_FEATURE == ENABLE)) + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - The device has been disconnected + // JCB to be fix + if(Is_device_disconnection() && Is_host_device_disconnection_interrupt_enabled()) { + TRACE_DEBUG("device disconnect\n\r"); + host_disable_all_pipe(); + Host_ack_device_disconnection(); + device_state=DEVICE_DISCONNECTED; + Usb_send_event(EVT_HOST_DISCONNECTION); + TRACE_INFO("Device disconnected\n\r"); + Host_device_disconnection_action(); +#if (USB_OTG_FEATURE == ENABLE) + Clear_all_user_request(); +#endif + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - Device connection + if(Is_device_connection() && Is_host_device_connection_interrupt_enabled()) { + TRACE_DEBUG("device connect\n\r"); + Host_ack_device_connection(); + host_disable_all_pipe(); + Host_device_connection_action(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - Host Start of frame has been sent + if (Is_host_sof() && Is_host_sof_interrupt_enabled()) { + //TRACE_DEBUG_WP("_"); // host + Host_ack_sof(); + Usb_send_event(EVT_HOST_SOF); + private_sof_counter++; + + // delay timeout management for interrupt tranfer mode in host mode + if (private_sof_counter>=250) { // Count 1/4 sec + private_sof_counter=0; + for(i=0;iTIMEOUT_DELAY) && (Host_get_pipe_type()!=TYPE_INTERRUPT)) { + it_pipe_str[i].enable=DISABLE; + it_pipe_str[i].status=PIPE_DELAY_TIMEOUT; + Host_stop_pipe_interrupt(i); + if (is_any_interrupt_pipe_active()==FALSE) { // If no more transfer is armed + if (g_sav_int_sof_enable==FALSE) { + Host_disable_sof_interrupt(); + } + } + it_pipe_str[i].handle(PIPE_DELAY_TIMEOUT,it_pipe_str[i].nb_byte_processed); + } + Host_select_pipe(save_pipe_nb); + } + } + } + Host_sof_action(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - Host Wake-up has been received + if (Is_host_hwup() && Is_host_hwup_interrupt_enabled()) { + TRACE_DEBUG("Host wake up\n\r"); + Host_disable_hwup_interrupt(); // Wake up interrupt should be disable host is now wake up ! + Host_disable_remote_wakeup_interrupt(); + // CAUTION HWUP can be cleared only when USB clock is active (not frozen)! + Usb_unfreeze_clock(); // Enable clock on USB interface + Host_enable_sof(); // start sending SOF + Host_ack_hwup(); // Clear HWUP interrupt flag + Host_ack_remote_wakeup(); + Usb_send_event(EVT_HOST_HWUP); // Send software event + Usb_send_event(EVT_HOST_REMOTE_WAKEUP); + Host_hwup_action(); // Map custom action +#if (USB_OTG_FEATURE == ENABLE) + if (Is_usb_hnp()) { + Usb_host_reject_hnp(); + Usb_disable_hnp_error_interrupt(); + Usb_disable_role_exchange_interrupt(); + } +#endif + Host_send_resume(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // Remote Wake Up has been received + if (Is_host_remote_wakeup_interrupt_enabled() && Is_host_remote_wakeup()) { + TRACE_DEBUG("Remote wake up\n\r"); + Host_disable_remote_wakeup_interrupt(); + Host_disable_hwup_interrupt(); + Host_ack_remote_wakeup(); + Host_ack_hwup(); // Clear HWUP interrupt flag + Usb_unfreeze_clock(); // Enable clock on USB interface + Host_enable_sof(); // start sending SOF + Usb_send_event(EVT_HOST_REMOTE_WAKEUP); + Usb_send_event(EVT_HOST_HWUP); // Send software event +#if (USB_OTG_FEATURE == ENABLE) + if (Is_usb_hnp()) { + Usb_host_reject_hnp(); + Usb_disable_hnp_error_interrupt(); + Usb_disable_role_exchange_interrupt(); + } +#endif + Host_send_resume(); + } +#endif // End HOST FEATURE MODE +} + + +#if (USB_OTG_FEATURE == ENABLE) + +//------------------------------------------------------------------------------ +/// OTG TIMER interrupt subroutine +/// This function is called each time a OTG Timer interrupt occurs +/// Function decrements the variables required by OTG program +void otg_timer_interrupt(void) +{ + /// OTG Messaging timer + if( (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_ALL) + || (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_FAIL)) { + if ((Get_failure_msg_delay() != 0x0000) && (Get_failure_msg_delay() != 0xFFFF)) { + Decrement_failure_msg_delay(); + } + if( (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_ALL) { + if ((Get_event_msg_delay() != 0x0000) && (Get_event_msg_delay() != 0xFFFF)) { + Decrement_event_msg_delay(); + } + } + } + /// Increments Tb_Srp counter if needed + if (Is_srp_sent_and_waiting_answer()) { + otg_tb_srp_cpt++; + } + /// Increments T_vbus_wait_connect if needed + if (Is_srp_received_and_waiting_connect()) { + otg_ta_srp_wait_connect++; + } + /// Decrements Ta_aidl_bdis timer if needed (A_suspend state) + if ((device_state == A_SUSPEND) && (otg_ta_aidl_bdis_tmr > 1)) { + otg_ta_aidl_bdis_tmr--; + } + /// Decrements Timeout_bdev_respond timer if needed + if ((device_state == DEVICE_DEFAULT) && (!Is_timeout_bdev_response_overflow())) { + otg_timeout_bdev_respond--; + } + /// Decrements Ta_vbus_rise timer if needed + if (!Is_ta_vbus_rise_counter_overflow()) { + otg_ta_vbus_rise--; + } + /// Decrements Ta_vbus_fall timer if needed + if (!Is_ta_vbus_fall_counter_overflow()) { + otg_end_hnp_vbus_delay--; + } + + /// Needed for compliance only + if (device_state == A_PERIPHERAL) { + if (Is_sof_interrupt_enabled() && (reset_received == TRUE)) { + if (otg_last_sof_stored != otg_last_sof_received) { + // No SOF is missing + otg_last_sof_received = otg_last_sof_stored; + } + else { + // SOF seems to be missing.. + Usb_freeze_clock(); + Usb_disable_sof_interrupt(); + reset_received = FALSE; + //jcb while (Timer16_get_counter_low() != 20); // overflow set to 62 in usb_task.h + Usb_unfreeze_clock(); + } + otg_last_sof_received = UDFNUML; + otg_last_sof_stored = UDFNUML; + } + } +} + + +//------------------------------------------------------------------------------ +/// OTG Messaging task initialization +/// Initializes variables and screen to prepare next messages to be handled +//------------------------------------------------------------------------------ +void Otg_message_task_init(void) +{ + TRACE_DEBUG("Otg_message_task_init\n\r"); + Otg_messaging_init(); + otg_msg_event_delay = 0; + otg_msg_failure_delay = 0; +} + + +//------------------------------------------------------------------------------ +/// OTG Messaging main task +/// OTG specifies that user must be kept informed of several events +/// This task allows user to display two kinds of messages : EVENT or FAILURE +/// For each new message, it can specify if the message remains displayed all +/// the time or only during a specified delay +//------------------------------------------------------------------------------ +void Otg_message_task(void) +{ + // Check if an OTG message must be erased (if it was set up for a specified delay) + if( (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_ALL) + || (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_FAIL)) { + if (Get_failure_msg_delay() == 0) { + Otg_clear_failure_message(); + } + if( (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_ALL) { + if (Get_event_msg_delay() == 0) { + Otg_clear_event_message(); + } + } + } +} +#endif // #if (USB_OTG_FEATURE == ENABLE) + + +//------------------------------------------------------------------------------ +/// Message "OTG not supported" +//------------------------------------------------------------------------------ +void otg_not_supported_device(void) +{ + TRACE_DEBUG("otg_not_supported_device\n\r"); + Otg_send_event(EVT_OTG_DEV_UNSUPPORTED); +} + + diff --git a/usb/otg/usb_task.h b/usb/otg/usb_task.h new file mode 100644 index 0000000..0ad2529 --- /dev/null +++ b/usb/otg/usb_task.h @@ -0,0 +1,232 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + + +//! @brief This file manages the USB task either device/host or both. +//! +//! The USB task selects the correct USB task (usb_device task or usb_host task +//! to be executed depending on the current mode available. +//! +//! This module also contains the general USB interrupt subroutine. This subroutine is used +//! to detect asynchronous USB events. +//! +//! Note: +//! - The usb_task belongs to the scheduler, the usb_device_task and usb_host do not, they are called +//! from the general usb_task +//! - See conf_usb.h file for more details about the configuration of this module + +#ifndef _USB_TASK_H_ +#define _USB_TASK_H_ + +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +/// Definitions of B-Device states +#define B_IDLE 0 +//#define B_SRP_INIT 1 +#define B_PERIPHERAL 2 +//#define B_WAIT_ACON 3 +#define B_HOST 4 +#define B_END_HNP_SUSPEND 5 + +// OTG B-Device SRP protocole specific states or events + +//! Is the current session a result of a SRP ? +//#define Start_session_with_srp() (otg_device_sessions |= 0x01) +#define End_session_with_srp() (otg_device_sessions &= ~0x01) +#define Is_session_started_with_srp() (((otg_device_sessions&0x01) != 0) ? TRUE : FALSE) + +//! Has a SRP been sent, and waiting for an answer +//#define Srp_sent_and_waiting_answer() (otg_device_sessions |= 0x02) +//#define Ack_srp_sent_and_answer() (otg_device_sessions &= ~0x02) +#define Is_srp_sent_and_waiting_answer() (((otg_device_sessions&0x02) != 0) ? TRUE : FALSE) + +//! Is the Tb_Srp counter enabled ? Cleared by timer if Tb_Srp_Fail elapsed +//! Tb_Srp_Fail must be between 5 and 6 sec. With an interrupt routine executed each 2ms, its value becomes 2500 (used:5.2sec) +// 0x0A28 = 2600, 2600x2 = 5200 => 5s +//#define TB_SRP_FAIL_MIN 0x0A28 +//extern U16 otg_tb_srp_cpt; +//#define Init_tb_srp_counter() (otg_tb_srp_cpt = 0) +//#define Is_tb_srp_counter_overflow() ((otg_tb_srp_cpt > TB_SRP_FAIL_MIN) ? TRUE : FALSE) + +// usb_task USB task entry point module + +//! usb_software_evts USB software Events Management +//! Macros to manage USB events detected under interrupt +#define Usb_send_event(x) g_usb_event |= (1< +#include "main.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "otg_user_task.h" +#include "usb_task.h" +#include "usb/otg/usb_drv.h" +#include "usb/otg/usb_host_task.h" + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + + + +extern volatile unsigned int timer_set_counter; +#define Timer16_select(...) +#define Timer16_set_counter(value) timer_set_counter = value +#define Timer16_get_counter_low() (unsigned char)timer_set_counter + + +/// Returns the OTG features sent by the host by a SetFeature +/// Allow also to clear the features (only on a bus Reset or Session End) +#define Is_host_requested_hnp() (((otg_features_supported&USBFeatureRequest_OTG_B_HNP_ENABLE) != 0) ? TRUE : FALSE) +#define Clear_otg_features_from_host() (otg_features_supported = 0) + +#define Set_otg_custom_timer(ep) // STUB: todo + +#define USB_MODE_UNDEFINED 0x00 +#define USB_MODE_HOST 0x01 +#define USB_MODE_DEVICE 0x02 + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +U8 otg_device_sessions; +U8 b_uut_device_state; +U16 otg_tb_srp_cpt; + +/// usb_connected is used to store USB events detected upon +/// USB general interrupt subroutine +/// Its value is managed by the following macros (See usb_task.h file) +/// Usb_send_event(x) +/// Usb_ack_event(x) +/// Usb_clear_all_event() +/// Is_usb_event(x) +/// Is_not_usb_event(x) +volatile U16 g_usb_event=0; + + +/// +/// Private : (U8) private_sof_counter +/// Incremented by host SOF interrupt subroutime +/// This counter is used to detect timeout in host requests. +/// It must not be modified by the user application tasks. +//// +volatile U8 private_sof_counter=0; +extern volatile S_pipe_int it_pipe_str[MAX_EP_NB]; + +//------------------------------------------------------------------------------ +// Local Variables +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Internal Functions +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes the USB process +/// Depending on the mode supported (HOST/DEVICE/DUAL_ROLE) the function calls +/// the coresponding USB mode initialization function +//------------------------------------------------------------------------------ +void usb_task_init(void) +{ + // ---- REDUCED HOST ONLY USB MODE ----------------------------------------- + //jcbUsb_force_host_mode(); + usb_host_task_init(); +} + + +//------------------------------------------------------------------------------ +/// Entry point of the USB mamnagement +/// Depending on the USB mode supported (HOST/DEVICE/DUAL_ROLE) the function +/// calls the coresponding USB management function +//------------------------------------------------------------------------------ +void usb_task(void) +{ + // ---- REDUCED HOST ONLY USB MODE ----------------------------------------- + usb_host_task(); +} + + + +//------------------------------------------------------------------------------ +/// USB interrupt subroutine +/// +/// This function is called each time a USB interrupt occurs. +/// The following USB DEVICE events are taken in charge: +/// - VBus On / Off +/// - Start Of Frame +/// - Suspend +/// - Wake-Up +/// - Resume +/// - Reset +/// - Start of frame +/// +/// The following USB HOST events are taken in charge: +/// - Device connection +/// - Device Disconnection +/// - Start Of Frame +/// - ID pin change +/// - SOF (or Keep alive in low speed) sent +/// - Wake up on USB line detected +/// +/// The following USB HOST events are taken in charge: +/// - HNP success (Role Exchange) +/// - HNP failure (HNP Error) +/// +/// For each event, the user can launch an action by completing +/// the associate define (See conf_usb.h file to add action upon events) +/// +/// Note: Only interrupts events that are enabled are processed +//------------------------------------------------------------------------------ +void usb_general_interrupt(void) +{ + //TRACE_DEBUG("usb_general_interrupt\n\r"); + U8 i; + U8 save_pipe_nb; + + // ---------- HOST events management ----------------------------------- + // --------------------------------------------------------------------- + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - The device has been disconnected + if(Is_device_disconnection() && Is_host_device_disconnection_interrupt_enabled()) { + TRACE_DEBUG("device disconnect\n\r"); + host_disable_all_pipe(); + Host_ack_device_disconnection(); + device_state=DEVICE_DISCONNECTED; + Usb_send_event(EVT_HOST_DISCONNECTION); + TRACE_INFO("Device disconnected\n\r"); + Host_device_disconnection_action(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - Device connection + if(Is_device_connection() && Is_host_device_connection_interrupt_enabled()) { + TRACE_DEBUG("device connect\n\r"); + Host_ack_device_connection(); + host_disable_all_pipe(); + Host_device_connection_action(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - Host Start of frame has been sent + if (Is_host_sof() && Is_host_sof_interrupt_enabled()) { + //TRACE_DEBUG_WP("_"); // host + Host_ack_sof(); + Usb_send_event(EVT_HOST_SOF); + private_sof_counter++; + + // delay timeout management for interrupt tranfer mode in host mode +#if ((USB_HOST_PIPE_INTERRUPT_TRANSFER==ENABLE) && (TIMEOUT_DELAY_ENABLE==ENABLE)) + if (private_sof_counter>=250) { // Count 1/4 sec + private_sof_counter=0; + for(i=0;iTIMEOUT_DELAY) && (Host_get_pipe_type()!=TYPE_INTERRUPT)) { + it_pipe_str[i].enable=DISABLE; + it_pipe_str[i].status=PIPE_DELAY_TIMEOUT; + Host_stop_pipe_interrupt(i); + if (is_any_interrupt_pipe_active()==FALSE) { // If no more transfer is armed + if (g_sav_int_sof_enable==FALSE) { + Host_disable_sof_interrupt(); + } + } + it_pipe_str[i].handle(PIPE_DELAY_TIMEOUT,it_pipe_str[i].nb_byte_processed); + } + Host_select_pipe(save_pipe_nb); + } + } + } +#endif // (USB_HOST_PIPE_INTERRUPT_TRANSFER==ENABLE) && (TIMEOUT_DELAY_ENABLE==ENABLE)) + Host_sof_action(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - Host Wake-up has been received + if (Is_host_hwup() && Is_host_hwup_interrupt_enabled()) { + TRACE_DEBUG("Host wake up\n\r"); + Host_disable_hwup_interrupt(); // Wake up interrupt should be disable host is now wake up ! + Host_disable_remote_wakeup_interrupt(); + // CAUTION HWUP can be cleared only when USB clock is active (not frozen)! + Usb_unfreeze_clock(); // Enable clock on USB interface + Host_enable_sof(); // start sending SOF + Host_ack_hwup(); // Clear HWUP interrupt flag + Host_ack_remote_wakeup(); + Usb_send_event(EVT_HOST_HWUP); // Send software event + Usb_send_event(EVT_HOST_REMOTE_WAKEUP); + Host_hwup_action(); // Map custom action + Host_send_resume(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // Remote Wake Up has been received + if (Is_host_remote_wakeup_interrupt_enabled() && Is_host_remote_wakeup()) { + TRACE_DEBUG("Remote wake up\n\r"); + Host_disable_remote_wakeup_interrupt(); + Host_disable_hwup_interrupt(); + Host_ack_remote_wakeup(); + Host_ack_hwup(); // Clear HWUP interrupt flag + Usb_unfreeze_clock(); // Enable clock on USB interface + Host_enable_sof(); // start sending SOF + Usb_send_event(EVT_HOST_REMOTE_WAKEUP); + Usb_send_event(EVT_HOST_HWUP); // Send software event + Host_send_resume(); + } +} + +//------------------------------------------------------------------------------ +/// Message "OTG not supported" +//------------------------------------------------------------------------------ +void otg_not_supported_device(void) +{ + TRACE_DEBUG("otg_not_supported_device\n\r"); + Otg_send_event(EVT_OTG_DEV_UNSUPPORTED); +} + + diff --git a/usb/otg/usb_task_with_SRP_HNP.c b/usb/otg/usb_task_with_SRP_HNP.c new file mode 100644 index 0000000..e5204de --- /dev/null +++ b/usb/otg/usb_task_with_SRP_HNP.c @@ -0,0 +1,852 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + + + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include "main.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "otg_user_task.h" +#include "usb_task.h" +#include "usb/otg/usb_drv.h" +#include "usb/otg/usb_host_task.h" + +#include +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + + + +extern volatile unsigned int timer_set_counter; +#define Timer16_select(...) +#define Timer16_set_counter(value) timer_set_counter = value +#define Timer16_get_counter_low() (unsigned char)timer_set_counter + + +/// Returns the OTG features sent by the host by a SetFeature +/// Allow also to clear the features (only on a bus Reset or Session End) +#define Is_host_requested_hnp() (((otg_features_supported&USBFeatureRequest_OTG_B_HNP_ENABLE) != 0) ? TRUE : FALSE) +#define Clear_otg_features_from_host() (otg_features_supported = 0) + +#define Set_otg_custom_timer(ep) // STUB: todo + +#define USB_MODE_UNDEFINED 0x00 +#define USB_MODE_HOST 0x01 +#define USB_MODE_DEVICE 0x02 + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +U8 otg_device_sessions; +U8 b_uut_device_state; +U16 otg_tb_srp_cpt; + +/// usb_connected is used to store USB events detected upon +/// USB general interrupt subroutine +/// Its value is managed by the following macros (See usb_task.h file) +/// Usb_send_event(x) +/// Usb_ack_event(x) +/// Usb_clear_all_event() +/// Is_usb_event(x) +/// Is_not_usb_event(x) +volatile U16 g_usb_event=0; + +/// +/// Public : (bit) usb_connected +/// usb_connected is set to TRUE when VBUS has been detected +/// usb_connected is set to FALSE otherwise +bit usb_connected; + +/// +/// Public : (U8) usb_configuration_nb +/// Store the number of the USB configuration used by the USB device +/// when its value is different from zero, it means the device mode is enumerated +U8 usb_configuration_nb; + +/// +/// Public : (U8) remote_wakeup_feature +/// Store a host request for remote wake up (set feature received) +//// +U8 remote_wakeup_feature; + +/// +/// Private : (U8) private_sof_counter +/// Incremented by host SOF interrupt subroutime +/// This counter is used to detect timeout in host requests. +/// It must not be modified by the user application tasks. +//// +volatile U8 private_sof_counter=0; + +extern volatile S_pipe_int it_pipe_str[MAX_EP_NB]; + + +/// +/// Public : (U8) g_usb_mode +/// Used in dual role application (both device/host) to store +/// the current mode the usb controller is operating +//// +U8 g_usb_mode=USB_MODE_UNDEFINED; +U8 g_old_usb_mode; + + +/// +/// Public : (U8) otg_features_supported; +/// -> A-Device side : indicates if the B-Device supports HNP and SRP (this is the bmAttributes field of OTG Decriptor) +/// -> B-Device side : indicates if the A-Device has enabled the "a_hnp_support" and "b_hnp_enable" features +volatile U8 otg_features_supported; + +/// Public : (U8) otg_user_request; +/// Store the last request of the user (see usb_device_task.h) +U8 otg_user_request; + +/// Public : (U16) otg_msg_event_delay; +/// Contains the current display duration of the OTG event message +U16 otg_msg_event_delay; + +/// Public : (U16) otg_msg_failure_delay; +/// Contains the current display duration of the OTG failure message +U16 otg_msg_failure_delay; + +/// Public : (U16) g_otg_event; +/// Contains several bits corresponding to differents OTG events (similar to g_usb_event) +volatile U16 g_otg_event; + +/// Public : (U8) otg_device_nb_hnp_retry; +/// Counts the number of times a HNP fails, before aborting the operations +U8 otg_device_nb_hnp_retry; + +U8 id_changed_to_host_event; + +volatile U8 otg_last_sof_received; // last SOF received in SOF interrupt +volatile U8 otg_last_sof_stored; // last SOF value stored in OTG Timer interrupt +volatile U8 reset_received; // indicates if a reset has been received from B-Host after a HNP (used in A-Periph mode) + +/// @brief VBUS Overload management +/// +/// Nothing to do ! If the condition is not defined in the board driver file +/// (i.e. if the board does not support Vbus overcurrent detection), +/// the macro is defined to false for firmware compatibility +#define Is_vbus_overcurrent() (FALSE) + +/// Private function prototypes +/// Tasks for OTG Messaging features +void Otg_message_task_init(void); +void Otg_message_task(void); + + +//------------------------------------------------------------------------------ +// Local Variables +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Internal Functions +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes the USB process +/// Depending on the mode supported (HOST/DEVICE/DUAL_ROLE) the function calls +/// the coresponding USB mode initialization function +//------------------------------------------------------------------------------ +void usb_task_init(void) +{ + // DUAL ROLE DEVICE USB MODE + Otg_message_task_init(); // OTG program needs to display event messages to the user + b_uut_device_state = B_IDLE; // init state machines variables + device_state = DEVICE_UNATTACHED; + otg_device_nb_hnp_retry = BDEV_HNP_NB_RETRY; + Clear_all_user_request(); + Usb_enable_uid_pin(); + + g_usb_mode=USB_MODE_UNDEFINED; + + if(Is_usb_id_device()) { + g_usb_mode=USB_MODE_DEVICE; +#ifdef MSD_PROJECT + MSDDriver_Initialize(luns, numMedias); +#else + // HID + HIDDMouseDriver_Initialize(); +#endif + id_changed_to_host_event = DISABLE; + } + else { + Usb_send_event(EVT_USB_HOST_FUNCTION); + g_usb_mode=USB_MODE_HOST; + // Startup with ID=0, Ack ID pin transistion (default hwd start up is device mode) + Usb_ack_id_transition(); + Usb_enable_id_interrupt(); + usb_host_task_init(); + id_changed_to_host_event = ENABLE; + } + // Store current usb mode, for mode change detection + g_old_usb_mode = g_usb_mode; +} + + +//------------------------------------------------------------------------------ +/// Entry point of the USB mamnagement +/// Depending on the USB mode supported (HOST/DEVICE/DUAL_ROLE) the function +/// calls the coresponding USB management function +//------------------------------------------------------------------------------ +void usb_task(void) +{ + // DUAL ROLE DEVICE USB MODE + if(Is_usb_id_device()) { + g_usb_mode = USB_MODE_DEVICE; + } + else { + g_usb_mode = USB_MODE_HOST; + } + g_old_usb_mode = g_usb_mode; // Store current usb mode, for mode change detection + // Depending on current usb mode, launch the correct usb task (device or host) + + // Configure OTG timers + Set_otg_custom_timer(VBUSRISE_70MS); + Set_otg_custom_timer(VBUSPULSE_40MS); + Set_otg_custom_timer(VFALLTMOUT_131MS); + Set_otg_custom_timer(SRPMINDET_100US); + + switch(g_usb_mode) { + case USB_MODE_DEVICE: + //usb_device_task(); + //MSDDriver_StateMachine(); + Scheduler_task_3(); + break; + + case USB_MODE_HOST: + if( pOTGDescriptor->bOTGADevSRPReaction == VBUS_PULSE) { + Usb_select_vbus_srp_method(); + } + else { + Usb_select_data_srp_method(); + } + usb_host_task(); + // Handle Vbus overcurrent error (auto-disabled if not supported or not defined in board driver file) + if (Is_vbus_overcurrent()) { + Otg_print_new_event_message(OTGMSG_VBUS_SURCHARGE,OTG_TEMPO_3SEC); + } + break; + + case USB_MODE_UNDEFINED: // No break ! + default: + break; + } + Otg_message_task(); +} + + + +//------------------------------------------------------------------------------ +/// USB interrupt subroutine +/// +/// This function is called each time a USB interrupt occurs. +/// The following USB DEVICE events are taken in charge: +/// - VBus On / Off +/// - Start Of Frame +/// - Suspend +/// - Wake-Up +/// - Resume +/// - Reset +/// - Start of frame +/// +/// The following USB HOST events are taken in charge: +/// - Device connection +/// - Device Disconnection +/// - Start Of Frame +/// - ID pin change +/// - SOF (or Keep alive in low speed) sent +/// - Wake up on USB line detected +/// +/// The following USB HOST events are taken in charge: +/// - HNP success (Role Exchange) +/// - HNP failure (HNP Error) +/// +/// For each event, the user can launch an action by completing +/// the associate define (See conf_usb.h file to add action upon events) +/// +/// Note: Only interrupts events that are enabled are processed +//------------------------------------------------------------------------------ +void usb_general_interrupt(void) +{ + //TRACE_DEBUG("usb_general_interrupt\n\r"); + + // ---------- DEVICE events management ----------------------------------- + // ----------------------------------------------------------------------- + + //- VBUS state detection + // ----------------------------------------------------------------------- + /// Arbitrer + // ----------------------------------------------------------------------- + if (Is_usb_vbus_transition() && Is_usb_vbus_interrupt_enabled() + && Is_usb_id_device()) { + Usb_ack_vbus_transition(); + + if (Is_usb_vbus_high()) { + usb_connected = TRUE; + Usb_vbus_on_action(); + Usb_send_event(EVT_USB_POWERED); + //jcb Usb_enable_reset_interrupt(); + //usb_start_device(); + USBD_Connect();//Usb_attach(); + } + else { + TRACE_DEBUG("VBUS low\n\r"); + USBD_Disconnect(); + Usb_device_stop_hnp(); + TRACE_DEBUG("Usb_select_device4\n\r"); + Usb_select_device(); + Clear_all_user_request(); + Usb_vbus_off_action(); + usb_connected = FALSE; + usb_configuration_nb = 0; + Usb_send_event(EVT_USB_UNPOWERED); + } + + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - Device start of frame received + if (Is_usb_sof() && Is_sof_interrupt_enabled()) { + // TRACE_DEBUG_WP("F"); // device + Usb_ack_sof(); + Usb_sof_action(); + //sof_seen_in_session = TRUE; + otg_last_sof_received = UDFNUML; // store last frame number received + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - Device Suspend event (no more USB activity detected) + if (Is_usb_suspend()) { //&& Is_suspend_interrupt_enabled()) { + //TRACE_DEBUG_WP("D\n\r"); + // 1st : B-PERIPH mode ? + if (Is_usb_id_device()) { + // HNP Handler + TRACE_DEBUG("HNP Handler\n\r"); + //TRACE_DEBUG("device_state = %d\n\r", device_state); + //TRACE_DEBUG("b_uut_device_state = %d\n\r", b_uut_device_state); + if (Is_host_requested_hnp() // "b_hnp_enable" feature received + && (Is_session_started_with_srp() || Is_user_requested_hnp() )) { + if (otg_device_nb_hnp_retry == 0) { + otg_features_supported &= ~USBFeatureRequest_OTG_B_HNP_ENABLE; + } + else { + Ack_user_request_hnp(); + Usb_ack_hnp_error_interrupt(); + Usb_ack_role_exchange_interrupt(); + Usb_enable_role_exchange_interrupt(); + Usb_enable_hnp_error_interrupt(); + Usb_device_initiate_hnp(); + otg_device_nb_hnp_retry--; + } + } + else + { + // Remote wake-up handler + //TRACE_DEBUG("Remote wake-up handler\n\r"); + //TRACE_DEBUG("device_state = %d\n\r", device_state); + //TRACE_DEBUG("b_uut_device_state = %d\n\r", b_uut_device_state); + if ((remote_wakeup_feature == ENABLE) && (usb_configuration_nb != 0)) + { + //TRACE_DEBUG("enabled\n\r"); + // After that user can execute "Usb_initiate_remote_wake_up()" to initiate a remote wake-up + // Note that the suspend interrupt flag SUSPI must still be set to enable upstream resume + // So the SUSPE enable bit must be cleared to avoid redundant interrupt + // **************** + // Please note also that is Vbus is lost during an upstream resume (Host disconnection), + // the RMWKUP bit (used to initiate remote wake up and that is normally cleared by hardware when sent) + // remains set after the event, so that a good way to handle this feature is : + // Usb_initiate_remote_wake_up(); + // while (Is_usb_pending_remote_wake_up()) + // { + // if (Is_usb_vbus_low()) + // { + // // Emergency action (reset macro, etc.) if Vbus lost during resuming + // break; + // } + // } + // Usb_ack_remote_wake_up_start(); + // **************** + } + else { + //TRACE_DEBUG("disabled: %d %d\n\r", usb_configuration_nb, remote_wakeup_feature); + // No remote wake-up supported + Usb_send_event(EVT_USB_SUSPEND); + } + } + } + else + { + //TRACE_DEBUG("ici\n\r"); + // A-PERIPH mode (will cause a session end, handled in usb_host_task.c) + Usb_send_event(EVT_USB_SUSPEND); + Usb_suspend_action(); + //jcb Usb_ack_suspend(); + } + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - Wake up event (USB activity detected): Used to resume + if (Is_usb_wake_up() && Is_swake_up_interrupt_enabled()) { + TRACE_DEBUG("W\n\r"); + Usb_unfreeze_clock(); + Usb_send_event(EVT_USB_WAKE_UP); + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - Resume state bus detection + if (Is_usb_resume() && Is_resume_interrupt_enabled()) { + TRACE_DEBUG("Resume state bus detect\n\r"); + Usb_send_event(EVT_USB_RESUME); + } + + // ----------------------------------------------------------------------- + /// Device + // ----------------------------------------------------------------------- + // - USB bus reset detection + if (Is_usb_reset()&& Is_reset_interrupt_enabled()) { + TRACE_DEBUG_WP("B\n\r"); + if (Is_usb_id_host()) { + //TRACE_DEBUG_WP("id_host\n\r"); + dev_configure_endpoint(EP_CONTROL, + TYPE_CONTROL, + DIRECTION_OUT, + SIZE_64, + ONE_BANK, + NYET_DISABLED); + } + // First initialization is important to be synchronized + // A reset must first have been received + if (device_state == A_PERIPHERAL) { + //TRACE_DEBUG_WP("r A_PERIPHERAL\n\r"); + otg_last_sof_received = UDFNUML; + otg_last_sof_stored = UDFNUML; + Usb_ack_sof(); + Usb_enable_sof_interrupt(); + reset_received = TRUE; + Timer16_set_counter(0); + } + Usb_reset_action(); + Usb_send_event(EVT_USB_RESET); + } + + // ---------- OTG events management ------------------------------------ + // --------------------------------------------------------------------- + + // ----------------------------------------------------------------------- + /// Arbitrer + // ----------------------------------------------------------------------- + // - OTG HNP Success detection + if (Is_usb_role_exchange_interrupt() && Is_role_exchange_interrupt_enabled()) { + // TRACE_DEBUG("OTG HNP detect\n\r"); + Usb_ack_role_exchange_interrupt(); + Host_ack_device_connection(); + Host_ack_device_disconnection(); + Otg_send_event(EVT_OTG_HNP_SUCCESS); + End_session_with_srp(); + Clear_otg_features_from_host(); + if (Is_usb_id_host()) { + // HOST (A- or B-) mode + if ((device_state != A_PERIPHERAL) && (device_state != A_END_HNP_WAIT_VFALL)) { + static volatile unsigned int jcb; + // Current mode is A-HOST, device will take the A-PERIPHERAL role + b_uut_device_state = B_PERIPHERAL; + device_state = A_PERIPHERAL; + usb_connected = FALSE; + usb_configuration_nb = 0; + Usb_select_device(); + USBD_Connect();//Usb_attach(); + Usb_unfreeze_clock(); + Usb_disable_role_exchange_interrupt(); + Usb_disable_hnp_error_interrupt(); + Usb_device_stop_hnp(); + Usb_ack_reset(); + Timer16_set_counter(0); + Usb_freeze_clock(); // USB clock can be freezed to slow down events and condition detection + //jcb while (Timer16_get_counter_low() != 20); + jcb=0; + while( jcb <100000){ jcb++; } + + Usb_unfreeze_clock(); + reset_received = FALSE; + Usb_disable_sof_interrupt(); // will be set in the next OTG Timer IT (mandatory) + + Usb_enable_suspend_interrupt(); + Usb_enable_reset_interrupt(); + dev_configure_endpoint(EP_CONTROL, + TYPE_CONTROL, + DIRECTION_OUT, + SIZE_64, + ONE_BANK, + NYET_DISABLED); + } + } + else { + // In B_HOST mode, the HNPREQ bit must not be cleared because it releases the bus in suspend mode (and sof can't start) + if ((b_uut_device_state != B_HOST) && (b_uut_device_state != B_END_HNP_SUSPEND)) { + static volatile unsigned int jcb2; + // Current mode is B-PERIPHERAL, device will go into B-HOST role + End_session_with_srp(); + Clear_otg_features_from_host(); + b_uut_device_state = B_HOST; + device_state = DEVICE_ATTACHED; + usb_connected = FALSE; + usb_configuration_nb = 0; + TRACE_DEBUG("Select host 3\n\r"); + Usb_select_host(); + + TRACE_DEBUG("Send reset\n\r"); + Host_send_reset(); // send the first RESET + while (Host_is_reset()); + TRACE_DEBUG("Reset passed\n\r"); + + jcb2=0; + while( jcb2 <1000000){ jcb2++; } + Host_enable_sof(); // start Host (sof) + Usb_disable_role_exchange_interrupt(); + Usb_disable_hnp_error_interrupt(); + Clear_all_user_request(); + + TRACE_DEBUG("Select host 3\n\r"); + } + } + } + + // ----------------------------------------------------------------------- + /// Arbitrer + // ----------------------------------------------------------------------- + // - OTG HNP Failure detection + if (Is_usb_hnp() && Is_usb_hnp_error_interrupt()&& Is_hnp_error_interrupt_enabled()) { + TRACE_DEBUG("OTG HNP failure\n\r"); + Usb_device_stop_hnp(); + Usb_disable_role_exchange_interrupt(); + Usb_disable_hnp_error_interrupt(); + Usb_ack_hnp_error_interrupt(); + if (Is_usb_id_device()) { + Otg_send_event(EVT_OTG_HNP_ERROR); + Clear_all_user_request(); + } + } + + // ---------- HOST events management ----------------------------------- + // --------------------------------------------------------------------- + + // ----------------------------------------------------------------------- + /// Arbitrer + // ----------------------------------------------------------------------- + // - ID pin change detection + if(Is_usb_id_transition()&&Is_usb_id_interrupt_enabled()) { + TRACE_DEBUG("ID pin change\n\r"); + TRACE_DEBUG("device_state = %d\n\r", device_state); + TRACE_DEBUG("b_uut_device_state = %d\n\r", b_uut_device_state); + Usb_device_stop_hnp(); + Clear_all_user_request(); + if(Is_usb_id_device()) { + g_usb_mode = USB_MODE_DEVICE; + } + else { + g_usb_mode = USB_MODE_HOST; + } + Usb_ack_id_transition(); + if( g_usb_mode != g_old_usb_mode) { // Basic Debounce + if(Is_usb_id_device()) { // Going into device mode + Usb_send_event(EVT_USB_DEVICE_FUNCTION); + b_uut_device_state = B_IDLE; + device_state = DEVICE_UNATTACHED; + id_changed_to_host_event = DISABLE; + } + else { // Going into host mode + b_uut_device_state = B_IDLE; + device_state = DEVICE_UNATTACHED; + Usb_send_event(EVT_USB_HOST_FUNCTION); + id_changed_to_host_event = ENABLE; + } + Usb_id_transition_action(); + TRACE_INFO("Pin Id changed\n\r"); + } + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - The device has been disconnected + // JCB to be fix + if(Is_device_disconnection() && Is_host_device_disconnection_interrupt_enabled()) { + TRACE_DEBUG("device disconnect\n\r"); + host_disable_all_pipe(); + Host_ack_device_disconnection(); + device_state=DEVICE_DISCONNECTED; + Usb_send_event(EVT_HOST_DISCONNECTION); + TRACE_INFO("Device disconnected\n\r"); + Host_device_disconnection_action(); + Clear_all_user_request(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - Device connection + if(Is_device_connection() && Is_host_device_connection_interrupt_enabled()) { + TRACE_DEBUG("device connect\n\r"); + Host_ack_device_connection(); + host_disable_all_pipe(); + Host_device_connection_action(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - Host Start of frame has been sent + if (Is_host_sof() && Is_host_sof_interrupt_enabled()) { + //TRACE_DEBUG_WP("_"); // host + Host_ack_sof(); + Usb_send_event(EVT_HOST_SOF); + private_sof_counter++; + + // delay timeout management for interrupt tranfer mode in host mode +#if ((USB_HOST_PIPE_INTERRUPT_TRANSFER==ENABLE) && (TIMEOUT_DELAY_ENABLE==ENABLE)) + if (private_sof_counter>=250) { // Count 1/4 sec + private_sof_counter=0; + for(i=0;iTIMEOUT_DELAY) && (Host_get_pipe_type()!=TYPE_INTERRUPT)) { + it_pipe_str[i].enable=DISABLE; + it_pipe_str[i].status=PIPE_DELAY_TIMEOUT; + Host_stop_pipe_interrupt(i); + if (is_any_interrupt_pipe_active()==FALSE) { // If no more transfer is armed + if (g_sav_int_sof_enable==FALSE) { + Host_disable_sof_interrupt(); + } + } + it_pipe_str[i].handle(PIPE_DELAY_TIMEOUT,it_pipe_str[i].nb_byte_processed); + } + Host_select_pipe(save_pipe_nb); + } + } + } +#endif // (USB_HOST_PIPE_INTERRUPT_TRANSFER==ENABLE) && (TIMEOUT_DELAY_ENABLE==ENABLE)) + Host_sof_action(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // - Host Wake-up has been received + if (Is_host_hwup() && Is_host_hwup_interrupt_enabled()) { + TRACE_DEBUG("Host wake up\n\r"); + Host_disable_hwup_interrupt(); // Wake up interrupt should be disable host is now wake up ! + Host_disable_remote_wakeup_interrupt(); + // CAUTION HWUP can be cleared only when USB clock is active (not frozen)! + Usb_unfreeze_clock(); // Enable clock on USB interface + Host_enable_sof(); // start sending SOF + Host_ack_hwup(); // Clear HWUP interrupt flag + Host_ack_remote_wakeup(); + Usb_send_event(EVT_HOST_HWUP); // Send software event + Usb_send_event(EVT_HOST_REMOTE_WAKEUP); + Host_hwup_action(); // Map custom action + if (Is_usb_hnp()) { + Usb_host_reject_hnp(); + Usb_disable_hnp_error_interrupt(); + Usb_disable_role_exchange_interrupt(); + } + Host_send_resume(); + } + + // ----------------------------------------------------------------------- + /// Host + // ----------------------------------------------------------------------- + // Remote Wake Up has been received + if (Is_host_remote_wakeup_interrupt_enabled() && Is_host_remote_wakeup()) { + TRACE_DEBUG("Remote wake up\n\r"); + Host_disable_remote_wakeup_interrupt(); + Host_disable_hwup_interrupt(); + Host_ack_remote_wakeup(); + Host_ack_hwup(); // Clear HWUP interrupt flag + Usb_unfreeze_clock(); // Enable clock on USB interface + Host_enable_sof(); // start sending SOF + Usb_send_event(EVT_HOST_REMOTE_WAKEUP); + Usb_send_event(EVT_HOST_HWUP); // Send software event + if (Is_usb_hnp()) { + Usb_host_reject_hnp(); + Usb_disable_hnp_error_interrupt(); + Usb_disable_role_exchange_interrupt(); + } + Host_send_resume(); + } +} + + +//------------------------------------------------------------------------------ +/// OTG TIMER interrupt subroutine +/// This function is called each time a OTG Timer interrupt occurs +/// Function decrements the variables required by OTG program +void otg_timer_interrupt(void) +{ + /// OTG Messaging timer + if( (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_ALL) + || (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_FAIL)) { + if ((Get_failure_msg_delay() != 0x0000) && (Get_failure_msg_delay() != 0xFFFF)) { + Decrement_failure_msg_delay(); + } + if(pOTGDescriptor->bOTGMessagingOutput == OTGMSG_ALL) { + if ((Get_event_msg_delay() != 0x0000) && (Get_event_msg_delay() != 0xFFFF)) { + Decrement_event_msg_delay(); + } + } + } + /// Increments Tb_Srp counter if needed + if (Is_srp_sent_and_waiting_answer()) { + otg_tb_srp_cpt++; + } + /// Increments T_vbus_wait_connect if needed + if (Is_srp_received_and_waiting_connect()) { + otg_ta_srp_wait_connect++; + } + /// Decrements Ta_aidl_bdis timer if needed (A_suspend state) + if ((device_state == A_SUSPEND) && (otg_ta_aidl_bdis_tmr > 1)) { + otg_ta_aidl_bdis_tmr--; + } + /// Decrements Timeout_bdev_respond timer if needed + if ((device_state == DEVICE_DEFAULT) && (!Is_timeout_bdev_response_overflow())) { + otg_timeout_bdev_respond--; + } + /// Decrements Ta_vbus_rise timer if needed + if (!Is_ta_vbus_rise_counter_overflow()) { + otg_ta_vbus_rise--; + } + /// Decrements Ta_vbus_fall timer if needed + if (!Is_ta_vbus_fall_counter_overflow()) { + otg_end_hnp_vbus_delay--; + } + + /// Needed for compliance only + if (device_state == A_PERIPHERAL) { + if (Is_sof_interrupt_enabled() && (reset_received == TRUE)) { + if (otg_last_sof_stored != otg_last_sof_received) { + // No SOF is missing + otg_last_sof_received = otg_last_sof_stored; + } + else { + // SOF seems to be missing.. + Usb_freeze_clock(); + Usb_disable_sof_interrupt(); + reset_received = FALSE; + //jcb while (Timer16_get_counter_low() != 20); // overflow set to 62 in usb_task.h + Usb_unfreeze_clock(); + } + otg_last_sof_received = UDFNUML; + otg_last_sof_stored = UDFNUML; + } + } +} + + +//------------------------------------------------------------------------------ +/// OTG Messaging task initialization +/// Initializes variables and screen to prepare next messages to be handled +//------------------------------------------------------------------------------ +void Otg_message_task_init(void) +{ + TRACE_DEBUG("Otg_message_task_init\n\r"); + Otg_messaging_init(); + otg_msg_event_delay = 0; + otg_msg_failure_delay = 0; +} + + +//------------------------------------------------------------------------------ +/// OTG Messaging main task +/// OTG specifies that user must be kept informed of several events +/// This task allows user to display two kinds of messages : EVENT or FAILURE +/// For each new message, it can specify if the message remains displayed all +/// the time or only during a specified delay +//------------------------------------------------------------------------------ +void Otg_message_task(void) +{ + // Check if an OTG message must be erased (if it was set up for a specified delay) + if( (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_ALL) + || (pOTGDescriptor->bOTGMessagingOutput == OTGMSG_FAIL)) { + if (Get_failure_msg_delay() == 0) { + Otg_clear_failure_message(); + } + if(pOTGDescriptor->bOTGMessagingOutput == OTGMSG_ALL) { + if (Get_event_msg_delay() == 0) { + Otg_clear_event_message(); + } + } + } +} + + +//------------------------------------------------------------------------------ +/// Message "OTG not supported" +//------------------------------------------------------------------------------ +void otg_not_supported_device(void) +{ + TRACE_DEBUG("otg_not_supported_device\n\r"); + Otg_send_event(EVT_OTG_DEV_UNSUPPORTED); +} + + diff --git a/usb/usb.dir b/usb/usb.dir new file mode 100644 index 0000000..bd207b1 --- /dev/null +++ b/usb/usb.dir @@ -0,0 +1,532 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// !!!Purpose +/// +/// This directory provides a library of highly re-usable code to build +/// USB applications with Atmel AT91 microcontrollers. +/// +/// !!!Contents +/// The directory can basically be divided into three sections for their usage: +/// - common: %common USB definitions and routines, including standard USB +/// spec. and the following classes: audio, cdc, hid, massstorage; +/// - device: re-usable & portable software USB %device modules, including +/// general UDP driver for AT91 microcontroller and the following +/// devices: audio-speaker, ccid, cdc-serial, hid-keyboard, +/// massstorage; +/// - host: re-usable & portable software USB host modules +/// +/// !!!AT91 USB device framework +/// "AT91 USB device framework" is architectured as following: +/// - #Hardware layer#: low-level operations on the USB UDP controller +/// - device/core, suffixed with UDP, UDPHS, OTGHS +/// - #USB %device API#: offers hardware-independent methods and structures +/// - device/core, other files: driver, events and callbacks +/// - common/core: general USB descriptors and requests +/// - common/, other directories: general USB class descriptors and requests +/// - #Applicatioin layer#: the USB class driver and user/demo applicaiton +/// - device/, other directories, named with the class driver function +/// - project directory, with main.c +/// +/// "USB Device Framework Architecture" +/// \image USBFrameworkArchitecture.png "USB Framework Architecture" +/// +/// --- +/// +/// For more information about what a particular group contains, please refer to +/// its documentation page. +/// +/// \note +/// Depending on the project, not all the subdirectories will be available +/// (i.e. the #host# directory will not be in projects without USB host). +//------------------------------------------------------------------------------ + +/** + \page "AT91 USB device framework" + + AT91 USB %device framework is a device-side USB framework. It enables rapid + development of USB-compliant class drivers such as the Mass Storage Device + (MSD) or the Communication Device Class (CDC) and etc. + + This page shows the index to describe the AT91 USB %device framework. + - USBD: USB Device + + -# "USB Device Framework Architecture" + -# "USB Device Framework Description" + -# "Standard USB Structures" + -# "USBD API" + -# "USBD Callback API" + -# "USBD Standard Request Handler" + -# "USB Device Framework Usage" + -# "USBD File Architecture" + -# "USBD Headers" + -# "Building the Framework" + -# "USB Device Enumeration" + +*/ + +/** + \page "USB Device Framework Architecture" + + !!!Framework Architecture + + The following three-tiered structure is used: + - A #hardware layer# which performs low-level operations on the USB controller. + - The #USB API# offers hardware-independent methods and structures. + - The #application layer#, made up of a USB class driver and the user + application. + + The framework includes the USBD API and the hardware layer as well as a standard + request handler. The application layer is build on top of that to provide the + %device functionalty. + + There are also callbacks automatically called by the USBD API to perform + specific operations, to perform communication between the USBD API and the + application layer. + + \image USBFrameworkArchitecture.png "USB Framework Architecture" + +*/ + +/* (Image Link Backup) +USBFrameworkArchitecture.png + + + + + + + + +*/ + +/** + \page "USB Device Framework Description" + + !!!Framework Discription + + The framework is comprised of serveral components: + -# "Standard USB Structures" + -# "USBD API" + - Structures + - Methods + -# "USBD Callback API" + -# "USBD Standard Request Handler" +*/ + +/** + \page "USB Device Framework Usage" + + !!!File Architecture + + The USB framework is made up of the following files: + at91lib\\boards: %device register definition, board-related code and + %device startup code in assembly language\n + at91lib\\utility: debug methods and definitions\n + at91lib\\peripherals\\dbgu: DBGU port usage for debug\n + at91lib\\peripherals\\pio: PIO interface usage for Vbus ...\n + at91lib\\peripherals\\aic: Interrupt configurationi functions\n + at91lib\\usb\\common\\core: structures and methods of standard descriptors + and requests\n + at91lib\\usb\\device\\core: UDP controller driver methods and USBD API + definitions\n + usb-device-core-project: basic enumeration program, with main.c and + Makefile to build the project\n + + !!!Headers + + When programming your own application, most if not all the headers described + in the file architecture of the framework must be included. However, since + each header has its own dependencies, they must be included in a particular + order. + + Here is the standard inclusion order: +\code +#include +#include +#include +#include +#include +#include +#include +#include +#include +\endcode + If a custom class driver has been added, then its header must probably be + linked last. + + !!!Building the Framework + + A Makefile is provided to make it easier to compile the framework. The }make} + program and arm-elf-gcc is necessary to use it. + + Several options are available to build the framework in different ways: + - CHIP + - Target chip for which to build the program. + - Possible values: at91sam7s64, at91sam7s128, at91sam7s256, at91sam7s512, + at91sam7s321, at91sam7se32, at91sam7se256, at91sam7se512, at91sam7x128, + at91sam7x256, at91sam7s512, at91sam7xc128, at91sam7xc256, at91sam7xc512, + at91sam9260, at91sam9261, at91sam9263 + - Default: at91sam7s256 + - BOARD + - Board used with the chip. + - Possible values: at91sam7s-ek, at91sam7se-ek, at91sam7x-ek, + at91sam7xc-ek, at91sam7a3-ek, at91sam9260-ek, at91sam9261-ek, + at91sam9263-ek + - Default: at91sam7s-ek + +*/ + +/** + \page "USB Device Enumeration" + + This page is a step-by-step guide on how to use the USB Device framework + to produce a simple program that performs USB enumeration. In this example, + everything is put into a single file. You can look at the main.c file provided + with the framework to view the end result. + + !!!Including the Necessary Headers + + Prior to using the framework, several header files have to be included. Please + refer to "USB Device Framework Usage" for more information. + + !!!Declaring Global Varibles + + Several object instances are necessary to use the various functions and methods + of the USB framework. As following. + + !!USBD Driver + The very first step is declare the USB driver which is then used by the Class + driver. The USBDDriver structure is used as a container for several variables, + which must therefore be created first. + + !Endpoints + Depending on the application, a particular number of endpoints have to be + defined. For example, an MSD driver needs three endpoints whereas a CDC driver + needs four. Refer to the corresponding specification for more information + about the required number of endpoints. Since this example should only perform + the USB enumeration, it will declare only one endpoint: Control endpoint 0. + + Endpoints is configrued by USBEndpointDescriptor in USBDDriverDescriptors for + the driver. The FIFO banks is automatically set to its maximum value. + + !Callbacks + To replace the default callback, you should remove the default callback file + from makefile and add your own function defintion. + +||callback function file||callback function +|USBDCallbacks_Initialized.o|USBDCallbacks_Initialized +|USBDCallbacks_Reset.o|USBDCallbacks_Reset +|USBDCallbacks_Suspended.o|USBDCallbacks_Suspended +|USBDCallbacks_Resumed.o|USBDCallbacks_Resumed +|- #MUST# be defined|USBDCallbacks_RequestReceived + + !Driver + Depending on the chip used, there may or may not be a need to declare a low- + level driver variable. + + The default driver global variable is simply called usbdDriver, and will + sufficient for this example. + \code +USBDDriver usbdDriver; + \endcode + + !!Descriptors + The USB specification 2.0 defines a set of descriptors used to give + information about the %device. Depending on the USB class implemented, + different descriptors have to be used with varying values. + + In this example program, only a few descriptors are required,. The %device + descriptor is always mandatory, so it will have to be defined. At least one + configuration descriptor is required, so one is implemented. The described + configuration must have at least one interface, so one more descriptor is + needed. Finally, no string descriptors are used: + + !Device Descriptor + The device descriptor used by this example looks like this: + \code +/// Device descriptor. +const USBDeviceDescriptor usbDeviceDescriptor = { + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + 0, // No device class code + 0, // No device subclass code + 0, // No device protocol code + BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0), + 0x03EB, // Atmel vendor ID + 0x0001, // Product ID + 0x0001, // Product release 0.01 + 0, // No manufacturer string descriptor + 0, // No product string descriptor + 0, // No serial number string descriptor + 1 // One possible configuration +}; + \endcode + The values are nothing special here. Note that the first three fields have the + same data in them (unless using USB 1.1). It is also very common to define the + class, subclass and protocol values at the interface level. + + - Note: The }vendor ID} value is provided by the USB-IF organization. The + }product ID} is vendor-specific and can be assigned any value. + + !Configuration & Interface + When the configuration descriptor is requested by the host, via the + GET_DESCRIPTOR command, the device must not only transmit this descriptor but + also all the necessary interface and endpoint descriptors. + + In order to do that easily, a structure must be defined for holding all the + information. This way, the data to send is contiguous, making the request + much simpler to fulfill. In the current example, the configuration descriptor + must be followed by the first interface descriptor. The following structure is + declared for that: + \code +// Configuration descriptors with one interface. +struct SimpleConfigurationDescriptors { + + USBConfigurationDescriptor configuration; + USBInterfaceDescriptor interface; +}; + \endcode + Now, the actual descriptors can be declared: + \code +// Configuration descriptors. +const struct SimpleConfigurationDescriptors configurationDescriptors = { + + // Configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(struct SimpleConfigurationDescriptors), + 0, // No interface in this configuration + 1, // This is configuration #1 + 0, // No string descriptor for this configuration + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + // Interface descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0 + 0, // This is setting #0 for interface + 0, // Interface has no endpoint + 0, // No interface class code + 0, // No interface subclass code + 0, // No interface protocol code + 0, // No string descriptor + } +}; + \endcode + Again, those are very generic values. For the interface descriptor, most of + them are zeroed. This is because this example does not implement any + functionality other than doing the USB enumeration. + + !!Class Driver + The demonstration program is going to use the standard request handler + discussed in "USBD Standard Request Handler" to perform the USB enumeration. + To be able to do that, several structures must be declared. + + !Descriptors List + The USBDDriver object needs a pointer to a list of descriptors. This is + necessary to be able to answer the GET_DESCRIPTOR request. A + USBDDriverDescriptors can be used to do that. + + The actual descriptors list can be instantiated: + \code +// List of descriptors used by the device. +const USBDDriverDescriptors usbdDriverDescriptors = { + + &usbDeviceDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptors, +#ifdef BOARD_USB_UDPHS + 0, // No full-speed device qualifier descriptor + 0, // No full-speed other speed configuration descriptor + &usbDeviceDescriptor, + (const USBConfigurationDescriptor *) &configurationDescriptors, + 0, // No high-speed device qualifier descriptor + 0, // No high-speed other speed configuration descriptor +#else + 0, // No full-speed device qualifier descriptor + 0, // No full-speed other speed configuration descriptor + 0, // No high-speed device descriptor + 0, // No high-speed configuration descriptor + 0, // No high-speed device qualifier descriptor + 0, // No high-speed other speed configuration descriptor +#endif + 0, // No string descriptor + 0 // No string descriptor +}; + \endcode + The core configuration descriptor, which is actually made up of the + configuation descriptor and the first interface descriptor, has to be cast to + the USBConfigurationDescriptor type. + + !!!Interrupt Service Routines + + . + + !!USB Controller Interrupt + The USB controller peripheral generates an interrupt when an event occurs. + Since that event must be forwarded to the USBD_IrqHandler method, an + interrupt service routine must be installed to do that. + \code + void ISR_Usb() + { + USBD_IrqHandler(); + } + \endcode + Currently the default USBDCallbacks_Initialized will initialize the + interrupt service routine automatically: + \code +void USBDCallbacks_Initialized() +{ + AIC_ConfigureIT(AT91C_ID_UDP, 0, USBD_IrqHandler); + AIC_EnableIT(AT91C_ID_UDP); +} + \endcode + So the only thing you should do to initialize the interrupt service is to call + USBD_Init() in main(). + + !!VBus PIO Interrupt + The Vbus power line can be monitored (if a PIO pin is connected to it) by the + user application to enable or disable the USB controller peripheral when the + %device is connected/disconnected. To do that, an interrupt must be programmed + when the status of Vbus changes. The ISR should call the USBD_Connect or + USBD_Disconnect function as follows: + \code +void ISR_Vbus(const Pin *pPin) +{ + // Check current level on VBus + if (PIO_Get(&pinVbus)) { + USBD_Connect(); + } + else { + USBD_Disconnect(); + } +} + \endcode + + !!!Callbacks + A typical application based on this USB framework needs to instantiate most of + the callbacks available. This section describes how to do that for a simple + enumeration program. + + !!Init + When an OS is not being used, the primary function that the {Init{ callback + must perform is interrupt handler installation. The previously defined ISR + is thus configured and enabled: + \code +void USBDCallbacks_Initialized() +{ + // Configure and enable the UDP interrupt + AIC_ConfigureIT(AT91C_ID_UDP, 0, USBD_IrqHandler); + AIC_EnableIT(AT91C_ID_UDP); +} + \endcode + The default callback is defined in USBDCallbacks_Initialized.c. + + !!Suspend & Resume + The Suspend callback is used by the USBD API to notify the device that it + should enter low-power mode if required. The default callback is defined + in USBDCallbacks_Suspended.c. + \code +void USBDCallbacks_Suspended(void) +{ + // Turn off LEDs + LED_Clear(USBD_LEDPOWER); + LED_Clear(USBD_LEDUSB); +} + \endcode + The Resume callback has to perform the reverse operation. The default callback + is defined in USBDCallbacks_Resumed.c. + \code +void USBDCallbacks_Resumed(void) +{ + // Initialize LEDs + LED_Configure(USBD_LEDPOWER); + LED_Set(USBD_LEDPOWER); + LED_Configure(USBD_LEDUSB); + LED_Clear(USBD_LEDUSB); +} + \endcode + + - Note: }It is not necessary to disable the USB controller logic (transceiver, + clocks, %peripheral) here. This is done directly by the USBD_IrqHandler + function prior to triggering the callback. Typically, the callback must carry + out the following operations: + - Disable the PLL + - Switch to the slow 32 KHz clock + - Turn off the clocks of used peripherals} + + !!NewRequest + Since this example software should only perform the USB enumeration, the + NewRequest callback can simply forward the call to the standard request + handler method: + \code +void USBDCallbacks_RequestReceived(const USBGenericRequest *request) +{ + USBDDriver_RequestHandler(&usbdDriver, request); +} + \endcode + + !!!Main + The Main function of the program is used for PIO and driver (Class and USB) + initialization, software connections of the device (by using USBD_Connect), + and implementation of the product functionality. + + In this case, the Main performs the first two steps. After that, since the + enumeration is done through the event handler and the device does not do + anything, it can simply enter an infinite loop: + + \code +int main() +{ + // If they are present, configure Vbus & Wake-up pins + PIO_InitializeInterrupts(0); + + // USB initialization + USBDDriver_Initialize(&usbdDriver, &usbdDriverDescriptors, 0); + USBD_Init(); + + // connect if needed + VBUS_CONFIGURE(); + while (USBD_GetState() < USBD_STATE_CONFIGURED); + + // Main loop + while(1) + { + // Put USB class driver implementaion here + } +} + \endcode +*/ \ No newline at end of file -- cgit v1.2.3