/***************************************************************************
                                  descript.c
                             -------------------
    project:  USB device for Philips ISP1181

    begin                : Wed Sep 4 2002
    copyright            : (C) 2002 by HBM GmbH, Siegfried Wessler
    email                : siegfried.wessler@hbm.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program 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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/


#include  <asm/io.h>      // DISABLE_INTERRUPT, ENABLE_INTERRUPT

#include  "types.h"
#include  "global.h"
#include  "isp1181.h"
#include  "descript.h"


#ifdef  DEBUG_ON
  INT32 debug_count = 0;      // counter for debugging feature in control_handler()
  boolean debug_trigger = FALSE;  
#endif


UINT8   num_active_endpoints;
UINT16  config_descriptor_length;


USB_DEVICE_DESCRIPTOR DeviceDescr =
{
  USB_DEVICE_DESCRIPTOR_LENGTH,       // UINT8 bLength
  USB_DEVICE_DESCRIPTOR_TYPE,         // UINT8 bDescriptorType: DEVICE descriptor
  USB_SPEC_ID,                        // UINT16 bcdUSB: BCD of the supported USB specification
  VENDORSPEC,                         // UINT8 bDeviceClass: user defined device class
  VENDORSPEC,                         // UINT8 bDeviceSubClass: user defined device subclass
  VENDORSPEC,                         // UINT8 bDeviceProtocol: user defined device protocol
  EP_CTRL_PACKET_SIZE,                // UINT8 bMaxPacketSize0: max packet size, usually 64
  USB_VENDOR_ID,                      // UINT16 idVendor: HBM's USB-IF vendor id
  USB_PRODUCT_ID,                     // UINT16 idProduct: HBM's product id
  USB_REVISION_ID,                    // UINT16 bcdDevice: HBM's revision id
  STR_INDEX_MANUFACTURER,             // UINT8 iManufacturer: index of manufactor's string
  STR_INDEX_PRODUCT,                  // UINT8 iProduct: index of product's string
  STR_INDEX_SERIALNUMBER,             // UINT8 iSerialNumber: index of serial number string
  1                                   // UINT8 bNumConfigurations: number of configurations of this device
};


USB_CONFIGURATION_DESCRIPTOR ConfigDescr =
{
  USB_CONFIGURATION_DESCRIPTOR_LENGTH,    // bLength: length of configuration descriptor
  USB_CONFIGURATION_DESCRIPTOR_TYPE,      // bDescriptorType: CONFIGURATION descriptor
  0,                                      // wTotalLength: loaded with "config_descriptor_length"
                                          //  in main.c at startup or after reconfiguration
  1,                                      // bNumInterfaces: number of interfaces
  1,                                      // bConfigurationValue: id number of this configuration
  STR_INDEX_CONFIGURATION,                // iConfiguration: index of configuration string
  USB_ATTR_SELF_POWERED | 0x80,           // bmAttributes: self powered
  1                                       // MaxPower: max. 2 mA
};


USB_INTERFACE_DESCRIPTOR InterfaceDescr =
{
  USB_INTERFACE_DESCRIPTOR_LENGTH,        // bLength: length of interface descriptor
  USB_INTERFACE_DESCRIPTOR_TYPE,          // bDescriptorType: INTERFACE descriptor
  0,                                      // bInterfaceNumber: interface id number
  0,                                      // bAlternateSetting: alternate setting
  2,                                      // bNumEndpoints: number of (non 0) endpoints,
                                          //  loaded with "num_active_endpoints" in main.c at startup
                                          //  or after reconfiguration
  VENDORSPEC,                             // bInterfaceClass
  VENDORSPEC,                             // bInterfaceSubClass
  VENDORSPEC,                             // bInterfaceProtocol
  STR_INDEX_INTERFACE,                    // bInterface: index of intface string
};


USB_ENDPOINT_DESCRIPTOR EndpointDescr[MAX_ENDPOINTS] =
{
  { // Pipe 1 -> Endpoint 1 = MAIN_OUT
    USB_ENDPOINT_DESCRIPTOR_LENGTH,       // bLength: length of endpoint 1 descriptor
    USB_ENDPOINT_DESCRIPTOR_TYPE,         // bDescriptorType: ENDPOINT descriptor
    EP_MAIN_OUT -1,                       // bEndpointAddress: address (OUT)
    USB_ATTR_BULK,                        // bmAttributes:  BULK
    EP_MAIN_OUT_FIFO_SIZE,                // wMaxPacketSize: 64
    0                                     // bInterval: (ms), ignored in bulk mode
  },
  { // Pipe 2 -> Endpoint 2 = MAIN_IN
    USB_ENDPOINT_DESCRIPTOR_LENGTH,       // length of endpoint 2 descriptor
    USB_ENDPOINT_DESCRIPTOR_TYPE,         // ENDPOINT descriptor
    (EP_MAIN_IN -1) | 0x80,               // address (IN)
    USB_ATTR_BULK,                        // attributes  (BULK)
    EP_MAIN_IN_FIFO_SIZE,                 // max packet size (64)
    0                                     // interval (ms), ignored in bulk mode
  },

  // all other endpoints will be defined dynamically; loaded with default values:
  {
    USB_ENDPOINT_DESCRIPTOR_LENGTH,       // length of endpoint descriptor
    USB_ENDPOINT_DESCRIPTOR_TYPE,         // ENDPOINT descriptor
    EP_ISO1_IN -1,                        // address (OUT)
    USB_ATTR_ISOCHRON,                    // attributes  (ISOCHRONOUS)
    0,                                    // PacketBufferSize
    1                                     // interval (ms)
  },
  {
    USB_ENDPOINT_DESCRIPTOR_LENGTH,       // length of endpoint descriptor
    USB_ENDPOINT_DESCRIPTOR_TYPE,         // ENDPOINT descriptor
    EP_ISO1_IN -1,                        // address (OUT)
    USB_ATTR_ISOCHRON,                    // attributes  (ISOCHRONOUS)
    0,                                    // PacketBufferSize
    1                                     // interval (ms)
  },
  {
    USB_ENDPOINT_DESCRIPTOR_LENGTH,       // length of endpoint descriptor
    USB_ENDPOINT_DESCRIPTOR_TYPE,         // ENDPOINT descriptor
    EP_ISO1_IN -1,                        // address (OUT)
    USB_ATTR_ISOCHRON,                    // attributes  (ISOCHRONOUS)
    0,                                    // PacketBufferSize
    1                                     // interval (ms)
  },
  {
    USB_ENDPOINT_DESCRIPTOR_LENGTH,       // length of endpoint descriptor
    USB_ENDPOINT_DESCRIPTOR_TYPE,         // ENDPOINT descriptor
    EP_ISO1_IN -1,                        // address (OUT)
    USB_ATTR_ISOCHRON,                    // attributes  (ISOCHRONOUS)
    0,                                    // PacketBufferSize
    1                                     // interval (ms)
  },
  {
    USB_ENDPOINT_DESCRIPTOR_LENGTH,       // length of endpoint descriptor
    USB_ENDPOINT_DESCRIPTOR_TYPE,         // ENDPOINT descriptor
    EP_ISO1_IN -1,                        // address (OUT)
    USB_ATTR_ISOCHRON,                    // attributes  (ISOCHRONOUS)
    0,                                    // PacketBufferSize
    1                                     // interval (ms)
  },
  {
    USB_ENDPOINT_DESCRIPTOR_LENGTH,       // length of endpoint descriptor
    USB_ENDPOINT_DESCRIPTOR_TYPE,         // ENDPOINT descriptor
    EP_ISO1_IN -1,                        // address (OUT)
    USB_ATTR_ISOCHRON,                    // attributes  (ISOCHRONOUS)
    0,                                    // PacketBufferSize
    1                                     // interval (ms)
  },
  {
    USB_ENDPOINT_DESCRIPTOR_LENGTH,       // length of endpoint descriptor
    USB_ENDPOINT_DESCRIPTOR_TYPE,         // ENDPOINT descriptor
    EP_ISO1_IN -1,                        // address (OUT)
    USB_ATTR_ISOCHRON,                    // attributes  (ISOCHRONOUS)
    0,                                    // PacketBufferSize
    1                                     // interval (ms)
  },
  {
    USB_ENDPOINT_DESCRIPTOR_LENGTH,       // length of endpoint descriptor
    USB_ENDPOINT_DESCRIPTOR_TYPE,         // ENDPOINT descriptor
    EP_ISO1_IN -1,                        // address (OUT)
    USB_ATTR_ISOCHRON,                    // attributes  (ISOCHRONOUS)
    0,                                    // PacketBufferSize
    1                                     // interval (ms)
  },
  {
    USB_ENDPOINT_DESCRIPTOR_LENGTH,       // length of endpoint descriptor
    USB_ENDPOINT_DESCRIPTOR_TYPE,         // ENDPOINT descriptor
    EP_ISO1_IN -1,                        // address (OUT)
    USB_ATTR_ISOCHRON,                    // attributes  (ISOCHRONOUS)
    0,                                    // PacketBufferSize
    1                                     // interval (ms)
  },
  {
    USB_ENDPOINT_DESCRIPTOR_LENGTH,       // length of endpoint descriptor
    USB_ENDPOINT_DESCRIPTOR_TYPE,         // ENDPOINT descriptor
    EP_ISO1_IN -1,                        // address (OUT)
    USB_ATTR_ISOCHRON,                    // attributes  (ISOCHRONOUS)
    0,                                    // PacketBufferSize
    1                                     // interval (ms)
  },
  {
    USB_ENDPOINT_DESCRIPTOR_LENGTH,       // length of endpoint descriptor
    USB_ENDPOINT_DESCRIPTOR_TYPE,         // ENDPOINT descriptor
    EP_ISO1_IN -1,                        // address (OUT)
    USB_ATTR_ISOCHRON,                    // attributes  (ISOCHRONOUS)
    0,                                    // PacketBufferSize
    1                                     // interval (ms)
  },
  {
    USB_ENDPOINT_DESCRIPTOR_LENGTH,       // length of endpoint descriptor
    USB_ENDPOINT_DESCRIPTOR_TYPE,         // ENDPOINT descriptor
    EP_ISO1_IN -1,                        // address (OUT)
    USB_ATTR_ISOCHRON,                    // attributes  (ISOCHRONOUS)
    0,                                    // PacketBufferSize
    1                                     // interval (ms)
  },

};


USB_STRING_LANGUAGE_DESCRIPTOR  strLanguage =
{
  sizeof(USB_STRING_LANGUAGE_DESCRIPTOR), // bLength
  USB_STRING_DESCRIPTOR_TYPE,             // bDescriptorType
  USB_LANGUAGE_ENGLISH                    // ulanguageID
};


USB_STRING_INTERFACE_DESCRIPTOR  strInterface =
{
  sizeof(USB_STRING_INTERFACE_DESCRIPTOR),
  USB_STRING_DESCRIPTOR_TYPE,
  { 'I',0,'n',0,'t',0,'e',0,'r',0,'f',0,'a',0,'c',0,'e',0,' ',0,'0',0 }
};


USB_STRING_CONFIGURATION_DESCRIPTOR  strConfiguration =
{
  sizeof(USB_STRING_CONFIGURATION_DESCRIPTOR),
  USB_STRING_DESCRIPTOR_TYPE,
  { 'C',0, 'o',0, 'n',0, 'f',0, 'i',0, 'g',0, ' ',0, '0',0 }
};


USB_STRING_SERIALNUMBER_DESCRIPTOR  strSerialNum =
{
  sizeof(strSerialNum),
  USB_STRING_DESCRIPTOR_TYPE,
  {'0',0, '0',0, '0',0, '0',0, '0',0, '0',0, '0',0, '0',0, '0',0, '0',0}  // to be fill with USB_SerialNo_Str
};

#ifdef CP42
  char  USB_SerialNo_Str[] = {'C','P','4','2','p','0','0','0','0','0',0};   // Default string, overwritten by "force_id" or by Ioctl in main.c.
#endif
#ifdef CP22
  char  USB_SerialNo_Str[] = {'C','P','2','2','p','0','0','0','0','0',0};
#endif


USB_STRING_PRODUCT_DESCRIPTOR  strProduct =
{
  sizeof(USB_STRING_PRODUCT_DESCRIPTOR),
  USB_STRING_DESCRIPTOR_TYPE,
  {
  'H',0, 'B',0, 'M',0, ' ',0,
#ifdef CP22
  'C',0, 'P',0, '2',0, '2',0,
#endif
#ifdef CP42
  'C',0, 'P',0, '4',0, '2',0,
#endif
  }
};


USB_STRING_MANUFACTURER_DESCRIPTOR  strManufacturer =
{
  sizeof(USB_STRING_MANUFACTURER_DESCRIPTOR),
  USB_STRING_DESCRIPTOR_TYPE,
  {
  'H',0, 'o',0, 't',0, 't',0, 'i',0, 'n',0, 'g',0, 'e',0, 'r',0, ' ',0,
  'B',0, 'a',0, 'l',0, 'd',0, 'w',0, 'i',0, 'n',0, ' ',0,
  'M',0, 'e',0, 's',0, 's',0, 't',0, 'e',0, 'c',0, 'h',0, 'n',0, 'i',0, 'k',0
  }
};



void  copy_serialstr_to_serialdescr(void)
{
  UINT8 i;

  i = 0;
  while (USB_SerialNo_Str[i] != 0)
  {
    strSerialNum.SerialNum[i*2] = USB_SerialNo_Str[i];
    strSerialNum.SerialNum[i*2 +1] = 0;   // Unicode
    i++;
  }

  while ( i < SERIALNUM_LENGTH )
  {
    strSerialNum.SerialNum[i*2] = ' ';
    strSerialNum.SerialNum[i*2 +1] = 0;   // Unicode
    i++;
  }
}



//****************************************

void isp_StallCtrlEndpointRead(void)
{

  usb_wrc(ISP_STALL_CTRL_OUT);
  usb_wrc(ISP_STALL_CTRL_IN);

  DPRINT("isp_StallCtrlEndpointRead\n");

}


void isp_StallCtrlEndpointWrite(void)
{

  usb_wrc(ISP_STALL_CTRL_IN);
  usb_wrc(ISP_STALL_CTRL_OUT);

  DPRINT("isp_StallCtrlEndpointWrite\n");

}


void StallCtrlEndpoint(void)
{

  if (ControlData.DeviceRequest.bmRequestType & USB_ENDPOINT_DIRECTION_MASK)
    isp_StallCtrlEndpointRead();
  else
    isp_StallCtrlEndpointWrite();

}


UINT8 GetEndpointIndex(void)
{
UINT8 endp;

endp = (ControlData.DeviceRequest.wIndex & USB_ENDPOINTS_MASK);
if (endp > 0)
  return (endp +1);
else
  return (endp);

}


void code_transmit(UINT8 * pRomData, INT16 len)
{

  DPRINT("code_transmit:%i", len);

  ControlData.wCount = 0;
  if(ControlData.wLength > len)
    ControlData.wLength = len;

  ControlData.pData = pRomData;
  if( ControlData.wLength >= EP_CTRL_PACKET_SIZE)
  {
    isp_WriteCtrlEndpoint(ControlData.pData, EP_CTRL_PACKET_SIZE);
    ControlData.wCount += EP_CTRL_PACKET_SIZE;

    control_state = USB_TRANSMIT;
  }
  else
  {
    isp_WriteCtrlEndpoint(pRomData, ControlData.wLength);
    ControlData.wCount += ControlData.wLength;

    control_state = USB_IDLE;
  }

}   // code_transmit


void  transmit_complete_descriptor(void)
{
  UINT8 bBuffer[255];
  UINT8 *pBuffer;
  UINT8 i;

  memcpy(&bBuffer, &ConfigDescr, USB_CONFIGURATION_DESCRIPTOR_LENGTH);
  pBuffer = bBuffer +USB_CONFIGURATION_DESCRIPTOR_LENGTH;
  memcpy(pBuffer, &InterfaceDescr, USB_INTERFACE_DESCRIPTOR_LENGTH);
  pBuffer += USB_INTERFACE_DESCRIPTOR_LENGTH;
  for (i=0; i<num_active_endpoints; i++)


  {
    memcpy(pBuffer, &EndpointDescr[i], USB_ENDPOINT_DESCRIPTOR_LENGTH);
    pBuffer += USB_ENDPOINT_DESCRIPTOR_LENGTH;
  }

  code_transmit((UINT8 *) &bBuffer, config_descriptor_length);   // config_descriptor_length is dynamic!

}   //  transmit_complete_descriptor


// **********************************************

void get_status(void)
{
  UINT8 endp, txdat[2];
  UINT8 bRecipient;
  UINT8 c1;

  bRecipient = ControlData.DeviceRequest.bmRequestType & USB_RECIPIENT;
  txdat[0]=0;
  txdat[1]=0;


  if (!(ControlData.DeviceRequest.bmRequestType & USB_ENDPOINT_DIRECTION_MASK))
    isp_StallCtrlEndpointWrite();

  if ( (ControlData.DeviceRequest.wValue == 0)
       && (ControlData.DeviceRequest.wLength == 2) )
  {
    switch (bRecipient)
    {
      case USB_RECIPIENT_DEVICE:
        DPRINT("get_status: USB_RECIPIENT_DEVICE, flag_remote_wakeup=%d\n", flag_remote_wakeup);
        if (flag_remote_wakeup)
          txdat[0] = 2;   // send 2 0
        isp_WriteCtrlEndpoint(txdat, 2);
        break;

      case USB_RECIPIENT_INTERFACE:
        DPRINT("get_status: USB_RECIPIENT_INTERFACE\n");
        isp_WriteCtrlEndpoint(txdat, 2);          // send 0 0
        break;

      case USB_RECIPIENT_ENDPOINT:
        endp = GetEndpointIndex();
        DPRINT("get_status: USB_RECIPIENT_ENDPOINT, endp=0x%02X\n", endp);
        c1 = usb_wrc_rd1b(ISP_EP_CHECK +endp);
        if (c1 & ISP_CHECK_EPSTAL)
          txdat[0] = 1;
        isp_WriteCtrlEndpoint(txdat, 2);
        break;

      default:
        isp_StallCtrlEndpointRead();
        break;
    }
  }
  else
    isp_StallCtrlEndpointRead();

}   // get_status



void clear_feature(void)
{
UINT8 endp;
UINT8 bRecipient = ControlData.DeviceRequest.bmRequestType & USB_RECIPIENT;

  DPRINT("  clear_feature.\n");
    
  if (ControlData.DeviceRequest.bmRequestType & USB_ENDPOINT_DIRECTION_MASK)
    isp_StallCtrlEndpointRead();

  if (ControlData.DeviceRequest.wLength == 0)
  {

    switch (bRecipient)

    {
      case USB_RECIPIENT_DEVICE:
        if (ControlData.DeviceRequest.wValue == USB_FEATURE_REMOTE_WAKEUP)
        {
          DPRINT("  clear_feature: remote wakeup\n");
          flag_remote_wakeup = FALSE;
          isp_WriteCtrlEndpoint(0, 0);
        }
        else
          isp_StallCtrlEndpointWrite();
        break;

      case USB_RECIPIENT_ENDPOINT:
        if (ControlData.DeviceRequest.wValue == USB_FEATURE_ENDPOINT_STALL)
        {
          endp = GetEndpointIndex();

          DPRINT("  clear_feature: Unstall Endp=0x%02X\n", endp);
          usb_wrc(ISP_UNSTALL_EP +endp);
          isp_WriteCtrlEndpoint(0, 0);
        }
        else
        {
          isp_StallCtrlEndpointWrite();
        }
        break;

      default:
        isp_StallCtrlEndpointWrite();
        break;

    } // switch
  }
  else
  {
    isp_StallCtrlEndpointWrite();
  }

}   // clear_feature



void set_feature(void)
{
  UINT8 endp;
  UINT8 bRecipient = ControlData.DeviceRequest.bmRequestType & USB_RECIPIENT;
  
  if (ControlData.DeviceRequest.bmRequestType & USB_ENDPOINT_DIRECTION_MASK)
    isp_StallCtrlEndpointRead();

  if (ControlData.DeviceRequest.wLength == 0)
  {
    switch (bRecipient)
    {
      case USB_RECIPIENT_DEVICE:
        if (ControlData.DeviceRequest.wValue == USB_FEATURE_REMOTE_WAKEUP)
        {
          DPRINT("  set_feature: remote wakeup\n");
          flag_remote_wakeup = TRUE;
          isp_WriteCtrlEndpoint(0, 0);
        }
        else
          isp_StallCtrlEndpointWrite();
        break;

      case USB_RECIPIENT_ENDPOINT:
        endp = GetEndpointIndex();
        DPRINT("  set_feature, Endp=0x%02X - vorher:  Status=0x%02X\n", endp, usb_wrc_rd1b(ISP_EP_CHECK +endp));
        if (ControlData.DeviceRequest.wValue == USB_FEATURE_ENDPOINT_STALL)
        {
          DPRINT("  set_feature: Stall Endp=0x%02X\n", endp);
          usb_wrc(ISP_STALL_EP +endp);
          isp_WriteCtrlEndpoint(0, 0);
          DPRINT("  set_feature, nachher: Status=0x%02X\n", usb_wrc_rd1b(ISP_EP_CHECK +endp));
        }
        else
        {
          isp_StallCtrlEndpointWrite();
        }
        break;

      default:
        isp_StallCtrlEndpointWrite();
        break;

    } // switch
  }
  else
  {
    isp_StallCtrlEndpointWrite();
  }

}   // set_feature


void set_address(void)
{
UINT8 bAddress;

  bAddress = (ControlData.DeviceRequest.wValue & DEVICE_ADDRESS_MASK) | ISP_ADDR_DEVEN;
  usb_wrc_wr1b(ISP_WR_ADDR, bAddress);

  isp_WriteCtrlEndpoint(0, 0);

  DPRINT("  set_address: bAddress=%02X\n", bAddress);

}   // set_address


void get_descriptor(void)
{
  UINT8 bDescriptor;
  UINT8 bDescriptorIndex;


  DPRINT("  get_descriptor: ");

  if (!(ControlData.DeviceRequest.bmRequestType & USB_REQUEST_DIRECTION_MASK))
    isp_StallCtrlEndpointWrite();


  bDescriptor = ControlData.DeviceRequest.wValue >> 8;

  switch (bDescriptor)
  {
    case USB_DEVICE_DESCRIPTOR_TYPE:
      DPRINT("DEVICE_DESCR\n");
      code_transmit((UINT8 *) &DeviceDescr, USB_DEVICE_DESCRIPTOR_LENGTH);
      break;

    case USB_CONFIGURATION_DESCRIPTOR_TYPE:
      DPRINT("CONFIG_DESCR\n");
      transmit_complete_descriptor();
      break;

    case USB_INTERFACE_DESCRIPTOR_TYPE:
      DPRINT("INTERFACE_DESCR\n");
      code_transmit((UINT8 *) &InterfaceDescr, USB_INTERFACE_DESCRIPTOR_LENGTH);
      break;

    case USB_STRING_DESCRIPTOR_TYPE:
      bDescriptorIndex = ControlData.DeviceRequest.wValue & 0x000F;
      DPRINT("STRING_DESCR (wValue=%04X):", ControlData.DeviceRequest.wValue);
      switch (bDescriptorIndex)
      {
        case  STR_INDEX_LANGUAGE:
          DPRINT("Language\n");
          code_transmit((UINT8 *) &strLanguage, sizeof(USB_STRING_LANGUAGE_DESCRIPTOR));
          break;

        case  STR_INDEX_MANUFACTURER:
          DPRINT("Manufacturer\n");
          code_transmit((UINT8 *) &strManufacturer, sizeof(USB_STRING_MANUFACTURER_DESCRIPTOR));
          break;

        case  STR_INDEX_PRODUCT:
          DPRINT("Product\n");
          code_transmit((UINT8 *) &strProduct, sizeof(USB_STRING_PRODUCT_DESCRIPTOR));
          break;

        case  STR_INDEX_SERIALNUMBER:
          DPRINT("Serialnumber\n");
          code_transmit((UINT8 *) &strSerialNum, sizeof(USB_STRING_SERIALNUMBER_DESCRIPTOR));
          break;

        case  STR_INDEX_CONFIGURATION:
          DPRINT("Configuration\n");
          code_transmit((UINT8 *) &strConfiguration, sizeof(USB_STRING_CONFIGURATION_DESCRIPTOR));
          break;

        case  STR_INDEX_INTERFACE:
          DPRINT("Interface\n");
          code_transmit((UINT8 *) &strInterface, sizeof(USB_STRING_INTERFACE_DESCRIPTOR));
          break;

        default:
          DPRINT("Index unknown\n");
          isp_StallCtrlEndpointRead();
          break;
      }
      break;

    case USB_ENDPOINT_DESCRIPTOR_TYPE:

    case USB_POWER_DESCRIPTOR_TYPE:
    default:
      isp_StallCtrlEndpointRead();
      break;

  }

}   // get_descriptor


void get_configuration(void)
{
UINT8 btemp;

  if (flag_configuration)
    btemp = 1;
  else
    btemp = 0;

  DPRINT("  get_configuration\n");
  
  isp_WriteCtrlEndpoint(&btemp, 1);
  
}   // get_configuration


void set_configuration(void)
{

  DPRINT("  set_configuration\n");


  if (ControlData.DeviceRequest.bmRequestType & USB_ENDPOINT_DIRECTION_MASK)
    isp_StallCtrlEndpointWrite();

  if ( (ControlData.DeviceRequest.wIndex == 0)
       && (ControlData.DeviceRequest.wLength == 0) )
  {
    if (ControlData.DeviceRequest.wValue == 0)
    {
      /* put device in unconfigured state */
      flag_configuration = FALSE;
      isp_WriteCtrlEndpoint(0, 0);
    }
    else
    {
      if (ControlData.DeviceRequest.wValue == 1)
      {
        /* Configure device */
        flag_configuration = TRUE;
        isp_WriteCtrlEndpoint(0, 0);

      }
      else
        isp_StallCtrlEndpointWrite();
    }
  }
  else
    isp_StallCtrlEndpointWrite();

}   // set_configuration


void get_interface(void)
{

  UINT8 txdat = 0;        /* Only/Current interface = 0 */
  
  DPRINT("  get_interface\n");
  
  isp_WriteCtrlEndpoint(&txdat, 1);
  
}   // get_interface



void set_interface(void)
{

  DPRINT("  set_interface\n");
  
  if ((ControlData.DeviceRequest.wValue == 0) && (ControlData.DeviceRequest.wIndex == 0))
    {

    isp_WriteCtrlEndpoint(0, 0);
    }
  else
    {

    isp_StallCtrlEndpointWrite();
    }

}   // set_interface



//  ************************************************************


void control_handler(void)
{
UINT8 type, req;
  
  type = ControlData.DeviceRequest.bmRequestType & USB_REQUEST_TYPE_MASK;
  req = ControlData.DeviceRequest.bRequest & USB_REQUEST_MASK;

  DPRINT("* control_handler [%d]: type=%02Xh, req=%02Xh\n", (UINT16)debug_count, type, req);

  if (type == USB_STANDARD_REQUEST)
  {
    switch (req)
    {
      case GET_STATUS:        get_status();
                              break;

      case CLEAR_FEATURE:     clear_feature();
                              break;

      case SET_FEATURE:       set_feature();
                              break;

      case SET_ADDRESS:       set_address();
                              break;

      case GET_DESCRIPTOR:    get_descriptor();

                              break;

      case GET_CONFIGURATION: get_configuration();
                              break;

      case SET_CONFIGURATION: set_configuration();
                              break;

      case GET_INTERFACE:     get_interface();
                              break;

      case SET_INTERFACE:     set_interface();
                              break;

      default:                StallCtrlEndpoint();// unknown, stall it
                              break;
    }
  }
  else
  {

    StallCtrlEndpoint();
  }
  
}   // control_handler

