Harald Welte has submitted this change and it was merged. ( 
https://gerrit.osmocom.org/13997 )

Change subject: Add a new (skeleton of a) USB CCID class driver
......................................................................

Add a new (skeleton of a) USB CCID class driver

This tries to implement a USB CCID (Chip Card Interface Device) Class
core driver in "ASF4 style".  Code is currently mainly untested.

Change-Id: Ia4d8a6cdc3de26fdc83dcbf89db894b513915a9a
---
M sysmoOCTSIM/gcc/Makefile
A sysmoOCTSIM/usb/class/ccid/device/ccid_df.c
A sysmoOCTSIM/usb/class/ccid/device/ccid_df.h
3 files changed, 314 insertions(+), 3 deletions(-)



diff --git a/sysmoOCTSIM/gcc/Makefile b/sysmoOCTSIM/gcc/Makefile
index 2dba3e3..080aa41 100644
--- a/sysmoOCTSIM/gcc/Makefile
+++ b/sysmoOCTSIM/gcc/Makefile
@@ -2,6 +2,8 @@
 # Automatically-generated file. Do not edit!
 
################################################################################

+EXTRA_CFLAGS=-I/usr/local/arm-none-eabi/include -I../../ccid
+
 ifdef SystemRoot
        SHELL = cmd.exe
        MK_DIR = mkdir
@@ -35,6 +37,7 @@
 usb \
 hpl/dmac \
 usb/class/cdc/device \
+usb/class/ccid/device \
 stdio_redirect \
 hal/utils/src \
 hpl/usb \
@@ -56,6 +59,7 @@
 hpl/core/hpl_core_m4.o \
 hal/src/hal_cache.o \
 usb/class/cdc/device/cdcdf_acm.o \
+usb/class/ccid/device/ccid_df.o \
 hal/utils/src/utils_syscalls.o \
 stdio_redirect/gcc/read.o \
 gcc/system_same54.o \
@@ -107,6 +111,7 @@
 "hpl/core/hpl_core_m4.o" \
 "hal/src/hal_cache.o" \
 "usb/class/cdc/device/cdcdf_acm.o" \
+"usb/class/ccid/device/ccid_df.o" \
 "hal/utils/src/utils_syscalls.o" \
 "stdio_redirect/gcc/read.o" \
 "gcc/system_same54.o" \
@@ -250,7 +255,7 @@
        @echo ARM/GNU C Compiler
        $(QUOTE)arm-none-eabi-gcc$(QUOTE) -x c -mthumb -DDEBUG -Os 
-ffunction-sections -mlong-calls -g3 -Wall -c -std=gnu99 \
 -D__SAME54N19A__ -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 \
--I"../" -I"../config" -I"../hal/include" -I"../hal/utils/include" 
-I"../hpl/cmcc" -I"../hpl/core" -I"../hpl/dmac" -I"../hpl/gclk" -I"../hpl/mclk" 
-I"../hpl/osc32kctrl" -I"../hpl/oscctrl" -I"../hpl/pm" -I"../hpl/port" 
-I"../hpl/ramecc" -I"../hpl/sercom" -I"../hpl/usb" -I"../hri" -I"../" 
-I"../config" -I"../usb" -I"../usb/class/cdc" -I"../usb/class/cdc/device" 
-I"../usb/device" -I"../" -I"../config" -I"../stdio_redirect" -I"../" 
-I"../dma_m2m" -I"../" -I"../CMSIS/Core/Include" -I"../include"  \
+-I"../" -I"../config" -I"../hal/include" -I"../hal/utils/include" 
-I"../hpl/cmcc" -I"../hpl/core" -I"../hpl/dmac" -I"../hpl/gclk" -I"../hpl/mclk" 
-I"../hpl/osc32kctrl" -I"../hpl/oscctrl" -I"../hpl/pm" -I"../hpl/port" 
-I"../hpl/ramecc" -I"../hpl/sercom" -I"../hpl/usb" -I"../hri" -I"../" 
-I"../config" -I"../usb" -I"../usb/class/cdc" -I"../usb/class/cdc/device" 
-I"../usb/class/ccid" -I"../usb/class/ccid/device" -I"../usb/device" -I"../" 
-I"../config" -I"../stdio_redirect" -I"../" -I"../dma_m2m" -I"../" 
-I"../CMSIS/Core/Include" -I"../include"  \
 -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)"  -o "$@" "$<"
        @echo Finished building: $<

@@ -259,7 +264,7 @@
        @echo ARM/GNU Assembler
        $(QUOTE)arm-none-eabi-as$(QUOTE) -x c -mthumb -DDEBUG -Os 
-ffunction-sections -mlong-calls -g3 -Wall -c -std=gnu99 \
 -D__SAME54N19A__ -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 \
--I"../" -I"../config" -I"../hal/include" -I"../hal/utils/include" 
-I"../hpl/cmcc" -I"../hpl/core" -I"../hpl/dmac" -I"../hpl/gclk" -I"../hpl/mclk" 
-I"../hpl/osc32kctrl" -I"../hpl/oscctrl" -I"../hpl/pm" -I"../hpl/port" 
-I"../hpl/ramecc" -I"../hpl/sercom" -I"../hpl/usb" -I"../hri" -I"../" 
-I"../config" -I"../usb" -I"../usb/class/cdc" -I"../usb/class/cdc/device" 
-I"../usb/device" -I"../" -I"../config" -I"../stdio_redirect" -I"../" 
-I"../dma_m2m" -I"../" -I"../CMSIS/Core/Include" -I"../include"  \
+-I"../" -I"../config" -I"../hal/include" -I"../hal/utils/include" 
-I"../hpl/cmcc" -I"../hpl/core" -I"../hpl/dmac" -I"../hpl/gclk" -I"../hpl/mclk" 
-I"../hpl/osc32kctrl" -I"../hpl/oscctrl" -I"../hpl/pm" -I"../hpl/port" 
-I"../hpl/ramecc" -I"../hpl/sercom" -I"../hpl/usb" -I"../hri" -I"../" 
-I"../config" -I"../usb" -I"../usb/class/cdc" -I"../usb/class/cdc/device" 
-I"../usb/class/ccid" -I"../usb/class/ccid/device" -I"../usb/device" -I"../" 
-I"../config" -I"../stdio_redirect" -I"../" -I"../dma_m2m" -I"../" 
-I"../CMSIS/Core/Include" -I"../include"  \
 -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)"  -o "$@" "$<"
        @echo Finished building: $<

@@ -268,7 +273,7 @@
        @echo ARM/GNU Preprocessing Assembler
        $(QUOTE)arm-none-eabi-gcc$(QUOTE) -x c -mthumb -DDEBUG -Os 
-ffunction-sections -mlong-calls -g3 -Wall -c -std=gnu99 \
 -D__SAME54N19A__ -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 \
--I"../" -I"../config" -I"../hal/include" -I"../hal/utils/include" 
-I"../hpl/cmcc" -I"../hpl/core" -I"../hpl/dmac" -I"../hpl/gclk" -I"../hpl/mclk" 
-I"../hpl/osc32kctrl" -I"../hpl/oscctrl" -I"../hpl/pm" -I"../hpl/port" 
-I"../hpl/ramecc" -I"../hpl/sercom" -I"../hpl/usb" -I"../hri" -I"../" 
-I"../config" -I"../usb" -I"../usb/class/cdc" -I"../usb/class/cdc/device" 
-I"../usb/device" -I"../" -I"../config" -I"../stdio_redirect" -I"../" 
-I"../dma_m2m" -I"../" -I"../CMSIS/Core/Include" -I"../include"  \
+-I"../" -I"../config" -I"../hal/include" -I"../hal/utils/include" 
-I"../hpl/cmcc" -I"../hpl/core" -I"../hpl/dmac" -I"../hpl/gclk" -I"../hpl/mclk" 
-I"../hpl/osc32kctrl" -I"../hpl/oscctrl" -I"../hpl/pm" -I"../hpl/port" 
-I"../hpl/ramecc" -I"../hpl/sercom" -I"../hpl/usb" -I"../hri" -I"../" 
-I"../config" -I"../usb" -I"../usb/class/cdc" -I"../usb/class/cdc/device" 
-I"../usb/class/ccid" -I"../usb/class/ccid/device" -I"../usb/device" -I"../" 
-I"../config" -I"../stdio_redirect" -I"../" -I"../dma_m2m" -I"../" 
-I"../CMSIS/Core/Include" -I"../include"  \
 -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)"  -o "$@" "$<"
        @echo Finished building: $<

diff --git a/sysmoOCTSIM/usb/class/ccid/device/ccid_df.c 
b/sysmoOCTSIM/usb/class/ccid/device/ccid_df.c
new file mode 100644
index 0000000..018208a
--- /dev/null
+++ b/sysmoOCTSIM/usb/class/ccid/device/ccid_df.c
@@ -0,0 +1,289 @@
+/**
+ * \file
+ *
+ * \brief USB Device Stack CCID Function Implementation.
+ *
+ * Copyroght (c) 2019 by Harald Welte <lafo...@gnumonks.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
+ */
+
+#include "ccid_df.h"
+#include "ccid_proto.h"
+#include "usb_includes.h"
+
+#ifndef USB_CLASS_CCID
+#define        USB_CLASS_CCID  11
+#endif
+
+struct ccid_df_func_data {
+       uint8_t func_iface;     /*!< interface number */
+       uint8_t func_ep_in;     /*!< IN endpoint number */
+       uint8_t func_ep_out;    /*!< OUT endpoint number */
+       uint8_t func_ep_irq;    /*!< IRQ endpoint number */
+       bool enabled;           /*!< is this driver/function enabled? */
+       const struct usb_ccid_class_descriptor *ccid_cd;
+};
+
+static struct usbdf_driver _ccid_df;
+static struct ccid_df_func_data _ccid_df_funcd;
+
+/* FIXME: make those configurable, ensure they're sized according to
+ * bNumClockSupported / bNumDataRatesSupported */
+static uint32_t ccid_clock_frequencies[] = { LE32(20000) };
+static uint32_t ccid_baud_rates[] = { LE32(9600) };
+
+static int32_t ccid_df_enable(struct usbdf_driver *drv, struct 
usbd_descriptors *desc)
+{
+       struct ccid_df_func_data *func_data = (struct ccid_df_func_data 
*)(drv->func_data);
+       usb_iface_desc_t ifc_desc;
+       uint8_t *ifc, *ep;
+
+       ifc = desc->sod;
+       /* FIXME: iterate over multiple interfaces? */
+
+       if (!ifc)
+               return ERR_NOT_FOUND;
+
+       ifc_desc.bInterfaceNumber = ifc[2];
+       ifc_desc.bInterfaceClass = ifc[5];
+
+       if (ifc_desc.bInterfaceClass != USB_CLASS_CCID)
+               return ERR_NOT_FOUND;
+
+       if (func_data->func_iface == ifc_desc.bInterfaceNumber)
+               return ERR_ALREADY_INITIALIZED;
+       else if (func_data->func_iface != 0xff)
+               return ERR_NO_RESOURCE;
+
+       func_data->func_iface = ifc_desc.bInterfaceNumber;
+
+       ep = usb_find_desc(ifc, desc->eod, USB_DT_ENDPOINT);
+       while (NULL != ep) {
+               usb_ep_desc_t ep_desc;
+               ep_desc.bEndpointAddress = ep[2];
+               ep_desc.bmAttributes = ep[3];
+               ep_desc.wMaxPacketSize = usb_get_u16(ep + 4);
+               if (usb_d_ep_init(ep_desc.bEndpointAddress, 
ep_desc.bmAttributes, ep_desc.wMaxPacketSize))
+                       return ERR_NOT_INITIALIZED;
+               if (ep_desc.bEndpointAddress & USB_EP_DIR_IN) {
+                       if ((ep_desc.bmAttributes & USB_EP_XTYPE_MASK) == 
USB_EP_XTYPE_INTERRUPT)
+                               func_data->func_ep_irq = 
ep_desc.bEndpointAddress;
+                       else
+                               func_data->func_ep_in = 
ep_desc.bEndpointAddress;
+               } else {
+                       func_data->func_ep_out = ep_desc.bEndpointAddress;
+               }
+               usb_d_ep_enable(ep_desc.bEndpointAddress);
+               desc->sod = ep;
+               ep = usb_find_ep_desc(usb_desc_next(desc->sod), desc->eod);
+       }
+
+       ASSERT(func_data->func_ep_irq);
+       ASSERT(func_data->func_ep_in);
+       ASSERT(func_data->func_ep_out);
+
+       _ccid_df_funcd.enabled = true;
+       return ERR_NONE;
+}
+
+static int32_t ccid_df_disable(struct usbdf_driver *drv, struct 
usbd_descriptors *desc)
+{
+       struct ccid_df_func_data *func_data = (struct ccid_df_func_data 
*)(drv->func_data);
+       usb_iface_desc_t ifc_desc;
+
+       if (desc) {
+               ifc_desc.bInterfaceClass = desc->sod[5];
+               if (ifc_desc.bInterfaceClass != USB_CLASS_CCID)
+                       return ERR_NOT_FOUND;
+       }
+
+       func_data->func_iface = 0xff;
+       if (func_data->func_ep_in != 0xff) {
+               func_data->func_ep_in = 0xff;
+               usb_d_ep_deinit(func_data->func_ep_in);
+       }
+       if (func_data->func_ep_out != 0xff) {
+               func_data->func_ep_out = 0xff;
+               usb_d_ep_deinit(func_data->func_ep_out);
+       }
+       if (func_data->func_ep_irq != 0xff) {
+               func_data->func_ep_irq = 0xff;
+               usb_d_ep_deinit(func_data->func_ep_irq);
+       }
+
+       _ccid_df_funcd.enabled = true;
+       return ERR_NONE;
+}
+
+/*! \brief CCID Control Function (callback with USB core) */
+static int32_t ccid_df_ctrl(struct usbdf_driver *drv, enum usbdf_control ctrl, 
void *param)
+{
+       switch (ctrl) {
+       case USBDF_ENABLE:
+               return ccid_df_enable(drv, (struct usbd_descriptors *)param);
+       case USBDF_DISABLE:
+               return ccid_df_disable(drv, (struct usbd_descriptors *)param);
+       case USBDF_GET_IFACE:
+               return ERR_UNSUPPORTED_OP;
+       default:
+               return ERR_INVALID_ARG;
+       }
+}
+
+/* Section 5.3.1: ABORT */
+static int32_t ccid_df_ctrl_req_ccid_abort(uint8_t ep, struct usb_req *req,
+                                          enum usb_ctrl_stage stage)
+{
+       const struct usb_ccid_class_descriptor *ccid_cd = 
_ccid_df_funcd.ccid_cd;
+       uint8_t slot_nr = req->wValue & 0xff;
+
+       if (slot_nr > ccid_cd->bMaxSlotIndex)
+               return ERR_INVALID_ARG;
+       slot_nr = req->wValue;
+
+       /* FIXME: Implement Abort handling, particularly in combination with
+        * the PC_to_RDR_Abort on the OUT EP */
+       return ERR_NONE;
+}
+
+/* Section 5.3.2: return array of DWORD containing clock frequencies in kHz */
+static int32_t ccid_df_ctrl_req_ccid_get_clock_freq(uint8_t ep, struct usb_req 
*req,
+                                                   enum usb_ctrl_stage stage)
+{
+       const struct usb_ccid_class_descriptor *ccid_cd = 
_ccid_df_funcd.ccid_cd;
+
+       if (stage != USB_DATA_STAGE)
+               return ERR_NONE;
+
+       if (req->wLength != ccid_cd->bNumClockSupported * sizeof(uint32_t))
+               return ERR_INVALID_DATA;
+
+       return usbdc_xfer(ep, (uint8_t *)ccid_clock_frequencies, req->wLength, 
false);
+}
+
+/* Section 5.3.3: return array of DWORD containing data rates in bps */
+static int32_t ccid_df_ctrl_req_ccid_get_data_rates(uint8_t ep, struct usb_req 
*req,
+                                                   enum usb_ctrl_stage stage)
+{
+       const struct usb_ccid_class_descriptor *ccid_cd = 
_ccid_df_funcd.ccid_cd;
+
+       if (stage != USB_DATA_STAGE)
+               return ERR_NONE;
+
+       if (req->wLength != ccid_cd->bNumDataRatesSupported * sizeof(uint32_t))
+               return ERR_INVALID_DATA;
+
+       return usbdc_xfer(ep, (uint8_t *)ccid_baud_rates, req->wLength, false);
+}
+
+
+/* process a control endpoint request */
+static int32_t ccid_df_ctrl_req(uint8_t ep, struct usb_req *req, enum 
usb_ctrl_stage stage)
+{
+       /* verify this is a class-specific request */
+       if (0x01 != ((req->bmRequestType >> 5) & 0x03))
+                return ERR_NOT_FOUND;
+
+       /* Verify req->wIndex == interface */
+       if (req->wIndex != _ccid_df_funcd.func_iface)
+                return ERR_NOT_FOUND;
+
+       switch (req->bRequest) {
+       case CLASS_SPEC_CCID_ABORT:
+               if (req->bmRequestType & USB_EP_DIR_IN)
+                       return ERR_INVALID_ARG;
+               return ccid_df_ctrl_req_ccid_abort(ep, req, stage);
+       case CLASS_SPEC_CCID_GET_CLOCK_FREQ:
+               if (!(req->bmRequestType & USB_EP_DIR_IN))
+                       return ERR_INVALID_ARG;
+               return ccid_df_ctrl_req_ccid_get_clock_freq(ep, req, stage);
+       case CLASS_SPEC_CCID_GET_DATA_RATES:
+               if (!(req->bmRequestType & USB_EP_DIR_IN))
+                       return ERR_INVALID_ARG;
+               return ccid_df_ctrl_req_ccid_get_data_rates(ep, req, stage);
+       default:
+               return ERR_NOT_FOUND;
+       }
+}
+
+static struct usbdc_handler ccid_df_req_h = { NULL, (FUNC_PTR) 
ccid_df_ctrl_req };
+
+int32_t ccid_df_init(void)
+{
+       if (usbdc_get_state() > USBD_S_POWER)
+               return ERR_DENIED;
+
+       _ccid_df.ctrl = ccid_df_ctrl;
+       _ccid_df.func_data = &_ccid_df_funcd;
+
+       /* register the actual USB Function */
+       usbdc_register_function(&_ccid_df);
+       /* register the call-back for control endpoint handling */
+       usbdc_register_handler(USBDC_HDL_REQ, &ccid_df_req_h);
+
+       return ERR_NONE;
+}
+
+void ccid_df_deinit(void)
+{
+       usb_d_ep_deinit(_ccid_df_funcd.func_ep_in);
+       usb_d_ep_deinit(_ccid_df_funcd.func_ep_out);
+       usb_d_ep_deinit(_ccid_df_funcd.func_ep_irq);
+}
+
+int32_t ccid_df_read_out(uint8_t *buf, uint32_t size)
+{
+       if (!ccid_df_is_enabled())
+               return ERR_DENIED;
+       return usbdc_xfer(_ccid_df_funcd.func_ep_out, buf, size, false);
+}
+
+int32_t ccid_df_write_in(uint8_t *buf, uint32_t size)
+{
+       if (!ccid_df_is_enabled())
+               return ERR_DENIED;
+       return usbdc_xfer(_ccid_df_funcd.func_ep_in, buf, size, true);
+}
+
+int32_t ccid_df_write_irq(uint8_t *buf, uint32_t size)
+{
+       if (!ccid_df_is_enabled())
+               return ERR_DENIED;
+       return usbdc_xfer(_ccid_df_funcd.func_ep_irq, buf, size, true);
+}
+
+int32_t ccid_df_register_callback(enum ccid_df_cb_type cb_type, FUNC_PTR func)
+{
+       switch (cb_type) {
+       case CCID_DF_CB_READ_OUT:
+               usb_d_ep_register_callback(_ccid_df_funcd.func_ep_out, 
USB_D_EP_CB_XFER, func);
+               break;
+       case CCID_DF_CB_WRITE_IN:
+               usb_d_ep_register_callback(_ccid_df_funcd.func_ep_in, 
USB_D_EP_CB_XFER, func);
+               break;
+       case CCID_DF_CB_WRITE_IRQ:
+               usb_d_ep_register_callback(_ccid_df_funcd.func_ep_irq, 
USB_D_EP_CB_XFER, func);
+               break;
+       default:
+               return ERR_INVALID_ARG;
+       }
+       return ERR_NONE;
+}
+
+bool ccid_df_is_enabled(void)
+{
+       return _ccid_df_funcd.enabled;
+}
diff --git a/sysmoOCTSIM/usb/class/ccid/device/ccid_df.h 
b/sysmoOCTSIM/usb/class/ccid/device/ccid_df.h
new file mode 100644
index 0000000..21fa99e
--- /dev/null
+++ b/sysmoOCTSIM/usb/class/ccid/device/ccid_df.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "usbdc.h"
+
+enum ccid_df_cb_type {
+       CCID_DF_CB_READ_OUT,
+       CCID_DF_CB_WRITE_IN,
+       CCID_DF_CB_WRITE_IRQ,
+};
+
+int32_t ccid_df_init(void);
+void ccid_df_deinit(void);
+int32_t ccid_df_read_out(uint8_t *buf, uint32_t size);
+int32_t ccid_df_write_in(uint8_t *buf, uint32_t size);
+int32_t ccid_df_write_irq(uint8_t *buf, uint32_t size);
+int32_t ccid_df_register_callback(enum ccid_df_cb_type cb_type, FUNC_PTR ptr);
+bool ccid_df_is_enabled(void);

--
To view, visit https://gerrit.osmocom.org/13997
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-ccid-firmware
Gerrit-Branch: master
Gerrit-MessageType: merged
Gerrit-Change-Id: Ia4d8a6cdc3de26fdc83dcbf89db894b513915a9a
Gerrit-Change-Number: 13997
Gerrit-PatchSet: 3
Gerrit-Owner: Harald Welte <lafo...@gnumonks.org>
Gerrit-Reviewer: Jenkins Builder (1000002)

Reply via email to