2010-08-18 03:57:45 +00:00
|
|
|
/*
|
2012-05-22 03:07:02 +00:00
|
|
|
* usb_ctrl.c - USB control pipe device specific code for Gnuk
|
2010-08-30 02:39:10 +00:00
|
|
|
*
|
2012-05-10 10:01:01 +00:00
|
|
|
* Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
|
2010-08-30 02:39:10 +00:00
|
|
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
|
|
|
*
|
|
|
|
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
|
|
|
*
|
|
|
|
* Gnuk is free software: you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* Gnuk 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 General Public
|
|
|
|
* License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2010-09-09 08:50:34 +00:00
|
|
|
/* Packet size of USB Bulk transfer for full speed */
|
|
|
|
#define GNUK_MAX_PACKET_SIZE 64
|
|
|
|
|
2010-08-30 02:39:10 +00:00
|
|
|
#include "config.h"
|
2012-05-10 10:01:01 +00:00
|
|
|
#include "ch.h"
|
2012-06-04 07:31:40 +00:00
|
|
|
#include "hal.h"
|
2012-05-10 10:01:01 +00:00
|
|
|
#include "usb_lld.h"
|
2010-08-18 03:57:45 +00:00
|
|
|
#include "usb_conf.h"
|
2012-05-17 08:02:49 +00:00
|
|
|
#include "gnuk.h"
|
2010-08-18 03:57:45 +00:00
|
|
|
|
2010-08-30 02:39:10 +00:00
|
|
|
#ifdef ENABLE_VIRTUAL_COM_PORT
|
2012-05-10 10:01:01 +00:00
|
|
|
#include "usb-cdc.h"
|
2011-12-09 08:53:45 +00:00
|
|
|
|
2012-05-10 10:01:01 +00:00
|
|
|
struct line_coding
|
|
|
|
{
|
|
|
|
uint32_t bitrate;
|
|
|
|
uint8_t format;
|
|
|
|
uint8_t paritytype;
|
|
|
|
uint8_t datatype;
|
|
|
|
};
|
2011-01-07 07:18:47 +00:00
|
|
|
|
2012-05-17 08:02:49 +00:00
|
|
|
static struct line_coding line_coding = {
|
2012-05-10 10:01:01 +00:00
|
|
|
115200, /* baud rate: 115200 */
|
|
|
|
0x00, /* stop bits: 1 */
|
|
|
|
0x00, /* parity: none */
|
|
|
|
0x08 /* bits: 8 */
|
|
|
|
};
|
2011-12-28 13:16:14 +00:00
|
|
|
|
2012-05-10 10:01:01 +00:00
|
|
|
static int
|
2012-05-18 02:39:04 +00:00
|
|
|
vcom_port_data_setup (uint8_t req, uint8_t req_no)
|
2010-08-18 03:57:45 +00:00
|
|
|
{
|
2012-05-18 02:39:04 +00:00
|
|
|
if (USB_SETUP_GET (req))
|
|
|
|
{
|
|
|
|
if (req_no == USB_CDC_REQ_GET_LINE_CODING)
|
|
|
|
{
|
|
|
|
usb_lld_set_data_to_send (&line_coding, sizeof(line_coding));
|
|
|
|
return USB_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else /* USB_SETUP_SET (req) */
|
|
|
|
{
|
|
|
|
if (req_no == USB_CDC_REQ_SET_LINE_CODING)
|
|
|
|
{
|
|
|
|
usb_lld_set_data_to_recv (&line_coding, sizeof(line_coding));
|
|
|
|
return USB_SUCCESS;
|
|
|
|
}
|
|
|
|
else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
|
|
|
|
/* Do nothing and success */
|
|
|
|
return USB_SUCCESS;
|
|
|
|
}
|
2010-08-18 03:57:45 +00:00
|
|
|
|
2012-05-10 10:01:01 +00:00
|
|
|
return USB_UNSUPPORT;
|
|
|
|
}
|
2012-05-14 04:32:47 +00:00
|
|
|
|
|
|
|
#define VCOM_NUM_INTERFACES 2
|
|
|
|
#else
|
|
|
|
#define VCOM_NUM_INTERFACES 0
|
2010-09-04 09:44:01 +00:00
|
|
|
#endif
|
2010-08-18 03:57:45 +00:00
|
|
|
|
2011-12-12 09:12:43 +00:00
|
|
|
#ifdef PINPAD_DND_SUPPORT
|
2012-05-14 06:38:03 +00:00
|
|
|
#include "usb-msc.h"
|
2012-05-14 04:32:47 +00:00
|
|
|
#define MSC_NUM_INTERFACES 1
|
|
|
|
#else
|
|
|
|
#define MSC_NUM_INTERFACES 0
|
2011-12-12 09:12:43 +00:00
|
|
|
#endif
|
|
|
|
|
2012-05-14 04:32:47 +00:00
|
|
|
#define NUM_INTERFACES (1+VCOM_NUM_INTERFACES+MSC_NUM_INTERFACES)
|
|
|
|
#define MSC_INTERFACE_NO (1+VCOM_NUM_INTERFACES)
|
2010-08-18 03:57:45 +00:00
|
|
|
|
2012-05-10 10:01:01 +00:00
|
|
|
uint32_t bDeviceState = UNCONNECTED; /* USB device status */
|
2010-08-18 03:57:45 +00:00
|
|
|
|
2011-02-01 06:25:36 +00:00
|
|
|
static void
|
2012-05-17 04:29:39 +00:00
|
|
|
gnuk_setup_endpoints_for_interface (uint16_t interface, int stop)
|
2011-02-01 06:25:36 +00:00
|
|
|
{
|
2012-05-10 10:01:01 +00:00
|
|
|
if (interface == 0)
|
2011-02-01 06:25:36 +00:00
|
|
|
{
|
2012-05-17 04:29:39 +00:00
|
|
|
if (!stop)
|
|
|
|
usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, ENDP1_RXADDR, ENDP1_TXADDR,
|
|
|
|
GNUK_MAX_PACKET_SIZE);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
usb_lld_stall_rx (ENDP1);
|
|
|
|
usb_lld_stall_tx (ENDP1);
|
|
|
|
}
|
2011-02-01 06:25:36 +00:00
|
|
|
}
|
|
|
|
#ifdef ENABLE_VIRTUAL_COM_PORT
|
2012-05-10 10:01:01 +00:00
|
|
|
else if (interface == 1)
|
2011-02-01 06:25:36 +00:00
|
|
|
{
|
2012-05-17 04:29:39 +00:00
|
|
|
if (!stop)
|
|
|
|
usb_lld_setup_endpoint (ENDP4, EP_INTERRUPT, 0, 0, ENDP4_TXADDR, 0);
|
|
|
|
else
|
|
|
|
usb_lld_stall_tx (ENDP4);
|
2011-02-01 06:25:36 +00:00
|
|
|
}
|
2012-05-10 10:01:01 +00:00
|
|
|
else if (interface == 2)
|
2011-02-01 06:25:36 +00:00
|
|
|
{
|
2012-05-17 04:29:39 +00:00
|
|
|
if (!stop)
|
|
|
|
{
|
|
|
|
usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, 0, ENDP3_TXADDR, 0);
|
|
|
|
usb_lld_setup_endpoint (ENDP5, EP_BULK, 0, ENDP5_RXADDR, 0,
|
|
|
|
VIRTUAL_COM_PORT_DATA_SIZE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
usb_lld_stall_tx (ENDP3);
|
|
|
|
usb_lld_stall_rx (ENDP5);
|
|
|
|
}
|
2011-02-01 06:25:36 +00:00
|
|
|
}
|
|
|
|
#endif
|
2011-12-12 09:12:43 +00:00
|
|
|
#ifdef PINPAD_DND_SUPPORT
|
2012-05-14 04:32:47 +00:00
|
|
|
else if (interface == MSC_INTERFACE_NO)
|
2011-12-12 09:12:43 +00:00
|
|
|
{
|
2012-05-17 04:29:39 +00:00
|
|
|
if (!stop)
|
|
|
|
{
|
|
|
|
usb_lld_setup_endpoint (ENDP6, EP_BULK, 0,
|
|
|
|
ENDP6_RXADDR, ENDP6_TXADDR, 64);
|
|
|
|
usb_lld_stall_rx (ENDP6);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
usb_lld_stall_tx (ENDP6);
|
|
|
|
usb_lld_stall_rx (ENDP6);
|
|
|
|
}
|
2011-12-12 09:12:43 +00:00
|
|
|
}
|
|
|
|
#endif
|
2011-02-01 06:25:36 +00:00
|
|
|
}
|
|
|
|
|
2012-05-10 10:01:01 +00:00
|
|
|
static void
|
|
|
|
gnuk_device_reset (void)
|
2010-08-18 03:57:45 +00:00
|
|
|
{
|
2012-05-10 10:01:01 +00:00
|
|
|
int i;
|
2010-08-18 03:57:45 +00:00
|
|
|
|
2012-05-10 10:01:01 +00:00
|
|
|
/* Set DEVICE as not configured */
|
|
|
|
usb_lld_set_configuration (0);
|
|
|
|
|
|
|
|
/* Current Feature initialization */
|
|
|
|
usb_lld_set_feature (Config_Descriptor.Descriptor[7]);
|
|
|
|
|
|
|
|
usb_lld_reset ();
|
|
|
|
|
|
|
|
/* Initialize Endpoint 0 */
|
2012-05-11 23:06:33 +00:00
|
|
|
usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR,
|
2012-05-10 10:01:01 +00:00
|
|
|
GNUK_MAX_PACKET_SIZE);
|
|
|
|
|
|
|
|
for (i = 0; i < NUM_INTERFACES; i++)
|
2012-05-17 04:29:39 +00:00
|
|
|
gnuk_setup_endpoints_for_interface (i, 0);
|
2012-05-10 10:01:01 +00:00
|
|
|
|
|
|
|
bDeviceState = ATTACHED;
|
2010-08-18 03:57:45 +00:00
|
|
|
}
|
2010-08-30 02:39:10 +00:00
|
|
|
|
2010-12-10 07:31:25 +00:00
|
|
|
#define USB_CCID_REQ_ABORT 0x01
|
|
|
|
#define USB_CCID_REQ_GET_CLOCK_FREQUENCIES 0x02
|
|
|
|
#define USB_CCID_REQ_GET_DATA_RATES 0x03
|
|
|
|
|
|
|
|
static const uint8_t freq_table[] = { 0xf3, 0x0d, 0, 0, }; /* dwDefaultClock */
|
|
|
|
|
|
|
|
static const uint8_t data_rate_table[] = { 0x80, 0x25, 0, 0, }; /* dwDataRate */
|
|
|
|
|
2011-12-28 03:27:16 +00:00
|
|
|
#if defined(PINPAD_DND_SUPPORT)
|
2011-12-09 08:53:45 +00:00
|
|
|
static const uint8_t lun_table[] = { 0, 0, 0, 0, };
|
2011-12-28 03:27:16 +00:00
|
|
|
#endif
|
2011-12-09 08:53:45 +00:00
|
|
|
|
2012-05-18 17:05:31 +00:00
|
|
|
static const uint8_t *const mem_info[] = { &_regnual_start, &__heap_end__, };
|
2012-05-17 08:02:49 +00:00
|
|
|
|
|
|
|
#define USB_FSIJ_GNUK_MEMINFO 0
|
|
|
|
#define USB_FSIJ_GNUK_DOWNLOAD 1
|
|
|
|
#define USB_FSIJ_GNUK_EXEC 2
|
|
|
|
|
2012-06-05 01:33:50 +00:00
|
|
|
static uint32_t rbit (uint32_t v)
|
2010-09-04 09:44:01 +00:00
|
|
|
{
|
2012-06-04 07:31:40 +00:00
|
|
|
uint32_t r;
|
2012-05-18 17:05:31 +00:00
|
|
|
|
2012-06-05 01:33:50 +00:00
|
|
|
asm ("rbit %0, %1" : "=r" (r) : "r" (v));
|
2012-06-04 07:31:40 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* After calling this function, CRC module remain enabled. */
|
|
|
|
static int download_check_crc32 (const uint32_t *end_p)
|
|
|
|
{
|
|
|
|
uint32_t crc32 = *end_p;
|
|
|
|
const uint32_t *p;
|
|
|
|
|
|
|
|
RCC->AHBENR |= RCC_AHBENR_CRCEN;
|
|
|
|
CRC->CR = CRC_CR_RESET;
|
|
|
|
|
|
|
|
for (p = (const uint32_t *)&_regnual_start; p < end_p; p++)
|
2012-06-05 01:33:50 +00:00
|
|
|
CRC->DR = rbit (*p);
|
2012-05-18 17:05:31 +00:00
|
|
|
|
2012-06-05 01:33:50 +00:00
|
|
|
if ((rbit (CRC->DR) ^ crc32) == 0xffffffff)
|
2012-06-04 07:31:40 +00:00
|
|
|
return USB_SUCCESS;
|
|
|
|
|
|
|
|
return USB_UNSUPPORT;
|
2010-09-04 09:44:01 +00:00
|
|
|
}
|
2010-12-10 07:31:25 +00:00
|
|
|
|
2012-05-10 10:01:01 +00:00
|
|
|
static int
|
2012-05-18 02:39:04 +00:00
|
|
|
gnuk_setup (uint8_t req, uint8_t req_no,
|
|
|
|
uint16_t value, uint16_t index, uint16_t len)
|
2010-12-10 07:31:25 +00:00
|
|
|
{
|
2012-05-18 02:39:04 +00:00
|
|
|
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
|
2012-05-17 08:02:49 +00:00
|
|
|
|
2012-05-18 02:39:04 +00:00
|
|
|
if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
|
2012-05-17 08:02:49 +00:00
|
|
|
{
|
2012-05-18 02:39:04 +00:00
|
|
|
if (USB_SETUP_GET (req))
|
2012-05-17 08:02:49 +00:00
|
|
|
{
|
2012-05-18 02:39:04 +00:00
|
|
|
if (req_no == USB_FSIJ_GNUK_MEMINFO)
|
|
|
|
{
|
|
|
|
usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
|
|
|
|
return USB_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else /* SETUP_SET */
|
|
|
|
{
|
|
|
|
uint8_t *addr = (uint8_t *)(0x20000000 + value * 0x100 + index);
|
|
|
|
|
|
|
|
if (req_no == USB_FSIJ_GNUK_DOWNLOAD)
|
|
|
|
{
|
|
|
|
if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
|
|
|
|
return USB_UNSUPPORT;
|
|
|
|
|
2012-05-18 07:54:17 +00:00
|
|
|
if (addr < &_regnual_start || addr + len > &__heap_end__)
|
2012-05-18 02:39:04 +00:00
|
|
|
return USB_UNSUPPORT;
|
|
|
|
|
2012-05-23 03:17:11 +00:00
|
|
|
if (index + len < 256)
|
|
|
|
memset (addr + index + len, 0, 256 - (index + len));
|
|
|
|
|
2012-05-18 02:39:04 +00:00
|
|
|
usb_lld_set_data_to_recv (addr, len);
|
|
|
|
return USB_SUCCESS;
|
|
|
|
}
|
|
|
|
else if (req_no == USB_FSIJ_GNUK_EXEC && len == 0)
|
|
|
|
{
|
|
|
|
if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
|
|
|
|
return USB_UNSUPPORT;
|
|
|
|
|
2012-06-04 07:31:40 +00:00
|
|
|
if (((uint32_t)addr & 0x03))
|
|
|
|
return USB_UNSUPPORT;
|
|
|
|
|
|
|
|
return download_check_crc32 ((uint32_t *)addr);
|
2012-05-18 02:39:04 +00:00
|
|
|
}
|
2012-05-17 08:02:49 +00:00
|
|
|
}
|
|
|
|
}
|
2012-05-18 02:39:04 +00:00
|
|
|
else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
|
2012-05-10 10:01:01 +00:00
|
|
|
if (index == 0)
|
2010-12-10 07:31:25 +00:00
|
|
|
{
|
2012-05-18 02:39:04 +00:00
|
|
|
if (USB_SETUP_GET (req))
|
|
|
|
{
|
|
|
|
if (req_no == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
|
|
|
|
{
|
|
|
|
usb_lld_set_data_to_send (freq_table, sizeof (freq_table));
|
|
|
|
return USB_SUCCESS;
|
|
|
|
}
|
|
|
|
else if (req_no == USB_CCID_REQ_GET_DATA_RATES)
|
|
|
|
{
|
|
|
|
usb_lld_set_data_to_send (data_rate_table,
|
|
|
|
sizeof (data_rate_table));
|
|
|
|
return USB_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
2010-12-10 07:31:25 +00:00
|
|
|
else
|
2012-05-18 02:39:04 +00:00
|
|
|
{
|
|
|
|
if (req_no == USB_CCID_REQ_ABORT)
|
|
|
|
/* wValue: bSeq, bSlot */
|
|
|
|
/* Abortion is not supported in Gnuk */
|
|
|
|
return USB_UNSUPPORT;
|
|
|
|
}
|
2010-12-10 07:31:25 +00:00
|
|
|
}
|
2012-05-14 04:32:47 +00:00
|
|
|
#ifdef ENABLE_VIRTUAL_COM_PORT
|
2012-05-10 10:01:01 +00:00
|
|
|
else if (index == 1)
|
2012-05-18 02:39:04 +00:00
|
|
|
return vcom_port_data_setup (req, req_no);
|
2012-05-14 04:32:47 +00:00
|
|
|
#endif
|
|
|
|
#ifdef PINPAD_DND_SUPPORT
|
|
|
|
else if (index == MSC_INTERFACE_NO)
|
2010-12-10 07:31:25 +00:00
|
|
|
{
|
2012-05-18 02:39:04 +00:00
|
|
|
if (USB_SETUP_GET (req))
|
2011-12-09 08:53:45 +00:00
|
|
|
{
|
2012-05-18 02:39:04 +00:00
|
|
|
if (req_no == MSC_GET_MAX_LUN_COMMAND)
|
|
|
|
{
|
|
|
|
usb_lld_set_data_to_send (lun_table, sizeof (lun_table));
|
|
|
|
return USB_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (req_no == MSC_MASS_STORAGE_RESET_COMMAND)
|
2011-12-09 08:53:45 +00:00
|
|
|
/* Should call resetting MSC thread, something like msc_reset() */
|
|
|
|
return USB_SUCCESS;
|
2010-12-10 07:31:25 +00:00
|
|
|
}
|
2011-12-09 08:53:45 +00:00
|
|
|
#endif
|
2012-05-17 08:02:49 +00:00
|
|
|
|
|
|
|
return USB_UNSUPPORT;
|
2010-12-10 07:31:25 +00:00
|
|
|
}
|
2010-09-04 09:44:01 +00:00
|
|
|
|
2012-05-18 02:39:04 +00:00
|
|
|
static void gnuk_ctrl_write_finish (uint8_t req, uint8_t req_no,
|
|
|
|
uint16_t value, uint16_t index,
|
|
|
|
uint16_t len)
|
|
|
|
{
|
|
|
|
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
|
|
|
|
|
|
|
|
if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT)
|
|
|
|
&& USB_SETUP_SET (req) && req_no == USB_FSIJ_GNUK_EXEC && len == 0)
|
|
|
|
{
|
|
|
|
if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
|
|
|
|
return;
|
|
|
|
|
|
|
|
(void)value; (void)index;
|
|
|
|
usb_lld_prepare_shutdown (); /* No further USB communication */
|
|
|
|
*icc_state_p = ICC_STATE_EXEC_REQUESTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-10 10:01:01 +00:00
|
|
|
static int
|
|
|
|
gnuk_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
|
|
|
|
{
|
|
|
|
(void)index;
|
|
|
|
if (desc_type == DEVICE_DESCRIPTOR)
|
|
|
|
{
|
|
|
|
usb_lld_set_data_to_send (Device_Descriptor.Descriptor,
|
|
|
|
Device_Descriptor.Descriptor_Size);
|
|
|
|
return USB_SUCCESS;
|
|
|
|
}
|
|
|
|
else if (desc_type == CONFIG_DESCRIPTOR)
|
|
|
|
{
|
|
|
|
usb_lld_set_data_to_send (Config_Descriptor.Descriptor,
|
|
|
|
Config_Descriptor.Descriptor_Size);
|
|
|
|
return USB_SUCCESS;
|
|
|
|
}
|
|
|
|
else if (desc_type == STRING_DESCRIPTOR)
|
|
|
|
{
|
|
|
|
uint8_t desc_index = value & 0xff;
|
|
|
|
|
|
|
|
if (desc_index < NUM_STRING_DESC)
|
|
|
|
{
|
|
|
|
usb_lld_set_data_to_send (String_Descriptors[desc_index].Descriptor,
|
|
|
|
String_Descriptors[desc_index].Descriptor_Size);
|
|
|
|
return USB_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return USB_UNSUPPORT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int gnuk_usb_event (uint8_t event_type, uint16_t value)
|
|
|
|
{
|
2012-05-17 08:02:49 +00:00
|
|
|
int i;
|
2012-06-01 00:34:28 +00:00
|
|
|
uint8_t current_conf;
|
2012-05-17 08:02:49 +00:00
|
|
|
|
2012-05-10 10:01:01 +00:00
|
|
|
switch (event_type)
|
|
|
|
{
|
|
|
|
case USB_EVENT_ADDRESS:
|
|
|
|
bDeviceState = ADDRESSED;
|
2012-05-18 07:54:17 +00:00
|
|
|
return USB_SUCCESS;
|
2012-05-10 10:01:01 +00:00
|
|
|
case USB_EVENT_CONFIG:
|
2012-06-01 00:34:28 +00:00
|
|
|
current_conf = usb_lld_current_configuration ();
|
|
|
|
if (current_conf == 0)
|
2012-05-10 10:01:01 +00:00
|
|
|
{
|
|
|
|
if (value != 1)
|
|
|
|
return USB_UNSUPPORT;
|
|
|
|
|
|
|
|
usb_lld_set_configuration (value);
|
|
|
|
for (i = 0; i < NUM_INTERFACES; i++)
|
2012-05-17 04:29:39 +00:00
|
|
|
gnuk_setup_endpoints_for_interface (i, 0);
|
2012-05-10 10:01:01 +00:00
|
|
|
bDeviceState = CONFIGURED;
|
|
|
|
}
|
2012-06-01 00:34:28 +00:00
|
|
|
else if (current_conf != value)
|
2012-05-10 10:01:01 +00:00
|
|
|
{
|
|
|
|
if (value != 0)
|
|
|
|
return USB_UNSUPPORT;
|
|
|
|
|
|
|
|
usb_lld_set_configuration (0);
|
2012-05-17 04:29:39 +00:00
|
|
|
for (i = 0; i < NUM_INTERFACES; i++)
|
|
|
|
gnuk_setup_endpoints_for_interface (i, 1);
|
2012-05-10 10:01:01 +00:00
|
|
|
bDeviceState = ADDRESSED;
|
|
|
|
}
|
2012-06-01 00:34:28 +00:00
|
|
|
/* Do nothing when current_conf == value */
|
2012-05-18 07:54:17 +00:00
|
|
|
return USB_SUCCESS;
|
2012-05-10 10:01:01 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return USB_UNSUPPORT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int gnuk_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
|
|
|
|
{
|
|
|
|
static uint8_t zero = 0;
|
|
|
|
|
|
|
|
if (interface >= NUM_INTERFACES)
|
|
|
|
return USB_UNSUPPORT;
|
|
|
|
|
|
|
|
switch (cmd)
|
|
|
|
{
|
|
|
|
case USB_SET_INTERFACE:
|
|
|
|
if (alt != 0)
|
|
|
|
return USB_UNSUPPORT;
|
|
|
|
else
|
|
|
|
{
|
2012-05-17 04:29:39 +00:00
|
|
|
gnuk_setup_endpoints_for_interface (interface, 0);
|
2012-05-10 10:01:01 +00:00
|
|
|
return USB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
case USB_GET_INTERFACE:
|
|
|
|
usb_lld_set_data_to_send (&zero, 1);
|
|
|
|
return USB_SUCCESS;
|
|
|
|
|
|
|
|
default:
|
|
|
|
case USB_QUERY_INTERFACE:
|
|
|
|
return USB_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-18 03:57:45 +00:00
|
|
|
/*
|
|
|
|
* Interface to USB core
|
|
|
|
*/
|
|
|
|
|
2012-05-10 10:01:01 +00:00
|
|
|
const struct usb_device_method Device_Method = {
|
2010-08-18 03:57:45 +00:00
|
|
|
gnuk_device_reset,
|
2012-05-18 02:39:04 +00:00
|
|
|
gnuk_ctrl_write_finish,
|
|
|
|
gnuk_setup,
|
2012-05-10 10:01:01 +00:00
|
|
|
gnuk_get_descriptor,
|
|
|
|
gnuk_usb_event,
|
|
|
|
gnuk_interface,
|
2010-08-18 03:57:45 +00:00
|
|
|
};
|
2012-05-25 06:20:08 +00:00
|
|
|
|
|
|
|
CH_IRQ_HANDLER (Vector90)
|
|
|
|
{
|
|
|
|
CH_IRQ_PROLOGUE();
|
|
|
|
chSysLockFromIsr();
|
|
|
|
|
|
|
|
usb_interrupt_handler ();
|
|
|
|
|
|
|
|
chSysUnlockFromIsr();
|
|
|
|
CH_IRQ_EPILOGUE();
|
|
|
|
}
|