/*C************************************************************************** * NAME: usb_kbd_enum.c *---------------------------------------------------------------------------- * Copyright (c) 2003 Atmel. *---------------------------------------------------------------------------- * RELEASE: c5131-usb-kbd-light-1_0_2 * REVISION: 1.2 *---------------------------------------------------------------------------- * PURPOSE: * This file contains the USB Endpoint 0 management routines corresponding * to a USB HID keyboard implementation. *****************************************************************************/ /*_____ I N C L U D E S ____________________________________________________*/ #include "config.h" #include "lib_mcu\usb\usb_drv.h" #include "usb_kbd_enum.h" /*_____ M A C R O S ________________________________________________________*/ /*_____ D E F I N I T I O N ________________________________________________*/ code struct usb_st_device_descriptor usb_device_descriptor = { sizeof(usb_device_descriptor), DEVICE, USB_SPECIFICATION, DEVICE_CLASS, DEVICE_SUB_CLASS, DEVICE_PROTOCOL, EP_CONTROL_LENGTH, VENDOR_ID, PRODUCT_ID, RELEASE_NUMBER, MAN_INDEX, PROD_INDEX, SN_INDEX, NB_CONFIGURATION }; code struct usb_st_manufacturer usb_manufacturer = { sizeof(usb_manufacturer), STRING, USB_MANUFACTURER_NAME }; code struct usb_st_product usb_product = { sizeof(usb_product), STRING, USB_PRODUCT_NAME }; code struct usb_st_serial_number usb_serial_number = { sizeof(usb_serial_number), STRING, USB_SERIAL_NUMBER }; code struct usb_st_language_descriptor usb_language = { sizeof(usb_language), STRING, LANGUAGE_ID }; code struct { struct usb_st_configuration_descriptor cfg; struct usb_st_interface_descriptor ifc; struct usb_st_hid_descriptor hid ; struct usb_st_endpoint_descriptor ep1 ; Uchar rep[SIZE_OF_REPORT] ; } usb_configuration = { { 9, CONFIGURATION, CONF_LENGTH, NB_INTERFACE, CONF_NB, CONF_INDEX, CONF_ATTRIBUTES, MAX_POWER}, { 9, INTERFACE, INTERFACE_NB, ALTERNATE, NB_ENDPOINT, INTERFACE_CLASS, INTERFACE_SUB_CLASS, INTERFACE_PROTOCOL, INTERFACE_INDEX }, { 9, HID, 0x1101, 8, 1, REPORT, 0x3B00 }, { 7, ENDPOINT, ENDPOINT_NB_1, EP_ATTRIBUTES_1, EP_SIZE_1, EP_INTERVAL_1 }, { 0x05,0x01, /* Usage Page (Generic Desktop) */ 0x09,0x04, /* Usage (Keyboard) */ 0xA1,0x01, /* Collection (Application) */ 0x05,0x07, /* Usage Page (Keyboard) */ 0x19,224, /* Usage Minimum (224) */ 0x29,231, /* Usage Maximum (231) */ 0x15,0x00, /* Logical Minimum (0) */ 0x25,0x01, /* Logical Maximum (1) */ 0x75,0x01, /* Report Size (1) */ 0x95,0x08, /* Report Count (8) */ 0x81,0x02, /* Input (Data, Variable, Absolute) */ 0x81,0x01, /* Input (Constant) */ 0x19,0x00, /* Usage Minimum (0) */ 0x29,101, /* Usage Maximum (101) */ 0x15,0x00, /* Logical Minimum (0) */ 0x25,101, /* Logical Maximum (101) */ 0x75,0x08, /* Report Size (8) */ 0x95,0x06, /* Report Count (6) */ 0x81,0x00, /* Input (Data, Array) */ 0x05,0x08, /* Usage Page (LED) */ 0x19,0x01, /* Usage Minimum (1) */ 0x29,0x05, /* Usage Maximum (5) */ 0x15,0x00, /* Logical Minimum (0) */ 0x25,0x01, /* Logical Maximum (1) */ 0x75,0x01, /* Report Size (1) */ 0x95,0x05, /* Report Count (5) */ 0x91,0x02, /* Output (Data, Variable, Absolute) */ 0x95,0x03, /* Report Count (3) */ 0x91,0x01, /* Output (Constant) */ 0xC0 /* End Collection */ } }; static bit zlp; static Uchar endpoint_status[2]; static Uchar hid_idle_duration; static Uchar *pbuffer; static Uchar bmRequestType; Uchar usb_configuration_nb; extern bit usb_connected; /*_____ D E C L A R A T I O N ______________________________________________*/ static void usb_get_descriptor (void); static void usb_read_request (void); static void usb_set_address (void); static void usb_set_configuration (void); static void usb_clear_feature (void); static void usb_set_feature (void); static void usb_get_status (void); static void usb_get_configuration (void); static void usb_get_interface (void); static void usb_hid_set_report (void); static void usb_hid_set_idle (void); static void usb_hid_get_idle (void); /*F************************************************************************** * NAME: usb_var_init *---------------------------------------------------------------------------- * PARAMS: * * return: *---------------------------------------------------------------------------- * PURPOSE: * This function initializes the USB controller and resets the endpoints FIFOs. *---------------------------------------------------------------------------- * EXAMPLE: *---------------------------------------------------------------------------- * NOTE: *---------------------------------------------------------------------------- * REQUIREMENTS: *****************************************************************************/ void usb_var_init (void) { endpoint_status[EP_CONTROL] = 0x00; endpoint_status[EP_IN] = 0x00; usb_connected = FALSE; usb_configuration_nb = 0x00; } /*F************************************************************************** * NAME: usb_ep_init *---------------------------------------------------------------------------- * PARAMS: * * return: *---------------------------------------------------------------------------- * PURPOSE: * This function configures the endpoints. *---------------------------------------------------------------------------- * EXAMPLE: *---------------------------------------------------------------------------- * NOTE: *---------------------------------------------------------------------------- * REQUIREMENTS: *****************************************************************************/ void usb_ep_init (void) { usb_configure_endpoint(EP_IN , INTERRUPT_IN); usb_reset_endpoint(EP_IN); } /*F************************************************************************** * NAME: usb_enumeration_process *---------------------------------------------------------------------------- * PARAMS: * * return: *---------------------------------------------------------------------------- * PURPOSE: * This function manages the enumeration process *---------------------------------------------------------------------------- * EXAMPLE: *---------------------------------------------------------------------------- * NOTE: *---------------------------------------------------------------------------- * REQUIREMENTS: *****************************************************************************/ void usb_enumeration_process (void) { Usb_select_ep(EP_CONTROL); usb_read_request(); } /*F************************************************************************** * NAME: usb_read_request *---------------------------------------------------------------------------- * PARAMS: * * return: *---------------------------------------------------------------------------- * PURPOSE: * This function reads the SETUP request sent to the default control endpoint * and the appropriate function. When exiting of the usb_read_request * function, the device is ready to manage the next request. *---------------------------------------------------------------------------- * EXAMPLE: *---------------------------------------------------------------------------- * NOTE: list of supported requests: * GET_DESCRIPTOR * GET_CONFIGURATION * SET_ADDRESS * SET_CONFIGURATION or SET_REPORT * CLEAR_FEATURE * SET_FEATURE * GET_STATUS * GET_MAX_LUN * MASS_STORAGE_RESET *---------------------------------------------------------------------------- * REQUIREMENTS: *****************************************************************************/ void usb_read_request (void) { bmRequestType = Usb_read_byte(); /* read bmRequestType */ switch (Usb_read_byte()) /* test the bRequest value */ { case GET_DESCRIPTOR: usb_get_descriptor(); break; case GET_CONFIGURATION: usb_get_configuration(); break; case SET_ADDRESS: usb_set_address(); break; case SET_CONFIGURATION: /* or SET_REPORT */ if (bmRequestType == 0) { usb_set_configuration(); } else { usb_hid_set_report(); } break; case CLEAR_FEATURE: usb_clear_feature(); break; case SET_FEATURE: usb_set_feature(); break; case GET_STATUS: usb_get_status(); break; case GET_INTERFACE: /* HID_SET_IDLE */ if (bmRequestType == 0x81) { usb_get_interface(); } else { usb_hid_set_idle(); } break; case HID_GET_IDLE: usb_hid_get_idle(); break; case SET_DESCRIPTOR: case SET_INTERFACE: case SYNCH_FRAME: default: Usb_clear_rx_setup(); Usb_set_stall_request(); while (!Usb_stall_sent()); Usb_clear_stall_request(); Usb_clear_stalled(); break; } Usb_clear_DIR(); } /*F************************************************************************** * NAME: usb_set_address *---------------------------------------------------------------------------- * PARAMS: * * return: *---------------------------------------------------------------------------- * PURPOSE: * This function manages the SET_ADDRESS request. The new address is stored * in the USBADDR register *---------------------------------------------------------------------------- * EXAMPLE: *---------------------------------------------------------------------------- * NOTE: *---------------------------------------------------------------------------- * REQUIREMENTS: *****************************************************************************/ void usb_set_address (void) { Uchar add; add = Usb_read_byte(); /* store the LSB of wValue = address */ Usb_clear_rx_setup(); Usb_set_tx_ready(); /* send a ZLP for STATUS phase */ Usb_set_FADDEN(); /* The FEN bit and the FADDEN bit in the USBCON register will be set to allow the USB controller to answer only to requests sent at the new address */ while (!(Usb_tx_complete())); Usb_clear_tx_complete(); Usb_configure_address(add); /* FEN bit is set in USBADDR Register */ } /*F************************************************************************** * NAME: usb_set_configuration *---------------------------------------------------------------------------- * PARAMS: * * return: *---------------------------------------------------------------------------- * PURPOSE: * This function manages the SET_CONFIGURATION request. *---------------------------------------------------------------------------- * EXAMPLE: *---------------------------------------------------------------------------- * NOTE: *---------------------------------------------------------------------------- * REQUIREMENTS: *****************************************************************************/ void usb_set_configuration (void) { Uchar configuration_number; configuration_number = Usb_read_byte(); /* read the conf. num. in wValue */ Usb_clear_DIR(); Usb_clear_rx_setup(); /* switch (configuration_number) { case 0: Usb_clear_CONFG(); usb_configurion = 0x00; break; case CONF_NB: Usb_set_CONFG(); Usb_set_usb_configured(); break; default: Usb_set_stall_request(); while (!Usb_stall_sent()); Usb_clear_stall_request(); Usb_clear_stalled(); return; }*/ if (configuration_number <= CONF_NB) { usb_configuration_nb = configuration_number; } else { Usb_set_stall_request(); while (!Usb_stall_sent()); Usb_clear_stall_request(); Usb_clear_stalled(); return; } Usb_set_tx_ready(); /* send a ZLP for STATUS phase */ while (!Usb_tx_complete()); Usb_clear_tx_complete(); usb_ep_init(); /* endpoints configuration */ } /*F************************************************************************** * NAME: usb_get_descriptor *---------------------------------------------------------------------------- * PARAMS: * * return: *---------------------------------------------------------------------------- * PURPOSE: * This function manages the GET_DESCRIPTOR request. *---------------------------------------------------------------------------- * EXAMPLE: *---------------------------------------------------------------------------- * NOTE: *---------------------------------------------------------------------------- * REQUIREMENTS: *****************************************************************************/ void usb_get_descriptor (void) { Uchar data_to_transfer; Uint16 wLength; Uchar descriptor_type; Uchar string_type; zlp = FALSE; /* no zero length packet */ string_type = Usb_read_byte(); /* read LSB of wValue */ descriptor_type = Usb_read_byte(); /* read MSB of wValue */ switch (descriptor_type) { case DEVICE: { data_to_transfer = sizeof (usb_device_descriptor); pbuffer = &(usb_device_descriptor.bLength); break; } case CONFIGURATION: { data_to_transfer = sizeof (usb_configuration); pbuffer = &(usb_configuration.cfg.bLength); break; } case REPORT: { data_to_transfer = SIZE_OF_REPORT; pbuffer = &(usb_configuration.rep[0]); break; } case HID: { data_to_transfer = sizeof(usb_configuration.hid); pbuffer = &(usb_configuration.hid.bLength); break; } case STRING: { switch (string_type) { case LANG_ID: { data_to_transfer = sizeof (usb_language); pbuffer = &(usb_language.bLength); break; } case MAN_INDEX: { data_to_transfer = sizeof (usb_manufacturer); pbuffer = &(usb_manufacturer.bLength); break; } case PROD_INDEX: { data_to_transfer = sizeof (usb_product); pbuffer = &(usb_product.bLength); break; } case SN_INDEX: { data_to_transfer = sizeof (usb_serial_number); pbuffer = &(usb_serial_number.bLength); break; } default: { Usb_clear_rx_setup(); Usb_set_stall_request(); while ((!(Usb_stall_sent())) && (Usb_setup_received())); Usb_clear_stalled(); Usb_clear_stall_request(); Usb_clear_DIR(); return; } } break; } default: { Usb_clear_rx_setup(); Usb_set_stall_request(); while ((!(Usb_stall_sent())) && (Usb_setup_received())); Usb_clear_stalled(); Usb_clear_stall_request(); Usb_clear_DIR(); return; } } ACC = Usb_read_byte(); /* don't care of wIndex field */ ACC = Usb_read_byte(); ((Uchar*)&wLength)[1] = Usb_read_byte(); /* read wLength */ ((Uchar*)&wLength)[0] = Usb_read_byte(); if (wLength > data_to_transfer) { if ((data_to_transfer % EP_CONTROL_LENGTH) == 0) { zlp = TRUE; } /*EP_CONTROL_LENGTH IS bMaxPacketSizeO */ /*zlp = zero length packet = success*/ else { zlp = FALSE; } /* no need of zero length packet */ } else { data_to_transfer = (Uchar)wLength; /* send only requested number of data */ } Usb_clear_rx_setup() ; /* clear the receive setup flag */ Usb_set_DIR(); /* set out on EP0 */ while (data_to_transfer > EP_CONTROL_LENGTH) /* data_to_transfer = size of the descriptor structure */ { pbuffer = usb_send_ep0_packet(pbuffer, EP_CONTROL_LENGTH); data_to_transfer -= EP_CONTROL_LENGTH; /* Data = Data - EP */ /* if 3 transactions eg: on 3rd loop, descriptor structure - 2*ep_control_length /* while ((!(Usb_rx_complete())) && (!(Usb_tx_complete()))); Usb_clear_tx_complete(); if ((Usb_rx_complete())) /* if cancel from USB Host */ { Usb_clear_tx_ready(); Usb_clear_rx(); return; } } /* send last data packet */ pbuffer = usb_send_ep0_packet(pbuffer, data_to_transfer); data_to_transfer = 0; while ((!(Usb_rx_complete())) && (!(Usb_tx_complete()))); Usb_clear_tx_complete(); if ((Usb_rx_complete())) /* if cancel from USB Host */ { Usb_clear_tx_ready(); Usb_clear_rx(); return; } if (zlp == TRUE) { usb_send_ep0_packet(pbuffer, 0); while ((!(Usb_rx_complete())) && (!(Usb_tx_complete()))); Usb_clear_tx_complete(); if ((Usb_rx_complete())) /* if cancel from USB Host */ { Usb_clear_tx_ready(); Usb_clear_rx(); return; } } while ((!(Usb_rx_complete())) && (!(Usb_setup_received()))); if (Usb_setup_received()) { return; } if (Usb_rx_complete()) { Usb_clear_DIR(); /* set in on EP0 */ Usb_clear_rx(); } } /*F************************************************************************** * NAME: usb_get_configuration *---------------------------------------------------------------------------- * PARAMS: * * return: *---------------------------------------------------------------------------- * PURPOSE: * This function manages the GET_CONFIGURATION request. *---------------------------------------------------------------------------- * EXAMPLE: *---------------------------------------------------------------------------- * NOTE: *---------------------------------------------------------------------------- * REQUIREMENTS: *****************************************************************************/ void usb_get_configuration (void) { Usb_clear_rx_setup(); Usb_set_DIR(); /* if (Usb_get_usb_configured()) { Usb_write_byte(1); } else { Usb_write_byte(0); } */ Usb_write_byte(usb_configuration_nb); Usb_set_tx_ready(); while (!(Usb_tx_complete())); Usb_clear_tx_complete(); while (!(Usb_rx_complete())); Usb_clear_rx(); Usb_clear_DIR(); } /*F************************************************************************** * NAME: usb_get_interface *---------------------------------------------------------------------------- * PARAMS: * * return: *---------------------------------------------------------------------------- * PURPOSE: * This function manages the GET_INTERFACE request. *---------------------------------------------------------------------------- * EXAMPLE: *---------------------------------------------------------------------------- * NOTE: *---------------------------------------------------------------------------- * REQUIREMENTS: *****************************************************************************/ void usb_get_interface (void) { Usb_clear_rx_setup(); Usb_set_DIR(); Usb_set_stall_request(); /* send STALL if only one interface configuration */ while (!Usb_stall_sent()); Usb_clear_stall_request(); Usb_clear_stalled(); Usb_clear_DIR(); } /*F************************************************************************** * NAME: usb_get_status *---------------------------------------------------------------------------- * PARAMS: * * return: *---------------------------------------------------------------------------- * PURPOSE: * This function manages the GET_STATUS request. *---------------------------------------------------------------------------- * EXAMPLE: *---------------------------------------------------------------------------- * NOTE: *---------------------------------------------------------------------------- * REQUIREMENTS: *****************************************************************************/ void usb_get_status (void) { Uchar wIndex; ACC = Usb_read_byte(); /* dummy read */ ACC = Usb_read_byte(); /* dummy read */ wIndex = Usb_read_byte(); Usb_clear_rx_setup(); Usb_set_DIR(); switch(bmRequestType) { case REQUEST_DEVICE_STATUS: Usb_write_byte(SELF_POWERED); break; case REQUEST_INTERFACE_STATUS: Usb_write_byte(0x00); break; case REQUEST_ENDPOINT_STATUS: wIndex = wIndex & MSK_EP_DIR; Usb_write_byte(endpoint_status[wIndex]); break; } Usb_write_byte(0x00); Usb_set_tx_ready(); while ((!(Usb_tx_complete())) || (Usb_setup_received())); Usb_clear_tx_complete(); while ((!(Usb_rx_complete())) || (Usb_setup_received())); Usb_clear_rx(); Usb_clear_DIR(); } /*F************************************************************************** * NAME: usb_set_feature *---------------------------------------------------------------------------- * PARAMS: * * return: *---------------------------------------------------------------------------- * PURPOSE: * This function manages the SET_FEATURE request. *---------------------------------------------------------------------------- * EXAMPLE: *---------------------------------------------------------------------------- * NOTE: *---------------------------------------------------------------------------- * REQUIREMENTS: *****************************************************************************/ void usb_set_feature (void) { if (bmRequestType == ZERO_TYPE) { Usb_clear_rx_setup(); Usb_set_stall_request(); while (!(Usb_stall_sent())); Usb_clear_stall_request(); } if (bmRequestType == INTERFACE_TYPE) { Usb_clear_rx_setup(); Usb_set_stall_request(); while (!(Usb_stall_sent())); Usb_clear_stall_request(); } if (bmRequestType == ENDPOINT_TYPE) { if (Usb_read_byte() == 0x00) { ACC = Usb_read_byte(); /* dummy read */ switch (Usb_read_byte()) /* check wIndex */ { case ENDPOINT_1: { Usb_select_ep(EP_IN); Usb_set_stall_request(); Usb_select_ep(EP_CONTROL); endpoint_status[EP_IN] = 0x01; Usb_clear_rx_setup(); Usb_set_tx_ready(); while (!(Usb_tx_complete())); Usb_clear_tx_complete(); break; } default: { Usb_clear_rx_setup(); Usb_set_stall_request(); while (!(Usb_stall_sent())); Usb_clear_stall_request(); Usb_clear_stalled(); break; } } } } } /*F************************************************************************** * NAME: usb_clear_feature *---------------------------------------------------------------------------- * PARAMS: * * return: *---------------------------------------------------------------------------- * PURPOSE: * This function manages the SET_FEATURE request. *---------------------------------------------------------------------------- * EXAMPLE: *---------------------------------------------------------------------------- * NOTE: *---------------------------------------------------------------------------- * REQUIREMENTS: *****************************************************************************/ void usb_clear_feature (void) { if (bmRequestType == ZERO_TYPE) { Usb_clear_rx_setup(); Usb_set_stall_request(); while (!(Usb_stall_sent())); Usb_clear_stall_request(); } if (bmRequestType == INTERFACE_TYPE) { Usb_clear_rx_setup(); Usb_set_stall_request(); while (!(Usb_stall_sent())); Usb_clear_stall_request(); } if (bmRequestType == ENDPOINT_TYPE) { if (Usb_read_byte() == 0x00) { ACC = Usb_read_byte(); /* dummy read */ switch (Usb_read_byte()) /* check wIndex */ { case ENDPOINT_1: { Usb_select_ep(EP_IN); Usb_clear_stall_request(); usb_reset_endpoint(EP_IN); Usb_select_ep(EP_CONTROL); endpoint_status[EP_IN] = 0x00; Usb_clear_rx_setup(); Usb_set_tx_ready(); while (!(Usb_tx_complete())); Usb_clear_tx_complete(); break; } case ENDPOINT_0: { Usb_clear_rx_setup(); Usb_set_tx_ready(); while (!(Usb_tx_complete())); Usb_clear_tx_complete(); break; } default: { Usb_clear_rx_setup(); Usb_set_stall_request(); while (!(Usb_stall_sent())); Usb_clear_stall_request(); break; } } } } } /*F************************************************************************** * NAME: usb_hid_set_report *---------------------------------------------------------------------------- * PARAMS: * * return: *---------------------------------------------------------------------------- * PURPOSE: * This function manages the SET_REPORT request (HID Class) *---------------------------------------------------------------------------- * EXAMPLE: *---------------------------------------------------------------------------- * NOTE: *---------------------------------------------------------------------------- * REQUIREMENTS: *****************************************************************************/ void usb_hid_set_report (void) { Usb_clear_rx_setup(); while(!Usb_rx_complete() ); Usb_clear_rx(); Usb_set_tx_ready(); /* send a ZLP for STATUS phase */ while(!(Usb_tx_complete())); Usb_clear_tx_complete(); } /*F************************************************************************** * NAME: usb_hid_set_idle *---------------------------------------------------------------------------- * PARAMS: * * return: *---------------------------------------------------------------------------- * PURPOSE: * This function manages the HID_SET_IDLE request. *---------------------------------------------------------------------------- * EXAMPLE: *---------------------------------------------------------------------------- * NOTE: *---------------------------------------------------------------------------- * REQUIREMENTS: *****************************************************************************/ void usb_hid_set_idle (void) { ACC = Usb_read_byte(); hid_idle_duration = Usb_read_byte(); /* wValue contains the duration */ Usb_clear_rx_setup(); Usb_set_tx_ready(); /* send a ZLP for STATUS phase */ while(!(Usb_tx_complete())); Usb_clear_tx_complete(); } /*F************************************************************************** * NAME: usb_hid_get_idle *---------------------------------------------------------------------------- * PARAMS: * * return: *---------------------------------------------------------------------------- * PURPOSE: * This function manages the GET_IDLE request. *---------------------------------------------------------------------------- * EXAMPLE: *---------------------------------------------------------------------------- * NOTE: *---------------------------------------------------------------------------- * REQUIREMENTS: *****************************************************************************/ void usb_hid_get_idle (void) { Usb_clear_rx_setup(); Usb_set_DIR(); Usb_write_byte(hid_idle_duration); Usb_set_tx_ready(); /* send a ZLP for STATUS phase */ while(!(Usb_tx_complete())); Usb_clear_tx_complete(); while (!(Usb_rx_complete())); Usb_clear_rx(); Usb_clear_DIR(); } /*_____ E N D O F F I L E _________________________________________________*/