2010-08-18 03:57:45 +00:00
|
|
|
/*
|
2010-08-30 02:39:10 +00:00
|
|
|
* usb_prop.c - glue/interface code between Gnuk and USB-FS-Device_Lib
|
|
|
|
*
|
2011-01-27 06:09:59 +00:00
|
|
|
* Copyright (C) 2010, 2011 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"
|
2010-08-18 03:57:45 +00:00
|
|
|
#include "usb_lib.h"
|
|
|
|
#include "usb_conf.h"
|
|
|
|
#include "usb_prop.h"
|
|
|
|
#include "usb_desc.h"
|
|
|
|
#include "usb_pwr.h"
|
|
|
|
#include "hw_config.h"
|
|
|
|
|
2010-08-30 02:39:10 +00:00
|
|
|
#ifdef ENABLE_VIRTUAL_COM_PORT
|
|
|
|
#include "usb-cdc-vport.c"
|
2010-08-18 03:57:45 +00:00
|
|
|
#endif
|
|
|
|
|
2011-01-07 07:18:47 +00:00
|
|
|
|
2010-08-18 03:57:45 +00:00
|
|
|
static void
|
|
|
|
gnuk_device_init (void)
|
|
|
|
{
|
|
|
|
pInformation->Current_Configuration = 0;
|
|
|
|
|
|
|
|
/* Connect the device */
|
|
|
|
PowerOn ();
|
|
|
|
|
|
|
|
/* Perform basic device initialization operations */
|
|
|
|
USB_SIL_Init ();
|
|
|
|
|
|
|
|
bDeviceState = UNCONNECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gnuk_device_reset (void)
|
|
|
|
{
|
2010-08-30 02:39:10 +00:00
|
|
|
/* Set DEVICE as not configured */
|
2010-08-18 03:57:45 +00:00
|
|
|
pInformation->Current_Configuration = 0;
|
|
|
|
|
|
|
|
/* Current Feature initialization */
|
|
|
|
pInformation->Current_Feature = Config_Descriptor.Descriptor[7];
|
|
|
|
|
2010-08-30 02:39:10 +00:00
|
|
|
/* Set DEVICE with the default Interface*/
|
2010-08-18 03:57:45 +00:00
|
|
|
pInformation->Current_Interface = 0;
|
|
|
|
|
|
|
|
SetBTABLE (BTABLE_ADDRESS);
|
|
|
|
|
|
|
|
/* Initialize Endpoint 0 */
|
|
|
|
SetEPType (ENDP0, EP_CONTROL);
|
|
|
|
SetEPTxStatus (ENDP0, EP_TX_STALL);
|
|
|
|
SetEPRxAddr (ENDP0, ENDP0_RXADDR);
|
|
|
|
SetEPTxAddr (ENDP0, ENDP0_TXADDR);
|
|
|
|
Clear_Status_Out (ENDP0);
|
|
|
|
SetEPRxCount (ENDP0, GNUK_MAX_PACKET_SIZE);
|
|
|
|
SetEPRxValid (ENDP0);
|
|
|
|
|
|
|
|
/* Initialize Endpoint 1 */
|
|
|
|
SetEPType (ENDP1, EP_BULK);
|
|
|
|
SetEPTxAddr (ENDP1, ENDP1_TXADDR);
|
|
|
|
SetEPTxStatus (ENDP1, EP_TX_NAK);
|
|
|
|
SetEPRxStatus (ENDP1, EP_RX_DIS);
|
|
|
|
|
|
|
|
/* Initialize Endpoint 2 */
|
2010-09-04 09:44:01 +00:00
|
|
|
SetEPType (ENDP2, EP_BULK);
|
|
|
|
SetEPRxAddr (ENDP2, ENDP2_RXADDR);
|
|
|
|
SetEPRxCount (ENDP2, GNUK_MAX_PACKET_SIZE);
|
|
|
|
SetEPRxStatus (ENDP2, EP_RX_VALID);
|
|
|
|
SetEPTxStatus (ENDP2, EP_TX_DIS);
|
2010-08-18 03:57:45 +00:00
|
|
|
|
2010-09-04 09:44:01 +00:00
|
|
|
#ifdef ENABLE_VIRTUAL_COM_PORT
|
2010-08-18 03:57:45 +00:00
|
|
|
/* Initialize Endpoint 3 */
|
|
|
|
SetEPType (ENDP3, EP_BULK);
|
2010-09-04 09:44:01 +00:00
|
|
|
SetEPTxAddr (ENDP3, ENDP3_TXADDR);
|
|
|
|
SetEPTxStatus (ENDP3, EP_TX_NAK);
|
|
|
|
SetEPRxStatus (ENDP3, EP_RX_DIS);
|
2010-08-18 03:57:45 +00:00
|
|
|
|
|
|
|
/* Initialize Endpoint 4 */
|
2010-09-04 09:44:01 +00:00
|
|
|
SetEPType (ENDP4, EP_INTERRUPT);
|
2010-08-18 03:57:45 +00:00
|
|
|
SetEPTxAddr (ENDP4, ENDP4_TXADDR);
|
|
|
|
SetEPTxStatus (ENDP4, EP_TX_NAK);
|
|
|
|
SetEPRxStatus (ENDP4, EP_RX_DIS);
|
|
|
|
|
|
|
|
/* Initialize Endpoint 5 */
|
|
|
|
SetEPType (ENDP5, EP_BULK);
|
|
|
|
SetEPRxAddr (ENDP5, ENDP5_RXADDR);
|
2010-09-04 09:44:01 +00:00
|
|
|
SetEPRxCount (ENDP5, VIRTUAL_COM_PORT_DATA_SIZE);
|
2010-08-18 03:57:45 +00:00
|
|
|
SetEPRxStatus (ENDP5, EP_RX_VALID);
|
|
|
|
SetEPTxStatus (ENDP5, EP_TX_DIS);
|
2010-09-04 09:44:01 +00:00
|
|
|
#endif
|
2010-08-18 03:57:45 +00:00
|
|
|
|
|
|
|
/* Set this device to response on default address */
|
|
|
|
SetDeviceAddress (0);
|
|
|
|
|
|
|
|
bDeviceState = ATTACHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gnuk_device_SetConfiguration (void)
|
|
|
|
{
|
|
|
|
DEVICE_INFO *pInfo = &Device_Info;
|
|
|
|
|
|
|
|
if (pInfo->Current_Configuration != 0)
|
|
|
|
/* Device configured */
|
|
|
|
bDeviceState = CONFIGURED;
|
|
|
|
}
|
|
|
|
|
2011-02-01 06:25:36 +00:00
|
|
|
static void
|
|
|
|
gnuk_device_SetInterface (void)
|
|
|
|
{
|
|
|
|
uint16_t intf = pInformation->USBwIndex0;
|
|
|
|
|
|
|
|
/* alternateSetting: pInformation->USBwValue0 should be 0 */
|
|
|
|
|
|
|
|
if (intf == 0)
|
|
|
|
{
|
2011-02-24 06:54:40 +00:00
|
|
|
ClearDTOG_RX (ENDP2);
|
|
|
|
ClearDTOG_TX (ENDP1);
|
2011-02-01 06:25:36 +00:00
|
|
|
}
|
|
|
|
#ifdef ENABLE_VIRTUAL_COM_PORT
|
|
|
|
else if (intf == 1)
|
|
|
|
{
|
2011-02-24 06:54:40 +00:00
|
|
|
ClearDTOG_TX (ENDP4);
|
2011-02-01 06:25:36 +00:00
|
|
|
}
|
|
|
|
else if (intf == 2)
|
|
|
|
{
|
2011-02-24 06:54:40 +00:00
|
|
|
ClearDTOG_RX (ENDP5);
|
|
|
|
ClearDTOG_TX (ENDP3);
|
2011-02-01 06:25:36 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-08-18 03:57:45 +00:00
|
|
|
static void
|
|
|
|
gnuk_device_SetDeviceAddress (void)
|
|
|
|
{
|
|
|
|
bDeviceState = ADDRESSED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* IN from port 0 */
|
|
|
|
static void
|
|
|
|
gnuk_device_Status_In (void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/* OUT to port 0 */
|
|
|
|
static void
|
|
|
|
gnuk_device_Status_Out (void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint8_t *
|
|
|
|
gnuk_device_GetDeviceDescriptor (uint16_t Length)
|
|
|
|
{
|
2010-09-04 09:44:01 +00:00
|
|
|
return Standard_GetDescriptorData (Length,
|
|
|
|
(PONE_DESCRIPTOR)&Device_Descriptor);
|
2010-08-18 03:57:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static uint8_t *
|
|
|
|
gnuk_device_GetConfigDescriptor (uint16_t Length)
|
|
|
|
{
|
2010-09-04 09:44:01 +00:00
|
|
|
return Standard_GetDescriptorData (Length,
|
|
|
|
(PONE_DESCRIPTOR)&Config_Descriptor);
|
2010-08-18 03:57:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static uint8_t *
|
|
|
|
gnuk_device_GetStringDescriptor (uint16_t Length)
|
|
|
|
{
|
|
|
|
uint8_t wValue0 = pInformation->USBwValue0;
|
2011-05-11 01:56:36 +00:00
|
|
|
|
2011-05-11 07:47:26 +00:00
|
|
|
if (wValue0 >= (sizeof (String_Descriptor) / sizeof (ONE_DESCRIPTOR)))
|
2010-08-18 03:57:45 +00:00
|
|
|
return NULL;
|
|
|
|
else
|
2011-05-11 01:56:36 +00:00
|
|
|
return
|
|
|
|
Standard_GetDescriptorData (Length,
|
|
|
|
(PONE_DESCRIPTOR)&String_Descriptor[wValue0]);
|
2010-08-18 03:57:45 +00:00
|
|
|
}
|
|
|
|
|
2011-01-28 15:00:47 +00:00
|
|
|
#ifdef ENABLE_VIRTUAL_COM_PORT
|
|
|
|
#define NUM_INTERFACES 3 /* two for CDC, one for CCID */
|
2011-02-01 06:25:36 +00:00
|
|
|
#else
|
2011-01-28 15:00:47 +00:00
|
|
|
#define NUM_INTERFACES 1 /* CCID only */
|
|
|
|
#endif
|
|
|
|
|
2010-08-18 03:57:45 +00:00
|
|
|
static RESULT
|
|
|
|
gnuk_device_Get_Interface_Setting (uint8_t Interface, uint8_t AlternateSetting)
|
|
|
|
{
|
2011-01-28 15:00:47 +00:00
|
|
|
if (AlternateSetting > 0) /* Any interface, we have no alternate */
|
2010-08-18 03:57:45 +00:00
|
|
|
return USB_UNSUPPORT;
|
2011-01-28 15:00:47 +00:00
|
|
|
else if (Interface > NUM_INTERFACES)
|
2010-08-18 03:57:45 +00:00
|
|
|
return USB_UNSUPPORT;
|
|
|
|
|
|
|
|
return USB_SUCCESS;
|
|
|
|
}
|
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 uint8_t *
|
|
|
|
gnuk_clock_frequencies (uint16_t len)
|
|
|
|
{
|
|
|
|
if (len == 0)
|
|
|
|
{
|
|
|
|
pInformation->Ctrl_Info.Usb_wLength = sizeof (freq_table);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (uint8_t *)freq_table;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const uint8_t data_rate_table[] = { 0x80, 0x25, 0, 0, }; /* dwDataRate */
|
|
|
|
static uint8_t *
|
|
|
|
gnuk_data_rates (uint16_t len)
|
|
|
|
{
|
|
|
|
if (len == 0)
|
|
|
|
{
|
|
|
|
pInformation->Ctrl_Info.Usb_wLength = sizeof (data_rate_table);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (uint8_t *)data_rate_table;
|
|
|
|
}
|
|
|
|
|
2010-09-04 09:44:01 +00:00
|
|
|
static RESULT
|
2010-12-10 07:31:25 +00:00
|
|
|
gnuk_setup_with_data (uint8_t RequestNo)
|
2010-09-04 09:44:01 +00:00
|
|
|
{
|
2010-12-10 07:31:25 +00:00
|
|
|
if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
|
|
|
|
if (pInformation->USBwIndex0 == 0) /* Interface */
|
|
|
|
{
|
|
|
|
if (RequestNo == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
|
|
|
|
{
|
|
|
|
pInformation->Ctrl_Info.CopyData = gnuk_clock_frequencies;
|
|
|
|
pInformation->Ctrl_Info.Usb_wOffset = 0;
|
|
|
|
gnuk_clock_frequencies (0);
|
|
|
|
return USB_SUCCESS;
|
|
|
|
}
|
|
|
|
else if (RequestNo == USB_CCID_REQ_GET_DATA_RATES)
|
|
|
|
{
|
|
|
|
pInformation->Ctrl_Info.CopyData = gnuk_data_rates;
|
|
|
|
pInformation->Ctrl_Info.Usb_wOffset = 0;
|
|
|
|
gnuk_data_rates (0);
|
|
|
|
return USB_SUCCESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return USB_UNSUPPORT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#if defined(ENABLE_VIRTUAL_COM_PORT)
|
|
|
|
return Virtual_Com_Port_Data_Setup (RequestNo);
|
|
|
|
#else
|
|
|
|
return USB_UNSUPPORT;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return USB_UNSUPPORT;
|
2010-09-04 09:44:01 +00:00
|
|
|
}
|
2010-12-10 07:31:25 +00:00
|
|
|
|
|
|
|
static RESULT
|
|
|
|
gnuk_setup_with_nodata (uint8_t RequestNo)
|
|
|
|
{
|
|
|
|
if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
|
|
|
|
if (pInformation->USBwIndex0 == 0) /* Interface */
|
|
|
|
{
|
|
|
|
if (RequestNo == USB_CCID_REQ_ABORT)
|
|
|
|
/* wValue: bSeq, bSlot */
|
|
|
|
/* Abortion is not supported in Gnuk */
|
|
|
|
return USB_UNSUPPORT;
|
|
|
|
else
|
|
|
|
return USB_UNSUPPORT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#if defined(ENABLE_VIRTUAL_COM_PORT)
|
|
|
|
return Virtual_Com_Port_NoData_Setup (RequestNo);
|
|
|
|
#else
|
|
|
|
return USB_UNSUPPORT;
|
2010-09-04 09:44:01 +00:00
|
|
|
#endif
|
2010-12-10 07:31:25 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
return USB_UNSUPPORT;
|
|
|
|
}
|
2010-09-04 09:44:01 +00:00
|
|
|
|
2010-08-18 03:57:45 +00:00
|
|
|
/*
|
|
|
|
* Interface to USB core
|
|
|
|
*/
|
|
|
|
|
2010-09-04 04:48:26 +00:00
|
|
|
const DEVICE_PROP Device_Property = {
|
2010-08-18 03:57:45 +00:00
|
|
|
gnuk_device_init,
|
|
|
|
gnuk_device_reset,
|
|
|
|
gnuk_device_Status_In,
|
|
|
|
gnuk_device_Status_Out,
|
2010-12-10 07:31:25 +00:00
|
|
|
gnuk_setup_with_data,
|
|
|
|
gnuk_setup_with_nodata,
|
2010-08-18 03:57:45 +00:00
|
|
|
gnuk_device_Get_Interface_Setting,
|
|
|
|
gnuk_device_GetDeviceDescriptor,
|
|
|
|
gnuk_device_GetConfigDescriptor,
|
|
|
|
gnuk_device_GetStringDescriptor,
|
|
|
|
0,
|
|
|
|
GNUK_MAX_PACKET_SIZE
|
|
|
|
};
|
|
|
|
|
2010-09-04 04:48:26 +00:00
|
|
|
const DEVICE Device_Table = {
|
2010-08-18 03:57:45 +00:00
|
|
|
EP_NUM,
|
|
|
|
1
|
|
|
|
};
|
|
|
|
|
2010-09-04 04:48:26 +00:00
|
|
|
const USER_STANDARD_REQUESTS User_Standard_Requests = {
|
2010-08-18 03:57:45 +00:00
|
|
|
NOP_Process, /* GetConfiguration */
|
|
|
|
gnuk_device_SetConfiguration,
|
|
|
|
NOP_Process, /* GetInterface */
|
2011-02-01 06:25:36 +00:00
|
|
|
gnuk_device_SetInterface,
|
2010-08-18 03:57:45 +00:00
|
|
|
NOP_Process, /* GetStatus */
|
|
|
|
NOP_Process, /* ClearFeature */
|
|
|
|
NOP_Process, /* SetEndPointFeature */
|
|
|
|
NOP_Process, /* SetDeviceFeature */
|
|
|
|
gnuk_device_SetDeviceAddress
|
|
|
|
};
|