From ccbc004f9110611c243d01b27da39029a1f34831 Mon Sep 17 00:00:00 2001 From: "Sergey Semyonov (Serge)" Date: Thu, 17 Feb 2011 11:32:46 +0000 Subject: [PATCH] usb: keyboard driver git-svn-id: svn://kolibrios.org@1875 a494cfbc-eb01-0410-851d-a64ba20cac60 --- drivers/usb/uhci/hcd.inc | 94 ++++++++------- drivers/usb/uhci/hid.inc | 234 ++++++++++++++++++++++++++++++++++++-- drivers/usb/uhci/makefile | 60 +++++----- drivers/usb/uhci/usb.c | 31 ++--- 4 files changed, 327 insertions(+), 92 deletions(-) diff --git a/drivers/usb/uhci/hcd.inc b/drivers/usb/uhci/hcd.inc index b5a372041e..602f2205c5 100644 --- a/drivers/usb/uhci/hcd.inc +++ b/drivers/usb/uhci/hcd.inc @@ -236,16 +236,6 @@ bool init_hc(hc_t *hc) for (i = SKEL_ISO + 1; i < SKEL_ASYNC; ++i) hc->qh[i]->qlink = hc->qh[SKEL_ASYNC]->dma | 2; -/* - td = alloc_td(); - - td->link = 1; - td->status = (1<<24) | (1<<23) ; - td->token = TOKEN( 0x7FF, DATA0, 0, 0, 0xE1); - td->buffer = 0; - td->bk = NULL; -*/ - for (i = 0; i < 1024; i++) { int qnum; @@ -282,12 +272,13 @@ bool init_hc(hc_t *hc) for (port = 0; port < hc->numports; ++port) out16(hc->iobase + USBPORTSC1 + (port * 2), 0x200); - delay(100/10); for (port = 0; port < 2; ++port) { time_t timeout; + delay(100/10); + u32_t status = in16(hc->iobase + USBPORTSC1 + (port * 2)); dbgprintf("port%d status %x\n", port, status); @@ -404,44 +395,64 @@ bool set_address(udev_t *dev) return true; } -request_t *create_request(udev_t *dev, endp_t *enp, u32_t dir, - void *data, size_t req_size) -{ - td_t *td, *td_prev; - addr_t data_dma; - hc_t *hc = dev->host; - size_t packet_size = enp->size; - size_t size = req_size; - addr_t td_dma; +#define ALIGN16(x) (((x)+15)&~15) - request_t *rq = (request_t*)kmalloc(sizeof(request_t),0); +#define MakePtr( cast, ptr, addValue ) (cast)((addr_t)(ptr)+(addr_t)(addValue)) + +request_t *alloc_rq_buffer(udev_t *dev, endp_t *enp, u32_t dir, + size_t data_size) +{ + size_t packet_size = dev->ep0_size; + int dsize = data_size; + size_t buf_size; + + addr_t buf_dma; + addr_t td_dma; + addr_t data_dma; + + request_t *rq; + + td_t *td, *td_prev; + int td_count = 0; + + while(dsize > 0) + { + td_count++; + dsize-= packet_size; + }; + + buf_size = ALIGN16(sizeof(request_t)) + ALIGN16(data_size) + + td_count*sizeof(td_t); + + rq = (request_t*)hcd_buffer_alloc(buf_size, &buf_dma); + memset(rq, 0, buf_size); + + data_dma = buf_dma + ALIGN16(sizeof(request_t)); + td_dma = data_dma + ALIGN16(data_size); INIT_LIST_HEAD(&rq->list); - rq->data = (addr_t)data; - rq->size = req_size; + rq->data = MakePtr(addr_t, rq, ALIGN16(sizeof(request_t))); + td = MakePtr(td_t*, rq->data, ALIGN16(data_size)); + rq->td_head = td; + rq->size = data_size; rq->dev = dev; - if(data) - data_dma = DMA(data); - td_prev = NULL; - while(size > 0) + dsize = data_size; + + while(dsize != 0) { - if ( size < packet_size) + if ( dsize < packet_size) { - packet_size = size; + packet_size = dsize; }; - td = dma_pool_alloc(hc->td_pool, 0, &td_dma); td->dma = td_dma; td->link = 1; - if(rq->td_head == NULL) - rq->td_head = td; - if( td_prev ) td_prev->link = td->dma | 4; td->status = TD_CTRL_ACTIVE | dev->speed; @@ -452,13 +463,16 @@ request_t *create_request(udev_t *dev, endp_t *enp, u32_t dir, td_prev = td; + td++; + td_dma+= sizeof(td_t); data_dma+= packet_size; - size-= packet_size; + + dsize-= packet_size; enp->toggle ^= DATA1; }; - td->status |= TD_CTRL_IOC; - rq->td_tail = td; + td_prev->status |= TD_CTRL_IOC; + rq->td_tail = td_prev; rq->evh = CreateEvent(NULL, MANUAL_DESTROY); @@ -499,7 +513,7 @@ bool ctrl_request(udev_t *dev, void *req, u32_t pid, td0 = dma_pool_alloc(hc->td_pool, 0, &td_dma); td0->dma = td_dma; - dbgprintf("alloc td0 %x dma %x\n", td0, td_dma); +// dbgprintf("alloc td0 %x dma %x\n", td0, td_dma); td0->status = 0x00800000 | dev->speed; td0->token = TOKEN( 8, DATA0, 0, dev->addr, 0x2D); @@ -521,7 +535,7 @@ bool ctrl_request(udev_t *dev, void *req, u32_t pid, td = dma_pool_alloc(hc->td_pool, 0, &td_dma); td->dma = td_dma; - dbgprintf("alloc td %x dma %x\n", td, td->dma); +// dbgprintf("alloc td %x dma %x\n", td, td->dma); td_prev->link = td->dma | 4; td->status = TD_CTRL_ACTIVE | dev->speed; @@ -539,7 +553,7 @@ bool ctrl_request(udev_t *dev, void *req, u32_t pid, td = dma_pool_alloc(hc->td_pool, 0, &td_dma); td->dma = td_dma; - dbgprintf("alloc td %x dma %x\n", td, td->dma); +// dbgprintf("alloc td %x dma %x\n", td, td->dma); td_prev->link = td->dma | 4; @@ -564,7 +578,7 @@ bool ctrl_request(udev_t *dev, void *req, u32_t pid, u32_t efl = safe_cli(); - list_add_tail(&rq->list, &dev->host->rq_list); + list_add_tail(&rq->list, &dev->host->rq_list); qh = dev->host->qh[SKEL_ASYNC]; diff --git a/drivers/usb/uhci/hid.inc b/drivers/usb/uhci/hid.inc index e1a0adc9d8..dfacc66247 100644 --- a/drivers/usb/uhci/hid.inc +++ b/drivers/usb/uhci/hid.inc @@ -15,6 +15,7 @@ struct hid_descriptor { } __attribute__ ((packed)); void create_hid_mouse(udev_t *dev, endpoint_descr_t *en_d); +void create_hid_keyboard(udev_t *dev, endpoint_descr_t *en_d); bool init_hid(udev_t *dev) { @@ -93,8 +94,16 @@ bool init_hid(udev_t *dev) ep->wMaxPacketSize, ep->bInterval); dptr+= ep->bLength; - if( interface->bInterfaceProtocol == 2) - create_hid_mouse(dev, ep); + switch(interface->bInterfaceProtocol) + { + case 1: + create_hid_keyboard(dev, ep); + break; + + case 2: + create_hid_mouse(dev, ep); + break; + } // } return true; }; @@ -118,7 +127,164 @@ bool mouse_handler(udev_t *dev, struct tag_request *rq) u32_t efl = safe_cli(); list_add_tail(&rq->list, &dev->host->rq_list); - qh = dev->host->qh[6]; + qh = dev->host->qh[rq->qnum]; + qh->qelem = rq->td_head->dma; + mb(); + safe_sti(efl); + + return true; +}; + +typedef union +{ + uint16_t value; + struct + { + uint8_t code; + uint8_t ecode; + }; +}scancode_t; + +static const uint16_t usb_keycode[256] = +{ + /* 0 1 2 3 4 5 6 7 */ + /* 8 9 A B C D E F */ + + 0x0000, 0x0000, 0x0000, 0x0000, 0x001E, 0x0030, 0x002E, 0x0020, /* 0x00 */ + 0x0012, 0x0021, 0x0022, 0x0023, 0x0017, 0x0024, 0x0025, 0x0026, + + 0x0032, 0x0031, 0x0018, 0x0019, 0x0010, 0x0013, 0x001F, 0x0014, /* 0x10 */ + 0x0016, 0x002F, 0x0011, 0x002D, 0x0015, 0x002C, 0x0002, 0x0003, + + 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, /* 0x20 */ + 0x001C, 0x0001, 0x000E, 0x000F, 0x0039, 0x000C, 0x000D, 0x001A, + + 0x001B, 0x002B, 0x002B, 0x0027, 0x0028, 0x0029, 0x0033, 0x0034, /* 0x30 */ + 0x0035, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x0040, + + 0x0041, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, 0xE037, 0x0046, /* 0x40 */ + 0x0000, 0xE052, 0xE047, 0xE049, 0xE053, 0xE04F, 0xE051, 0xE04D, + + 0xE04B, 0xE050, 0xE048, 0x0045, 0xE035, 0x0037, 0x004A, 0x004E, /* 0x50 */ + 0xE01C, 0x004F, 0x0050, 0x0051, 0x004B, 0x004C, 0x004D, 0x0047, + + 0x0048, 0x0049, 0x0052, 0x0053, 0x0056, 0xE05D, 0xE05E, 0x0059, /* 0x60 */ + 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, + + 0x006C, 0x006D, 0x006E, 0x0076, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x70 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x007E, 0x0000, 0x0073, /* 0x80 */ + 0x0070, 0x007D, 0x0079, 0x007B, 0x005C, 0x0000, 0x0000, 0x0000, + + 0x00F2, 0x00F1, 0x0078, 0x0077, 0x0076, 0x0000, 0x0000, 0x0000, /* 0x90 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0xA0 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0xB0 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0xC0 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0xD0 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + + 0x001D, 0x002A, 0x0038, 0xE05B, 0xE01D, 0x0036, 0xE038, 0xE05C, /* 0xE0 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0xFE0 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + +}; + +static uint8_t kbd_old[8]; + +bool keyboard_handler(udev_t *dev, struct tag_request *rq) +{ + td_t *td; + qh_t *qh; + + uint8_t *data; + int i; + + td = rq->td_head; + + if( (td->status &0x7FF)==rq->size-1) + { + uint8_t action; + scancode_t scan; + + data = (uint8_t*)rq->data; + + action = data[0] ^ kbd_old[0]; + + for (i = 0; i < 8; i++) + { + if(action & 1) + { + scan.value = usb_keycode[i+224]; + + if(data[0]>>i & 1) + { + if(scan.ecode) + SetKeyboardData(scan.ecode); + SetKeyboardData(scan.code); + } + else + { + if(scan.ecode) + SetKeyboardData(scan.ecode); + SetKeyboardData(scan.code|0x80); + }; + } + action >>= 1; + } + + + for (i = 2; i < 8; i++) + { + if ((kbd_old[i] > 3) && (memscan(data+2, kbd_old[i], 6) == data+8)) + { + scan.value = usb_keycode[kbd_old[i]]; + + if (scan.value) + { + if(scan.ecode) + SetKeyboardData(scan.ecode); + SetKeyboardData(scan.code|0x80); + // input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0); + } + else + dbgprintf("Unknown key (scancode %#x) released.\n", kbd_old[i]); + } + + if ((data[i] > 3) && (memscan(kbd_old+2, data[i], 6) == kbd_old+8)) + { + scan.value = usb_keycode[data[i]]; + + if (scan.value) + { + if(scan.ecode) + SetKeyboardData(scan.ecode); + SetKeyboardData(scan.code); + //input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1); + } + else + dbgprintf("Unknown key (scancode %#x) released.\n", data[i]); + } + } + memcpy(kbd_old, data, 8); + }; + + td->status = TD_CTRL_ACTIVE | TD_CTRL_IOC | dev->speed; + td->token ^= DATA1; + + u32_t efl = safe_cli(); + list_add_tail(&rq->list, &dev->host->rq_list); + qh = dev->host->qh[rq->qnum]; qh->qelem = rq->td_head->dma; mb(); safe_sti(efl); @@ -135,9 +301,6 @@ void create_hid_mouse(udev_t *dev, endpoint_descr_t *en_d) addr_t size; u32_t toggle; - void *packet; - - td_t *td; qh_t *qh; static u16_t __attribute__((aligned(16))) @@ -150,18 +313,69 @@ void create_hid_mouse(udev_t *dev, endpoint_descr_t *en_d) enp.size = en_d->wMaxPacketSize; enp.toggle = DATA0; - packet = kzalloc(enp.size, 0); + rq = alloc_rq_buffer(dev, &enp, DIN, enp.size); - rq = create_request(dev, &enp, DIN, packet, enp.size); rq->qnum = 6; rq->handler = &mouse_handler; u32_t efl = safe_cli(); list_add_tail(&rq->list, &dev->host->rq_list); - qh = dev->host->qh[6]; + qh = dev->host->qh[rq->qnum]; qh->qelem = rq->td_head->dma; mb(); safe_sti(efl); - dbgprintf("create_hid_mouse\n"); + dbgprintf("%s\n",__FUNCTION__); } + +void create_hid_keyboard(udev_t *dev, endpoint_descr_t *en_d) +{ + request_t *rq; + endp_t enp; + + addr_t address; + addr_t size; + u32_t toggle; + + qh_t *qh; + + static u16_t __attribute__((aligned(16))) + req_set_conf[4] = {0x0900,0x0001,0x0000,0x0000}; + + if( !ctrl_request(dev, req_set_conf, DOUT, 0, 0)) + return; + + enp.address = en_d->bEndpointAddress; + enp.size = en_d->wMaxPacketSize; + enp.toggle = DATA0; + + rq = alloc_rq_buffer(dev, &enp, DIN, enp.size); + + rq->qnum = 4; + rq->handler = &keyboard_handler; + + u32_t efl = safe_cli(); + list_add_tail(&rq->list, &dev->host->rq_list); + qh = dev->host->qh[rq->qnum]; + qh->qelem = rq->td_head->dma; + mb(); + safe_sti(efl); + + dbgprintf("%s\n",__FUNCTION__); +} + +void *memscan(void *addr, int c, size_t size) +{ + if (!size) + return addr; + __asm__ __volatile__( + "repnz; scasb \n\t" + "jnz 1f \n\t" + "dec %%edi \n\t" + "1:" + : "=D" (addr), "=c" (size) + : "D" (addr), "1" (size), "a" (c) + : "memory"); + return addr; +} + diff --git a/drivers/usb/uhci/makefile b/drivers/usb/uhci/makefile index 1d881d94a2..d5d67de6aa 100644 --- a/drivers/usb/uhci/makefile +++ b/drivers/usb/uhci/makefile @@ -1,48 +1,52 @@ CC = gcc + + +DRV_DIR = $(CURDIR)/../.. + +DRV_INCLUDES = $(DRV_DIR)/include + + +INCLUDES = -I$(DRV_INCLUDES) -I$(DRV_DIR)/include/linux + +DEFINES = -D__KERNEL__ -DCONFIG_X86_32 + CFLAGS = -c -O2 -fomit-frame-pointer -fno-builtin-printf -LDFLAGS = -nostdlib -shared -s -Map usb.map --image-base 0\ + +LDFLAGS = -nostdlib -shared -s -Map acpi.map --image-base 0\ --file-alignment 512 --section-alignment 4096 -DEFINES = -D__KERNEL__ -DCONFIG_X86_32 +LIBPATH:= -L$(DRV_DIR)/ddk -DRV_TOPDIR = $(CURDIR)/../.. - -DRV_INCLUDES = $(DRV_TOPDIR)/include - -INCLUDES = -I$(DRV_INCLUDES) \ - -I$(DRV_INCLUDES)/linux - -LIBPATH = $(DRV_TOPDIR)/ddk +LIBS:= -lgcc -lddk -lcore +NAME= usb -SRC_DEP:= pci.inc \ - detect.inc \ - hcd.inc \ - hid.inc +NAME_SRCS= usb.c \ + buffer.c -USB_SRC:= usb.c +SRC_DEP = hcd.inc \ + detect.inc \ + hid.inc \ + pci.inc \ -USB_OBJ:= usb.obj -LIBS:= -lddk -lcore +all: $(NAME).dll -USB = usb.dll +NAME_OBJS = $(patsubst %.S, %.o, $(patsubst %.asm, %.o,\ + $(patsubst %.c, %.o, $(NAME_SRCS)))) -all: $(USB) -$(USB): $(USB_OBJ) $(SRC_DEP) $(HFILES) Makefile - ld $(LDFLAGS) -L$(LIBPATH) -T usb.lds -o $@ $(USB_OBJ) $(LIBS) - kpack.exe usb.dll usb.drv +$(NAME).dll: $(NAME_OBJS) usb.lds Makefile + ld $(LIBPATH) $(LDFLAGS) -T usb.lds -o $@ $(NAME_OBJS) $(LIBS) + kpack $(NAME).dll $(NAME).drv -usb.obj : usb.c $(SRC_DEP) $(HFILES) Makefile - $(CC) $(DEFINES) $(INCLUDES) $(CFLAGS) -o usb.obj usb.c +%.o : %.c $(HFILES) $(SRC_DEP) Makefile + $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o $@ $< -%.obj : %.c $(HFILES) - $(CC) $(CFLAGS) -o $@ $< - -%.obj: %.asm +%.o : %.S $(HFILES) Makefile as -o $@ $< + diff --git a/drivers/usb/uhci/usb.c b/drivers/usb/uhci/usb.c index d896106373..d9d51be11f 100644 --- a/drivers/usb/uhci/usb.c +++ b/drivers/usb/uhci/usb.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "usb.h" @@ -39,22 +40,24 @@ u32_t drvEntry(int action, char *cmdline) return 0; }; - qh_slab.available = 256; - qh_slab.start = KernelAlloc(4096); - qh_slab.nextavail = (addr_t)qh_slab.start; - qh_slab.dma = GetPgAddr(qh_slab.start); + hcd_buffer_create(); - qh_t *p; - addr_t dma; + qh_slab.available = 256; + qh_slab.start = KernelAlloc(4096); + qh_slab.nextavail = (addr_t)qh_slab.start; + qh_slab.dma = GetPgAddr(qh_slab.start); - for (i = 0, p = (qh_t*)qh_slab.start, dma = qh_slab.dma; - i < 256; i++, p++, dma+= sizeof(qh_t)) - { - p->qlink = (addr_t)(p+1); - p->qelem = 1; - p->dma = dma; - p->r1 = 0; - }; + qh_t *p; + addr_t dma; + + for (i = 0, p = (qh_t*)qh_slab.start, dma = qh_slab.dma; + i < 256; i++, p++, dma+= sizeof(qh_t)) + { + p->qlink = (addr_t)(p+1); + p->qelem = 1; + p->dma = dma; + p->r1 = 0; + }; hc = (hc_t*)hc_list.next;