diff --git a/BaS_gcc.files b/BaS_gcc.files index e83bdf1..75ded73 100644 --- a/BaS_gcc.files +++ b/BaS_gcc.files @@ -270,3 +270,4 @@ tos/Makefile usb/usb_hub.c include/usb_hub.h tos/Makefile +usb/usb_kbd.c diff --git a/Makefile b/Makefile index b8556f6..9fd36cb 100644 --- a/Makefile +++ b/Makefile @@ -97,6 +97,7 @@ CSRCS= \ ehci-hcd.c \ usb_hub.c \ usb_mouse.c \ + usb_kbd.c \ ikbd.c \ \ nbuf.c \ diff --git a/bas.lk.in b/bas.lk.in index a9b85d3..7e955c8 100644 --- a/bas.lk.in +++ b/bas.lk.in @@ -53,6 +53,7 @@ SECTIONS OBJDIR/driver_mem.o(.text) OBJDIR/usb_hub.o(.text) OBJDIR/usb_mouse.o(.text) + OBJDIR/usb_kbd.o(.text) OBJDIR/ohci-hcd.o(.text) OBJDIR/ehci-hcd.o(.text) OBJDIR/wait.o(.text) diff --git a/include/mod_devicetable.h b/include/mod_devicetable.h index 8e480b5..443c6e4 100644 --- a/include/mod_devicetable.h +++ b/include/mod_devicetable.h @@ -3,10 +3,14 @@ #define PCI_ANY_ID (~0) -struct pci_device_id { - unsigned long vendor, device; /* Vendor and device ID or PCI_ANY_ID*/ - unsigned long subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ - unsigned long class, class_mask; /* (class,subclass,prog-if) triplet */ +struct pci_device_id +{ + unsigned long vendor; /* Vendor and device ID or PCI_ANY_ID*/ + unsigned long device; + unsigned long subvendor; /* Subsystem ID's or PCI_ANY_ID */ + unsigned long subdevice; + unsigned long class; /* (class,subclass,prog-if) triplet */ + unsigned long class_mask; unsigned long driver_data; /* Data private to the driver */ }; @@ -15,7 +19,8 @@ struct pci_device_id { #define IEEE1394_MATCH_SPECIFIER_ID 0x0004 #define IEEE1394_MATCH_VERSION 0x0008 -struct ieee1394_device_id { +struct ieee1394_device_id +{ unsigned long match_flags; unsigned long vendor_id; unsigned long model_id; @@ -81,7 +86,8 @@ struct ieee1394_device_id { * matches towards the beginning of your table, so that driver_info can * record quirks of specific products. */ -struct usb_device_id { +struct usb_device_id +{ /* which fields to match against? */ unsigned short match_flags; @@ -106,10 +112,10 @@ struct usb_device_id { }; /* Some useful macros to use to create struct usb_device_id */ -#define USB_DEVICE_ID_MATCH_VENDOR 0x0001 -#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002 -#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004 -#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008 +#define USB_DEVICE_ID_MATCH_VENDOR 0x0001 +#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002 +#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004 +#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008 #define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010 #define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020 #define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040 @@ -118,18 +124,19 @@ struct usb_device_id { #define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200 /* s390 CCW devices */ -struct ccw_device_id { +struct ccw_device_id +{ unsigned short match_flags; /* which fields to match against */ - unsigned short cu_type; /* control unit type */ - unsigned short dev_type; /* device type */ - unsigned char cu_model; /* control unit model */ - unsigned char dev_model; /* device model */ + unsigned short cu_type; /* control unit type */ + unsigned short dev_type; /* device type */ + unsigned char cu_model; /* control unit model */ + unsigned char dev_model; /* device model */ unsigned long driver_info; }; -#define CCW_DEVICE_ID_MATCH_CU_TYPE 0x01 +#define CCW_DEVICE_ID_MATCH_CU_TYPE 0x01 #define CCW_DEVICE_ID_MATCH_CU_MODEL 0x02 #define CCW_DEVICE_ID_MATCH_DEVICE_TYPE 0x04 #define CCW_DEVICE_ID_MATCH_DEVICE_MODEL 0x08 @@ -138,15 +145,18 @@ struct ccw_device_id { #define PNP_ID_LEN 8 #define PNP_MAX_DEVICES 8 -struct pnp_device_id { +struct pnp_device_id +{ unsigned char id[PNP_ID_LEN]; unsigned long driver_data; }; -struct pnp_card_device_id { +struct pnp_card_device_id +{ unsigned char id[PNP_ID_LEN]; unsigned long driver_data; - struct { + struct + { unsigned char id[PNP_ID_LEN]; } devs[PNP_MAX_DEVICES]; }; @@ -154,7 +164,8 @@ struct pnp_card_device_id { #define SERIO_ANY 0xff -struct serio_device_id { +struct serio_device_id +{ unsigned char type; unsigned char extra; unsigned char id; diff --git a/include/ohci.h b/include/ohci.h index c381f7e..9ffb901 100644 --- a/include/ohci.h +++ b/include/ohci.h @@ -31,7 +31,6 @@ static int cc_to_error[16] = /* Not Access */ -1 }; -#ifdef DEBUG_OHCI static const char *cc_to_string[16] = { "No Error", @@ -64,7 +63,6 @@ static const char *cc_to_string[16] = "NOT ACCESSED:\r\nThis code is set by software before the TD is placed\r\n" \ "on a list to be processed by the HC.(2)", }; -#endif /* DEBUG_OHCI */ /* ED States */ diff --git a/include/pci.h b/include/pci.h index 2e5587d..a8a7e9a 100644 --- a/include/pci.h +++ b/include/pci.h @@ -91,9 +91,12 @@ #define PCICSR_STEPPING (1 << 7) /* if set: stepping enabled */ #define PCICSR_SERR (1 << 8) /* if set: SERR pin enabled */ #define PCICSR_FAST_BTOB_E (1 << 9) /* if set: fast back-to-back enabled */ +#define PCICSR_INT_DISABLE (1 << 10) /* if set: disable interrupts from this device */ /* * bit definitions for PCICSR upper half (Status Register) */ +#define PCICSR_INTERRUPT (1 << 3) /* device requested interrupt */ +#define PCICSR_CAPABILITIES (1 << 4) /* if set, capabilities pointer is valid */ #define PCICSR_66MHZ (1 << 5) /* 66 MHz capable */ #define PCICSR_UDF (1 << 6) /* UDF supported */ #define PCICSR_FAST_BTOB (1 << 7) /* Fast back-to-back enabled */ @@ -243,7 +246,9 @@ extern int32_t pci_write_config_longword(int32_t handle, int offset, uint32_t va extern int32_t pci_write_config_word(int32_t handle, int offset, uint16_t value); extern int32_t pci_write_config_byte(int32_t handle, int offset, uint8_t value); -extern int32_t pci_hook_interrupt(int32_t handle, void *interrupt_handler, void *parameter); +typedef int (*pci_interrupt_handler)(int param); + +extern int32_t pci_hook_interrupt(int32_t handle, pci_interrupt_handler handler, void *parameter); extern int32_t pci_unhook_interrupt(int32_t handle); extern struct pci_rd *pci_get_resource(int32_t handle); diff --git a/include/usb.h b/include/usb.h index 0604804..2509a3b 100644 --- a/include/usb.h +++ b/include/usb.h @@ -55,15 +55,15 @@ extern int sprintD(char *s, const char *fmt, ...); #define USB_ALTSETTINGALLOC 4 #define USB_MAXALTSETTING 128 /* Hard limit */ -#define USB_MAX_BUS 3 -#define USB_MAX_DEVICE 16 -#define USB_MAXCONFIG 8 -#define USB_MAXINTERFACES 8 -#define USB_MAXENDPOINTS 16 -#define USB_MAXCHILDREN 8 /* This is arbitrary */ -#define USB_MAX_HUB 16 +#define USB_MAX_BUS 3 +#define USB_MAX_DEVICE 16 +#define USB_MAXCONFIG 8 +#define USB_MAXINTERFACES 8 +#define USB_MAXENDPOINTS 16 +#define USB_MAXCHILDREN 8 /* This is arbitrary */ +#define USB_MAX_HUB 16 -#define USB_CNTL_TIMEOUT 100 /* 100ms timeout */ +#define USB_CNTL_TIMEOUT 100 /* 100 ms timeout */ #define USB_BUFSIZ 512 @@ -97,14 +97,14 @@ struct usb_device_descriptor { uint8_t bLength; uint8_t bDescriptorType; - uint16_t bcdUSB; + uint16_t bcdUSB; uint8_t bDeviceClass; uint8_t bDeviceSubClass; uint8_t bDeviceProtocol; uint8_t bMaxPacketSize0; - uint16_t idVendor; - uint16_t idProduct; - uint16_t bcdDevice; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; uint8_t iManufacturer; uint8_t iProduct; uint8_t iSerialNumber; @@ -118,7 +118,7 @@ struct usb_endpoint_descriptor uint8_t bDescriptorType; uint8_t bEndpointAddress; uint8_t bmAttributes; - uint16_t wMaxPacketSize; + uint16_t wMaxPacketSize; uint8_t bInterval; uint8_t bRefresh; uint8_t bSynchAddress; @@ -172,16 +172,18 @@ enum struct usb_device { - int devnum; /* Device number on USB bus */ - int speed; /* full/low/high */ + int devnum; /* Device number on USB bus */ + int speed; /* full/low/high */ char mf[32]; /* manufacturer */ - char prod[32]; /* product */ + char prod[32]; /* product */ char serial[32]; /* serial number */ /* Maximum packet size; one of: PACKET_SIZE_* */ int maxpacketsize; + /* one bit for each endpoint ([0] = IN, [1] = OUT) */ unsigned int toggle[2]; + /* endpoint halts; one bit per endpoint # & direction; * [0] = IN, [1] = OUT */ @@ -189,16 +191,17 @@ struct usb_device int epmaxpacketin[16]; /* INput endpoint specific maximums */ int epmaxpacketout[16]; /* OUTput endpoint specific maximums */ - int configno; /* selected config number */ - struct usb_device_descriptor descriptor; /* Device Descriptor */ - struct usb_config_descriptor config; /* config descriptor */ + int configno; /* selected config number */ + struct usb_device_descriptor descriptor; /* Device Descriptor */ + struct usb_config_descriptor config; /* config descriptor */ - int have_langid; /* whether string_langid is valid yet */ - int string_langid; /* language ID for strings */ + int have_langid; /* whether string_langid is valid yet */ + int string_langid; /* language ID for strings */ int (*irq_handle)(struct usb_device *dev); uint32_t irq_status; - int irq_act_len; /* transfered bytes */ + int irq_act_len; /* transfered bytes */ void *privptr; + /* * Child devices - if this is a hub device * Each instance needs its own set of data structures. @@ -227,7 +230,7 @@ typedef struct } v; } USB_COOKIE; -/********************************************************************** +/* * this is how the lowlevel part communicate with the outer world */ @@ -322,8 +325,9 @@ extern int usb_set_interface(struct usb_device *dev, int interface, int alternat * specification, so that much of the uhci driver can just mask the bits * appropriately. */ + /* Create various pipes... */ -#define create_pipe(dev,endpoint) \ +#define create_pipe(dev, endpoint) \ (((dev)->devnum << 8) | (endpoint << 15) | \ ((dev)->speed << 26) | (dev)->maxpacketsize) #define default_pipe(dev) ((dev)->speed << 26) diff --git a/pci/ohci-hcd.c b/pci/ohci-hcd.c index 52d00c0..5660eea 100644 --- a/pci/ohci-hcd.c +++ b/pci/ohci-hcd.c @@ -48,12 +48,9 @@ #include "bas_string.h" /* for memset() */ #include "pci.h" -//extern xQueueHandle queue_poll_hub; - #undef OHCI_USE_NPS /* force NoPowerSwitching mode */ #undef OHCI_VERBOSE_DEBUG /* not always helpful */ -#undef SHOW_INFO #undef OHCI_FILL_TRACE //#define DEBUG_OHCI @@ -62,6 +59,7 @@ #else #define dbg(format, arg...) do { ; } while (0) #endif /* DEBUG_OHCI */ +#define err(format, arg...) do { xprintf("DEBUG: %s(): " format, __FUNCTION__, ##arg); } while (0) #include "usb.h" #include "ohci.h" @@ -149,9 +147,6 @@ struct pci_device_id ohci_usb_pci_table[] = } }; -#define err(format, arg...) do { dbg("ERROR: " format "\r\n", ## arg); } while (0) -#define info(format, arg...) dbg("INFO: " format "\r\n", ## arg) - /* global ohci_t */ static ohci_t gohci[2]; int ohci_inited; @@ -1080,8 +1075,10 @@ static void check_status(ohci_t *ohci, td_t *td_list) } } -/* replies to the request have to be on a FIFO basis so - * we reverse the reversed done-list */ +/* + * replies to the request have to be on a FIFO basis so + * we reverse the reversed done-list + */ static td_t *dl_reverse_done_list(ohci_t *ohci) { uint32_t td_list_hc; @@ -1089,18 +1086,24 @@ static td_t *dl_reverse_done_list(ohci_t *ohci) td_t *td_list = NULL; td_list_hc = swpl(ohci->hcca->done_head) & ~0xf; + if (td_list_hc) + { td_list_hc += ohci->dma_offset; + } + ohci->hcca->done_head = 0; while (td_list_hc) { - td_list = (td_t *)td_list_hc; + td_list = (td_t *) td_list_hc; check_status(ohci, td_list); td_list->next_dl_td = td_rev; td_rev = td_list; td_list_hc = swpl(td_list->hwNextTD) & ~0xf; if (td_list_hc) + { td_list_hc += ohci->dma_offset; + } } return td_list; } @@ -1110,9 +1113,13 @@ static td_t *dl_reverse_done_list(ohci_t *ohci) static void finish_urb(ohci_t *ohci, urb_priv_t *urb, int status) { if ((status & (ED_OPER | ED_UNLINK)) && (urb->state != URB_DEL)) + { urb->finished = sohci_return_job(ohci, urb); + } else + { dbg("finish_urb: strange.., ED state %x, \r\n", status); + } } /* @@ -1125,17 +1132,22 @@ static int takeback_td(ohci_t *ohci, td_t *td_list) { ed_t *ed; int cc; - int stat = 0; - /* urb_t *urb; */ + int stat = 0; urb_priv_t *lurb_priv; - uint32_t tdINFO, edHeadP, edTailP; + uint32_t tdINFO; + uint32_t edHeadP; + uint32_t edTailP; + tdINFO = swpl(td_list->hwINFO); + ed = td_list->ed; if (ed == NULL) { - err("OHCI usb-%s-%c cannot get error code ED is null", ohci->slot_name, (char)ohci->controller + '0'); + err("OHCI usb-%s-%c cannot get error code ED is null\r\n", ohci->slot_name, (char) ohci->controller + '0'); + return stat; } + lurb_priv = ed->purb; dl_transfer_length(ohci, td_list); lurb_priv->td_cnt++; @@ -1144,26 +1156,40 @@ static int takeback_td(ohci_t *ohci, td_t *td_list) cc = TD_CC_GET(tdINFO); if (cc) { - //err("OHCI usb-%s-%c error: %s (%x)", ohci->slot_name, (char)ohci->controller + '0', cc_to_string[cc], cc); + err("OHCI usb-%s-%c error: %s (%x)\r\n", ohci->slot_name, (char) ohci->controller + '0', cc_to_string[cc], cc); stat = cc_to_error[cc]; } - /* see if this done list makes for all TD's of current URB, - * and mark the URB finished if so */ + /* + * see if this done list makes for all TD's of current URB, + * and mark the URB finished if so + */ if (lurb_priv->td_cnt == lurb_priv->length) + { finish_urb(ohci, lurb_priv, ed->state); + } + if (ohci->irq) - dbg("dl_done_list: processing TD %x, len %x", lurb_priv->td_cnt, lurb_priv->length); + { + dbg("dl_done_list: processing TD %x, len %x\r\n", lurb_priv->td_cnt, lurb_priv->length); + } + if (ed->state != ED_NEW && (!usb_pipeint(lurb_priv->pipe))) { edHeadP = swpl(ed->hwHeadP) & ~0xf; edTailP = swpl(ed->hwTailP); + /* unlink eds if they are not busy */ if ((edHeadP == edTailP) && (ed->state == ED_OPER)) + { ep_unlink(ohci, ed); + } } + if (cc && (ed->type == PIPE_INTERRUPT)) /* added, but it's not the better method */ + { ep_unlink(ohci, ed); + } return stat; } @@ -1171,9 +1197,11 @@ static int dl_done_list(ohci_t *ohci) { int stat = 0; td_t *td_list = dl_reverse_done_list(ohci); + while (td_list) { td_t *td_next = td_list->next_dl_td; + stat = takeback_td(ohci, td_list); td_list = td_next; } @@ -1289,12 +1317,12 @@ static unsigned char root_hub_str_index1[] = #define OK(x) len = (x); break #ifdef DEBUG_OHCI #define WR_RH_STAT(x) { info("WR:status %#8x", (x)); writel((x), &ohci->regs->roothub.status); } -#define WR_RH_PORTSTAT(x) { info("WR:portstatus[%d] %#8x", wIndex-1, (x)); writel((x), &ohci->regs->roothub.portstatus[wIndex-1]); } +#define WR_RH_PORTSTAT(x) { info("WR:portstatus[%d] %#8x", wIndex - 1, (x)); writel((x), &ohci->regs->roothub.portstatus[wIndex - 1]); } #else #define WR_RH_STAT(x) { writel((x), &ohci->regs->roothub.status); } -#define WR_RH_PORTSTAT(x) { writel((x), &ohci->regs->roothub.portstatus[wIndex-1]); } +#define WR_RH_PORTSTAT(x) { writel((x), &ohci->regs->roothub.portstatus[wIndex - 1]); } #endif -#define RD_RH_STAT roothub_status(ohci) +#define RD_RH_STAT roothub_status(ohci) #define RD_RH_PORTSTAT roothub_portstatus(ohci, wIndex-1) /* request to virtual root hub */ @@ -1309,12 +1337,14 @@ int rh_check_port_status(ohci_t *controller) for (i = 0; i < ndp; i++) { temp = roothub_portstatus(controller, i); + /* check for a device disconnect */ if (((temp & (RH_PS_PESC | RH_PS_CSC)) == (RH_PS_PESC | RH_PS_CSC)) && ((temp & RH_PS_CCS) == 0)) { res = i; break; } + /* check for a device connect */ if ((temp & RH_PS_CSC) && (temp & RH_PS_CCS)) { @@ -1343,49 +1373,60 @@ static int ohci_submit_rh_msg(ohci_t *ohci, struct usb_device *dev, uint32_t pip pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe)); #else if (ohci->irq) + { wait(1 * 1000); + } #endif + if (usb_pipeint(pipe)) { - info("Root-Hub submit IRQ: NOT implemented"); + err("Root-Hub submit IRQ: NOT implemented"); return 0; } + bmRType_bReq = cmd->requesttype | (cmd->request << 8); wValue = swpw(cmd->value); wIndex = swpw(cmd->index); wLength = swpw(cmd->length); - info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x", dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength); + dbg("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x\r\n", dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength); switch (bmRType_bReq) { - /* Request Destination: - without flags: Device, - RH_INTERFACE: interface, - RH_ENDPOINT: endpoint, - RH_CLASS means HUB here, - RH_OTHER | RH_CLASS almost ever means HUB_PORT here - */ + /* + * Request Destination: + * without flags: Device, + * RH_INTERFACE: interface, + * RH_ENDPOINT: endpoint, + * RH_CLASS means HUB here, + * RH_OTHER | RH_CLASS almost ever means HUB_PORT here + */ case RH_GET_STATUS: - *(uint16_t *)data_buf = swpw(1); + *(uint16_t *) data_buf = swpw(1); OK(2); + case RH_GET_STATUS | RH_INTERFACE: *(uint16_t *)data_buf = swpw(0); OK(2); + case RH_GET_STATUS | RH_ENDPOINT: *(uint16_t *)data_buf = swpw(0); OK(2); + case RH_GET_STATUS | RH_CLASS: *(uint32_t *)data_buf = swpl(RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE)); OK(4); + case RH_GET_STATUS | RH_OTHER | RH_CLASS: *(uint32_t *)data_buf = swpl(RD_RH_PORTSTAT); OK(4); + case RH_CLEAR_FEATURE | RH_ENDPOINT: switch (wValue) { case (RH_ENDPOINT_STALL): OK(0); } break; + case RH_CLEAR_FEATURE | RH_CLASS: switch (wValue) { @@ -1393,6 +1434,7 @@ static int ohci_submit_rh_msg(ohci_t *ohci, struct usb_device *dev, uint32_t pip case (RH_C_HUB_OVER_CURRENT): WR_RH_STAT(RH_HS_OCIC); OK(0); } break; + case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: switch (wValue) { @@ -1406,6 +1448,7 @@ static int ohci_submit_rh_msg(ohci_t *ohci, struct usb_device *dev, uint32_t pip case (RH_C_PORT_RESET): WR_RH_PORTSTAT(RH_PS_PRSC); OK(0); } break; + case RH_SET_FEATURE | RH_OTHER | RH_CLASS: switch (wValue) { @@ -1426,9 +1469,11 @@ static int ohci_submit_rh_msg(ohci_t *ohci, struct usb_device *dev, uint32_t pip OK(0); } break; + case RH_SET_ADDRESS: ohci->rh.devnum = wValue; OK(0); + case RH_GET_DESCRIPTOR: switch ((wValue & 0xff00) >> 8) { @@ -1436,10 +1481,12 @@ static int ohci_submit_rh_msg(ohci_t *ohci, struct usb_device *dev, uint32_t pip len = min_t(unsigned int, leni, min_t(unsigned int, sizeof(root_hub_dev_des), wLength)); data_buf = root_hub_dev_des; OK(len); + case(0x02): /* configuration descriptor */ len = min_t(unsigned int, leni, min_t(unsigned int, sizeof(root_hub_config_des), wLength)); data_buf = root_hub_config_des; OK(len); + case(0x03): /* string descriptors */ if (wValue == 0x0300) { @@ -1453,43 +1500,59 @@ static int ohci_submit_rh_msg(ohci_t *ohci, struct usb_device *dev, uint32_t pip data_buf = root_hub_str_index1; OK(len); } + default: stat = USB_ST_STALLED; } break; + case RH_GET_DESCRIPTOR | RH_CLASS: - { - uint32_t temp = roothub_a(ohci); - data_buf[0] = 9; /* min length; */ - data_buf[1] = 0x29; -// data_buf[2] = temp & RH_A_NDP; - data_buf[2] = (uint8_t)ohci->ndp; - data_buf[3] = 0; - if (temp & RH_A_PSM) /* per-port power switching? */ - data_buf[3] |= 0x1; - if (temp & RH_A_NOCP) /* no overcurrent reporting? */ - data_buf[3] |= 0x10; - else if (temp & RH_A_OCPM) /* per-port overcurrent reporting? */ - data_buf[3] |= 0x8; - /* corresponds to data_buf[4-7] */ - datab[1] = 0; - data_buf[5] = (temp & RH_A_POTPGT) >> 24; - temp = roothub_b(ohci); - data_buf[7] = temp & RH_B_DR; - if (data_buf[2] < 7) - data_buf[8] = 0xff; - else - { - data_buf[0] += 2; - data_buf[8] = (temp & RH_B_DR) >> 8; - data_buf[10] = data_buf[9] = 0xff; - } - len = min_t(unsigned int, leni, min_t(unsigned int, data_buf [0], wLength)); - OK(len); - } - case RH_GET_CONFIGURATION: *(uint8_t *) data_buf = 0x01; OK(1); - case RH_SET_CONFIGURATION: WR_RH_STAT(0x10000); OK(0); - default: + { + uint32_t temp = roothub_a(ohci); + data_buf[0] = 9; /* min length; */ + data_buf[1] = 0x29; +// data_buf[2] = temp & RH_A_NDP; + data_buf[2] = (uint8_t)ohci->ndp; + data_buf[3] = 0; + + if (temp & RH_A_PSM) /* per-port power switching? */ + { + data_buf[3] |= 0x1; + } + + if (temp & RH_A_NOCP) /* no overcurrent reporting? */ + { + data_buf[3] |= 0x10; + } + else if (temp & RH_A_OCPM) /* per-port overcurrent reporting? */ + { + data_buf[3] |= 0x8; + } + + /* corresponds to data_buf[4-7] */ + datab[1] = 0; + data_buf[5] = (temp & RH_A_POTPGT) >> 24; + temp = roothub_b(ohci); + data_buf[7] = temp & RH_B_DR; + if (data_buf[2] < 7) + { + data_buf[8] = 0xff; + } + else + { + data_buf[0] += 2; + data_buf[8] = (temp & RH_B_DR) >> 8; + data_buf[10] = data_buf[9] = 0xff; + } + len = min_t(unsigned int, leni, min_t(unsigned int, data_buf[0], wLength)); + OK(len); + } + + case RH_GET_CONFIGURATION: *(uint8_t *) data_buf = 0x01; OK(1); + + case RH_SET_CONFIGURATION: WR_RH_STAT(0x10000); OK(0); + + default: dbg("unsupported root hub command"); stat = USB_ST_STALLED; } @@ -1497,25 +1560,38 @@ static int ohci_submit_rh_msg(ohci_t *ohci, struct usb_device *dev, uint32_t pip ohci_dump_roothub(ohci, 1); #else if (ohci->irq) + { wait(1 * 1000); + } #endif - len = min_t(int, len, leni); + + len = min_t(int, len, leni); + if (data != data_buf) + { memcpy(data, data_buf, len); - dev->act_len = len; + } + + dev->act_len = len; dev->status = stat; + #ifdef DEBUG_OHCI pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/); #else - if (ohci->irq) + + if (ohci->irq) + { wait(1 * 1000); + } #endif - return stat; + + return stat; } -/*-------------------------------------------------------------------------*/ -/* common code for handling submit messages - used for all but root hub accesses. */ +/* + * common code for handling submit messages - used for all but root hub accesses. + */ static int submit_common_msg(ohci_t *ohci, struct usb_device *dev, uint32_t pipe, void *buffer, int transfer_len, struct devrequest *setup, int interval) @@ -1523,14 +1599,16 @@ static int submit_common_msg(ohci_t *ohci, struct usb_device *dev, uint32_t pipe int stat = 0; int maxsize = usb_maxpacket(dev, pipe); int timeout; - urb_priv_t *urb = (urb_priv_t *) driver_mem_alloc(sizeof(urb_priv_t)); + urb_priv_t *urb = driver_mem_alloc(sizeof(urb_priv_t)); if (urb == NULL) { - err("submit_common_msg malloc failed"); + err("submit_common_msg driver_mem_alloc() failed\r\n"); + return -1; } memset(urb, 0, sizeof(urb_priv_t)); + urb->dev = dev; urb->pipe = pipe; urb->transfer_buffer = buffer; @@ -1541,6 +1619,7 @@ static int submit_common_msg(ohci_t *ohci, struct usb_device *dev, uint32_t pipe if (ohci->devgone == dev) { dev->status = USB_ST_CRC_ERR; + dbg("device is gone...\r\n"); return 0; } #ifdef DEBUG_OHCI @@ -1548,18 +1627,20 @@ static int submit_common_msg(ohci_t *ohci, struct usb_device *dev, uint32_t pipe pkt_print(ohci, urb, dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe)); #else if (ohci->irq) + { wait(1 * 1000); + } #endif if (!maxsize) { - err("submit_common_message: pipesize for pipe %lx is zero", pipe); + err("submit_common_message: pipesize for pipe %lx is zero\r\n", pipe); return -1; } if (sohci_submit_job(ohci, urb, setup) < 0) { - err("sohci_submit_job failed"); + err("sohci_submit_job failed\r\n"); return -1; } @@ -1567,22 +1648,31 @@ static int submit_common_msg(ohci_t *ohci, struct usb_device *dev, uint32_t pipe wait(10 * 1000); /* ohci_dump_status(ohci); */ #endif + /* allow more time for a BULK device to react - some are slow */ + #define BULK_TO 5000 /* timeout in milliseconds */ if (usb_pipebulk(pipe)) + { timeout = BULK_TO; + } else + { timeout = 1000; + } /* wait for it to complete */ while (ohci->irq) { /* check whether the controller is done */ flush_data_cache(ohci); + #ifndef CONFIG_USB_INTERRUPT_POLLING if (ohci->irq_enabled) + { stat = ohci->stat_irq; + } else #endif stat = hc_interrupt(ohci); @@ -1638,7 +1728,7 @@ static int submit_common_msg(ohci_t *ohci, struct usb_device *dev, uint32_t pipe /* submit routines called from usb.c */ int ohci_submit_bulk_msg(struct usb_device *dev, uint32_t pipe, void *buffer, int transfer_len) { - info("submit_bulk_msg dev 0x%p ohci 0x%p buffer 0x%p len %d", dev, dev->priv_hcd, buffer, transfer_len); + err("submit_bulk_msg dev 0x%p ohci 0x%p buffer 0x%p len %d", dev, dev->priv_hcd, buffer, transfer_len); return submit_common_msg((ohci_t *)dev->priv_hcd, dev, pipe, buffer, transfer_len, NULL, 0); } @@ -1646,12 +1736,16 @@ int ohci_submit_control_msg(struct usb_device *dev, uint32_t pipe, void *buffer, { ohci_t *ohci = (ohci_t *)dev->priv_hcd; int maxsize = usb_maxpacket(dev, pipe); - info("submit_control_msg dev 0x%p ohci 0x%p", dev, ohci); + + dbg("submit_control_msg dev 0x%p ohci 0x%p\r\n", dev, ohci); + #ifdef DEBUG_OHCI pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe)); #else if (ohci->irq) + { wait(1 * 1000); + } #endif if (!maxsize) @@ -1663,6 +1757,7 @@ int ohci_submit_control_msg(struct usb_device *dev, uint32_t pipe, void *buffer, if (((pipe >> 8) & 0x7f) == ohci->rh.devnum) { ohci->rh.dev = dev; + /* root hub - redirect */ return ohci_submit_rh_msg(ohci, dev, pipe, buffer, transfer_len, setup); } @@ -1671,7 +1766,7 @@ int ohci_submit_control_msg(struct usb_device *dev, uint32_t pipe, void *buffer, int ohci_submit_int_msg(struct usb_device *dev, uint32_t pipe, void *buffer, int transfer_len, int interval) { - info("submit_int_msg dev 0x%p ohci 0x%p buffer 0x%p len %d", dev, dev->priv_hcd, buffer, transfer_len); + err("submit_int_msg dev 0x%p ohci 0x%p buffer 0x%p len %d", dev, dev->priv_hcd, buffer, transfer_len); return submit_common_msg((ohci_t *)dev->priv_hcd, dev, pipe, buffer, transfer_len, NULL, interval); } @@ -1769,7 +1864,7 @@ static int hc_reset(ohci_t *ohci) { /* SMM owns the HC */ writel(OHCI_OCR, &ohci->regs->cmdstatus);/* request ownership */ - info("USB HC TakeOver from SMM"); + err("USB HC TakeOver from SMM"); while (readl(&ohci->regs->control) & OHCI_CTRL_IR) { wait(10); @@ -1895,21 +1990,26 @@ void ohci_usb_event_poll(int interrupt) #endif /* CONFIG_USB_INTERRUPT_POLLING */ -/* an interrupt happens */ +/* + * an interrupt happens + */ static int hc_interrupt(ohci_t *ohci) { struct ohci_regs *regs = ohci->regs; - int ints, stat = -1; + int ints; + int stat = -1; if ((ohci->hcca->done_head != 0) && !(swpl(ohci->hcca->done_head) & 0x01)) + { ints = OHCI_INTR_WDH; + } else { ints = readl(®s->intrstatus); - if (ints == ~(uint32_t) 0) + if (ints == ~ 0UL) { ohci->disabled++; - err("OHCI usb-%s-%c device removed!", ohci->slot_name, (char)ohci->controller + '0'); + err("OHCI usb-%s-%c device removed!\r\n", ohci->slot_name, (char) ohci->controller + '0'); return -1; } else @@ -1917,14 +2017,17 @@ static int hc_interrupt(ohci_t *ohci) ints &= readl(®s->intrenable); if (ints == 0) { -// dbg("hc_interrupt: returning..\r\n"); - return 0xff; + dbg("no interrupt...\r\n"); + + return 0xff; } } } if (ohci->irq) - dbg("Interrupt: 0x%x frame: 0x%x bus: %d", ints, swpw(ohci->hcca->frame_no), ohci->controller); + { + dbg("Interrupt: 0x%x frame: 0x%x bus: %d\r\n", ints, swpw(ohci->hcca->frame_no), ohci->controller); + } if (ints & OHCI_INTR_RHSC) /* root hub status change */ { @@ -1950,7 +2053,7 @@ static int hc_interrupt(ohci_t *ohci) (void) status; err("OHCI Unrecoverable Error, controller usb-%s-%c disabled\r\n(SR:0x%04X%s%s%s%s%s%s)", - ohci->slot_name, (char)ohci->controller + '0', status & 0xFFFF, + ohci->slot_name, (char) ohci->controller + '0', status & 0xFFFF, status & 0x8000 ? ", Parity error" : "", status & 0x4000 ? ", Signaled system error" : "", status & 0x2000 ? ", Received master abort" : "", @@ -1962,18 +2065,24 @@ static int hc_interrupt(ohci_t *ohci) ohci_dump(ohci, 1); #else if (ohci->irq) + { wait(1); + } #endif /* HC Reset */ ohci->hc_control = 0; writel(ohci->hc_control, &ohci->regs->control); - return -1; + + return -1; } if (ints & OHCI_INTR_WDH) { if (ohci->irq) + { wait(1); + } + writel(OHCI_INTR_WDH, ®s->intrdisable); (void) readl(®s->intrdisable); /* flush */ stat = dl_done_list(ohci); @@ -2086,13 +2195,13 @@ int ohci_usb_lowlevel_init(int32_t handle, const struct pci_device_id *ent, void else if (!ohci->handle) /* for restart USB cmd */ return(-1); - info("ohci %p", ohci); + err("ohci %p", ohci); ohci->controller = PCI_FUNCTION_FROM_HANDLE(ohci->handle); // ohci->controller = (ohci->handle >> 16) & 3; /* PCI function */ /* this must be aligned to a 256 byte boundary */ - ohci->hcca_unaligned = (struct ohci_hcca *) driver_mem_alloc(sizeof(struct ohci_hcca) + 256); + ohci->hcca_unaligned = driver_mem_alloc(sizeof(struct ohci_hcca) + 256); if (ohci->hcca_unaligned == NULL) { err("HCCA malloc failed"); @@ -2102,8 +2211,8 @@ int ohci_usb_lowlevel_init(int32_t handle, const struct pci_device_id *ent, void /* align the storage */ ohci->hcca = (struct ohci_hcca *) (((uint32_t) ohci->hcca_unaligned + 255) & ~255); memset(ohci->hcca, 0, sizeof(struct ohci_hcca)); - info("aligned ghcca %p", ohci->hcca); - ohci->ohci_dev_unaligned = (struct ohci_device *) driver_mem_alloc(sizeof(struct ohci_device) + 8); + err("aligned ghcca %p", ohci->hcca); + ohci->ohci_dev_unaligned = driver_mem_alloc(sizeof(struct ohci_device) + 8); if (ohci->ohci_dev_unaligned == NULL) { err("EDs malloc failed"); @@ -2112,9 +2221,9 @@ int ohci_usb_lowlevel_init(int32_t handle, const struct pci_device_id *ent, void } ohci->ohci_dev = (struct ohci_device *) (((uint32_t) ohci->ohci_dev_unaligned + 7) & ~7); memset(ohci->ohci_dev, 0, sizeof(struct ohci_device)); - info("aligned EDs %p", ohci->ohci_dev); + err("aligned EDs %p", ohci->ohci_dev); - ohci->td_unaligned = (struct td *) driver_mem_alloc(sizeof(struct td) * (NUM_TD + 1)); + ohci->td_unaligned = driver_mem_alloc(sizeof(struct td) * (NUM_TD + 1)); if (ohci->td_unaligned == NULL) { err("TDs malloc failed"); @@ -2126,7 +2235,7 @@ int ohci_usb_lowlevel_init(int32_t handle, const struct pci_device_id *ent, void dbg("memset from %p to %p\r\n", ptd, ptd + sizeof(td_t) * NUM_TD); memset(ptd, 0, sizeof(td_t) * NUM_TD); - info("aligned TDs %p", ptd); + err("aligned TDs %p", ptd); ohci->disabled = 1; ohci->sleeping = 0; diff --git a/pci/pci.c b/pci/pci.c index 82dcaa3..6c0548c 100644 --- a/pci/pci.c +++ b/pci/pci.c @@ -78,19 +78,26 @@ static int num_pci_classes = sizeof(pci_classes) / sizeof(struct pci_class); /* holds the handle of a card at position = array index */ static int32_t handles[NUM_CARDS]; -/* holds the interrupt handler addresses (see pci_hook_interrupt() and pci_unhook_interrupt()) of the PCI cards */ -struct pci_interrupt -{ - void (*handler)(void); - int32_t parameter; - struct pci_interrupt *next; -}; -#define MAX_INTERRUPTS (NUM_CARDS * 3) -static struct pci_interrupt interrupts[MAX_INTERRUPTS]; - /* holds the card's resource descriptors; filled in pci_device_config() */ static struct pci_rd resource_descriptors[NUM_CARDS][NUM_RESOURCES]; +typedef int (*pci_interrupt_handler)(int param); + +/* + * holds the interrupt handler addresses (see pci_hook_interrupt() + * and pci_unhook_interrupt()) of the PCI cards + */ +struct pci_interrupt +{ + int32_t handle; + int irq; + pci_interrupt_handler handler; + int32_t parameter; + struct pci_interrupt *next; +}; + +#define MAX_INTERRUPTS (NUM_CARDS * 3) +static struct pci_interrupt interrupts[MAX_INTERRUPTS]; __attribute__((aligned(16))) void chip_errata_135(void) { @@ -154,15 +161,23 @@ __attribute__((interrupt)) void pci_interrupt(void) */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" + static int32_t pci_get_interrupt_cause(int32_t *handles) { int32_t handle; + /* + * loop through all PCI devices... + */ while ((handle = *handles++) != -1) { - uint32_t csr = swpl(pci_read_config_longword(handle, PCICSR)); + uint16_t command_register = swpw(pci_read_config_word(handle, PCICR)); + uint16_t status_register = swpw(pci_read_config_word(handle, PCISR)); - if ((csr & (1 << 3)) && (csr & !(csr & (1 << 10)))) + /* + * ...to see which device caused the interrupt + */ + if ((status_register & PCICSR_INTERRUPT) && !(command_register & PCICSR_INT_DISABLE)) { /* device has interrupts enabled and has an active interrupt, so its probably ours */ @@ -175,11 +190,21 @@ static int32_t pci_get_interrupt_cause(int32_t *handles) static int32_t pci_call_interrupt_chain(int32_t handle, int32_t data) { + int i; + + for (i = 0; i < MAX_INTERRUPTS; i++) + { + if (interrupts[i].handle == handle) + { + interrupts[i].handler(data); + + return 1; + } + } return data; /* unmodified - means: not handled */ } #pragma GCC diagnostic pop -#ifdef MACHINE_M5484LITE /* * This gets called from irq5 in exceptions.S * Once we arrive here, the SR has been set to disable interrupts and the gcc scratch registers have been saved @@ -191,7 +216,9 @@ void irq5_handler(void) int32_t newvalue; MCF_EPORT_EPFR |= (1 << 5); /* clear interrupt from edge port */ - xprintf("IRQ5!\r\n"); + + xprintf("IRQ5!\r\n"); + if ((handle = pci_get_interrupt_cause(handles)) > 0) { newvalue = pci_call_interrupt_chain(handle, value); @@ -202,6 +229,7 @@ void irq5_handler(void) } } +#ifdef MACHINE_M5484LITE /* * This gets called from irq7 in exceptions.S * Once we arrive here, the SR has been set to disable interrupts and the gcc scratch registers have been saved @@ -580,19 +608,41 @@ int32_t pci_find_classcode(uint32_t classcode, int index) return PCI_DEVICE_NOT_FOUND; } -int32_t pci_hook_interrupt(int32_t handle, void *handler, void *parameter) +int32_t pci_hook_interrupt(int32_t handle, pci_interrupt_handler handler, void *parameter) { - /* FIXME: implement */ - dbg("pci_hook_interrupt() still not implemented\r\n"); - return PCI_SUCCESSFUL; + int i; + + /* + * find empty slot + */ + for (i = 0; i < MAX_INTERRUPTS; i++) + { + if (interrupts[i].handle == 0) + { + interrupts[i].handle = handle; + interrupts[i].handler = handler; + interrupts[i].parameter = (int32_t) parameter; + + return PCI_SUCCESSFUL; + } + } + return PCI_BUFFER_TOO_SMALL; } int32_t pci_unhook_interrupt(int32_t handle) { - /* FIXME: implement */ + int i; - dbg("pci_unhook_interrupt() still not implemented\r\n"); - return PCI_SUCCESSFUL; + for (i = 0; i < MAX_INTERRUPTS; i++) + { + if (interrupts[i].handle == handle) + { + memset(&interrupts[i], 0, sizeof(struct pci_interrupt)); + + return PCI_SUCCESSFUL; + } + } + return PCI_DEVICE_NOT_FOUND; } /* @@ -1078,7 +1128,7 @@ void init_pci(void) xprintf("initializing PCI bridge:\r\n"); - (void) res; /* for now */ + (void) res; /* for now */ res = register_interrupt_handler(0, INT_SOURCE_PCIARB, 5, 5, pci_arb_interrupt); dbg("registered interrupt handler for PCI arbiter: %s\r\n", (res < 0 ? "failed" : "succeeded")); diff --git a/sys/exceptions.S b/sys/exceptions.S index b84567b..cf39f72 100644 --- a/sys/exceptions.S +++ b/sys/exceptions.S @@ -375,7 +375,7 @@ flpoow: irq1: irq 0x64,1,0x02 -irq2: // hbl +irq2: // hbl // move.b #3,2(sp) // rte irq 0x68,2,0x04 @@ -429,7 +429,7 @@ irq7text: .text #elif MACHINE_FIREBEE /* these handlers are only meaningful for the Firebee */ -irq5: // irq5 is tied to PCI INTC# and PCI INTD# on the M5484LITE +irq5: irq 0x74,5,0x20 irq6: // MFP interrupt from FPGA @@ -466,6 +466,22 @@ irq6_1: bne irq6_2 lea MCF_GPIO_PODR_FEC1L,a5 bset.b #4,(a5) // led off + +/* + * Firebee inthandler. 0xf0020000 delivers the interrupt vector + * + * 0: PIC_INT + * 1: E0_INT + * 2: DVI_INT + * 3: PCI_INT#A + * 4: PCI_INT#B + * 5: PCI_INT#C + * 6: PCI_INT#D + * 7: DSP_INT + * 8: VSYNC + * 9: HSYNC + */ + irq6_2: move.l 0xF0020000,a5 // vector holen add.l _rt_vbr,a5 // basis diff --git a/usb/usb.c b/usb/usb.c index bc66647..7f47b58 100644 --- a/usb/usb.c +++ b/usb/usb.c @@ -54,9 +54,6 @@ #include "usb.h" #include "usb_hub.h" -extern int usb_stor_curr_dev; -extern uint32_t usb_1st_disk_drive; - //#define DEBUG_USB #ifdef DEBUG_USB #define dbg(format, arg...) do { xprintf("DEBUG: %s(): " format, __FUNCTION__, ##arg); } while (0) @@ -97,7 +94,10 @@ int usb_init(int32_t handle, const struct pci_device_id *ent) struct hci *priv; int res = 0; if (bus_index >= USB_MAX_BUS) - return -1; + { + dbg("bus_index >= USB_MAX_BUS"); + return -1; + } dev_index[bus_index] = 0; asynch_allowed = 1; @@ -107,21 +107,29 @@ int usb_init(int32_t handle, const struct pci_device_id *ent) if (driver_mem_init()) { usb_started = 0; + dbg("driver_mem_init failed\r\n"); + return -1; /* out of memory */ } if (usb_dev == NULL) + { usb_dev = (struct usb_device *) driver_mem_alloc(sizeof(struct usb_device) * USB_MAX_BUS * USB_MAX_DEVICE); + } if (usb_dev == NULL) { usb_started = 0; + + dbg("could not allocate memory\r\n"); + return -1; /* out of memory */ } } else /* restart */ { int i; + res = 0; for (i = 0; i < USB_MAX_BUS; i++) { @@ -131,7 +139,7 @@ int usb_init(int32_t handle, const struct pci_device_id *ent) if (handle) { - res |= usb_init(handle, NULL); /* FIXME: recursive call! */ + res |= usb_init(handle, NULL); /* FIXME: recursive call!? */ } } } @@ -176,6 +184,9 @@ int usb_init(int32_t handle, const struct pci_device_id *ent) if (setup_packet == NULL) { usb_started = 0; + + dbg("could not allocate memory\r\n"); + return -1; /* no memory, no USB */ } } @@ -306,11 +317,13 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, unsigned short value, unsigned short index, void *data, unsigned short size, int timeout) { - struct hci *priv = (struct hci *)dev->priv_hcd; + struct hci *priv = (struct hci *) dev->priv_hcd; if ((timeout == 0) && (!asynch_allowed)) { /* request for a asynch control pipe is not allowed */ + + dbg("request for an async control pipe is not allowed\r\n"); return -1; } @@ -1064,7 +1077,9 @@ struct usb_device *usb_alloc_new_device(int bus_index, void *priv) */ int usb_new_device(struct usb_device *dev) { - int addr, err, tmp; + int addr; + int err; + int tmp; unsigned char *tmpbuf; #ifndef CONFIG_LEGACY_USB_INIT_SEQ @@ -1075,7 +1090,10 @@ int usb_new_device(struct usb_device *dev) #endif if (dev == NULL) + { + dbg("called with NULL device\r\n"); return 1; + } /* We still haven't set the Address yet */ addr = dev->devnum; @@ -1084,7 +1102,7 @@ int usb_new_device(struct usb_device *dev) tmpbuf = (unsigned char *) driver_mem_alloc(USB_BUFSIZ); if (tmpbuf == NULL) { - dbg("usb_new_device: malloc failure\r\n"); + dbg("malloc failure\r\n"); return 1; } @@ -1125,6 +1143,7 @@ int usb_new_device(struct usb_device *dev) */ desc = (struct usb_device_descriptor *) tmpbuf; dev->descriptor.bMaxPacketSize0 = 64; /* Start off at 64 bytes */ + /* Default to 64 byte max packet size */ dev->maxpacketsize = PACKET_SIZE_64; dev->epmaxpacketin[0] = 64; @@ -1260,7 +1279,9 @@ int usb_new_device(struct usb_device *dev) return 0; } -/* build device Tree */ +/* + * build device Tree + */ void usb_scan_devices(void *priv) { int i; @@ -1274,7 +1295,9 @@ void usb_scan_devices(void *priv) } dev_index[bus_index] = 0; - /* device 0 is always present (root hub, so let it analyze) */ + /* + * device 0 is always present (root hub, so let it analyze) + */ dev = usb_alloc_new_device(bus_index, priv); if (usb_new_device(dev)) { @@ -1289,29 +1312,24 @@ void usb_scan_devices(void *priv) xprintf("%d USB Device(s) found\r\n", dev_index[bus_index]); } - { + /* insert "driver" if possible */ + if (drv_usb_kbd_init() < 0) + { + xprintf("No USB keyboard found\r\n"); + } + else + { + xprintf("USB HID keyboard driver installed\r\n"); + } -#ifdef _NOT_USED_ /* not implemented yet */ - /* insert "driver" if possible */ - if (drv_usb_kbd_init() < 0) - { - xprintf("No USB keyboard found\r\n"); - } - else - { - xprintf("USB HID keyboard driver installed\r\n"); - } -#endif /* _NOT_USED */ - - if (drv_usb_mouse_init() < 0) - { - xprintf("No USB mouse found\r\n"); - } - else - { - xprintf("USB HID mouse driver installed\r\n"); - } - } + if (drv_usb_mouse_init() < 0) + { + xprintf("No USB mouse found\r\n"); + } + else + { + xprintf("USB HID mouse driver installed\r\n"); + } xprintf("Scan end\r\n"); } diff --git a/usb/usb_kbd.c b/usb/usb_kbd.c new file mode 100644 index 0000000..8a36a09 --- /dev/null +++ b/usb/usb_kbd.c @@ -0,0 +1,1389 @@ +/* + * (C) Copyright 2001 + * Denis Peter, MPL AG Switzerland + * + * Part of this source has been derived from the Linux USB + * project. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 "usb.h" + +//#define DEBUG_USBKBD +#ifdef DEBUG_USBKBD +#define dbg(format, arg...) do { xprintf("DEBUG: %s(): " format, __FUNCTION__, ##arg); } while (0) +#else +#define dbg(format, arg...) do { ; } while (0) +#endif /* DEBUG_USBKBD */ +#define err(format, arg...) do { xprintf("ERROR: %s(): " format, __FUNCTION__, ##arg); } while (0) + +#ifdef USE_COUNTRYCODE +static int usb_kbd_get_hid_desc(struct usb_device *dev); +#endif + +/* under TOS Repeat keys are build by timer C so infinite (0) or 1000 is a good value */ +#define REPEAT_RATE 0 // 40 /* 40msec -> 25cps */ + +#define MAX_VALUE_LOOKUP 0x90 +#define MAX_VALUE_ATARI 0x75 + +#define NUM_LOCK 0x53 +#define CAPS_LOCK 0x39 +#define SCROLL_LOCK 0x47 + +/* Modifier bits */ +#define LEFT_CNTR 0 +#define LEFT_SHIFT 1 +#define LEFT_ALT 2 +#define LEFT_GUI 3 +#define RIGHT_CNTR 4 +#define RIGHT_SHIFT 5 +#define RIGHT_ALT 6 +#define RIGHT_GUI 7 + +/* HID bCountryCode */ +#define CC_NOT 0 +#define CC_ISO 13 +#define CC_USA 33 +#define CC_FRG 9 +#define CC_FRA 8 +#define CC_UK 32 +#define CC_SPA 25 +#define CC_ITA 14 +#define CC_SWE 29 +#define CC_SWF 27 +#define CC_SWG 28 + +/* Language cookie */ +#define USA 0 /* English */ +#define FRG 1 /* German */ +#define FRA 2 /* French */ +#define UK 3 /* English */ +#define SPA 4 /* Spanish */ +#define ITA 5 /* Italian */ +#define SWE 6 /* Swiss */ +#define SWF 7 /* Swiss French */ +#define SWG 8 /* Swiss German */ + +//extern _IOREC *iorec; +//extern void (**ikbdvec)(); + +static unsigned char *new_packet; +static unsigned char old_packet[8]; +static unsigned char num_lock; +static unsigned char caps_lock; +static unsigned char scroll_lock; +static unsigned char old_modifier; +static union +{ + struct + { + unsigned reserved1:3; + unsigned force_alt_shift:1; + unsigned right_shift_host:1; + unsigned left_shift_host:1; + unsigned alt_host:1; + unsigned ctrl_host:1; + unsigned key_forced:1; + unsigned reserved2:3; + unsigned altgr_usb:1; + unsigned shift_usb:1; + unsigned altgr_usb_break:1; + unsigned shift_usb_break:1; + } b; + unsigned short s; +} flags; + +static unsigned char *leds; +static int kbd_installed; + +static unsigned char usb_kbd_to_atari_scancode[] = +{ + // A(Q) B C D + 0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x2E, 0x20, + // E F G H I J K L + 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, + // M(,) N O P Q(A) R S T + 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1F, 0x14, + // U V W(Z) X Y Z(W) 1 2 + 0x16, 0x2F, 0x11, 0x2D, 0x15, 0x2C, 0x02, 0x03, + // 3 4 5 6 7 8 9 0 + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + // RET ESC BACK TAB SPACE -()) = [(^) + 0x1C, 0x01, 0x0E, 0x0F, 0x39, 0x0C, 0x0D, 0x1A, + // ]($) \(*) EUR1 ;(M) ' ` ,(;) .(:) + 0x1B, 0x2B, 0x2B, 0x27, 0x28, 0x5B, 0x33, 0x34, + // /(!) CAPS F1 F2 F3 F4 F5 F6 + 0x35, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + // F7 F8 F9 F10 F11 F12 PrtSc ScLoc + 0x41, 0x42, 0x43, 0x44, 0x62, 0x61, 0x49, 0x4C, + //PAUSE INS HOME PgUp DEL END PgDn -> + 0x4F, 0x52, 0x47, 0x45, 0x53, 0x55, 0x46, 0x4D, + // <- DOWN UP NuLoc KP/ KP* KP- KP+ + 0x4B, 0x50, 0x48, 0x54, 0x65, 0x66, 0x4A, 0x4E, + // ENT KP1 KP2 KP3 KP4 KP5 KP6 KP7 + 0x72, 0x6D, 0x6E, 0x6F, 0x6A, 0x6B, 0x6C, 0x67, + // KP8 KP9 KP0 KP. >< APP POWER KP= + 0x68, 0x69, 0x70, 0x71, 0x60, 0x00, 0x00, 0x00, + // F13, F14, F15 F16 F17 F18 F19 F20 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // F21 F22 F23 F24 EXEC HELP MENU SEL + 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x60, 0x00, + // STOP AGAIN UNDO CUT COPY PASTE FIND MUTE + 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, + //VolUp Vold_packetn + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + //LCTRL LSHFT LALT LGUI RCTRL RSHFT RALT RGUI + 0x1D, 0x2A, 0x38, 0x56, 0x1D, 0x36, 0x38, 0x57 // virtual codes +}; + +static unsigned char usb_kbd_to_atari_fr_modifier[] = +{ + /* This table can change host SHIFT & ALT states for each scancode, values */ + /* are in hexa : bit 7: 1 for a valid entry */ + /* bit 6: 1 for force CTRL */ + /* bit 5: ALT, bit 4: SHIFT states for the AltGR table */ + /* bit 3: ALT, bit 2: SHIFT states for the Shift table */ + /* bit 1: ALT, bit 0: SHIFT states for the Unshift table */ + // A(Q) B C D + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // E F G H I J K L + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // M(,) N O P Q(A) R S T + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // U V W(Z) X Y Z(W) 1 2 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, + // 3 4 5 6 7 8 9 0 + 0x00, 0xB4, 0xA4, 0x94, 0x00, 0xA5, 0x84, 0xA4, + // RET ESC BACK TAB SPACE -()) = [(^) + 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0xB4, 0x00, + // ]($) \(*) ;(M) ' ` ,(;) .(:) + 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // /(!) CAPS F1 F2 F3 F4 F5 F6 + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // F7 F8 F9 F10 F11 F12 PrtSc ScLoc + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0x00, + //PAUSE INS HOME PgUp DEL END PgDn -> + 0x00, 0x00, 0x00, 0x95, 0x00, 0x95, 0x95, 0x00, + // <- DOWN UP NuLoc KP/ KP* KP- KP+ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // ENT KP1 KP2 KP3 KP4 KP5 KP6 KP7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // KP8 KP9 KP0 KP. >< APP POWER KP= + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // F13, F14, F15 F16 F17 F18 F19 F20 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // F21 F22 F23 F24 EXEC HELP MENU SEL + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x00, + // STOP AGAIN UNDO CUT COPY PASTE FIND MUTE + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + //VolUp Vold_packetn + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + //LCTRL LSHFT LALT LGUI RCTRL RSHFT RALT RGUI + 0x00, 0x00, 0x00, 0xEA, 0x00, 0x00, 0x00, 0xEA +}; + +static unsigned char usb_kbd_to_atari_fr_unshift[] = +{ + // A(Q) B C D + 0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x2E, 0x20, + // E F G H I J K L + 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, + // M(,) N O P Q(A) R S T + 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1F, 0x14, + // U V W(Z) X Y Z(W) 1 2 + 0x16, 0x2F, 0x11, 0x2D, 0x15, 0x2C, 0x02, 0x03, + // 3 4 5 6 7 8 9 0 + 0x04, 0x05, 0x06, 0x0D, 0x08, 0x0D, 0x0A, 0x0B, + // RET ESC BACK TAB SPACE -()) = [(^) + 0x1C, 0x01, 0x0E, 0x0F, 0x39, 0x0C, 0x35, 0x1A, + // ]($) \(*) ;(M) ' ` ,(;) .(:) + 0x1B, 0x1B, 0x00, 0x27, 0x28, 0x00, 0x33, 0x34, + // /(!) CAPS F1 F2 F3 F4 F5 F6 + 0x09, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + // F7 F8 F9 F10 F11 F12 PrtSc ScLoc + 0x41, 0x42, 0x43, 0x44, 0x62, 0x61, 0x62, 0x4C, + //PAUSE INS HOME PgUp DEL END PgDn -> + 0x4F, 0x52, 0x47, 0x45, 0x53, 0x47, 0x46, 0x4D, + // <- DOWN UP NuLoc KP/ KP* KP- KP+ + 0x4B, 0x50, 0x48, 0x00, 0x65, 0x66, 0x4A, 0x4E, + // ENT KP1 KP2 KP3 KP4 KP5 KP6 KP7 + 0x72, 0x6D, 0x6E, 0x6F, 0x6A, 0x6B, 0x6C, 0x67, + // KP8 KP9 KP0 KP. >< APP KP= + 0x68, 0x69, 0x70, 0x71, 0x60, 0x00, 0x00, 0x00, + // F13, F14, F15 F16 F17 F18 F19 F20 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // F21 F22 F23 F24 EXEC HELP MENU SEL + 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x60, 0x00, + // STOP AGAIN UNDO CUT COPY PASTE FIND MUTE + 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, + //VolUp Vold_packetn + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + //LCTRL LSHFT LALT LGUI RCTRL RSHFT RALT RGUI + 0x1D, 0x2A, 0x38, 0x0F, 0x1D, 0x36, 0x00, 0x0F +}; + +static unsigned char usb_kbd_to_atari_fr_shift[] = +{ + /* Hexa values, 00: unused => use the Unshift table */ + /* FF: invalid => no scancode */ + // A(Q) B C D + 0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x2E, 0x20, + // E F G H I J K L + 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, + // M(,) N O P Q(A) R S T + 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1F, 0x14, + // U V W(Z) X Y Z(W) 1 2 + 0x16, 0x2F, 0x11, 0x2D, 0x15, 0x2C, 0x02, 0x03, + // 3 4 5 6 7 8 9 0 + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + // RET ESC BACK TAB SPACE -()) = [(^) + 0x1C, 0x01, 0x0E, 0x0F, 0x39, 0x0C, 0x35, 0x1A, + // ]($) \(*) ;(M) ' ` ,(;) .(:) + 0x29, 0xFF, 0x00, 0x27, 0x28, 0x00, 0x33, 0x34, + // /(!) CAPS F1 F2 F3 F4 F5 F6 + 0x07, 0x3A, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + // F7 F8 F9 F10 F11 F12 PrtSc ScLoc + 0x5A, 0x5B, 0x5C, 0x5D, 0x62, 0x61, 0x62, 0x4C, + //PAUSE INS HOME PgUp DEL END PgDn -> + 0x4F, 0x52, 0x47, 0x48, 0x53, 0x47, 0x50, 0x4D, + // <- DOWN UP NuLoc KP/ KP* KP- KP+ + 0x4B, 0x50, 0x48, 0x00, 0x65, 0x66, 0x4A, 0x4E, + // ENT KP1 KP2 KP3 KP4 KP5 KP6 KP7 + 0x72, 0x6D, 0x6E, 0x6F, 0x6A, 0x6B, 0x6C, 0x67, + // KP8 KP9 KP0 KP. >< APP KP= + 0x68, 0x69, 0x70, 0x71, 0x60, 0x00, 0x00, 0x00, + // F13, F14, F15 F16 F17 F18 F19 F20 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // F21 F22 F23 F24 EXEC HELP MENU SEL + 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x60, 0x00, + // STOP AGAIN UNDO CUT COPY PASTE FIND MUTE + 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, + //VolUp Vold_packetn + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + //LCTRL LSHFT LALT LGUI RCTRL RSHFT RALT RGUI + 0x1D, 0x2A, 0x38, 0x0F, 0x1D, 0x36, 0x00, 0x0F +}; + +static unsigned char usb_kbd_to_atari_fr_altgr[] = +{ + /* Hexa values, 00: unused => use the Unshift table */ + /* FF: invalid => no scancode */ + // A(Q) B C D + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // E F G H I J K L + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // M(,) N O P Q(A) R S T + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // U V W(Z) X Y Z(W) 1 2 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2B, + // 3 4 5 6 7 8 9 0 + 0x2B, 0x1A, 0x1A, 0x2B, 0x29, 0x28, 0x1A, 0x2B, + // RET ESC BACK TAB SPACE -()) = [(^) + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1B, 0x1B, 0xFF, + // ]($) \(*) ;(M) ' ` ,(;) .(:) + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // /(!) CAPS F1 F2 F3 F4 F5 F6 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // F7 F8 F9 F10 F11 F12 PrtSc ScLoc + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + //PAUSE INS HOME PgUp DEL END PgDn -> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // <- DOWN UP NuLoc KP/ KP* KP- KP+ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4E, + // ENT KP1 KP2 KP3 KP4 KP5 KP6 KP7 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // KP8 KP9 KP0 KP. >< APP KP= + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // F13, F14, F15 F16 F17 F18 F19 F20 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // F21 F22 F23 F24 EXEC HELP MENU SEL + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0xFF, 0xFF, + // STOP AGAIN UNDO CUT COPY PASTE FIND MUTE + 0xFF, 0xFF, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + //VolUp Vold_packetn + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + //LCTRL LSHFT LALT LGUI RCTRL RSHFT RALT RGUI + 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF +}; + +static unsigned char usb_kbd_to_atari_de_modifier[] = +{ + /* This table can change host SHIFT & ALT states for each scancode, values */ + /* are in hexa : bit 7: 1 for a valid entry */ + /* bit 6: 1 for force CTRL */ + /* bit 5: ALT, bit 4: SHIFT states for the AltGR table */ + /* bit 3: ALT, bit 2: SHIFT states for the Shift table */ + /* bit 1: ALT, bit 0: SHIFT states for the Unshift table */ + // A(Q) B C D + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // E F G H I J K L + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // M(,) N O P Q(A) R S T + 0x00, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00, + // U V W(Z) X Y Z(W) 1 2 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // 3 4 5 6 7 8 9 0 + 0x00, 0x00, 0x00, 0x00, 0xB4, 0xA4, 0xA4, 0xB4, + // RET ESC BACK TAB SPACE -()) = [(^) + 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, + // ]($) \(*) ;(M) ' ` ,(;) .(:) + 0x00, 0x80, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, + // /(!) CAPS F1 F2 F3 F4 F5 F6 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // F7 F8 F9 F10 F11 F12 PrtSc ScLoc + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + //PAUSE INS HOME PgUp DEL END PgDn -> + 0x00, 0x00, 0x00, 0x81, 0x00, 0x95, 0x81, 0x00, + // <- DOWN UP NuLoc KP/ KP* KP- KP+ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // ENT KP1 KP2 KP3 KP4 KP5 KP6 KP7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // KP8 KP9 KP0 KP. >< APP POWER KP= + 0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, + // F13, F14, F15 F16 F17 F18 F19 F20 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // F21 F22 F23 F24 EXEC HELP MENU SEL + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x00, + // STOP AGAIN UNDO CUT COPY PASTE FIND MUTE + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + //VolUp Vold_packetn + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + //LCTRL LSHFT LALT LGUI RCTRL RSHFT RALT RGUI + 0x00, 0x00, 0x00, 0xEA, 0x00, 0x00, 0x00, 0xEA +}; + +static unsigned char usb_kbd_to_atari_de_unshift[] = +{ + // A(Q) B C D + 0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x2E, 0x20, + // E F G H I J K L + 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, + // M(,) N O P Q(A) R S T + 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1F, 0x14, + // U V W(Z) X Y Z(W) 1 2 + 0x16, 0x2F, 0x11, 0x2D, 0x15, 0x2C, 0x02, 0x03, + // 3 4 5 6 7 8 9 0 + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + // RET ESC BACK TAB SPACE -()) = [(^) + 0x1C, 0x01, 0x0E, 0x0F, 0x39, 0x0C, 0x0D, 0x1A, + // ]($) \(*) ;(M) ' ` ,(;) .(:) + 0x1B, 0x29, 0x00, 0x27, 0x28, 0x29, 0x33, 0x34, + // /(!) CAPS F1 F2 F3 F4 F5 F6 + 0x35, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + // F7 F8 F9 F10 F11 F12 PrtSc ScLoc + 0x41, 0x42, 0x43, 0x44, 0x63, 0x64, 0x62, 0x50, + //PAUSE INS HOME PgUp DEL END PgDn -> + 0x61, 0x52, 0x47, 0x48, 0x53, 0x47, 0x50, 0x4D, + // <- DOWN UP NuLoc KP/ KP* KP- KP+ + 0x4B, 0x50, 0x48, 0x54, 0x65, 0x66, 0x4A, 0x4E, + // ENT KP1 KP2 KP3 KP4 KP5 KP6 KP7 + 0x72, 0x6D, 0x6E, 0x6F, 0x6A, 0x6B, 0x6C, 0x67, + // KP8 KP9 KP0 KP. >< APP KP= + 0x68, 0x69, 0x70, 0x71, 0x60, 0x00, 0x00, 0x00, + // F13, F14, F15 F16 F17 F18 F19 F20 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // F21 F22 F23 F24 EXEC HELP MENU SEL + 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x60, 0x00, + // STOP AGAIN UNDO CUT COPY PASTE FIND MUTE + 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, + //VolUp Vold_packetn + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + //LCTRL LSHFT LALT LGUI RCTRL RSHFT RALT RGUI + 0x1D, 0x2A, 0x38, 0x0F, 0x1D, 0x36, 0x00, 0x0F +}; + +static unsigned char usb_kbd_to_atari_de_shift[] = +{ + /* Hexa values, 00: unused => use the Unshift table */ + /* FF: invalid => no scancode */ + // A(Q) B C D + 0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x2E, 0x20, + // E F G H I J K L + 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, + // M(,) N O P Q(A) R S T + 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1F, 0x14, + // U V W(Z) X Y Z(W) 1 2 + 0x16, 0x2F, 0x11, 0x2D, 0x15, 0x2C, 0x02, 0x03, + // 3 4 5 6 7 8 9 0 + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + // RET ESC BACK TAB SPACE -()) = [(^) + 0x1C, 0x01, 0x0E, 0x0F, 0x39, 0x0C, 0x0D, 0x1A, + // ]($) \(*) ;(M) ' ` ,(;) .(:) + 0x1B, 0x0D, 0x00, 0x27, 0x28, 0x34, 0x33, 0x34, + // /(!) CAPS F1 F2 F3 F4 F5 F6 + 0x35, 0x3A, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + // F7 F8 F9 F10 F11 F12 PrtSc ScLoc + 0x5A, 0x5B, 0x5C, 0x5D, 0x63, 0x64, 0x62, 0x50, + //PAUSE INS HOME PgUp DEL END PgDn -> + 0x61, 0x52, 0x47, 0x48, 0x53, 0x47, 0x50, 0x4D, + // <- DOWN UP NuLoc KP/ KP* KP- KP+ + 0x4B, 0x50, 0x48, 0x54, 0x65, 0x66, 0x4A, 0x4E, + // ENT KP1 KP2 KP3 KP4 KP5 KP6 KP7 + 0x72, 0x6D, 0x6E, 0x6F, 0x6A, 0x6B, 0x6C, 0x67, + // KP8 KP9 KP0 KP. >< APP KP= + 0x68, 0x69, 0x70, 0x71, 0x60, 0x00, 0x00, 0x00, + // F13, F14, F15 F16 F17 F18 F19 F20 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // F21 F22 F23 F24 EXEC HELP MENU SEL + 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x60, 0x00, + // STOP AGAIN UNDO CUT COPY PASTE FIND MUTE + 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, + //VolUp Vold_packetn + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + //LCTRL LSHFT LALT LGUI RCTRL RSHFT RALT RGUI + 0x1D, 0x2A, 0x38, 0x0F, 0x1D, 0x36, 0x00, 0x0F +}; + +static unsigned char usb_kbd_to_atari_de_altgr[] = +{ + /* Hexa values, 00: unused => use the Unshift table */ + /* FF: invalid => no scancode */ + // A(Q) B C D + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // E F G H I J K L + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // M(,) N O P Q(A) R S T + 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0xFF, 0xFF, 0xFF, + // U V W(Z) X Y Z(W) 1 2 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // 3 4 5 6 7 8 9 0 + 0xFF, 0xFF, 0xFF, 0xFF, 0x27, 0x27, 0x28, 0x28, + // RET ESC BACK TAB SPACE -()) = [(^) + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x2B, 0xFF, + // ]($) \(*) ;(M) ' ` ,(;) .(:) + 0x2B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // /(!) CAPS F1 F2 F3 F4 F5 F6 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // F7 F8 F9 F10 F11 F12 PrtSc ScLoc + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + //PAUSE INS HOME PgUp DEL END PgDn -> + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // <- DOWN UP NuLoc KP/ KP* KP- KP+ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4E, + // ENT KP1 KP2 KP3 KP4 KP5 KP6 KP7 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // KP8 KP9 KP0 KP. >< APP KP= + 0xFF, 0xFF, 0xFF, 0xFF, 0x2B, 0xFF, 0xFF, 0xFF, + // F13, F14, F15 F16 F17 F18 F19 F20 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // F21 F22 F23 F24 EXEC HELP MENU SEL + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0xFF, 0xFF, + // STOP AGAIN UNDO CUT COPY PASTE FIND MUTE + 0xFF, 0xFF, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + //VolUp Vold_packetn + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + //LCTRL LSHFT LALT LGUI RCTRL RSHFT RALT RGUI + 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF +}; + +static void *memscan(void *addr, int c, int size) +{ + unsigned char *p = (unsigned char *) addr; + + while (size) + { + if (*p == (char) c) + return (void *) p; + p++; + size--; + } + return (void *) p; +} + +static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum); + +/* + * deregistering the keyboard + */ +int usb_kbd_deregister(struct usb_device *dev) +{ + dev->irq_handle = NULL; + + if (new_packet != NULL) + { + driver_mem_free(new_packet); + new_packet = NULL; + } + + if (leds != NULL) + { + driver_mem_free(leds); + leds = NULL; + } + kbd_installed = 0; + + dbg("USB KBD deregistered\r\n"); + + return 1; +} + +/* registering the keyboard */ +int usb_kbd_register(struct usb_device *dev) +{ + if(!kbd_installed && (dev->devnum != -1) && (usb_kbd_probe(dev, 0) == 1)) + { /* Ok, we found a keyboard */ + //dbg("USB KBD found (iorec: 0x%x, USB: %d, devnum: %d)\r\n", iorec, dev->usbnum, dev->devnum); + num_lock = caps_lock = scroll_lock = old_modifier = 0; + flags.s = 0; + kbd_installed = 1; + dev->deregister = usb_kbd_deregister; + return 1; + } + /* no USB Keyboard found */ + return -1; +} + +/* search for keyboard and register it if found */ +int drv_usb_kbd_init(void) +{ + int i, j; + if(kbd_installed) + return -1; + /* scan all USB Devices */ + for(j = 0; j < USB_MAX_BUS; j++) + { + for(i = 0; i < USB_MAX_DEVICE; i++) + { + struct usb_device *dev = usb_get_dev_index(i, j); /* get device */ + if(dev == NULL) + break; + if(usb_kbd_register(dev) > 0) + return 1; + } + } + /* no USB Keyboard found */ + return -1; +} + +/************************************************************************** + * Low Level drivers + */ + +/* set the LEDs. Since this is used in the irq routine, the control job + is issued with a timeout of 0. This means, that the job is queued without + waiting for job completion */ + +static void usb_kbd_setled(struct usb_device *dev) +{ + struct usb_interface_descriptor *iface = &dev->config.if_desc[0]; + unsigned char *pleds = (unsigned char *)(((unsigned long)leds + 3) & ~3); + if(scroll_lock != 0) + *pleds = 4; + else + *pleds = 0; + if(caps_lock != 0) + *pleds |= 2; + if(num_lock != 0) + *pleds |= 1; + usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0x200, iface->bInterfaceNumber, pleds, 1, 0); +} + +static void usb_kbd_send_code(unsigned char code) +{ + //if((iorec != NULL) && (ikbdvec != NULL)) + // call_ikbdvec(code, iorec, ikbdvec); +} + +/* + * Translate the scancode + */ +static int usb_kbd_translate(unsigned char scancode, unsigned char modifier, int pressed) +{ + unsigned char keycode = 0; + unsigned char atari_modifier = 0; +#ifdef CONFIG_USB_INTERRUPT_POLLING + int level; +#endif + + int type = USA; + + dbg("USB KBD scancode: 0x%02x, modifier:0x%02x, pressed: %d\r\n", scancode, modifier, pressed); + flags.b.force_alt_shift = 0; + + if(scancode > MAX_VALUE_LOOKUP) + { + keycode = 0; + } + else + { + if(scancode == 0x8A) /* LEFT ALT */ + { + keycode = 0x38; /* Alt Atari */ + } + else + { + unsigned char *unshift_table = NULL; + unsigned char *shift_table = NULL; + unsigned char *altgr_table = NULL; + unsigned char *modifier_table = NULL; + unsigned long lang = USA; + + //USB_COOKIE *p = usb_get_cookie('_AKP'); + //if(p != NULL) + // lang = (p->v.l >> 8) & 0xFF; + +#ifdef USE_COUNTRYCODE + switch(usb_kbd_hid_desc.bCountryCode) + { + case CC_USA: lang = USA; break; + case CC_FRG: lang = FRG; break; + case CC_FRA: lang = FRA; break; + case CC_UK: lang = UK; break; + case CC_SPA: lang = SPA; break; + case CC_ITA: lang = ITA; break; + case CC_SWE: lang = SWE; break; + case CC_SWF: lang = SWF; break; + case CC_SWG: lang = SWG; break; + } +#endif + switch(lang) + { + case FRA: + case SWF: + unshift_table = usb_kbd_to_atari_fr_unshift; + shift_table = usb_kbd_to_atari_fr_shift; + altgr_table = usb_kbd_to_atari_fr_altgr; + modifier_table = usb_kbd_to_atari_fr_modifier; + type = FRA; + break; + + case FRG: + case SWG: + unshift_table = usb_kbd_to_atari_de_unshift; + shift_table = usb_kbd_to_atari_de_shift; + altgr_table = usb_kbd_to_atari_de_altgr; + modifier_table = usb_kbd_to_atari_de_modifier; + type = FRG; + break; + + default: + unshift_table = usb_kbd_to_atari_scancode; + break; + } + + if (modifier != old_modifier) + { + if (((modifier & (1 << LEFT_SHIFT)) != 0) || ((modifier & (1 << RIGHT_SHIFT)) != 0)) + { + if (!flags.b.shift_usb) + { + flags.b.shift_usb = 1; + flags.b.shift_usb_break = 1; + } + } + else + { + flags.b.shift_usb = 0; + } + + if ((modifier & (1 << RIGHT_ALT)) != 0) + { + if (!flags.b.altgr_usb) + { + flags.b.altgr_usb = 1; + flags.b.altgr_usb_break = 1; + } + } + else + { + flags.b.altgr_usb = 0; + } + old_modifier = modifier; + } + else if (pressed) + { + if (!flags.b.altgr_usb) + { + flags.b.altgr_usb_break = 0; + } + if (!flags.b.shift_usb) + { + flags.b.shift_usb_break = 0; + } + } + keycode = unshift_table[scancode]; + + if ((modifier & (1 << LEFT_ALT)) == 0) + { + /* + * This modifier table can change host SHIFT & ALT states for each scancode, values + * are in hexa : bit 7: 1 for a valid entry + * bit 6: 1 for force CTRL + * bit 5: ALT, bit 4: SHIFT states for the AltGR table + * bit 3: ALT, bit 2: SHIFT states for the Shift table + * bit 1: ALT, bit 0: SHIFT states for the Unshift table + */ + if (modifier_table != NULL) + { + atari_modifier = modifier_table[scancode]; + } + else + { + atari_modifier = 0; + } + + if ((atari_modifier & (1 << 7)) != 0) + { + flags.b.force_alt_shift = 1; + } + else + { + atari_modifier = 0; + } + + if (flags.b.altgr_usb_break) + { + if (altgr_table[scancode]) + { + keycode = altgr_table[scancode]; + if ((atari_modifier & (1 << 6)) != 0) + { + atari_modifier = (atari_modifier >> 4) | (atari_modifier & (1 << 6)); + } + else + { + atari_modifier >>= 4; + } + } + } + else if (flags.b.shift_usb_break) + { + if (shift_table[scancode]) + { + keycode = shift_table[scancode]; + if ((atari_modifier & (1 << 6)) != 0) + { + atari_modifier = (atari_modifier >> 2) | (atari_modifier & (1 << 6)); + } + else + { + atari_modifier >>= 2; + } + } + } + } + } + } + dbg("USB KBD atari-%s keycode:0x%02x, modifier:0x%02x, flags:0x%04x\r\n", (type == FRA) ? "fr" : (type == FRG) ? "de" : "us", keycode, atari_modifier, flags.s); + + if (keycode == 0x1D) /* CTRL */ + { + if(pressed) + flags.b.ctrl_host = 1; + else + flags.b.ctrl_host = 0; + } + if(keycode == 0x36) /* RSHIFT */ + { + if(pressed) + flags.b.right_shift_host = 1; + else + flags.b.right_shift_host = 0; + } + if(keycode == 0x2A) /* LSHIFT */ + { + if(pressed) + flags.b.left_shift_host = 1; + else + flags.b.left_shift_host = 0; + } +#ifdef CONFIG_USB_INTERRUPT_POLLING + level = asm_set_ipl(7); /* mask interrupts for use call_ikbdvec() */ +#endif + if(pressed && (flags.b.force_alt_shift)) + { + flags.b.key_forced = 1; + if(((atari_modifier & (1 << 6)) != 0) && flags.b.ctrl_host) + usb_kbd_send_code(0x1D); /* CTRL */ + if((atari_modifier & (1 << 0)) == 0) + { + if(flags.b.left_shift_host) + usb_kbd_send_code(0xAA); /* !LSHIFT */ + if(flags.b.right_shift_host) + usb_kbd_send_code(0xB6); /* !RSHIFT */ + } + else + { + if(!flags.b.left_shift_host) + usb_kbd_send_code(0x2A); /* LSHIFT */ + if(!flags.b.right_shift_host && (keycode != 0x60)) /* < */ + usb_kbd_send_code(0x36); /* RSHIFT */ + } + if((atari_modifier & (1 << 1)) == 0) + { + if(flags.b.alt_host) + usb_kbd_send_code(0xB8); /* !ALT */ + } + else + { + if(!flags.b.alt_host) + usb_kbd_send_code(0x38); /* ALT */ + } + } + if((keycode !=0) && (keycode <= MAX_VALUE_ATARI)) + usb_kbd_send_code(pressed ? keycode : keycode | 0x80); + if(!pressed && (flags.b.force_alt_shift)) + { + flags.b.key_forced = 0; + if(((atari_modifier & (1 << 6)) != 0) && flags.b.ctrl_host) + usb_kbd_send_code(0x9D); /* !CTRL */ + if((atari_modifier & (1 << 0)) == 0) + { + if(flags.b.left_shift_host) + usb_kbd_send_code(0x2A); /* LSHIFT */ + if(flags.b.right_shift_host) + usb_kbd_send_code(0x36); /* RSHIFT */ + } + else + { + if(!flags.b.left_shift_host) + usb_kbd_send_code(0xAA); /* !LSHIFT */ + if(!flags.b.right_shift_host) + usb_kbd_send_code(0xB6); /* !RSHIFT */ + } + if((atari_modifier & (1 << 1)) == 0) + { + if(flags.b.alt_host) + usb_kbd_send_code(0x38); /* ALT */ + } + else + { + if(!flags.b.alt_host) + usb_kbd_send_code(0xB8); /* !ALT */ + } + } +#ifdef CONFIG_USB_INTERRUPT_POLLING + asm_set_ipl(level); +#endif + if(pressed == 1) + { + if(scancode == NUM_LOCK) + { + num_lock = ~num_lock; + return 1; + } + if(scancode == CAPS_LOCK) + { + caps_lock = ~caps_lock; + return 1; + } + if(scancode == SCROLL_LOCK) + { + scroll_lock = ~scroll_lock; + return 1; + } + } + return 0; +} + +/* Interrupt service routine */ +static int usb_kbd_irq(struct usb_device *dev) +{ + int i,res; + if((dev->irq_status != 0) || (dev->irq_act_len != 8)) + { + dbg("USB KBD error %lX, len %d\r\n",dev->irq_status,dev->irq_act_len); + return 1; + } + res = 0; + for(i = 2; i < 8; i++) + { + if(old_packet[i] > 3 && memscan(&new_packet[2], old_packet[i], 6) == &new_packet[8]) + { + res |= usb_kbd_translate(old_packet[i], new_packet[0], 0); + old_packet[0] = new_packet[0]; + } + if(new_packet[i] > 3 && memscan(&old_packet[2], new_packet[i], 6) == &old_packet[8]) + { + res |= usb_kbd_translate(new_packet[i], new_packet[0], 1); + old_packet[0] = new_packet[0]; + } + } + if(new_packet[0] != old_packet[0]) /* modifier change */ + { + unsigned char modifier_change = new_packet[0] ^ old_packet[0]; + if(modifier_change & (1 << LEFT_CNTR)) + res |= usb_kbd_translate(0x88, new_packet[0], (new_packet[0] & (1 << LEFT_CNTR)) ? 1 : 0); + if(modifier_change & (1 << LEFT_SHIFT)) + res |= usb_kbd_translate(0x89, new_packet[0], (new_packet[0] & (1 << LEFT_SHIFT)) ? 1 : 0); + if(modifier_change & (1 << LEFT_ALT)) + res |= usb_kbd_translate(0x8A, new_packet[0], (new_packet[0] & (1 << LEFT_ALT)) ? 1 : 0); + if(modifier_change & (1 << LEFT_GUI)) + res |= usb_kbd_translate(0x8B, new_packet[0], (new_packet[0] & (1 << LEFT_GUI)) ? 1 : 0); + if(modifier_change & (1 << RIGHT_CNTR)) + res |= usb_kbd_translate(0x8C, new_packet[0], (new_packet[0] & (1 << RIGHT_CNTR)) ? 1 : 0); + if(modifier_change & (1 << RIGHT_SHIFT)) + res |= usb_kbd_translate(0x8D, new_packet[0], (new_packet[0] & (1 << RIGHT_SHIFT)) ? 1 : 0); + if(modifier_change & (1 << RIGHT_ALT)) + res |= usb_kbd_translate(0x8E, new_packet[0], (new_packet[0] & (1 << RIGHT_ALT)) ? 1 : 0); + if(modifier_change & (1 << RIGHT_GUI)) + res |= usb_kbd_translate(0x8F, new_packet[0], (new_packet[0] & (1 << RIGHT_GUI)) ? 1 : 0); + } + if(res == 1) + usb_kbd_setled(dev); + memcpy(&old_packet[0], &new_packet[0], 8); + return 1; /* install IRQ Handler again */ +} + +/* + * probes the USB device dev for keyboard type + */ +static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum) +{ + struct usb_interface_descriptor *iface; + struct usb_endpoint_descriptor *ep; + int pipe; + int maxp; + + if (dev->descriptor.bNumConfigurations != 1) + { + dbg("device has more than one single configuration\r\n"); + + return 0; + } + + iface = &dev->config.if_desc[ifnum]; + + if (iface->bInterfaceClass != USB_CLASS_HID) + { + dbg("device is not a HID device\r\n"); + + return 0; + } + + if(iface->bInterfaceSubClass != 1) + { + dbg("device interface subclass != USB_SUB_HID_BOOT\r\n"); + + return 0; + } + + if (iface->bInterfaceProtocol != USB_PROT_HID_KEYBOARD) + { + dbg("device is not a keyboard\r\n"); + + return 0; + } + + if (iface->bNumEndpoints != 1) + { + dbg("device has %d endpoints instead of 1\r\n", iface->bNumEndpoints); + + return 0; + } + + ep = &iface->ep_desc[0]; + + if (!(ep->bEndpointAddress & 0x80)) + { + dbg("ep->bEndpointAddress & 0x80 = 0x%x\r\n", ep->bEndpointAddress & 0x80); + + return 0; + } + + if ((ep->bmAttributes & 3) != 3) + { + dbg("ep->bmAttributes & 3 != 3 (%d)\r\n", ep->bmAttributes & 3); + + return 0; + } + + leds = (unsigned char *) driver_mem_alloc(8); + + if (leds == NULL) + { + dbg("could not allocate memory for leds\r\n"); + + return 0; + } + + new_packet = (unsigned char *) driver_mem_alloc(8); + if (new_packet == NULL) + { + dbg("could not allocate memory for new_packed\r\n"); + + driver_mem_free(leds); + + return 0; + } + + dbg("USB KBD found, set protocol...\r\n"); + + /* ok, we found a USB Keyboard, install it */ +#ifdef USE_COUNTRYCODE + if(usb_kbd_get_hid_desc(dev) < 0) + usb_kbd_hid_desc.bCountryCode = CC_NOT; +#endif + + usb_set_protocol(dev, iface->bInterfaceNumber, 0); + + dbg("USB KBD found, set idle...\r\n"); + usb_set_idle(dev, iface->bInterfaceNumber, REPEAT_RATE, 0); + + memset(&new_packet[0], 0, 8); + memset(&old_packet[0], 0, 8); + + pipe = usb_rcvintpipe(dev, ep->bEndpointAddress); + + maxp = usb_maxpacket(dev, pipe); + + dev->irq_handle = usb_kbd_irq; + + dbg("USB KBD enable interrupt pipe (maxp: %d)...\r\n", maxp); + usb_submit_int_msg(dev, pipe, &new_packet[0], maxp > 8 ? 8 : maxp, ep->bInterval); + + return 1; +} + +#ifdef USE_COUNTRYCODE + +/* + * We parse each description item into this structure. Short items data + * values are expanded to 32-bit signed int, long items contain a pointer + * into the data area. + */ + +struct hid_item +{ + unsigned char format; + unsigned char size; + unsigned char type; + unsigned char tag; + union + { + unsigned char u_8; + char s_8; + unsigned short u_16; + short s_16; + unsigned long u_32; + long s_32; + unsigned char *longdata; + } data; +}; + +/* HID report item format */ +#define HID_ITEM_FORMAT_SHORT 0 +#define HID_ITEM_FORMAT_LONG 1 + +/* Special tag indicating long items */ +#define HID_ITEM_TAG_LONG 15 + +#ifdef USB_KBD_DEBUG + +void usb_kbd_display_hid(struct usb_hid_descriptor *hid) +{ + board_printf("USB_HID_DESC:\r\n"); + board_printf(" bLenght 0x%x\r\n",hid->bLength); + board_printf(" bcdHID 0x%x\r\n",hid->bcdHID); + board_printf(" bCountryCode %d\r\n",hid->bCountryCode); + board_printf(" bNumDescriptors 0x%x\r\n",hid->bNumDescriptors); + board_printf(" bReportDescriptorType 0x%x\r\n",hid->bReportDescriptorType); + board_printf(" wDescriptorLength 0x%x\r\n",hid->wDescriptorLength); +} + +/* + * Fetch a report description item from the data stream. We support long + * items, though they are not used yet. + */ + +static int fetch_item(unsigned char *start, unsigned char *end, struct hid_item *item) +{ + if((end - start) > 0) + { + unsigned char b = *start++; + item->type = (b >> 2) & 3; + item->tag = (b >> 4) & 15; + if(item->tag == HID_ITEM_TAG_LONG) + { + item->format = HID_ITEM_FORMAT_LONG; + if((end - start) >= 2) + { + item->size = *start++; + item->tag = *start++; + if((end - start) >= item->size) + { + item->data.longdata = start; + start += item->size; + return item->size; + } + } + } + else + { + item->format = HID_ITEM_FORMAT_SHORT; + item->size = b & 3; + switch(item->size) + { + case 0: + return item->size; + case 1: + if((end - start) >= 1) + { + item->data.u_8 = *start++; + return item->size; + } + break; + case 2: + if((end - start) >= 2) + { + item->data.u_16 = le16_to_cpu(*(unsigned short *)start); + start+=2; + return item->size; + } + case 3: + item->size++; + if((end - start) >= 4) + { + item->data.u_32 = le32_to_cpu(*(unsigned long *)start); + start+=4; + return item->size; + } + } + } + } + return -1; +} + +#endif /* USB_KBD_DEBUG */ + +/* + * HID report descriptor item type (prefix bit 2,3) + */ + +#define HID_ITEM_TYPE_MAIN 0 +#define HID_ITEM_TYPE_GLOBAL 1 +#define HID_ITEM_TYPE_LOCAL 2 +#define HID_ITEM_TYPE_RESERVED 3 +/* + * HID report descriptor main item tags + */ + +#define HID_MAIN_ITEM_TAG_INPUT 8 +#define HID_MAIN_ITEM_TAG_OUTPUT 9 +#define HID_MAIN_ITEM_TAG_FEATURE 11 +#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10 +#define HID_MAIN_ITEM_TAG_END_COLLECTION 12 +/* + * HID report descriptor main item contents + */ + +#define HID_MAIN_ITEM_CONSTANT 0x001 +#define HID_MAIN_ITEM_VARIABLE 0x002 +#define HID_MAIN_ITEM_RELATIVE 0x004 +#define HID_MAIN_ITEM_WRAP 0x008 +#define HID_MAIN_ITEM_NONLINEAR 0x010 +#define HID_MAIN_ITEM_NO_PREFERRED 0x020 +#define HID_MAIN_ITEM_NULL_STATE 0x040 +#define HID_MAIN_ITEM_VOLATILE 0x080 +#define HID_MAIN_ITEM_BUFFERED_BYTE 0x100 + +/* + * HID report descriptor collection item types + */ + +#define HID_COLLECTION_PHYSICAL 0 +#define HID_COLLECTION_APPLICATION 1 +#define HID_COLLECTION_LOGICAL 2 +/* + * HID report descriptor global item tags + */ + +#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0 +#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM 1 +#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM 2 +#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM 3 +#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM 4 +#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 5 +#define HID_GLOBAL_ITEM_TAG_UNIT 6 +#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 7 +#define HID_GLOBAL_ITEM_TAG_REPORT_ID 8 +#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 9 +#define HID_GLOBAL_ITEM_TAG_PUSH 10 +#define HID_GLOBAL_ITEM_TAG_POP 11 + +/* + * HID report descriptor local item tags + */ + +#define HID_LOCAL_ITEM_TAG_USAGE 0 +#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM 1 +#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM 2 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 3 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM 4 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM 5 +#define HID_LOCAL_ITEM_TAG_STRING_INDEX 7 +#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM 8 +#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM 9 +#define HID_LOCAL_ITEM_TAG_DELIMITER 10 + +#ifdef USB_KBD_DEBUG +static void usb_kbd_show_item(struct hid_item *item) +{ + switch(item->type) + { + case HID_ITEM_TYPE_MAIN: + switch(item->tag) + { + case HID_MAIN_ITEM_TAG_INPUT: board_printf("Main Input"); break; + case HID_MAIN_ITEM_TAG_OUTPUT: board_printf("Main Output"); break; + case HID_MAIN_ITEM_TAG_FEATURE: board_printf("Main Feature"); break; + case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION: board_printf("Main Begin Collection"); break; + case HID_MAIN_ITEM_TAG_END_COLLECTION: board_printf("Main End Collection"); break; + default: board_printf("Main reserved %d",item->tag); break; + } + break; + case HID_ITEM_TYPE_GLOBAL: + switch(item->tag) + { + case HID_GLOBAL_ITEM_TAG_USAGE_PAGE: board_printf("- Global Usage Page"); break; + case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM: board_printf("- Global Logical Minimum"); break; + case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM: board_printf("- Global Logical Maximum"); break; + case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM: board_printf("- Global physical Minimum"); break; + case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM: board_printf("- Global physical Maximum"); break; + case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: board_printf("- Global Unit Exponent"); break; + case HID_GLOBAL_ITEM_TAG_UNIT: board_printf("- Global Unit"); break; + case HID_GLOBAL_ITEM_TAG_REPORT_SIZE: board_printf("- Global Report Size"); break; + case HID_GLOBAL_ITEM_TAG_REPORT_ID: board_printf("- Global Report ID"); break; + case HID_GLOBAL_ITEM_TAG_REPORT_COUNT: board_printf("- Global Report Count"); break; + case HID_GLOBAL_ITEM_TAG_PUSH: board_printf("- Global Push"); break; + case HID_GLOBAL_ITEM_TAG_POP: board_printf("- Global Pop"); break; + default: board_printf("- Global reserved %d",item->tag); break; + } + break; + case HID_ITEM_TYPE_LOCAL: + switch(item->tag) + { + case HID_LOCAL_ITEM_TAG_USAGE: board_printf("-- Local Usage"); break; + case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: board_printf("-- Local Usage Minimum"); break; + case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: board_printf("-- Local Usage Maximum"); break; + case HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX: board_printf("-- Local Designator Index"); break; + case HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM: board_printf("-- Local Designator Minimum"); break; + case HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM: board_printf("-- Local Designator Maximum"); break; + case HID_LOCAL_ITEM_TAG_STRING_INDEX: board_printf("-- Local String Index"); break; + case HID_LOCAL_ITEM_TAG_STRING_MINIMUM: board_printf("-- Local String Minimum"); break; + case HID_LOCAL_ITEM_TAG_STRING_MAXIMUM: board_printf("-- Local String Maximum"); break; + case HID_LOCAL_ITEM_TAG_DELIMITER: board_printf("-- Local Delimiter"); break; + default: board_printf("-- Local reserved %d",item->tag); break; + } + break; + default: + board_printf("--- reserved %d",item->type); + break; + } + board_printf(" "); + switch(item->size) + { + case 1: board_printf("%d",item->data.u_8); break; + case 2: board_printf("%d",item->data.u_16); break; + case 4: board_printf("%ld",item->data.u_32); break; + } + board_printf("\r\n"); +} +#endif /* USB_KBD_DEBUG */ + +static int usb_kbd_get_hid_desc(struct usb_device *dev) +{ + unsigned char *buffer = (unsigned char *)driver_mem_alloc(256); + struct usb_descriptor_header *head; + struct usb_config_descriptor *config; + int index, len; +#ifdef USB_KBD_DEBUG + int i; + unsigned char *start, *end; + struct hid_item item; +#endif + if(buffer == NULL) + return -1; + if(usb_get_configuration_no(dev, &buffer[0], 0) == -1) + { + driver_mem_free(buffer); + return -1; + } + head = (struct usb_descriptor_header *)&buffer[0]; + if(head->bDescriptorType!=USB_DT_CONFIG) + { + dbg(" ERROR: NOT USB_CONFIG_DESC %x\r\n",head->bDescriptorType); + driver_mem_free(buffer); + return -1; + } + index = head->bLength; + config = (struct usb_config_descriptor *)&buffer[0]; + len = le16_to_cpu(config->wTotalLength); + /* Ok the first entry must be a configuration entry, now process the others */ + head = (struct usb_descriptor_header *)&buffer[index]; + while(index+1 < len) + { + if(head->bDescriptorType == USB_DT_HID) + { + dbg("HID desc found\r\n"); + memcpy(&usb_kbd_hid_desc, &buffer[index],buffer[index]); + le16_to_cpus(&usb_kbd_hid_desc.bcdHID); + le16_to_cpus(&usb_kbd_hid_desc.wDescriptorLength); +#ifdef USB_KBD_DEBUG + usb_kbd_display_hid(&usb_kbd_hid_desc); +#endif + len = 0; + break; + } + index += head->bLength; + head = (struct usb_descriptor_header *)&buffer[index]; + } + if(len > 0) + { + driver_mem_free(buffer); + return -1; + } +#ifdef USB_KBD_DEBUG + len = usb_kbd_hid_desc.wDescriptorLength; + if((index = usb_get_class_descriptor(dev, 0, USB_DT_REPORT, 0, &buffer[0], len)) < 0) + { + dbg("reading report descriptor failed\r\n"); + driver_mem_free(buffer); + return -1; + } + dbg(" report descriptor (size %u, read %d)\r\n", len, index); + start = &buffer[0]; + end = &buffer[len]; + i = 0; + do + { + index = fetch_item(start, end, &item); + i += index; + i++; + if(index >= 0) + usb_kbd_show_item(&item); + start += index; + start++; + } + while(index >= 0); +#endif /* USB_KBD_DEBUG */ + driver_mem_free(buffer); + return 0; +} + +#endif /* USE_COUNTRYCODE */ + +/* + usb_get_report(dev, 0, 0, 1, &new_packet[0], 8); +*/ +