gnuk/src/usb_prop.c

367 lines
8.6 KiB
C
Raw Normal View History

2010-08-18 03:57:45 +00:00
/*
2012-05-10 10:01:01 +00:00
* usb_prop.c - interface code between Gnuk and USB
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"
#include "usb_lld.h"
2010-08-18 03:57:45 +00:00
#include "usb_conf.h"
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-10 10:01:01 +00:00
static const struct line_coding line_coding = {
115200, /* baud rate: 115200 */
0x00, /* stop bits: 1 */
0x00, /* parity: none */
0x08 /* bits: 8 */
};
2010-08-18 03:57:45 +00:00
static void
2012-05-10 10:01:01 +00:00
Virtual_Com_Port_Data_Setup (uint8_t RequestNo)
2010-08-18 03:57:45 +00:00
{
2012-05-10 10:01:01 +00:00
if (RequestNo != USB_CDC_REQ_GET_LINE_CODING)
return USB_UNSUPPORT;
2010-08-18 03:57:45 +00:00
2012-05-10 10:01:01 +00:00
/* RequestNo == USB_CDC_REQ_SET_LINE_CODING is not supported */
2010-08-18 03:57:45 +00:00
2012-05-10 10:01:01 +00:00
usb_lld_set_data_to_send (&line_coding, sizeof(line_coding));
return USB_SUCCESS;
2010-08-18 03:57:45 +00:00
}
2012-05-10 10:01:01 +00:00
static int
Virtual_Com_Port_NoData_Setup (uint8_t RequestNo)
2010-08-18 03:57:45 +00:00
{
2012-05-10 10:01:01 +00:00
if (RequestNo == 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;
}
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-10 10:01:01 +00:00
#include "usb_msc.h"
2011-12-12 09:12:43 +00:00
#endif
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
static void
2012-05-10 10:01:01 +00:00
gnuk_device_init (void)
2010-08-18 03:57:45 +00:00
{
2012-05-10 10:01:01 +00:00
usb_lld_set_configuration (0);
USB_Cable_Config (1);
bDeviceState = UNCONNECTED;
2010-08-18 03:57:45 +00:00
}
2011-02-01 06:25:36 +00:00
static void
2012-05-10 10:01:01 +00:00
gnuk_setup_endpoints_for_interface (uint16_t interface)
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-10 10:01:01 +00:00
/* Initialize Endpoint 1 */
usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, 0, ENDP1_TXADDR, 0);
/* Initialize Endpoint 2 */
usb_lld_setup_endpoint (ENDP2, EP_BULK, 0, ENDP2_RXADDR, 0,
GNUK_MAX_PACKET_SIZE);
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-10 10:01:01 +00:00
/* Initialize Endpoint 4 */
usb_lld_setup_endpoint (ENDP4, EP_INTERRUPT, 0, 0, ENDP4_TXADDR, 0);
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-10 10:01:01 +00:00
/* Initialize Endpoint 3 */
usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, 0, ENDP3_TXADDR, 0);
/* Initialize Endpoint 5 */
usb_lld_setup_endpoint (ENDP5, EP_BULK, 0, ENDP5_RXADDR, 0,
VIRTUAL_COM_PORT_DATA_SIZE);
2011-02-01 06:25:36 +00:00
}
#endif
2011-12-12 09:12:43 +00:00
#ifdef PINPAD_DND_SUPPORT
# ifdef ENABLE_VIRTUAL_COM_PORT
2012-05-10 10:01:01 +00:00
else if (interface == 3)
2011-12-12 09:12:43 +00:00
# else
2012-05-10 10:01:01 +00:00
else if (interface == 1)
# endif
2011-12-12 09:12:43 +00:00
{
2012-05-10 10:01:01 +00:00
/* Initialize Endpoint 6 */
usb_lld_setup_endpoint (ENDP6, EP_BULK, 0, 0, ENDP6_TXADDR, 0);
/* Initialize Endpoint 7 */
usb_lld_setup_endpoint (ENDP7, EP_BULK, 0, ENDP7_RXADDR, 0, 64);
usb_lld_stall_rx (ENDP7);
2011-12-12 09:12:43 +00:00
}
#endif
2011-02-01 06:25:36 +00:00
}
2011-12-12 09:12:43 +00:00
#ifdef PINPAD_DND_SUPPORT
# ifdef ENABLE_VIRTUAL_COM_PORT
# define NUM_INTERFACES 4 /* two for CDC, one for CCID, and MSC */
# else
# define NUM_INTERFACES 2 /* CCID and MSC */
# endif
2011-02-01 06:25:36 +00:00
#else
2011-12-12 09:12:43 +00:00
# ifdef ENABLE_VIRTUAL_COM_PORT
# define NUM_INTERFACES 3 /* two for CDC, one for CCID */
# else
# define NUM_INTERFACES 1 /* CCID only */
# endif
2011-01-28 15:00:47 +00:00
#endif
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 */
usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0,
ENDP0_RXADDR, ENDP0_TXADDR,
GNUK_MAX_PACKET_SIZE);
for (i = 0; i < NUM_INTERFACES; i++)
gnuk_setup_endpoints_for_interface (i);
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-10 10:01:01 +00:00
static void
gnuk_setup_with_data (uint8_t recipient, uint8_t RequestNo, uint16_t index)
2010-09-04 09:44:01 +00:00
{
2012-05-10 10:01:01 +00:00
if (recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) /* Interface */
if (index == 0)
2010-12-10 07:31:25 +00:00
{
if (RequestNo == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
2012-05-10 10:01:01 +00:00
usb_lld_set_data_to_send (freq_table, sizeof (freq_table));
2010-12-10 07:31:25 +00:00
else if (RequestNo == USB_CCID_REQ_GET_DATA_RATES)
2012-05-10 10:01:01 +00:00
usb_lld_set_data_to_send (data_rate_table, sizeof (data_rate_table));
2010-12-10 07:31:25 +00:00
}
2011-12-09 08:53:45 +00:00
#if defined(PINPAD_DND_SUPPORT)
# if defined(ENABLE_VIRTUAL_COM_PORT)
2012-05-10 10:01:01 +00:00
else if (index == 1)
Virtual_Com_Port_Data_Setup (RequestNo);
else if (index == 3)
2011-12-09 08:53:45 +00:00
# else
2012-05-10 10:01:01 +00:00
else if (index == 1)
2011-12-09 08:53:45 +00:00
# endif
2010-12-10 07:31:25 +00:00
{
2011-12-09 08:53:45 +00:00
if (RequestNo == MSC_GET_MAX_LUN_COMMAND)
2012-05-10 10:01:01 +00:00
usb_lld_set_data_to_send (lun_table, sizeof (lun_table));
2010-12-10 07:31:25 +00:00
}
2011-12-09 08:53:45 +00:00
#elif defined(ENABLE_VIRTUAL_COM_PORT)
2012-05-10 10:01:01 +00:00
else if (index == 1)
Virtual_Com_Port_Data_Setup (RequestNo);
2011-12-09 08:53:45 +00:00
#endif
2010-09-04 09:44:01 +00:00
}
2010-12-10 07:31:25 +00:00
2011-12-09 08:53:45 +00:00
2012-05-10 10:01:01 +00:00
static int
gnuk_setup_with_nodata (uint8_t recipient, uint8_t RequestNo, uint16_t index)
2010-12-10 07:31:25 +00:00
{
2012-05-10 10:01:01 +00:00
if (recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) /* Interface */
if (index == 0)
2010-12-10 07:31:25 +00:00
{
if (RequestNo == USB_CCID_REQ_ABORT)
/* wValue: bSeq, bSlot */
/* Abortion is not supported in Gnuk */
return USB_UNSUPPORT;
else
return USB_UNSUPPORT;
}
2011-12-09 08:53:45 +00:00
#if defined(PINPAD_DND_SUPPORT)
# if defined(ENABLE_VIRTUAL_COM_PORT)
2012-05-10 10:01:01 +00:00
else if (index == 1)
2011-12-09 08:53:45 +00:00
return Virtual_Com_Port_NoData_Setup (RequestNo);
2012-05-10 10:01:01 +00:00
else if (index == 3)
2011-12-09 08:53:45 +00:00
# else
2012-05-10 10:01:01 +00:00
else if (index == 1)
2011-12-09 08:53:45 +00:00
# endif
2010-12-10 07:31:25 +00:00
{
2011-12-09 08:53:45 +00:00
if (RequestNo == MSC_MASS_STORAGE_RESET_COMMAND)
{
/* Should call resetting MSC thread, something like msc_reset() */
return USB_SUCCESS;
}
else
return USB_UNSUPPORT;
2010-12-10 07:31:25 +00:00
}
2011-12-09 08:53:45 +00:00
#elif defined(ENABLE_VIRTUAL_COM_PORT)
2012-05-10 10:01:01 +00:00
else if (index == 1)
2011-12-09 08:53:45 +00:00
return Virtual_Com_Port_NoData_Setup (RequestNo);
#endif
else
return USB_UNSUPPORT;
2010-12-10 07:31:25 +00:00
else
return USB_UNSUPPORT;
}
2010-09-04 09:44:01 +00:00
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)
{
switch (event_type)
{
case USB_EVENT_RESET:
break;
case USB_EVENT_ADDRESS:
bDeviceState = ADDRESSED;
break;
case USB_EVENT_CONFIG:
if (usb_lld_current_configuration () == 0)
{
int i;
extern void *main_thread;
#define LED_STATUS_MODE (8)
if (value != 1)
return USB_UNSUPPORT;
usb_lld_set_configuration (value);
for (i = 0; i < NUM_INTERFACES; i++)
gnuk_setup_endpoints_for_interface (i);
bDeviceState = CONFIGURED;
chEvtSignalI (main_thread, LED_STATUS_MODE);
return USB_SUCCESS;
}
else
{
if (value != 0)
return USB_UNSUPPORT;
usb_lld_set_configuration (0);
// Disable all endpoints???
bDeviceState = ADDRESSED;
}
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
{
gnuk_setup_endpoints_for_interface (interface);
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_init,
gnuk_device_reset,
2010-12-10 07:31:25 +00:00
gnuk_setup_with_data,
gnuk_setup_with_nodata,
2012-05-10 10:01:01 +00:00
gnuk_get_descriptor,
gnuk_usb_event,
gnuk_interface,
2010-08-18 03:57:45 +00:00
};