www.pudn.com > OSBDM08.zip > usb.c


/* 
    Open Source BDM - USB communication 
	 /* Prominent Notice-This software was modified from TBDML software - 12/05 
    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. 
 
    This program 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, write to the Free Software 
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
*/ 
 
#include "hidef.h" 
#include "MC68HC908JB16.h" 
#include "commands.h" 
#include "usb.h" 
#include "led.h" 
#include "cmd_processing.h" 
#include "main.h" 
 
/* Data transfer format: two possibilities exist  
 
1. Bulk transfer over EP2 (non standard for low speed devices!) 
 
Data format:  1 byte: size (of cmd+data) 
              1 byte: cmd 
              size-1 bytes: data 
               
Returns at least one packet with status, but possibly more data depending on command executed. 
When the data is returned the command has finished. 
Start of transfer of another message into EP2 will discard any data ready to be transmitted back out of EP2 
 
Performance: ~20kB/s, roundtrip (8B IN & 8B OUT) ~ 4ms 
 
2. Control transfer over EP0 (standard approach and the only standard option for JB8/16) 
 
Data format:   
 
  - Setup frame: bmRequestType = 0x41 if data is to be transfered to the device   
  							 bmRequestType = 0xC1 if data is to be transfered out of the device  
								 bRequest = cmd 
								 wValue.lo = data0 
								 wValue.hi = data1 
								 wIndex.lo = data2 
								 wIndex.hi = data3 
								 wLength.hi = 0 
								 wLength.lo = # of bytes in data stage 
								  
  cmd, data0-3 is always transferred from host to device.  
  If the command parameters fit into 4 bytes, bmRequestType = 0xC1 can be used to read results of the command being transferred 
  If more than 4 bytes of parameters are needed, bmRequestType = 0x41 is used and data5,... is transferred in data stage 
  New setup frame will discard any data ready to be transmitted out of the device 
 
Performance: ~6.7kB/s, short command (5B IN, no data out) ~3ms, ave command (5B IN, 8B OUT) ~4ms, longer cmd (5B IN, 16B OUT) ~5ms 
 
*/ 
 
/* global and static variables, buffers, etc. */ 
 
#pragma DATA_SEG Z_RAM 
/* near variables (short addressing mode) */ 
static unsigned far char USB_State = US_ATTACHED; 
unsigned char command_buffer[105]; /* buffer for Rx and Tx of commands & results (size: 16x8byte frame + 5bytes from setup frame + 1 byte for status + 1 byte for endian byte swap = 135) */ 
                                                   /* data is always received starting at command_buffer+1 and transmitted starting at command_buffer+0 */ 
                                                   /* this is to make sure that status of the last command is preserved when receving the next command from the host */ 
static unsigned char *usb_dptr;       /* pointer to first empty location in buffer (Rx) or to hte first char to transmit (Tx) */ 
static unsigned char usb_ep0_dcntT;   /* data count to transmit */ 
static unsigned char usb_ep0_dcntR;   /* data count to receive */ 
static unsigned char usb_ep2_dcntT;   /* data count to transmit */ 
static unsigned char usb_ep2_dcntR;   /* data count to receive */ 
static unsigned char usb_ep0_zeroterm=0;  /* when non-zero it tells the EP0 Tx routine to terminate transfers by zero-length packet because the host has requested more data than available */ 
static unsigned char led_timer=0;     /* counter for timing the LED flashing */ 
led_state_e led_state;                /* led state variable (BLINK, ON, OFF) */ 
 
 
#pragma DATA_SEG FAR_RAM 
/* far variables */ 
#pragma DATA_SEG DEFAULT 
 
/* USB descriptors */ 
 
const device_descriptor DeviceDesc = { 
	sizeof(device_descriptor),  /* size */ 
	DT_DEVICE,			            /* Descriptor Type (=1) */ 
	{0x10, 0x01},		            /* USB Spec Release Number in BCD = 1.10 */ 
	0xff,                       /* Device Class Code (vendor specific) */ 
	0xff,                       /* Device Subclass Code	(vendor specific) */ 
	0xff,                       /* Device Protocol Code (vendor specific) */ 
	8,					                /* Maximum Packet Size for EP0 */ 
	{0x25, 0x04},		            /* Vendor ID - it is a Freescale micro, so lets use Freescale ID :-) */ 
	{0x00, 0x10},		            /* Product ID */ 
	{0x01, 0x00},		            /* Device Release Number in BCD */ 
	1,					                /* Index of String Desc for Manufacturer */ 
	2,					                /* Index of String Desc for Product */ 
	2,					                /* Index of String Desc for SerNo */ 
	1					                  /* Number of possible Configurations */ 
}; 
 
/* Configuration: Control EP0, Bulk IN EP2 & Bulk OUT EP2 */ 
/* Bulk transfers are not allowed for low speed devices by the spec, but seem to work and much faster! */ 
/* There will be several transactions per frame and the throughput is very high */ 
/* There are 2 options: either to use Bulk EP2 or Contol EP0 (in case Bulk on EP2 does not work on the specific machine) */ 
const struct { 
  configuration_descriptor ConfigDesc;   
  interface_descriptor InterfaceDesc0; 
  endpoint_descriptor Endpoint2INDesc; 
  endpoint_descriptor Endpoint2OUTDesc; 
} config_data = { 
  { /* configuration descriptor */ 
  	sizeof(configuration_descriptor),     /* size */ 
  	DT_CONFIGURATION,	                    /* Descriptor Type (=2) */ 
  	{sizeof(config_data),0x00},           /* Total Length of Data for this Configuration */ 
  	1,					                          /* Number of Interfaces supported by this Configuration */ 
  	1,					                          /* Designator Value for this Configuration */ 
  	2,					                          /* Index of String Desc for this Configuration */ 
  	0x80,				                          /* Bus powered, no wakeup */ 
  	150				                            /* Max. Power Consumption in this Configuration (in 2mA steps) = 250mA current for the target if needed... */ 
  }, 
  { /* interface 0 descriptor (EP0) */ 
  	sizeof(interface_descriptor), /* size */ 
  	DT_INTERFACE,		              /* Descriptor Type (=4) */ 
  	0,					                  /* Number of this Interface (0..) */ 
  	0,					                  /* Alternative for this Interface (if any) */ 
    2,					                  /* No of EPs used by this IF (excl. EP0) */ 
  	0xff,				                  /* IF Class Code */ 
  	0xff,               				  /* Interface Subclass Code */ 
  	0xff,				                  /* IF Protocol Code */ 
  	2					                    /* Index of String Desc for this Interface */ 
	}, 
	{ /* EP2 IN descriptor */ 
  	sizeof(endpoint_descriptor),  /* size */ 
  	DT_ENDPOINT,		              /* Descriptor Type (=5) */ 
  	0x82,				                  /* Endpoint Address (EP2) */ 
  	0x02,                 				/* Bulk IN endpoint */ 
  	{0x08, 0x00},		              /* Max. Endpoint Packet Size */ 
  	1	  				                  /* Polling Interval in frames/microframes */ 
	}, 
	{ /* EP2 OUT descriptor */ 
  	sizeof(endpoint_descriptor),  /* size */ 
  	DT_ENDPOINT,		              /* Descriptor Type (=5) */ 
  	0x02,				                  /* Endpoint Address (EP2) */ 
  	0x02,                 				/* Bulk OUT endpoint */ 
  	{0x08, 0x00},		              /* Max. Endpoint Packet Size */ 
  	1	  				                  /* Polling Interval in frames/microframes */ 
	} 
}; 
 
const char StringDesc0[]={0x04,DT_STRING,0x08,0x04,0x00}; /* Lang ID: 0x08 0x04 = 0x0408 = English (UK) */ 
const char StringDesc1[]="Freescale";									/* we are using Freescale VId so it is only fair to say that this is a Freescale product :-) */ 
const char StringDesc2[]="Open Source BDM v0.1";       /* product version */ 
const char * far const StringDescTable[]={StringDesc0,StringDesc1,StringDesc2}; /* pointers to the descriptors */ 
 
/* Functions */ 
 
/* copies data from flash to the zeropage buffer */ 
void copydown(unsigned char count, unsigned char * far src, unsigned char * dest) { 
  while(count--) *(dest++) = *(src++);  /* copy data while count lasts... */ 
} 
 
/* Copies string from flash to the zeropage buffer */ 
unsigned char copystring(unsigned char index, unsigned char * dest) { 
  unsigned char cnt=0; 
  const unsigned char * far src; 
  if (index) { 
    /* unicode copy */ 
    if (index<(sizeof(StringDescTable)/2)) {  /* if the string exists, copy it */ 
      unsigned char * dest_orig=dest; 
      dest+=2; 
      src = StringDescTable[index]; 
      while (*src) { 
        *(dest++) = *(src++); /* copy byte */ 
        *(dest++) = 0;        /* unicode */ 
        cnt+=2;               /* increment count */ 
      } 
      cnt+=2;                 /* account for the header */ 
      *(dest_orig++) = cnt;   /* create the header */ 
      *(dest_orig) = DT_STRING; 
    } 
  } else { 
    /* plain copy (string 0), it has the header already */ 
    src = StringDescTable[0]; 
    while (*src) { 
      *(dest++) = *(src++); /* copy byte */ 
      cnt++;                /* inrement count */ 
    } 
  } 
  return(cnt); 
} 
 
/* 1ms tick */ 
/* handles general timing functions and blinks the LED */ 
void usb_1ms_tick(void) { 
  if (led_timer) {  /* led is in the middle of blinking */ 
    led_timer--;    /* decrement the counter */ 
    if (led_timer==LED_OFF_TIME) LED_SW_OFF; /* switch the led off when the counter hits the off treshold */ 
  } else { 
    if (led_state==LED_ON) { 
      LED_SW_ON;    /* switch it on */ 
    } else if (led_state==LED_OFF) { 
      LED_SW_OFF;   /* switch it off */ 
    } else if (led_state==LED_BLINK) { 
      LED_SW_ON;								   /* switch it on */ 
      led_state=LED_ON;            /* change state to permanent ON */ 
      led_timer=LED_BLINK_PERIOD;  /* blink the LED once before it settles into the ON state */ 
    } 
  } 
} 
 
/* EP0 Tx */ 
void USB_ep0_tx(void) { 
  UCR0_TX0E=0;      /* disable EP0 transmitter */ 
  UIR2_TXD0FR = 1;  /* clear the interrupt flag to make sure the packet transmits */ 
  if (usb_ep0_dcntT!=0xff) { 
    /* transmit data from the buffer (must be in Zero Page) */ 
    UE0D0 = *(usb_dptr++); /* copy all 8 bytes, packet might be shorter than 8 bytes */ 
    UE0D1 = *(usb_dptr++); 
    UE0D2 = *(usb_dptr++); 
    UE0D3 = *(usb_dptr++); 
    UE0D4 = *(usb_dptr++); 
    UE0D5 = *(usb_dptr++); 
    UE0D6 = *(usb_dptr++); 
    UE0D7 = *(usb_dptr++); 
    if ((usb_ep0_dcntT>8)||((usb_ep0_dcntT==8)&&(usb_ep0_zeroterm))) { 
      UCR0 = ((UCR0^UCR0_TOSEQ_MASK)&UCR0_TOSEQ_MASK) | UCR0_TX0E_MASK | UCR0_RX0E_MASK + 8; /* enable transmission on EP0, toggle DATA0/1, length 8 (more data in buffer) */ 
      usb_ep0_dcntT-=8; 
    } else { 
      UCR0 = ((UCR0^UCR0_TOSEQ_MASK)&UCR0_TOSEQ_MASK) | UCR0_TX0E_MASK | UCR0_RX0E_MASK + usb_ep0_dcntT; /* enable transmission on EP0, toggle DATA0/1, length according to count */ 
      usb_ep0_dcntT = 0xff; /* no more transmission the next time */ 
      usb_ep0_zeroterm=0;   /* just finished transmission, switch zero-length termination off */       
    } 
  } else { 
    /* there is no data to transmit, but the interrupt occured anyway - this must be a special case or end of transmit condition */ 
    if ((USR0_SETUP)&&(((*(setup_packet*)&UE0D0).bmRequestType&0x60)==0)) { 
      /* the special case is a Setup frame of standard request which was received previously, now detemine what to do */ 
      switch ((*(setup_packet*)&UE0D0).bRequest) { 
        case SET_ADDRESS: 
          UADDR = UADDR_USBEN_MASK | (*(setup_packet*)&UE0D0).wValue.lo;  /* set the new address (confirmation of reception was just transmitted) */ 
          if ((*(setup_packet*)&UE0D0).wValue.lo) USB_State = US_ADDRESSED; else USB_State = US_DEFAULT;  
        case CLEAR_FEATURE: 
        case SET_CONFIGURATION: 
        case GET_CONFIGURATION: 
          break; 
      } 
    } 
  } 
} 
 
/* EP2 Tx */ 
void USB_ep2_tx(void) { 
  UCR2_TX2E=0;      /* disable EP2 transmitter */ 
  UIR2_TXD2FR = 1;  /* clear the interrupt flag to make sure the packet transmits */ 
  if (usb_ep2_dcntT==0) return; /* no data to transmit - return without enabling the transmitter */ 
  /* transmit data from the buffer (must be in Zero Page) */ 
  UE2D0 = *(usb_dptr++); /* copy all 8 bytes, packet might be shorter than 8 bytes */ 
  UE2D1 = *(usb_dptr++); 
  UE2D2 = *(usb_dptr++); 
  UE2D3 = *(usb_dptr++); 
  UE2D4 = *(usb_dptr++); 
  UE2D5 = *(usb_dptr++); 
  UE2D6 = *(usb_dptr++); 
  UE2D7 = *(usb_dptr++); 
  if (usb_ep2_dcntT>8) { 
    UCR2 = ((UCR2^UCR2_T2SEQ_MASK)&UCR2_T2SEQ_MASK) | UCR2_TX2E_MASK | UCR2_RX2E_MASK + 8; /* enable transmission on EP2, toggle DATA0/1, length 8 (more data in buffer) */ 
    usb_ep2_dcntT-=8; 
  } else { 
    UCR2 = ((UCR2^UCR2_T2SEQ_MASK)&UCR2_T2SEQ_MASK) | UCR2_TX2E_MASK | UCR2_RX2E_MASK + usb_ep2_dcntT; /* enable transmission on EP2, toggle DATA0/1, length according to count */ 
    usb_ep2_dcntT = 0;  /* no more data to transmit */ 
  } 
} 
 
/* EP0 Rx */ 
void USB_ep0_rx(void) { 
  unsigned char * ptr=&UE0D0; 
  while ((ptr<((&UE0D0)+8))&&(usb_ep0_dcntR)) { 
    *(usb_dptr++) = *(ptr++);  /* copy data */ 
    usb_ep0_dcntR--;           /* decrement count */    
  } 
  if (usb_ep0_dcntR==0) { 
    /* command reception complete */   
    command_exec(); 
    usb_ep0_dcntT=0xff;   /* make sure the Tx routine does not interpret the subsequent IRQ incorrectly */ 
    usb_ep0_zeroterm=0;   /* switch zero-length termination off */       
    UCR0 = UCR0_TOSEQ_MASK | UCR0_TX0E_MASK | UCR0_RX0E_MASK; /* enable transmission on EP0, DATA1, lenght 0 (status packet for the control transfer) */ 
  } 
} 
 
/* EP2 Rx */ 
void USB_ep2_rx(void) { 
  /* EP2 receives the messages in raw format (size of cmd+data, cmd, data0, data1, ...) */ 
  unsigned char * ptr=&UE2D0; 
  if (usb_ep2_dcntR==0) { 
    /* if the routine is called with no data to be received, it must be beginning of a message */ 
    UCR2_TX2E=0;      /* disable EP2 transmitter */ 
    usb_ep2_dcntR=UE2D0;  
    usb_dptr=command_buffer; 
    ptr = &UE2D1; /* skip copying the size */ 
  } 
  while ((ptr<((&UE2D0)+8))&&(usb_ep2_dcntR)) { 
    *(usb_dptr++) = *(ptr++);  /* copy data */ 
    usb_ep2_dcntR--;                /* decrement count */    
  } 
  if (usb_ep2_dcntR==0) { 
    /* command reception complete */   
    usb_ep2_dcntT = command_exec(); 
    usb_dptr = command_buffer; 
    USB_ep2_tx();     /* start transmitting the data */ 
  } 
} 
 
/* handles the set-up frame */ 
void USB_Setup(void) { 
  usb_ep0_dcntT=0xff;   /* stop any data transfer in progress upon reception of a new setup packet */ 
  usb_ep0_zeroterm=0;   /* switch zero-length termination off */       
  if (USR0!=USR0_SETUP_MASK + 8) {  /* check whether it is valid setup request (DATA0 && size==8) */ 
    UCR3 = UCR3_ISTALL0_MASK | UCR3_OSTALL0_MASK;   /* stall EP0 communication and wait for new setup */ 
  } else { 
    UCR0_TOSEQ=0; /* each setup transaction needs to start with DATA1 response (DATA0/1 inverted in tx) */ 
    if (((*(setup_packet*)&UE0D0).bmRequestType&0x60)==0) { /* standard request? */ 
      switch ((*(setup_packet*)&UE0D0).bRequest) { 
        case SET_CONFIGURATION: 
          if ((*(setup_packet*)&UE0D0).wValue.lo) { 
            /* non-zero configuration number */ 
            /* initialise EP2 */ 
            UCR3 |= UCR3_ENABLE2_MASK;  /* enable EP2 */             
            UCR2 = UCR2_T2SEQ_MASK | UCR2_RX2E_MASK; /* enable EP2 receiver, transaction starts with DATA0 and the flag is inverted before transmitting */ 
            usb_ep0_dcntT=0xff;         /* bring the state machine into a known idle state */ 
            usb_ep0_dcntR=0; 
            usb_ep2_dcntT=0; 
            usb_ep2_dcntR=0; 
            USB_State = US_CONFIGURED;  /* change state */   
          } else { 
            /* configuration zero means back to addressed state */ 
            USB_State = US_ADDRESSED; 
          } 
          /* next send back the confirmation... */ 
        case SET_INTERFACE: 
          /* do nothing, just send back a confirmation */ 
        case SET_ADDRESS: 
          /* Note: address of the device is going to change only after this transmission is completed */ 
        case CLEAR_FEATURE: 
          /* clear feature does nothing, just sends a confirmation */ 
          UCR0 = UCR0_TOSEQ_MASK | UCR0_TX0E_MASK | UCR0_RX0E_MASK; /* enable transmission on EP0, DATA1, lenght 0 (confirmation of new address reception) */ 
          return; 
        case GET_CONFIGURATION: 
          if (USB_State == US_CONFIGURED) UE0D0 = 1; else UE0D0 = 0; 
          UCR0 = UCR0_TOSEQ_MASK | UCR0_TX0E_MASK | UCR0_RX0E_MASK + 1; /* enable transmission on EP0, DATA1, lenght 1 */ 
        case GET_DESCRIPTOR:  
          { 
            unsigned char requested_length; 
            if ((*(setup_packet*)&UE0D0).wLength.hi) requested_length=0xff; else  /* no descriptor is longer than 255 bytes... */ 
              requested_length=(*(setup_packet*)&UE0D0).wLength.lo;   
            /* which descriptor? */ 
            switch ((*(setup_packet*)&UE0D0).wValue.hi) { 
              case DT_DEVICE:     /* device descriptor */ 
                copydown(sizeof(device_descriptor), &DeviceDesc, command_buffer); /* copy descriptor to the buffer */ 
  							usb_ep0_dcntT = sizeof(device_descriptor); /* update count */ 
                usb_dptr = command_buffer;                 /* data to transmit */ 
                if (usb_ep0_dcntT>=requested_length) { 
                  usb_ep0_dcntT=requested_length; 
                } else { 
                  usb_ep0_zeroterm=1; 
                } 
  							USB_ep0_tx();     /* start transmitting the data */ 
  							break; 
  						case DT_CONFIGURATION: 
                copydown(sizeof(config_data), &config_data, command_buffer); /* copy descriptor to the buffer */ 
  							usb_ep0_dcntT = sizeof(config_data); /* update count */ 
                usb_dptr = command_buffer;			 /* data to transmit */ 
                if (usb_ep0_dcntT>=requested_length) { 
                  usb_ep0_dcntT=requested_length; 
                } else { 
                  usb_ep0_zeroterm=1; 
                } 
  							USB_ep0_tx();     /* start transmitting the data */ 
  							break; 
  						case DT_STRING: 
                usb_ep0_dcntT = copystring((*(setup_packet*)&UE0D0).wValue.lo, command_buffer); 
                usb_dptr = command_buffer; /* data to transmit */ 
                if (usb_ep0_dcntT>=requested_length) { 
                  usb_ep0_dcntT=requested_length; 
                } else { 
                  usb_ep0_zeroterm=1; 
                } 
  							USB_ep0_tx();     /* start transmitting the data */ 
  							break; 
            } 
          } 
          return; 
      } 
    } else if (((*(setup_packet*)&UE0D0).bmRequestType&0x60)==0x40) { /* vendor specific request? */ 
      if ((*(setup_packet*)&UE0D0).bmRequestType&0x80) { 
        /* transfer dir device->host (it will be a command which reads data from the target or command which has 5 or less bytes) */   
        /* transfer 5 bytes from the status frame to the buffer */ 
        command_buffer[1]=UE0D1;  /* cmd */ 
        command_buffer[2]=UE0D2;  /* data0 */ 
        command_buffer[3]=UE0D3;  /* data1 */ 
        command_buffer[4]=UE0D4;  /* data2 */ 
        command_buffer[5]=UE0D5;  /* data3 */ 
        usb_ep0_dcntT=(*(setup_packet*)&UE0D0).wLength.lo; /* save transmit size, the host MUST NOT request more than 254 bytes! */ 
        command_exec(); 
        usb_dptr = command_buffer; /* point to data to return to the host */ 
				USB_ep0_tx();              /* start transmitting the data (or send an empty status frame in case there is no data to transmit) */ 
      } else { 
        /* transfer dir host->device (it will be a command which writes data to the target) */ 
        /* transfer size is 5+length (5 first bytes are thransferred in the setup frame) */ 
        command_buffer[1]=UE0D1;  /* cmd */ 
        command_buffer[2]=UE0D2;  /* data0 */ 
        command_buffer[3]=UE0D3;  /* data1 */ 
        command_buffer[4]=UE0D4;  /* data2 */ 
        command_buffer[5]=UE0D5;  /* data3 */ 
        usb_ep0_dcntR=(*(setup_packet*)&UE0D0).wLength.lo;  /* the host MUST NOT send more data than will fit into the buffer!! */ 
        if (usb_ep0_dcntR==0) { 
          /* no more data to follow */ 
          USB_ep0_rx(); /* the routine will not copy any data, but will launch command execution and status frame transmit */ 
                        /* this is cleaner as this code is in one place only */ 
          return; 
        } 
        /* data to follow, set-up pointer */   
				usb_dptr = command_buffer+6;  /* first 5 bytes stored already starting from position 1 */ 
      } 
      return; 
    } 
    /* non-standard or unsupported request */ 
    UCR3 = UCR3_ISTALL0_MASK | UCR3_OSTALL0_MASK;   /* stall EP0 communication and wait for new setup */ 
  } 
} 
 
/* USB interrupt service routine */ 
void interrupt usb_isr(void) { 
  suspend_timer=0;              /* keep the device out of stop */ 
  if (UIR1_EOPF) { 
    usb_1ms_tick();             /* call timing routine */ 
    UIR2_EOPFR = 1;             /* clear the flag */ 
  } else { 
    if (led_timer<255) led_timer++; /* interrupt request has a different reason, perform correction of LED tick (it is not going to be accurate, but this is better than nothing) */ 
    if (UIR1_RXD0F) {           /* EP0 Rx complete */ 
      UCR0_RX0E=0;              /* deactivate receiver */ 
      if (USR0_SETUP) {         /* was it a setup frame? */ 
        USB_Setup();            /* handle the setup frame */         
      } else {                  /* other EP0 Rx */ 
        if (USR0_RP0SIZ) USB_ep0_rx();  /* EP0 receives either zero-length status frames or valid data */  
      } 
      UIR2_RXD0FR = 1;          /* clear the flag and enable further reception */ 
      UCR0_RX0E=1;              /* reactivate receiver */ 
    } else if (UIR1_TXD0F) {    /* EP0 Tx complete */ 
      USB_ep0_tx();             /* handle Tx on EP0 */ 
      UIR2_TXD0FR = 1;          /* clear the flag */ 
    } else if (UIR1_RXD2F) {    /* EP2 Rx complete */ 
      UCR2_RX2E=0;              /* deactivate receiver */ 
      USB_ep2_rx();             /* receive the data */  
      UIR2_RXD2FR = 1;          /* clear the flag and enable further reception */ 
      UCR2_RX2E=1;              /* reactivate receiver */ 
    } else if (UIR1_TXD2F) {    /* EP2 Tx complete */ 
      USB_ep2_tx();             /* handle Tx on EP0 */ 
      UIR2_TXD2FR = 1;          /* clear the flag */ 
    } else if (UIR1_RSTF) {     /* bus reset */ 
      usb_init();               /* soft reset the USB interface */ 
      USB_State = US_DEFAULT;   /* change the state to reflect the reset has occured */ 
      UCR0 = UCR0_RX0E_MASK;    /* enable EP0 reception */ 
      UIR2_RSTFR = 1;           /* clear the flag */ 
    } else if (UIR1_RESUMF) {   /* resume interrupt */ 
      UIR0_SUSPND = 0;          /* clear the suspend flag */ 
      UIR2_RESUMFR = 1;         /* clear the interrupt flag */ 
      usb_ep0_dcntT=0xff;       /* special meaning - means no transmission in progress */ 
      usb_ep0_dcntR=0;          /* no data to receive */ 
      usb_ep2_dcntT=0;          /* no data to transmit */ 
      usb_ep2_dcntR=0;          /* no data to receive */ 
			led_timer=0; 
      led_state=LED_ON; 
    } 
  } 
} 
 
/* initialise the USB peripheral */ 
void usb_init(void) { 
  usb_ep0_dcntT=0xff;       /* special meaning - means no transmission in progress */ 
  usb_ep0_dcntR=0;          /* no data to receive */ 
  usb_ep2_dcntT=0;          /* no data to transmit */ 
  usb_ep2_dcntR=0;          /* no data to receive */ 
  led_timer=0; 
  led_state=LED_ON; 
  LED_INIT;                 /* usb interrupt drives the LED, so make sure it is initialised */ 
  UADDR = UADDR_USBEN_MASK; /* enable the USB module, assign address to the default value (0) */   
  UIR0 = UIR0_RXD2IE_MASK | UIR0_RXD0IE_MASK | UIR0_TXD2IE_MASK | UIR0_TXD0IE_MASK | UIR0_EOPIE_MASK;  /* enable Rx&Tx interupts on EP0 & EP2, enable end of frame interrupt */ 
  UCR0 = 0;                 /* reset EP0 */ 
  UCR1 = 0;                 /* reset EP1 */ 
  UCR2 = 0;                 /* reset EP2 */ 
  UCR4 = 0;                 /* normal operation */ 
  UCR3 = UCR3_TX1STR_MASK ; /*NO Pullup clear TX1ST & enable internal pull-up */ 
 
	USB_State = US_POWERED;		/* must be powered when running this code... */ 
}