diff options
author | Marti Bolivar <mbolivar@leaflabs.com> | 2011-09-23 17:56:24 -0400 |
---|---|---|
committer | Marti Bolivar <mbolivar@leaflabs.com> | 2011-10-18 13:30:18 -0400 |
commit | bbcbf65fd7d074268f4e25ae014965bceb995b79 (patch) | |
tree | d027563c1d4b860d3e77119ee26f75943ced80a2 /libmaple | |
parent | 2e392bbf59c4c746714d71c99757f02da4c57179 (diff) | |
download | librambutan-bbcbf65fd7d074268f4e25ae014965bceb995b79.tar.gz librambutan-bbcbf65fd7d074268f4e25ae014965bceb995b79.zip |
usb: Disentangle CDC ACM functionality.
Add new usb_cdcacm.h, which provides the virtual serial port API.
This file (and new usb_cdcacm.c) consolidate the VCOM support, which
was previously distributed through descriptors.[hc], usb.[hc],
usb_callbacks.[hc], and usb_config.h.
Add usb_init_usblib() to usb.h, as a way of initializing the USB
peripheral in terms of the data structures required by usb_lib. This
is used by the new usb_cdcacm_enable().
Create new usb_lib_globals.h, with declarations for the usb_lib global
state which is most used throughout the rest of the libmaple USB stack.
Remove descriptors.c and usb_callbacks.[hc]; they are no longer
necessary.
Update the USB README accordingly.
Signed-off-by: Marti Bolivar <mbolivar@leaflabs.com>
Diffstat (limited to 'libmaple')
-rw-r--r-- | libmaple/rules.mk | 3 | ||||
-rw-r--r-- | libmaple/usb/README | 23 | ||||
-rw-r--r-- | libmaple/usb/descriptors.c | 196 | ||||
-rw-r--r-- | libmaple/usb/descriptors.h | 7 | ||||
-rw-r--r--[-rwxr-xr-x] | libmaple/usb/usb.c | 174 | ||||
-rw-r--r--[-rwxr-xr-x] | libmaple/usb/usb.h | 15 | ||||
-rw-r--r-- | libmaple/usb/usb_callbacks.c | 352 | ||||
-rw-r--r-- | libmaple/usb/usb_callbacks.h | 77 | ||||
-rw-r--r-- | libmaple/usb/usb_cdcacm.c | 742 | ||||
-rw-r--r-- | libmaple/usb/usb_cdcacm.h | 59 | ||||
-rw-r--r-- | libmaple/usb/usb_config.h | 62 | ||||
-rw-r--r-- | libmaple/usb/usb_lib_globals.h | 55 | ||||
-rw-r--r--[-rwxr-xr-x] | libmaple/usb/usb_reg_map.c | 0 |
13 files changed, 881 insertions, 884 deletions
diff --git a/libmaple/rules.mk b/libmaple/rules.mk index dff21b1..a51143a 100644 --- a/libmaple/rules.mk +++ b/libmaple/rules.mk @@ -31,10 +31,9 @@ cSRCS_$(d) := adc.c \ timer.c \ usart.c \ util.c \ - usb/descriptors.c \ usb/usb.c \ - usb/usb_callbacks.c \ usb/usb_reg_map.c \ + usb/usb_cdcacm.c \ usb/usb_lib/usb_core.c \ usb/usb_lib/usb_init.c \ usb/usb_lib/usb_int.c \ diff --git a/libmaple/usb/README b/libmaple/usb/README index 2862116..2c55364 100644 --- a/libmaple/usb/README +++ b/libmaple/usb/README @@ -2,28 +2,22 @@ The USB submodule of libmaple is responsible for: Initializing the USB peripheral, scaling the peripheral clocks appropriately, enabling the interrupt channels to USB, defining - the USB isr, resetting the USB disc pin (used to tell the host + the USB IRQ, resetting the USB DISC pin (used to tell the host were alive). Additionally, the USB submodule defines the virtual - com port USB applications that is available to all user sketches - via SerialUSB.print() and others. + COM port interface that is exposed to user sketches via SerialUSB. To use it: - [This section is out of date. Does SerialUSB.begin() do the same - thing as the old Usb.init()?] - SerialUSB.print/ln, available(), read(), write() implement the same - interface as Serial1/2/3 - + interface as Serial1/2/3. Current Status: Currently, the USB submodule relies on the low level core library - provided by ST to access the USB peripheral registers and - implement the USB transfer protocol for control endpoint - transfers. The high level virtual com port application is - unfortunately hard to untangle from this low level dependence, and - when a new USB core library is written (to nix ST dependence) + provided by ST to implement the USB transfer protocol for control + endpoint transfers. The high level virtual com port application + is unfortunately hard to untangle from this low level dependence, + and when a new USB core library is written (to nix ST dependence) changes will likely have to be made to virtual com application code. Ideally, the new core library should mimic the form of MyUSB (LUFA), since this library (USB for AVR) is growing in popularity @@ -66,9 +60,6 @@ Current Status: be asserted (on Maple this is GPIO C12). Alternatively, the NVIC can be directly configured to disable the USB LP/HP IRQ's. - This library should exposed through usb.h; do not include any - other files direcly in your application. - The files inside of usb_lib were provided by ST and are subject to their own license, all other files were written by the LeafLabs team and fall under the MIT license. diff --git a/libmaple/usb/descriptors.c b/libmaple/usb/descriptors.c deleted file mode 100644 index a0bc046..0000000 --- a/libmaple/usb/descriptors.c +++ /dev/null @@ -1,196 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#include "descriptors.h" -#include "libmaple.h" -#include "usb_config.h" - -const USB_Descriptor_Device usbVcomDescriptor_Device = { - bLength: sizeof(USB_Descriptor_Device), - bDescriptorType: USB_DESCRIPTOR_TYPE_DEVICE, - bcdUSB: 0x0200, - bDeviceClass: USB_DEVICE_CLASS_CDC, - bDeviceSubClass: USB_DEVICE_SUBCLASS_CDC, - bDeviceProtocol: 0x00, - bMaxPacketSize0: 0x40, - idVendor: VCOM_ID_VENDOR, - idProduct: VCOM_ID_PRODUCT, - bcdDevice: 0x0200, - iManufacturer: 0x01, - iProduct: 0x02, - iSerialNumber: 0x00, - bNumConfigurations: 0x01 -}; - -const USB_Descriptor_Config usbVcomDescriptor_Config = { - Config_Header: { - bLength: sizeof(USB_Descriptor_Config_Header), - bDescriptorType: USB_DESCRIPTOR_TYPE_CONFIGURATION, - wTotalLength: sizeof(USB_Descriptor_Config), - bNumInterfaces: 0x02, - bConfigurationValue: 0x01, - iConfiguration: 0x00, - bmAttributes: (USB_CONFIG_ATTR_BUSPOWERED | - USB_CONFIG_ATTR_SELF_POWERED), - bMaxPower: USB_CONFIG_MAX_POWER, - }, - - CCI_Interface: - { - bLength: sizeof(USB_Descriptor_Interface), - bDescriptorType: USB_DESCRIPTOR_TYPE_INTERFACE, - bInterfaceNumber: 0x00, - bAlternateSetting: 0x00, - bNumEndpoints: 0x01, - bInterfaceClass: USB_INTERFACE_CLASS_CDC, - bInterfaceSubClass: USB_INTERFACE_SUBCLASS_CDC_ACM, - bInterfaceProtocol: 0x01, /* Common AT Commands */ - iInterface: 0x00 - }, - - CDC_Functional_IntHeader: - { - bLength: CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2), - bDescriptorType: 0x24, - SubType: 0x00, - Data: {0x01, 0x10} - }, - - CDC_Functional_CallManagement: - { - bLength: CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2), - bDescriptorType: 0x24, - SubType: 0x01, - Data: {0x03, 0x01} - }, - - CDC_Functional_ACM: - { - bLength: CDC_FUNCTIONAL_DESCRIPTOR_SIZE(1), - bDescriptorType: 0x24, - SubType: 0x02, - Data: {0x06} - }, - - CDC_Functional_Union: - { - bLength: CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2), - bDescriptorType: 0x24, - SubType: 0x06, - Data: {0x00, 0x01} - }, - - ManagementEndpoint: - { - bLength: sizeof(USB_Descriptor_Endpoint), - bDescriptorType: USB_DESCRIPTOR_TYPE_ENDPOINT, - bEndpointAddress: (USB_DESCRIPTOR_ENDPOINT_IN | VCOM_NOTIFICATION_EPNUM), - bmAttributes: EP_TYPE_INTERRUPT, - wMaxPacketSize: VCOM_NOTIFICATION_EPSIZE, - bInterval: 0xFF, - }, - - DCI_Interface: - { - bLength: sizeof(USB_Descriptor_Interface), - bDescriptorType: USB_DESCRIPTOR_TYPE_INTERFACE, - bInterfaceNumber: 0x01, - bAlternateSetting: 0x00, - bNumEndpoints: 0x02, - bInterfaceClass: USB_INTERFACE_CLASS_DIC, - bInterfaceSubClass: 0x00, /* None */ - bInterfaceProtocol: 0x00, /* None */ - iInterface: 0x00, - }, - - DataOutEndpoint: - { - bLength: sizeof(USB_Descriptor_Endpoint), - bDescriptorType: USB_DESCRIPTOR_TYPE_ENDPOINT, - bEndpointAddress: (USB_DESCRIPTOR_ENDPOINT_OUT | VCOM_RX_EPNUM), - bmAttributes: EP_TYPE_BULK, - wMaxPacketSize: VCOM_RX_EPSIZE, - bInterval: 0x00, - }, - - DataInEndpoint: - { - bLength: sizeof(USB_Descriptor_Endpoint), - bDescriptorType: USB_DESCRIPTOR_TYPE_ENDPOINT, - bEndpointAddress: (USB_DESCRIPTOR_ENDPOINT_IN | VCOM_TX_EPNUM), - bmAttributes: EP_TYPE_BULK, - wMaxPacketSize: VCOM_TX_EPSIZE, - bInterval: 0x00 - } -}; - -/***************************************************************************** - ***************************************************************************** - *** - *** FIXME FIXME FIXME NOT THE RIGHT THING! MOVE ALL THIS INTO TO WIRISH! - *** - ***************************************************************************** - *****************************************************************************/ - -const uint8 usbVcomDescriptor_LangID[USB_DESCRIPTOR_STRING_LEN(1)] = { - USB_DESCRIPTOR_STRING_LEN(1), - USB_DESCRIPTOR_TYPE_STRING, - 0x09, - 0x04 -}; - -const uint8 usbVcomDescriptor_iManufacturer[USB_DESCRIPTOR_STRING_LEN(8)] = { - USB_DESCRIPTOR_STRING_LEN(8), - USB_DESCRIPTOR_TYPE_STRING, - 'L', 0, 'e', 0, 'a', 0, 'f', 0, - 'L', 0, 'a', 0, 'b', 0, 's', 0 -}; - -/* - String Identifiers: - - we may choose to specify any or none of the following string - identifiers: - - iManufacturer: LeafLabs - iProduct: Maple R3 - iSerialNumber: NONE - iConfiguration: NONE - iInterface(CCI): NONE - iInterface(DCI): NONE - - additionally we must provide the unicode language identifier, - which is 0x0409 for US English -*/ -const uint8 usbVcomDescriptor_iProduct[USB_DESCRIPTOR_STRING_LEN(8)] = { - USB_DESCRIPTOR_STRING_LEN(8), - USB_DESCRIPTOR_TYPE_STRING, - 'M', 0, 'a', 0, 'p', 0, 'l', 0, - 'e', 0, ' ', 0, ' ', 0, ' ', 0 -}; - -/***************************************************************************** - *****************************************************************************/ diff --git a/libmaple/usb/descriptors.h b/libmaple/usb/descriptors.h index 77ff3bb..06d9ce7 100644 --- a/libmaple/usb/descriptors.h +++ b/libmaple/usb/descriptors.h @@ -25,7 +25,6 @@ #ifndef __DESCRIPTORS_H #define __DESCRIPTORS_H - #include "libmaple.h" #define USB_DESCRIPTOR_TYPE_DEVICE 0x01 @@ -52,7 +51,6 @@ #define USB_DESCRIPTOR_STRING_LEN(x) (2 + (x << 1)) - #if defined(__cplusplus) extern "C" { #endif @@ -74,7 +72,6 @@ extern "C" { uint8 Data[DataSize]; \ } __packed -/* See http://www.beyondlogic.org/usbnutshell/usb5.shtml#DeviceDescriptors */ typedef struct { uint8 bLength; uint8 bDescriptorType; @@ -92,7 +89,6 @@ typedef struct { uint8 bNumConfigurations; } __packed USB_Descriptor_Device; -/* http://www.beyondlogic.org/usbnutshell/usb5.shtml#ConfigurationDescriptors */ typedef struct { uint8 bLength; uint8 bDescriptorType; @@ -104,7 +100,6 @@ typedef struct { uint8 bMaxPower; } __packed USB_Descriptor_Config_Header; -/* See http://www.beyondlogic.org/usbnutshell/usb5.shtml#InterfaceDescriptors */ typedef struct { uint8 bLength; uint8 bDescriptorType; @@ -154,7 +149,7 @@ extern const uint8 usbVcomDescriptor_iManufacturer[USB_DESCRIPTOR_STRING_LEN(8)] extern const uint8 usbVcomDescriptor_iProduct[USB_DESCRIPTOR_STRING_LEN(8)]; #if defined(__cplusplus) - } +} #endif #endif // __DESCRIPTORS_H diff --git a/libmaple/usb/usb.c b/libmaple/usb/usb.c index 29d07d0..21a19db 100755..100644 --- a/libmaple/usb/usb.c +++ b/libmaple/usb/usb.c @@ -39,65 +39,17 @@ #include "usb_reg_map.h" #include "usb_config.h" -#include "usb_callbacks.h" +#include "usb_lib_globals.h" #include "usb_type.h" #include "usb_core.h" -static void usb_init(void); static void dispatch_ctr_lp(void); /* - * Globals required by usb_lib/ + * usb_lib/ globals */ -DEVICE Device_Table = - {NUM_ENDPTS, - 1}; - -DEVICE_PROP Device_Property = - {usbInit, - usbReset, - usbStatusIn, - usbStatusOut, - usbDataSetup, - usbNoDataSetup, - usbGetInterfaceSetting, - usbGetDeviceDescriptor, - usbGetConfigDescriptor, - usbGetStringDescriptor, - 0, - bMaxPacketSize}; - -USER_STANDARD_REQUESTS User_Standard_Requests = - {NOP_Process, - usbSetConfiguration, - NOP_Process, - NOP_Process, - NOP_Process, - NOP_Process, - NOP_Process, - NOP_Process, - usbSetDeviceAddress}; - -void (*pEpInt_IN[7])(void) = - {vcomDataTxCb, - vcomManagementCb, - NOP_Process, - NOP_Process, - NOP_Process, - NOP_Process, - NOP_Process}; - -void (*pEpInt_OUT[7])(void) = - {NOP_Process, - NOP_Process, - vcomDataRxCb, - NOP_Process, - NOP_Process, - NOP_Process, - NOP_Process}; - volatile uint16 wIstr = 0; uint8 EPindex; /* current endpoint */ DEVICE_INFO *pInformation; @@ -124,20 +76,15 @@ struct { * Routines */ -void usb_cdcacm_enable(gpio_dev *disc_dev, uint8 disc_bit) { - /* Present ourselves to the host */ - gpio_set_mode(disc_dev, disc_bit, GPIO_OUTPUT_PP); - gpio_write_bit(disc_dev, disc_bit, 0); // presents us to the host - - /* initialize USB peripheral */ - usb_init(); -} +void usb_init_usblib(DEVICE_PROP *device, USER_STANDARD_REQUESTS *user) { + rcc_clk_enable(RCC_USB); -void usb_cdcacm_disable(gpio_dev *disc_dev, uint8 disc_bit) { - // These are just guesses about how to do this, but it seems to work. - // TODO: verify this with USB spec - nvic_irq_disable(NVIC_USB_LP_CAN_RX0); - gpio_write_bit(disc_dev, disc_bit, 1); + pInformation = &Device_Info; + pInformation->ControlState = 2; /* FIXME [0.0.12] use + CONTROL_STATE enumerator */ + pProperty = device; + pUser_Standard_Requests = user; + pProperty->Init(); } void usbSuspend(void) { @@ -222,7 +169,7 @@ void __irq_usb_lp_can_rx0(void) { #if (ISR_MSK & USB_ISTR_RESET) if (wIstr & USB_ISTR_RESET & wInterrupt_Mask) { USB_BASE->ISTR = ~USB_ISTR_RESET; - Device_Property.Reset(); + pProperty->Reset(); } #endif @@ -290,91 +237,6 @@ void usbWaitReset(void) { nvic_sys_reset(); } -/* This low-level send bytes function is NON-BLOCKING; blocking behavior, with - * a timeout, is implemented in usercode (or in the Wirish C++ high level - * implementation). - * - * This function will quickly copy up to 64 bytes of data (out of an - * arbitrarily large buffer) into the USB peripheral TX buffer and return the - * number placed in that buffer. It is up to usercode to divide larger packets - * into 64-byte chunks to guarantee delivery. - * - * - */ -void usbBlockingSendByte(char ch) { - while (countTx); - UserToPMABufferCopy((uint8*)&ch,VCOM_TX_ADDR,1); - _SetEPTxCount(VCOM_TX_ENDP,1); - _SetEPTxValid(VCOM_TX_ENDP); - countTx = 1; - while (countTx); -} - -uint32 usbSendBytes(const uint8* sendBuf, uint32 len) { - /* Last transmission hasn't finished, abort */ - if (countTx) { - return 0; - } - - // We can only put VCOM_TX_EPSIZE bytes in the buffer - /* FIXME XXX then why are we only copying half as many? */ - if (len > VCOM_TX_EPSIZE / 2) { - len = VCOM_TX_EPSIZE / 2; - } - - // Try to load some bytes if we can - if (len) { - usb_copy_to_pma(sendBuf, len, VCOM_TX_ADDR); - usb_set_ep_tx_count(VCOM_TX_ENDP, len); - countTx += len; - usb_set_ep_tx_stat(VCOM_TX_ENDP, USB_EP_STAT_TX_VALID); - } - - return len; -} - -/* returns the number of available bytes are in the recv FIFO */ -uint32 usbBytesAvailable(void) { - return newBytes; -} - -/* Nonblocking byte receive. - * - * Copies up to len bytes from the local recieve FIFO (*NOT* the PMA) - * into recvBuf and deq's the FIFO. */ -uint32 usbReceiveBytes(uint8* recvBuf, uint32 len) { - static int offset = 0; - - if (len > newBytes) { - len = newBytes; - } - - int i; - for (i=0;i<len;i++) { - recvBuf[i] = (uint8)(vcomBufferRx[i+offset]); - } - - newBytes -= len; - offset += len; - - /* Re-enable the RX endpoint, which we had set to receive 0 bytes */ - if (newBytes == 0) { - usb_set_ep_rx_count(VCOM_RX_ENDP,VCOM_RX_EPSIZE); - usb_set_ep_rx_stat(VCOM_RX_ENDP, USB_EP_STAT_RX_VALID); - offset = 0; - } - - return len; -} - -uint8 usbGetDTR() { - return ((line_dtr_rts & CONTROL_LINE_DTR) != 0); -} - -uint8 usbGetRTS() { - return ((line_dtr_rts & CONTROL_LINE_RTS) != 0); -} - uint8 usbIsConfigured() { return (bDeviceState == CONFIGURED); } @@ -383,24 +245,10 @@ uint8 usbIsConnected() { return (bDeviceState != UNCONNECTED); } -uint16 usbGetPending() { - return countTx; -} - /* * Auxiliary routines */ -static void usb_init(void) { /* TODO make a public, improved version */ - rcc_clk_enable(RCC_USB); - - pInformation = &Device_Info; - pInformation->ControlState = 2; - pProperty = &Device_Property; - pUser_Standard_Requests = &User_Standard_Requests; - pProperty->Init(); -} - static inline uint8 dispatch_endpt_zero(void); static inline void dispatch_endpt(uint8 ep); static inline void set_rx_tx_status0(uint16 rx, uint16 tx); diff --git a/libmaple/usb/usb.h b/libmaple/usb/usb.h index 853300b..da6fa55 100755..100644 --- a/libmaple/usb/usb.h +++ b/libmaple/usb/usb.h @@ -60,8 +60,11 @@ typedef enum { extern volatile uint32 bDeviceState; -void usb_cdcacm_enable(gpio_dev*, uint8); -void usb_cdcacm_disable(gpio_dev*, uint8); +struct _DEVICE_PROP; +struct _USER_STANDARD_REQUESTS; +void usb_init_usblib(struct _DEVICE_PROP*, + struct _USER_STANDARD_REQUESTS*); + void usbSuspend(void); void usbResumeInit(void); void usbResume(RESUME_STATE); @@ -70,16 +73,8 @@ void usbResume(RESUME_STATE); void __irq_usb_lp_can_rx0(void); void usbWaitReset(void); -/* blocking functions for send/receive */ -void usbBlockingSendByte(char ch); -uint32 usbSendBytes(const uint8* sendBuf,uint32 len); -uint32 usbBytesAvailable(void); -uint32 usbReceiveBytes(uint8* recvBuf, uint32 len); -uint8 usbGetDTR(void); -uint8 usbGetRTS(void); uint8 usbIsConnected(void); uint8 usbIsConfigured(void); -uint16 usbGetPending(void); #ifdef __cplusplus } // extern "C" diff --git a/libmaple/usb/usb_callbacks.c b/libmaple/usb/usb_callbacks.c deleted file mode 100644 index 5a69d4c..0000000 --- a/libmaple/usb/usb_callbacks.c +++ /dev/null @@ -1,352 +0,0 @@ -/* insert license */ - -#include "nvic.h" - -#include "usb_callbacks.h" -#include "usb_lib.h" -#include "descriptors.h" -#include "usb_config.h" -#include "usb.h" - -/* macro'd register and peripheral definitions */ -#define EXC_RETURN 0xFFFFFFF9 -#define DEFAULT_CPSR 0x61000000 - -ONE_DESCRIPTOR Device_Descriptor = { - (uint8*)&usbVcomDescriptor_Device, - sizeof(USB_Descriptor_Device) -}; - -ONE_DESCRIPTOR Config_Descriptor = { - (uint8*)&usbVcomDescriptor_Config, - sizeof(USB_Descriptor_Config) -}; - -ONE_DESCRIPTOR String_Descriptor[3] = { - {(uint8*)&usbVcomDescriptor_LangID, USB_DESCRIPTOR_STRING_LEN(1)}, - {(uint8*)&usbVcomDescriptor_iManufacturer,USB_DESCRIPTOR_STRING_LEN(8)}, - {(uint8*)&usbVcomDescriptor_iProduct, USB_DESCRIPTOR_STRING_LEN(8)} -}; - -uint8 last_request = 0; - -USB_Line_Coding line_coding = { - bitrate: 115200, - format: 0x00, /* stop bits-1 */ - paritytype: 0x00, - datatype: 0x08 -}; - -uint8 vcomBufferRx[VCOM_RX_BUFLEN]; -volatile uint32 countTx = 0; -volatile uint32 recvBufIn = 0; -volatile uint32 recvBufOut = 0; -volatile uint32 maxNewBytes = VCOM_RX_BUFLEN; -volatile uint32 newBytes = 0; -RESET_STATE reset_state = DTR_UNSET; -uint8 line_dtr_rts = 0; - -void vcomDataTxCb(void) { - /* do whatever after data has been sent to host */ - - /* allows usbSendBytes to stop blocking */ - - /* assumes tx transactions are atomic 64 bytes (nearly certain they are) */ - countTx = 0; -} - -/* we could get arbitrarily complicated here for speed purposes - however, the simple scheme here is to implement a receive fifo - and always set the maximum to new bytes to the space remaining - in the fifo. this number will be reincremented after calls - to usbReceiveBytes */ -void vcomDataRxCb(void) { - /* do whatever after data has been received from host */ - - /* setEPRxCount on the previous cycle should garuntee - we havnt received more bytes than we can fit */ - newBytes = GetEPRxCount(VCOM_RX_ENDP); - SetEPRxStatus(VCOM_RX_ENDP,EP_RX_NAK); - - /* todo, not checking very carefully for edge cases. USUALLY, - if we emit the reset pulse and send 4 bytes, then newBytes - should be 4. But its POSSIBLE that this would be violated - in some cases */ - - /* magic number, {0x31, 0x45, 0x41, 0x46} is "1EAF" */ - uint8 chkBuf[4]; - uint8 cmpBuf[4] = {0x31, 0x45, 0x41, 0x46}; - if (reset_state == DTR_NEGEDGE) { - reset_state = DTR_LOW; - - if (newBytes >= 4) { - unsigned int target = (unsigned int)usbWaitReset | 0x1; - - PMAToUserBufferCopy(chkBuf,VCOM_RX_ADDR,4); - - int i; - USB_Bool cmpMatch = TRUE; - for (i=0; i<4; i++) { - if (chkBuf[i] != cmpBuf[i]) { - cmpMatch = FALSE; - } - } - - if (cmpMatch) { - asm volatile("mov r0, %[stack_top] \n\t" // Reset the stack - "mov sp, r0 \n\t" - "mov r0, #1 \n\t" - "mov r1, %[target_addr] \n\t" - "mov r2, %[cpsr] \n\t" - "push {r2} \n\t" // Fake xPSR - "push {r1} \n\t" // Target address for PC - "push {r0} \n\t" // Fake LR - "push {r0} \n\t" // Fake R12 - "push {r0} \n\t" // Fake R3 - "push {r0} \n\t" // Fake R2 - "push {r0} \n\t" // Fake R1 - "push {r0} \n\t" // Fake R0 - "mov lr, %[exc_return] \n\t" - "bx lr" - : - : [stack_top] "r" (STACK_TOP), - [target_addr] "r" (target), - [exc_return] "r" (EXC_RETURN), - [cpsr] "r" (DEFAULT_CPSR) - : "r0", "r1", "r2"); - /* should never get here */ - } - } - } - - PMAToUserBufferCopy(&vcomBufferRx[0],VCOM_RX_ADDR,newBytes); -} - -void vcomManagementCb(void) { - /* unused. This enpoint would callback if we had sent a linestate - changed notification */ -} - -u8* vcomGetSetLineCoding(uint16 length) { - if (length == 0) { - pInformation->Ctrl_Info.Usb_wLength = sizeof(USB_Line_Coding); - } - return (uint8*)&line_coding; -} - -void vcomSetLineState(void) { -} - -static RESULT usbPowerOn(void) { - u16 wRegVal; - - wRegVal = CNTR_FRES; - _SetCNTR(wRegVal); - - wInterrupt_Mask = 0; - _SetCNTR(wInterrupt_Mask); - _SetISTR(0); - wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM; // the bare minimum - _SetCNTR(wInterrupt_Mask); - - return USB_SUCCESS; -} - -void usbInit(void) { - pInformation->Current_Configuration = 0; - usbPowerOn(); - - _SetISTR(0); - wInterrupt_Mask = ISR_MSK; - _SetCNTR(wInterrupt_Mask); - - nvic_irq_enable(NVIC_USB_LP_CAN_RX0); - bDeviceState = UNCONNECTED; -} - -void usbReset(void) { - pInformation->Current_Configuration = 0; - - /* current feature is current bmAttributes */ - pInformation->Current_Feature = (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELF_POWERED); - - _SetBTABLE(USB_BTABLE_ADDRESS); - - /* setup control endpoint 0 */ - _SetEPType(ENDP0, EP_CONTROL); - _SetEPTxStatus(ENDP0, EP_TX_STALL); - _SetEPRxAddr(ENDP0,VCOM_CTRL_RX_ADDR); - _SetEPTxAddr(ENDP0,VCOM_CTRL_TX_ADDR); - Clear_Status_Out(ENDP0); - - SetEPRxCount(ENDP0, pProperty->MaxPacketSize); - SetEPRxValid(ENDP0); - - /* setup management endpoint 1 */ - SetEPType (VCOM_NOTIFICATION_ENDP, EP_INTERRUPT); - SetEPTxAddr (VCOM_NOTIFICATION_ENDP, VCOM_NOTIFICATION_ADDR); - SetEPTxStatus (VCOM_NOTIFICATION_ENDP, EP_TX_NAK); - SetEPRxStatus (VCOM_NOTIFICATION_ENDP, EP_RX_DIS); - - /* setup data endpoint OUT (rx) */ - /* SetEPType (VCOM_RX_ENDP, EP_BULK); */ - /* SetEPRxAddr (VCOM_RX_ENDP, VCOM_RX_ADDR); */ - /* SetEPRxCount (VCOM_RX_ENDP, VCOM_RX_EPSIZE); */ - /* // SetEPTxStatus (VCOM_RX_ENDP, EP_TX_DIS); */ - /* SetEPRxStatus (VCOM_RX_ENDP, EP_RX_VALID); */ - - SetEPType (3, EP_BULK); - SetEPRxAddr (3, 0x110); - SetEPRxCount (3,64); - // SetEPTxStatus (VCOM_RX_ENDP, EP_TX_DIS); - SetEPRxStatus (3, EP_RX_VALID); - - /* setup data endpoint IN (tx) */ - SetEPType (VCOM_TX_ENDP, EP_BULK); - SetEPTxAddr (VCOM_TX_ENDP, VCOM_TX_ADDR); - SetEPTxStatus (VCOM_TX_ENDP, EP_TX_NAK); - SetEPRxStatus (VCOM_TX_ENDP, EP_RX_DIS); - - bDeviceState = ATTACHED; - SetDeviceAddress(0); - - /* reset the rx fifo */ - recvBufIn = 0; - recvBufOut = 0; - maxNewBytes = VCOM_RX_EPSIZE; - countTx = 0; -} - - -void usbStatusIn(void) { - /* adjust the usart line coding - if we wish to couple the CDC line coding - with the real usart port */ -} - -void usbStatusOut(void) { -} - -RESULT usbDataSetup(uint8 request) { - uint8 *(*CopyRoutine)(uint16); - CopyRoutine = NULL; - - if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { - switch (request) { - case (GET_LINE_CODING): - CopyRoutine = vcomGetSetLineCoding; - last_request = GET_LINE_CODING; - break; - case (SET_LINE_CODING): - CopyRoutine = vcomGetSetLineCoding; - last_request = SET_LINE_CODING; - break; - default: break; - } - } - - if (CopyRoutine == NULL) { - return USB_UNSUPPORT; - } - - pInformation->Ctrl_Info.CopyData = CopyRoutine; - pInformation->Ctrl_Info.Usb_wOffset = 0; - (*CopyRoutine)(0); - return USB_SUCCESS; -} - -RESULT usbNoDataSetup(u8 request) { - uint8 new_signal; - - /* we support set com feature but dont handle it */ - if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { - - switch (request) { - case (SET_COMM_FEATURE): - return USB_SUCCESS; - case (SET_CONTROL_LINE_STATE): - /* to reset the board, pull both dtr and rts low - then pulse dtr by itself */ - new_signal = pInformation->USBwValues.bw.bb0 & (CONTROL_LINE_DTR | CONTROL_LINE_RTS); - line_dtr_rts = new_signal & 0x03; - - switch (reset_state) { - /* no default, covered enum */ - case DTR_UNSET: - if ((new_signal & CONTROL_LINE_DTR) == 0 ) { - reset_state = DTR_LOW; - } else { - reset_state = DTR_HIGH; - } - break; - - case DTR_HIGH: - if ((new_signal & CONTROL_LINE_DTR) == 0 ) { - reset_state = DTR_NEGEDGE; - } else { - reset_state = DTR_HIGH; - } - break; - - case DTR_NEGEDGE: - if ((new_signal & CONTROL_LINE_DTR) == 0 ) { - reset_state = DTR_LOW; - } else { - reset_state = DTR_HIGH; - } - break; - - case DTR_LOW: - if ((new_signal & CONTROL_LINE_DTR) == 0 ) { - reset_state = DTR_LOW; - } else { - reset_state = DTR_HIGH; - } - break; - } - - return USB_SUCCESS; - } - } - return USB_UNSUPPORT; -} - -RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting) { - if (alt_setting > 0) { - return USB_UNSUPPORT; - } else if (interface > 1) { - return USB_UNSUPPORT; - } - - return USB_SUCCESS; -} - - -u8* usbGetDeviceDescriptor(u16 length) { - return Standard_GetDescriptorData(length, &Device_Descriptor); -} - -u8* usbGetConfigDescriptor(u16 length) { - return Standard_GetDescriptorData(length, &Config_Descriptor); -} - -u8* usbGetStringDescriptor(u16 length) { - uint8 wValue0 = pInformation->USBwValue0; - - if (wValue0 > 2) { - return NULL; - } - return Standard_GetDescriptorData(length, &String_Descriptor[wValue0]); -} - -/* internal callbacks to respond to standard requests */ -void usbSetConfiguration(void) { - if (pInformation->Current_Configuration != 0) { - bDeviceState = CONFIGURED; - } -} - -void usbSetDeviceAddress(void) { - bDeviceState = ADDRESSED; -} - diff --git a/libmaple/usb/usb_callbacks.h b/libmaple/usb/usb_callbacks.h deleted file mode 100644 index a71af01..0000000 --- a/libmaple/usb/usb_callbacks.h +++ /dev/null @@ -1,77 +0,0 @@ -/* insert license */ - -#ifndef __USB_CALLBACKS -#define __USB_CALLBACKS - -#include "libmaple.h" -#include "usb_config.h" - -#include "usb_type.h" -#include "usb_core.h" - -#define SET_LINE_CODING 0x20 -#define GET_LINE_CODING 0x21 -#define SET_COMM_FEATURE 0x02 -#define SET_CONTROL_LINE_STATE 0x22 -#define CONTROL_LINE_DTR (0x01) -#define CONTROL_LINE_RTS (0x02) - -#if defined(__cplusplus) -extern "C" { -#endif - -typedef struct { - uint32 bitrate; - uint8 format; - uint8 paritytype; - uint8 datatype; -} USB_Line_Coding; - -typedef enum { - DTR_UNSET, - DTR_HIGH, - DTR_NEGEDGE, - DTR_LOW -} RESET_STATE; - -extern RESET_STATE reset_state; /* tracks DTR/RTS */ -extern uint8 line_dtr_rts; -extern volatile uint32 countTx; -extern uint8 vcomBufferRx[VCOM_RX_BUFLEN]; /* no reason this has to be VCOM_RX_EPSIZE, could be bigger */ -extern volatile uint32 recvBufIn; /* the FIFO in index to the recvbuffer */ -extern volatile uint32 recvBufOut; /* the FIFO out index to the recvbuffer */ -extern volatile uint32 maxNewBytes; -extern volatile uint32 newBytes; - -void vcomDataTxCb(void); -void vcomDataRxCb(void); -void vcomManagementCb(void); - -uint8* vcomGetSetLineCoding(uint16 length); -void vcomSetLineSate(void); - -void usbInit(void); -/* internal functions (as per the usb_core pProperty structure) */ -void usbInit(void); -void usbReset(void); -void usbStatusIn(void); -void usbStatusOut(void); - -RESULT usbDataSetup(uint8 request); -RESULT usbNoDataSetup(uint8 request); -RESULT usbGetInterfaceSetting(uint8,uint8); - -uint8* usbGetDeviceDescriptor(uint16 length); -uint8* usbGetConfigDescriptor(uint16 length); -uint8* usbGetStringDescriptor(uint16 length); - -/* internal callbacks to respond to standard requests */ -void usbSetConfiguration(void); -void usbSetDeviceAddress(void); - -#if defined(__cplusplus) -} -#endif - - -#endif diff --git a/libmaple/usb/usb_cdcacm.c b/libmaple/usb/usb_cdcacm.c new file mode 100644 index 0000000..1a3b4e6 --- /dev/null +++ b/libmaple/usb/usb_cdcacm.c @@ -0,0 +1,742 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file usb_cdcacm.c + * + * @brief USB CDC ACM (a.k.a. virtual serial terminal, VCOM) state and + * routines. + */ + +#include "usb_cdcacm.h" + +#include "nvic.h" + +#include "usb.h" +#include "usb_config.h" +#include "descriptors.h" +#include "usb_lib_globals.h" +#include "usb_reg_map.h" + +#include "usb_type.h" +#include "usb_core.h" +#include "usb_def.h" + +/****************************************************************************** + ****************************************************************************** + *** + *** HACK ALERT! FIXME FIXME FIXME FIXME! + *** + *** A bunch of LeafLabs-specific configuration lives in here for + *** now. This mess REALLY needs to get teased apart, with + *** appropriate pieces moved into Wirish. + *** + ****************************************************************************** + *****************************************************************************/ + +#if !(defined(BOARD_maple) || defined(BOARD_maple_RET6) || \ + defined(BOARD_maple_mini) || defined(BOARD_maple_native)) + +#warning ("Warning! USB VCOM relies on LeafLabs board-specific " \ + "configuration right now. If you want, you can pretend " \ + "you're one of our boards; i.e., #define BOARD_maple, " \ + "BOARD_maple_mini, etc. according to what matches your MCU " \ + "best." +#endif + +/* + * VCOM config + */ + +#define VCOM_ID_VENDOR 0x1EAF +#define VCOM_ID_PRODUCT 0x0004 + +#define VCOM_CTRL_EPNUM 0x00 +#define VCOM_CTRL_RX_ADDR 0x40 +#define VCOM_CTRL_TX_ADDR 0x80 +#define VCOM_CTRL_EPSIZE 0x40 + +#define VCOM_TX_ENDP 1 +#define VCOM_TX_EPNUM 0x01 +#define VCOM_TX_ADDR 0xC0 +#define VCOM_TX_EPSIZE 0x40 + +#define VCOM_NOTIFICATION_ENDP 2 +#define VCOM_NOTIFICATION_EPNUM 0x02 +#define VCOM_NOTIFICATION_ADDR 0x100 +#define VCOM_NOTIFICATION_EPSIZE 0x40 + +#define VCOM_RX_ENDP 3 +#define VCOM_RX_EPNUM 0x03 +#define VCOM_RX_ADDR 0x110 +#define VCOM_RX_EPSIZE 0x40 +#define VCOM_RX_BUFLEN (VCOM_RX_EPSIZE*3) + +#define USB_DEVICE_CLASS_CDC 0x02 +#define USB_DEVICE_SUBCLASS_CDC 0x00 + +#define SET_LINE_CODING 0x20 +#define GET_LINE_CODING 0x21 +#define SET_COMM_FEATURE 0x02 +#define SET_CONTROL_LINE_STATE 0x22 +#define CONTROL_LINE_DTR (0x01) +#define CONTROL_LINE_RTS (0x02) + +typedef struct { + uint32 bitrate; + uint8 format; + uint8 paritytype; + uint8 datatype; +} USB_Line_Coding; + +typedef enum { + DTR_UNSET, + DTR_HIGH, + DTR_NEGEDGE, + DTR_LOW +} RESET_STATE; + +const USB_Descriptor_Device usbVcomDescriptor_Device = { + .bLength = sizeof(USB_Descriptor_Device), + .bDescriptorType = USB_DESCRIPTOR_TYPE_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = USB_DEVICE_CLASS_CDC, + .bDeviceSubClass = USB_DEVICE_SUBCLASS_CDC, + .bDeviceProtocol = 0x00, + .bMaxPacketSize0 = 0x40, + .idVendor = VCOM_ID_VENDOR, + .idProduct = VCOM_ID_PRODUCT, + .bcdDevice = 0x0200, + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x00, + .bNumConfigurations = 0x01, +}; + +const USB_Descriptor_Config usbVcomDescriptor_Config = { + .Config_Header = { + .bLength = sizeof(USB_Descriptor_Config_Header), + .bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIGURATION, + .wTotalLength = sizeof(USB_Descriptor_Config), + .bNumInterfaces = 0x02, + .bConfigurationValue = 0x01, + .iConfiguration = 0x00, + .bmAttributes = (USB_CONFIG_ATTR_BUSPOWERED | + USB_CONFIG_ATTR_SELF_POWERED), + .bMaxPower = USB_CONFIG_MAX_POWER, + }, + + .CCI_Interface = { + .bLength = sizeof(USB_Descriptor_Interface), + .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, + .bInterfaceNumber = 0x00, + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x01, + .bInterfaceClass = USB_INTERFACE_CLASS_CDC, + .bInterfaceSubClass = USB_INTERFACE_SUBCLASS_CDC_ACM, + .bInterfaceProtocol = 0x01, /* Common AT Commands */ + .iInterface = 0x00, + }, + + .CDC_Functional_IntHeader = { + .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2), + .bDescriptorType = 0x24, + .SubType = 0x00, + .Data = {0x01, 0x10}, + }, + + .CDC_Functional_CallManagement = { + .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2), + .bDescriptorType = 0x24, + .SubType = 0x01, + .Data = {0x03, 0x01}, + }, + + .CDC_Functional_ACM = { + .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(1), + .bDescriptorType = 0x24, + .SubType = 0x02, + .Data = {0x06}, + }, + + .CDC_Functional_Union = { + .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2), + .bDescriptorType = 0x24, + .SubType = 0x06, + .Data = {0x00, 0x01}, + }, + + .ManagementEndpoint = { + .bLength = sizeof(USB_Descriptor_Endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | + VCOM_NOTIFICATION_EPNUM), + .bmAttributes = EP_TYPE_INTERRUPT, + .wMaxPacketSize = VCOM_NOTIFICATION_EPSIZE, + .bInterval = 0xFF, + }, + + .DCI_Interface = { + .bLength = sizeof(USB_Descriptor_Interface), + .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, + .bInterfaceNumber = 0x01, + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x02, + .bInterfaceClass = USB_INTERFACE_CLASS_DIC, + .bInterfaceSubClass = 0x00, /* None */ + .bInterfaceProtocol = 0x00, /* None */ + .iInterface = 0x00, + }, + + .DataOutEndpoint = { + .bLength = sizeof(USB_Descriptor_Endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_OUT | VCOM_RX_EPNUM), + .bmAttributes = EP_TYPE_BULK, + .wMaxPacketSize = VCOM_RX_EPSIZE, + .bInterval = 0x00, + }, + + .DataInEndpoint = { + .bLength = sizeof(USB_Descriptor_Endpoint), + .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | VCOM_TX_EPNUM), + .bmAttributes = EP_TYPE_BULK, + .wMaxPacketSize = VCOM_TX_EPSIZE, + .bInterval = 0x00, + }, +}; + +/* + String Identifiers: + + we may choose to specify any or none of the following string + identifiers: + + iManufacturer: LeafLabs + iProduct: Maple + iSerialNumber: NONE + iConfiguration: NONE + iInterface(CCI): NONE + iInterface(DCI): NONE + + additionally we must provide the unicode language identifier, + which is 0x0409 for US English +*/ + +const uint8 usbVcomDescriptor_LangID[USB_DESCRIPTOR_STRING_LEN(1)] = { + USB_DESCRIPTOR_STRING_LEN(1), + USB_DESCRIPTOR_TYPE_STRING, + 0x09, + 0x04, +}; + +const uint8 usbVcomDescriptor_iManufacturer[USB_DESCRIPTOR_STRING_LEN(8)] = { + USB_DESCRIPTOR_STRING_LEN(8), + USB_DESCRIPTOR_TYPE_STRING, + 'L', 0, 'e', 0, 'a', 0, 'f', 0, + 'L', 0, 'a', 0, 'b', 0, 's', 0, +}; + +const uint8 usbVcomDescriptor_iProduct[USB_DESCRIPTOR_STRING_LEN(8)] = { + USB_DESCRIPTOR_STRING_LEN(8), + USB_DESCRIPTOR_TYPE_STRING, + 'M', 0, 'a', 0, 'p', 0, 'l', 0, + 'e', 0, ' ', 0, ' ', 0, ' ', 0 +}; + +ONE_DESCRIPTOR Device_Descriptor = { + (uint8*)&usbVcomDescriptor_Device, + sizeof(USB_Descriptor_Device) +}; + +ONE_DESCRIPTOR Config_Descriptor = { + (uint8*)&usbVcomDescriptor_Config, + sizeof(USB_Descriptor_Config) +}; + +ONE_DESCRIPTOR String_Descriptor[3] = { + {(uint8*)&usbVcomDescriptor_LangID, USB_DESCRIPTOR_STRING_LEN(1)}, + {(uint8*)&usbVcomDescriptor_iManufacturer,USB_DESCRIPTOR_STRING_LEN(8)}, + {(uint8*)&usbVcomDescriptor_iProduct, USB_DESCRIPTOR_STRING_LEN(8)} +}; + +uint8 last_request = 0; + +USB_Line_Coding line_coding = { + .bitrate = 115200, + .format = 0x00, /* stop bits-1 */ + .paritytype = 0x00, + .datatype = 0x08 +}; + +uint8 vcomBufferRx[VCOM_RX_BUFLEN]; +volatile uint32 countTx = 0; +volatile uint32 recvBufIn = 0; +volatile uint32 recvBufOut = 0; +volatile uint32 maxNewBytes = VCOM_RX_BUFLEN; +volatile uint32 newBytes = 0; +RESET_STATE reset_state = DTR_UNSET; +uint8 line_dtr_rts = 0; + +/* + * VCOM callbacks + */ + +void vcomDataTxCb(void) { + /* assumes tx transactions are atomic 64 bytes (nearly certain they are) */ + countTx = 0; +} + +#define EXC_RETURN 0xFFFFFFF9 +#define DEFAULT_CPSR 0x61000000 +void vcomDataRxCb(void) { + /* FIXME this is mad buggy */ + + /* setEPRxCount on the previous cycle should garuntee + we havnt received more bytes than we can fit */ + newBytes = usb_get_ep_rx_count(VCOM_RX_ENDP); + usb_set_ep_rx_stat(VCOM_RX_ENDP, USB_EP_STAT_RX_NAK); + + /* magic number, {0x31, 0x45, 0x41, 0x46} is "1EAF" */ + uint8 chkBuf[4]; + uint8 cmpBuf[4] = {0x31, 0x45, 0x41, 0x46}; + if (reset_state == DTR_NEGEDGE) { + reset_state = DTR_LOW; + + if (newBytes >= 4) { + unsigned int target = (unsigned int)usbWaitReset | 0x1; + + usb_copy_from_pma(chkBuf, 4, VCOM_RX_ADDR); + + int i; + USB_Bool cmpMatch = TRUE; + for (i = 0; i < 4; i++) { + if (chkBuf[i] != cmpBuf[i]) { + cmpMatch = FALSE; + } + } + + if (cmpMatch) { + asm volatile("mov r0, %[stack_top] \n\t" // Reset stack + "mov sp, r0 \n\t" + "mov r0, #1 \n\t" + "mov r1, %[target_addr] \n\t" + "mov r2, %[cpsr] \n\t" + "push {r2} \n\t" // Fake xPSR + "push {r1} \n\t" // PC target addr + "push {r0} \n\t" // Fake LR + "push {r0} \n\t" // Fake R12 + "push {r0} \n\t" // Fake R3 + "push {r0} \n\t" // Fake R2 + "push {r0} \n\t" // Fake R1 + "push {r0} \n\t" // Fake R0 + "mov lr, %[exc_return] \n\t" + "bx lr" + : + : [stack_top] "r" (STACK_TOP), + [target_addr] "r" (target), + [exc_return] "r" (EXC_RETURN), + [cpsr] "r" (DEFAULT_CPSR) + : "r0", "r1", "r2"); + /* should never get here */ + } + } + } + + usb_copy_from_pma(vcomBufferRx, newBytes, VCOM_RX_ADDR); +} + +void vcomManagementCb(void) { + /* unused. This enpoint would callback if we had sent a linestate + changed notification */ +} + +u8* vcomGetSetLineCoding(uint16 length) { + if (length == 0) { + pInformation->Ctrl_Info.Usb_wLength = sizeof(USB_Line_Coding); + } + return (uint8*)&line_coding; +} + +void vcomSetLineState(void) { +} + +RESULT usbPowerOn(void) { + USB_BASE->CNTR = USB_CNTR_FRES; + + wInterrupt_Mask = 0; + USB_BASE->CNTR = wInterrupt_Mask; + USB_BASE->ISTR = 0; + wInterrupt_Mask = USB_CNTR_RESETM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; + USB_BASE->CNTR = wInterrupt_Mask; + + return USB_SUCCESS; +} + +void usbInit(void) { + pInformation->Current_Configuration = 0; + usbPowerOn(); + + USB_BASE->ISTR = 0; + wInterrupt_Mask = ISR_MSK; + USB_BASE->CNTR = wInterrupt_Mask; + + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); + bDeviceState = UNCONNECTED; +} + +void usbReset(void) { + pInformation->Current_Configuration = 0; + + /* current feature is current bmAttributes */ + pInformation->Current_Feature = (USB_CONFIG_ATTR_BUSPOWERED | + USB_CONFIG_ATTR_SELF_POWERED); + + USB_BASE->BTABLE = USB_BTABLE_ADDRESS; + + /* setup control endpoint 0 */ + usb_set_ep_type(USB_EP0, USB_EP_EP_TYPE_CONTROL); + usb_set_ep_tx_stat(USB_EP0, USB_EP_STAT_TX_STALL); + usb_set_ep_rx_addr(USB_EP0, VCOM_CTRL_RX_ADDR); + usb_set_ep_tx_addr(USB_EP0, VCOM_CTRL_TX_ADDR); + usb_clear_status_out(USB_EP0); + + usb_set_ep_rx_count(USB_EP0, pProperty->MaxPacketSize); + usb_set_ep_rx_stat(USB_EP0, USB_EP_STAT_RX_VALID); + + /* setup management endpoint 1 */ + usb_set_ep_type(VCOM_NOTIFICATION_ENDP, USB_EP_EP_TYPE_INTERRUPT); + usb_set_ep_tx_addr(VCOM_NOTIFICATION_ENDP, VCOM_NOTIFICATION_ADDR); + usb_set_ep_tx_stat(VCOM_NOTIFICATION_ENDP, USB_EP_STAT_TX_NAK); + usb_set_ep_rx_stat(VCOM_NOTIFICATION_ENDP, USB_EP_STAT_RX_DISABLED); + + /* TODO figure out differences in style between RX/TX EP setup */ + + /* set up data endpoint OUT (RX) */ + usb_set_ep_type(VCOM_RX_ENDP, USB_EP_EP_TYPE_BULK); + usb_set_ep_rx_addr(VCOM_RX_ENDP, 0x110); + usb_set_ep_rx_count(VCOM_RX_ENDP, 64); + usb_set_ep_rx_stat(VCOM_RX_ENDP, USB_EP_STAT_RX_VALID); + + /* set up data endpoint IN (TX) */ + usb_set_ep_type(VCOM_TX_ENDP, USB_EP_EP_TYPE_BULK); + usb_set_ep_tx_addr(VCOM_TX_ENDP, VCOM_TX_ADDR); + usb_set_ep_tx_stat(VCOM_TX_ENDP, USB_EP_STAT_TX_NAK); + usb_set_ep_rx_stat(VCOM_TX_ENDP, USB_EP_STAT_RX_DISABLED); + + bDeviceState = ATTACHED; + SetDeviceAddress(0); + + /* reset the rx fifo */ + recvBufIn = 0; + recvBufOut = 0; + maxNewBytes = VCOM_RX_EPSIZE; + countTx = 0; +} + +void usbStatusIn(void) { + /* adjust the usart line coding + if we wish to couple the CDC line coding + with the real usart port */ +} + +void usbStatusOut(void) { +} + +RESULT usbDataSetup(uint8 request) { + uint8 *(*CopyRoutine)(uint16); + CopyRoutine = NULL; + + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { + switch (request) { + case (GET_LINE_CODING): + CopyRoutine = vcomGetSetLineCoding; + last_request = GET_LINE_CODING; + break; + case (SET_LINE_CODING): + CopyRoutine = vcomGetSetLineCoding; + last_request = SET_LINE_CODING; + break; + default: + break; + } + } + + if (CopyRoutine == NULL) { + return USB_UNSUPPORT; + } + + pInformation->Ctrl_Info.CopyData = CopyRoutine; + pInformation->Ctrl_Info.Usb_wOffset = 0; + (*CopyRoutine)(0); + return USB_SUCCESS; +} + +RESULT usbNoDataSetup(u8 request) { + uint8 new_signal; + + /* we support set com feature but dont handle it */ + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { + + switch (request) { + case (SET_COMM_FEATURE): + return USB_SUCCESS; + case (SET_CONTROL_LINE_STATE): + /* to reset the board, pull both dtr and rts low + then pulse dtr by itself */ + new_signal = (pInformation->USBwValues.bw.bb0 & + (CONTROL_LINE_DTR | CONTROL_LINE_RTS)); + line_dtr_rts = new_signal & 0x03; + + switch (reset_state) { + /* no default, covered enum */ + case DTR_UNSET: + if ((new_signal & CONTROL_LINE_DTR) == 0 ) { + reset_state = DTR_LOW; + } else { + reset_state = DTR_HIGH; + } + break; + + case DTR_HIGH: + if ((new_signal & CONTROL_LINE_DTR) == 0 ) { + reset_state = DTR_NEGEDGE; + } else { + reset_state = DTR_HIGH; + } + break; + + case DTR_NEGEDGE: + if ((new_signal & CONTROL_LINE_DTR) == 0 ) { + reset_state = DTR_LOW; + } else { + reset_state = DTR_HIGH; + } + break; + + case DTR_LOW: + if ((new_signal & CONTROL_LINE_DTR) == 0 ) { + reset_state = DTR_LOW; + } else { + reset_state = DTR_HIGH; + } + break; + } + + return USB_SUCCESS; + } + } + return USB_UNSUPPORT; +} + +RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting) { + if (alt_setting > 0) { + return USB_UNSUPPORT; + } else if (interface > 1) { + return USB_UNSUPPORT; + } + + return USB_SUCCESS; +} + +u8* usbGetDeviceDescriptor(u16 length) { + return Standard_GetDescriptorData(length, &Device_Descriptor); +} + +u8* usbGetConfigDescriptor(u16 length) { + return Standard_GetDescriptorData(length, &Config_Descriptor); +} + +u8* usbGetStringDescriptor(u16 length) { + uint8 wValue0 = pInformation->USBwValue0; + + if (wValue0 > 2) { + return NULL; + } + return Standard_GetDescriptorData(length, &String_Descriptor[wValue0]); +} + +/* internal callbacks to respond to standard requests */ +void usbSetConfiguration(void) { + if (pInformation->Current_Configuration != 0) { + bDeviceState = CONFIGURED; + } +} + +void usbSetDeviceAddress(void) { + bDeviceState = ADDRESSED; +} + +/* + * Globals required by usb_lib/ + */ + +DEVICE Device_Table = + {NUM_ENDPTS, + 1}; + +DEVICE_PROP Device_Property = + {usbInit, + usbReset, + usbStatusIn, + usbStatusOut, + usbDataSetup, + usbNoDataSetup, + usbGetInterfaceSetting, + usbGetDeviceDescriptor, + usbGetConfigDescriptor, + usbGetStringDescriptor, + 0, + bMaxPacketSize}; + +USER_STANDARD_REQUESTS User_Standard_Requests = + {NOP_Process, + usbSetConfiguration, + NOP_Process, + NOP_Process, + NOP_Process, + NOP_Process, + NOP_Process, + NOP_Process, + usbSetDeviceAddress}; + +void (*pEpInt_IN[7])(void) = + {vcomDataTxCb, + vcomManagementCb, + NOP_Process, + NOP_Process, + NOP_Process, + NOP_Process, + NOP_Process}; + +void (*pEpInt_OUT[7])(void) = + {NOP_Process, + NOP_Process, + vcomDataRxCb, + NOP_Process, + NOP_Process, + NOP_Process, + NOP_Process}; + +/* + * CDC ACM routines + */ + +void usb_cdcacm_enable(gpio_dev *disc_dev, uint8 disc_bit) { + /* Present ourselves to the host */ + gpio_set_mode(disc_dev, disc_bit, GPIO_OUTPUT_PP); + gpio_write_bit(disc_dev, disc_bit, 0); // presents us to the host + + /* initialize USB peripheral */ + usb_init_usblib(&Device_Property, &User_Standard_Requests); +} + +void usb_cdcacm_disable(gpio_dev *disc_dev, uint8 disc_bit) { + // These are just guesses about how to do this, but it seems to work. + // TODO: verify this with USB spec + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); + gpio_write_bit(disc_dev, disc_bit, 1); +} + +void usb_cdcacm_putc(char ch) { + while (!usb_cdcacm_tx((uint8*)&ch, 1)) + ; +} + +/* This function is non-blocking. + * + * It copies data from a usercode buffer into the USB peripheral TX + * buffer and return the number placed in that buffer. + */ +uint32 usb_cdcacm_tx(const uint8* buf, uint32 len) { + /* Last transmission hasn't finished, abort */ + if (countTx) { + return 0; + } + + // We can only put VCOM_TX_EPSIZE bytes in the buffer + /* FIXME then why are we only copying half as many? */ + if (len > VCOM_TX_EPSIZE / 2) { + len = VCOM_TX_EPSIZE / 2; + } + + // Try to load some bytes if we can + if (len) { + usb_copy_to_pma(buf, len, VCOM_TX_ADDR); + usb_set_ep_tx_count(VCOM_TX_ENDP, len); + countTx += len; + usb_set_ep_tx_stat(VCOM_TX_ENDP, USB_EP_STAT_TX_VALID); + } + + return len; +} + +/* returns the number of available bytes are in the recv FIFO */ +uint32 usb_cdcacm_data_available(void) { + return newBytes; +} + +uint16 usb_cdcacm_get_pending() { + return countTx; +} + +/* Nonblocking byte receive. + * + * Copies up to len bytes from our private data buffer (*NOT* the PMA) + * into buf and deq's the FIFO. */ +uint32 usb_cdcacm_rx(uint8* buf, uint32 len) { + static int offset = 0; + int i; + + if (len > newBytes) { + len = newBytes; + } + + for (i = 0; i < len; i++) { + buf[i] = vcomBufferRx[i + offset]; + } + + newBytes -= len; + offset += len; + + /* Re-enable the RX endpoint, which we had set to receive 0 bytes */ + if (newBytes == 0) { + usb_set_ep_rx_count(VCOM_RX_ENDP, VCOM_RX_EPSIZE); + usb_set_ep_rx_stat(VCOM_RX_ENDP, USB_EP_STAT_RX_VALID); + offset = 0; + } + + return len; +} + +uint8 usb_cdcacm_get_dtr() { + return ((line_dtr_rts & CONTROL_LINE_DTR) != 0); +} + +uint8 usb_cdcacm_get_rts() { + return ((line_dtr_rts & CONTROL_LINE_RTS) != 0); +} diff --git a/libmaple/usb/usb_cdcacm.h b/libmaple/usb/usb_cdcacm.h new file mode 100644 index 0000000..8ca1c68 --- /dev/null +++ b/libmaple/usb/usb_cdcacm.h @@ -0,0 +1,59 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file usb_cdcacm.h + * @brief USB CDC ACM (virtual serial terminal) support + */ + +#ifndef _USB_CDCACM_H_ +#define _USB_CDCACM_H_ + +#include "libmaple_types.h" +#include "gpio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void usb_cdcacm_enable(gpio_dev*, uint8); +void usb_cdcacm_disable(gpio_dev*, uint8); + +void usb_cdcacm_putc(char ch); +uint32 usb_cdcacm_tx(const uint8* buf, uint32 len); +uint32 usb_cdcacm_rx(uint8* buf, uint32 len); + +uint32 usb_cdcacm_data_available(void); /* in RX buffer */ +uint16 usb_cdcacm_get_pending(void); + +uint8 usb_cdcacm_get_dtr(void); +uint8 usb_cdcacm_get_rts(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/usb/usb_config.h b/libmaple/usb/usb_config.h index 9facb96..5adfdd4 100644 --- a/libmaple/usb/usb_config.h +++ b/libmaple/usb/usb_config.h @@ -27,73 +27,11 @@ #ifndef __USB_CONFIG_H #define __USB_CONFIG_H -/****************************************************************************** - ****************************************************************************** - *** - *** HACK ALERT - *** - *** FIXME FIXME FIXME FIXME - *** - *** A bunch of board-specific #defines that are only used by the - *** USB routines got put into libmaple.h for what appear to be - *** historical reasons. I'm [mbolivar] putting them in here for - *** now, so that we can treat the usb/ directory as a black box, - *** freeing the rest of libmaple/ to be implemented as a - *** general-purpose STM32 library. All of this REALLY needs to get - *** moved into wirish when we get a chance to redo the USB stack. - *** - ****************************************************************************** - *****************************************************************************/ - -#define VCOM_ID_VENDOR 0x1EAF -#define VCOM_ID_PRODUCT 0x0004 #define RESET_DELAY (100000) #define USB_CONFIG_MAX_POWER (100 >> 1) -#if !(defined(BOARD_maple) || defined(BOARD_maple_RET6) || \ - defined(BOARD_maple_mini) || defined(BOARD_maple_native)) - -#warning ("Warning! The USB stack relies on LeafLabs board-specific " \ - "configuration right now. If you want, you can pretend " \ - "you're one of our boards; i.e., #define BOARD_maple, " \ - "BOARD_maple_mini, etc. according to what matches your MCU " \ - "best. You should also take a look at " \ - "libmaple/usb/descriptors.c; " \ - "we make some assumptions there that you probably won't like.") - -#endif - -/****************************************************************************** - ****************************************************************************** - *** - *** END HACK - *** - ****************************************************************************** - *****************************************************************************/ - - /* choose addresses to give endpoints the max 64 byte buffers */ #define USB_BTABLE_ADDRESS 0x00 -#define VCOM_CTRL_EPNUM 0x00 -#define VCOM_CTRL_RX_ADDR 0x40 -#define VCOM_CTRL_TX_ADDR 0x80 -#define VCOM_CTRL_EPSIZE 0x40 - -#define VCOM_TX_ENDP 1 -#define VCOM_TX_EPNUM 0x01 -#define VCOM_TX_ADDR 0xC0 -#define VCOM_TX_EPSIZE 0x40 - -#define VCOM_NOTIFICATION_ENDP 2 -#define VCOM_NOTIFICATION_EPNUM 0x02 -#define VCOM_NOTIFICATION_ADDR 0x100 -#define VCOM_NOTIFICATION_EPSIZE 0x40 - -#define VCOM_RX_ENDP 3 -#define VCOM_RX_EPNUM 0x03 -#define VCOM_RX_ADDR 0x110 -#define VCOM_RX_EPSIZE 0x40 -#define VCOM_RX_BUFLEN (VCOM_RX_EPSIZE*3) #define bMaxPacketSize 0x40 /* 64B, maximum for USB FS Devices */ diff --git a/libmaple/usb/usb_lib_globals.h b/libmaple/usb/usb_lib_globals.h new file mode 100644 index 0000000..854cb12 --- /dev/null +++ b/libmaple/usb/usb_lib_globals.h @@ -0,0 +1,55 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +#ifndef _USB_LIB_GLOBALS_H_ +#define _USB_LIB_GLOBALS_H_ + +#include "usb_type.h" +#include "usb_core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern void (*pEpInt_IN[7])(void); +extern void (*pEpInt_OUT[7])(void); +extern DEVICE_PROP Device_Property; +extern USER_STANDARD_REQUESTS User_Standard_Requests; +extern DEVICE Device_Table; +extern DEVICE_INFO Device_Info; +extern u16 SaveRState; +extern u16 SaveTState; +extern DEVICE_INFO* pInformation; +extern DEVICE_PROP* pProperty; +extern USER_STANDARD_REQUESTS *pUser_Standard_Requests; +extern u16 SaveState ; +extern u16 wInterrupt_Mask; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/usb/usb_reg_map.c b/libmaple/usb/usb_reg_map.c index 75562e1..75562e1 100755..100644 --- a/libmaple/usb/usb_reg_map.c +++ b/libmaple/usb/usb_reg_map.c |