From: Kevin O'Connor Date: Mon, 12 Oct 2009 14:09:15 +0000 (-0400) Subject: Add stubs for USB OHCI support. X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=seabios.git;a=commitdiff_plain;h=59f02834f38c63be537f63a702c69b68af913bfa Add stubs for USB OHCI support. Enable USB wrapper functions to call either ohci or ehci helpers. Implement pci_config_maskw in place of pci_set_bus_master. Introduce 'struct usb_pipe' in place of 'void *' for pipes. --- diff --git a/Makefile b/Makefile index 97dd795..b1af624 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ OUT=out/ SRCBOTH=output.c util.c block.c floppy.c ata.c misc.c mouse.c kbd.c pci.c \ serial.c clock.c pic.c cdrom.c ps2port.c smp.c resume.c \ pnpbios.c pirtable.c vgahooks.c pmm.c ramdisk.c \ - usb.c usb-uhci.c usb-hid.c paravirt.c + usb.c usb-uhci.c usb-ohci.c usb-hid.c paravirt.c SRC16=$(SRCBOTH) system.c disk.c apm.c pcibios.c font.c SRC32=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \ acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \ diff --git a/src/config.h b/src/config.h index fa0dd1d..ae83ae3 100644 --- a/src/config.h +++ b/src/config.h @@ -30,6 +30,8 @@ #define CONFIG_USB 1 // Support USB UHCI controllers #define CONFIG_USB_UHCI 1 +// Support USB OHCI controllers +#define CONFIG_USB_OHCI 0 // Support USB keyboards #define CONFIG_USB_KEYBOARD 1 // Support for IDE disk code diff --git a/src/pci.c b/src/pci.c index e6b74d5..143acf6 100644 --- a/src/pci.c +++ b/src/pci.c @@ -48,6 +48,15 @@ u8 pci_config_readb(u16 bdf, u32 addr) return inb(PORT_PCI_DATA + (addr & 3)); } +void +pci_config_maskw(u16 bdf, u32 addr, u16 off, u16 on) +{ + u16 val = pci_config_readw(bdf, addr); + val = (val & ~off) | on; + pci_config_writew(bdf, addr, val); +} + +// Helper function for foreachpci() macro - return next device int pci_next(int bdf, int *pmax) { @@ -156,10 +165,8 @@ pci_find_device(u16 vendid, u16 devid) int bdf, max; foreachpci(bdf, max) { u32 v = pci_config_readl(bdf, PCI_VENDOR_ID); - if (v != id) - continue; - // Found it. - return bdf; + if (v == id) + return bdf; } return -1; } @@ -171,18 +178,8 @@ pci_find_class(u16 classid) int bdf, max; foreachpci(bdf, max) { u16 v = pci_config_readw(bdf, PCI_CLASS_DEVICE); - if (v != classid) - continue; - // Found it. - return bdf; + if (v == classid) + return bdf; } return -1; } - -void -pci_set_bus_master(u16 bdf) -{ - u16 val = pci_config_readw(bdf, PCI_COMMAND); - val |= PCI_COMMAND_MASTER; - pci_config_writew(bdf, PCI_COMMAND, val); -} diff --git a/src/pci.h b/src/pci.h index 166b775..a0b6b9c 100644 --- a/src/pci.h +++ b/src/pci.h @@ -25,11 +25,11 @@ void pci_config_writeb(u16 bdf, u32 addr, u8 val); u32 pci_config_readl(u16 bdf, u32 addr); u16 pci_config_readw(u16 bdf, u32 addr); u8 pci_config_readb(u16 bdf, u32 addr); +void pci_config_maskw(u16 bdf, u32 addr, u16 off, u16 on); int pci_find_vga(); int pci_find_device(u16 vendid, u16 devid); int pci_find_class(u16 classid); -void pci_set_bus_master(u16 bdf); int pci_next(int bdf, int *pmax); #define foreachpci(BDF, MAX) \ diff --git a/src/usb-hid.c b/src/usb-hid.c index 7e5b309..6deb2b0 100644 --- a/src/usb-hid.c +++ b/src/usb-hid.c @@ -10,7 +10,7 @@ #include "usb.h" // usb_ctrlrequest #include "biosvar.h" // GET_GLOBAL -void *keyboard_pipe VAR16VISIBLE; +struct usb_pipe *keyboard_pipe VAR16VISIBLE; /**************************************************************** @@ -78,7 +78,7 @@ usb_keyboard_init(u32 endp, struct usb_interface_descriptor *iface, int imax) if (ret) return -1; - void *pipe = alloc_intr_pipe(inendp, epdesc->bInterval); + struct usb_pipe *pipe = alloc_intr_pipe(inendp, epdesc->bInterval); if (!pipe) return -1; keyboard_pipe = pipe; diff --git a/src/usb-ohci.c b/src/usb-ohci.c new file mode 100644 index 0000000..638b8a4 --- /dev/null +++ b/src/usb-ohci.c @@ -0,0 +1,109 @@ +// Code for handling OHCI USB controllers. +// +// Copyright (C) 2009 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // dprintf +#include "pci.h" // pci_bdf_to_bus +#include "config.h" // CONFIG_* +#include "ioport.h" // outw +#include "usb-ohci.h" // USBLEGSUP +#include "pci_regs.h" // PCI_BASE_ADDRESS_4 +#include "usb.h" // struct usb_s +#include "farptr.h" // GET_FLATPTR +#include "biosvar.h" // GET_GLOBAL + +static void +reset_ohci(struct usb_s *cntl) +{ +} + +static void +configure_ohci(struct usb_s *cntl) +{ + // XXX - check for SMM control? + + writel(&cntl->ohci.regs->intrdisable, OHCI_INTR_MIE); + + struct ohci_hcca *hcca = memalign_low(256, sizeof(*hcca)); + if (!hcca) { + dprintf(1, "No ram for ohci init\n"); + return; + } + + +} + +static void +start_ohci(struct usb_s *cntl) +{ +} + +// Find any devices connected to the root hub. +static int +check_ohci_ports(struct usb_s *cntl) +{ + return 0; +} + +int +ohci_init(struct usb_s *cntl) +{ + if (! CONFIG_USB_OHCI) + return 0; + + cntl->type = USB_TYPE_OHCI; + u32 baseaddr = pci_config_readl(cntl->bdf, PCI_BASE_ADDRESS_0); + cntl->ohci.regs = (void*)(baseaddr & PCI_BASE_ADDRESS_MEM_MASK); + + dprintf(3, "OHCI init on dev %02x:%02x.%x (regs=%p)\n" + , pci_bdf_to_bus(cntl->bdf), pci_bdf_to_dev(cntl->bdf) + , pci_bdf_to_fn(cntl->bdf), cntl->ohci.regs); + + // Enable bus mastering and memory access. + pci_config_maskw(cntl->bdf, PCI_COMMAND + , 0, PCI_COMMAND_MASTER|PCI_COMMAND_MEMORY); + + reset_ohci(cntl); + configure_ohci(cntl); + start_ohci(cntl); + + int count = check_ohci_ports(cntl); + if (! count) { + // XXX - no devices; free data structures. + return 0; + } + + return 0; +} + +int +ohci_control(u32 endp, int dir, const void *cmd, int cmdsize + , void *data, int datasize) +{ + if (! CONFIG_USB_OHCI) + return 0; + + dprintf(5, "ohci_control %x\n", endp); + return 0; +} + +struct usb_pipe * +ohci_alloc_intr_pipe(u32 endp, int period) +{ + if (! CONFIG_USB_OHCI) + return NULL; + + dprintf(7, "ohci_alloc_intr_pipe %x %d\n", endp, period); + return NULL; +} + +int +ohci_poll_intr(void *pipe, void *data) +{ + ASSERT16(); + if (! CONFIG_USB_OHCI) + return -1; + return -1; +} diff --git a/src/usb-ohci.h b/src/usb-ohci.h new file mode 100644 index 0000000..9d13f8c --- /dev/null +++ b/src/usb-ohci.h @@ -0,0 +1,97 @@ +#ifndef __USB_OHCI_H +#define __USB_OHCI_H + +// usb-ohci.c +struct usb_s; +int ohci_init(struct usb_s *cntl); +int ohci_control(u32 endp, int dir, const void *cmd, int cmdsize + , void *data, int datasize); +struct usb_pipe *ohci_alloc_intr_pipe(u32 endp, int period); +int ohci_poll_intr(void *pipe, void *data); + + +/**************************************************************** + * ohci structs and flags + ****************************************************************/ + +struct ohci_ed { + u32 hwINFO; + u32 hwTailP; + u32 hwHeadP; + u32 hwNextED; +} PACKED; + +#define ED_ISO (1 << 15) +#define ED_SKIP (1 << 14) +#define ED_LOWSPEED (1 << 13) +#define ED_OUT (0x01 << 11) +#define ED_IN (0x02 << 11) + +#define ED_C (0x02) +#define ED_H (0x01) + +struct ohci_td { + u32 hwINFO; + u32 hwCBP; + u32 hwNextTD; + u32 hwBE; +} PACKED; + +#define TD_CC 0xf0000000 +#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f) +#define TD_DI 0x00E00000 +#define TD_DI_SET(X) (((X) & 0x07)<< 21) + +#define TD_DONE 0x00020000 +#define TD_ISO 0x00010000 + +#define TD_EC 0x0C000000 +#define TD_T 0x03000000 +#define TD_T_DATA0 0x02000000 +#define TD_T_DATA1 0x03000000 +#define TD_T_TOGGLE 0x00000000 +#define TD_DP 0x00180000 +#define TD_DP_SETUP 0x00000000 +#define TD_DP_IN 0x00100000 +#define TD_DP_OUT 0x00080000 + +#define TD_R 0x00040000 + +struct ohci_hcca { + u32 int_table[32]; + u32 frame_no; + u32 done_head; + u8 reserved[120]; +} PACKED; + +struct ohci_regs { + u32 revision; + u32 control; + u32 cmdstatus; + u32 intrstatus; + u32 intrenable; + u32 intrdisable; + + u32 hcca; + u32 ed_periodcurrent; + u32 ed_controlhead; + u32 ed_controlcurrent; + u32 ed_bulkhead; + u32 ed_bulkcurrent; + u32 donehead; + + u32 fminterval; + u32 fmremaining; + u32 fmnumber; + u32 periodicstart; + u32 lsthresh; + + u32 roothub_a; + u32 roothub_b; + u32 roothub_status; + u32 roothub_portstatus[15]; +} PACKED; + +#define OHCI_INTR_MIE (1 << 31) + +#endif // usb-ohci.h diff --git a/src/usb-uhci.c b/src/usb-uhci.c index 814e3ec..4d3df45 100644 --- a/src/usb-uhci.c +++ b/src/usb-uhci.c @@ -23,12 +23,12 @@ reset_uhci(struct usb_s *cntl) pci_config_writew(cntl->bdf, USBLEGSUP, USBLEGSUP_RWC); // Reset the HC - outw(USBCMD_HCRESET, cntl->iobase + USBCMD); + outw(USBCMD_HCRESET, cntl->uhci.iobase + USBCMD); udelay(5); // Disable interrupts and commands (just to be safe). - outw(0, cntl->iobase + USBINTR); - outw(0, cntl->iobase + USBCMD); + outw(0, cntl->uhci.iobase + USBINTR); + outw(0, cntl->uhci.iobase + USBCMD); } static void @@ -40,7 +40,7 @@ configure_uhci(struct usb_s *cntl) struct uhci_qh *data_qh = malloc_low(sizeof(*data_qh)); struct uhci_qh *term_qh = malloc_high(sizeof(*term_qh)); if (!term_td || !fl || !data_qh || !term_qh) { - dprintf(1, "No ram for uhci init"); + dprintf(1, "No ram for uhci init\n"); return; } @@ -57,7 +57,7 @@ configure_uhci(struct usb_s *cntl) memset(data_qh, 0, sizeof(*data_qh)); data_qh->element = UHCI_PTR_TERM; data_qh->link = (u32)term_qh | UHCI_PTR_QH; - cntl->qh = data_qh; + cntl->uhci.qh = data_qh; // Set schedule to point to primary queue head int i; @@ -66,28 +66,28 @@ configure_uhci(struct usb_s *cntl) } // Set the frame length to the default: 1 ms exactly - outb(USBSOF_DEFAULT, cntl->iobase + USBSOF); + outb(USBSOF_DEFAULT, cntl->uhci.iobase + USBSOF); // Store the frame list base address - outl((u32)fl->links, cntl->iobase + USBFLBASEADD); + outl((u32)fl->links, cntl->uhci.iobase + USBFLBASEADD); // Set the current frame number - outw(0, cntl->iobase + USBFRNUM); + outw(0, cntl->uhci.iobase + USBFRNUM); } static void start_uhci(struct usb_s *cntl) { // Mark as configured and running with a 64-byte max packet. - outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, cntl->iobase + USBCMD); + outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, cntl->uhci.iobase + USBCMD); } // Find any devices connected to the root hub. static int check_ports(struct usb_s *cntl) { - u16 port1 = inw(cntl->iobase + USBPORTSC1); - u16 port2 = inw(cntl->iobase + USBPORTSC2); + u16 port1 = inw(cntl->uhci.iobase + USBPORTSC1); + u16 port2 = inw(cntl->uhci.iobase + USBPORTSC2); if (!((port1 & USBPORTSC_CCS) || (port2 & USBPORTSC_CCS))) // No devices @@ -95,30 +95,30 @@ check_ports(struct usb_s *cntl) // reset ports if (port1 & USBPORTSC_CCS) - outw(USBPORTSC_PR, cntl->iobase + USBPORTSC1); + outw(USBPORTSC_PR, cntl->uhci.iobase + USBPORTSC1); if (port2 & USBPORTSC_CCS) - outw(USBPORTSC_PR, cntl->iobase + USBPORTSC2); + outw(USBPORTSC_PR, cntl->uhci.iobase + USBPORTSC2); mdelay(10); - outw(0, cntl->iobase + USBPORTSC1); - outw(0, cntl->iobase + USBPORTSC2); + outw(0, cntl->uhci.iobase + USBPORTSC1); + outw(0, cntl->uhci.iobase + USBPORTSC2); mdelay(10); // Configure ports int totalcount = 0; - port1 = inw(cntl->iobase + USBPORTSC1); + port1 = inw(cntl->uhci.iobase + USBPORTSC1); if (port1 & USBPORTSC_CCS) { - outw(USBPORTSC_PE, cntl->iobase + USBPORTSC1); + outw(USBPORTSC_PE, cntl->uhci.iobase + USBPORTSC1); int count = configure_usb_device(cntl, !!(port1 & USBPORTSC_LSDA)); if (! count) - outw(0, cntl->iobase + USBPORTSC1); + outw(0, cntl->uhci.iobase + USBPORTSC1); totalcount += count; } - port2 = inw(cntl->iobase + USBPORTSC2); + port2 = inw(cntl->uhci.iobase + USBPORTSC2); if (port2 & USBPORTSC_CCS) { - outw(USBPORTSC_PE, cntl->iobase + USBPORTSC2); + outw(USBPORTSC_PE, cntl->uhci.iobase + USBPORTSC2); int count = configure_usb_device(cntl, !!(port2 & USBPORTSC_LSDA)); if (! count) - outw(0, cntl->iobase + USBPORTSC2); + outw(0, cntl->uhci.iobase + USBPORTSC2); totalcount += count; } return totalcount; @@ -130,14 +130,15 @@ uhci_init(struct usb_s *cntl) if (! CONFIG_USB_UHCI) return 0; - cntl->iobase = (pci_config_readl(cntl->bdf, PCI_BASE_ADDRESS_4) - & PCI_BASE_ADDRESS_IO_MASK); + cntl->type = USB_TYPE_UHCI; + cntl->uhci.iobase = (pci_config_readl(cntl->bdf, PCI_BASE_ADDRESS_4) + & PCI_BASE_ADDRESS_IO_MASK); dprintf(3, "UHCI init on dev %02x:%02x.%x (io=%x)\n" , pci_bdf_to_bus(cntl->bdf), pci_bdf_to_dev(cntl->bdf) - , pci_bdf_to_fn(cntl->bdf), cntl->iobase); + , pci_bdf_to_fn(cntl->bdf), cntl->uhci.iobase); - pci_set_bus_master(cntl->bdf); + pci_config_maskw(cntl->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER); reset_uhci(cntl); configure_uhci(cntl); @@ -213,7 +214,7 @@ uhci_control(u32 endp, int dir, const void *cmd, int cmdsize tds[i].buffer = 0; // Transfer data - struct uhci_qh *data_qh = cntl->qh; + struct uhci_qh *data_qh = cntl->uhci.qh; data_qh->element = (u32)&tds[0]; int ret = wait_qh(data_qh); if (ret) @@ -223,7 +224,7 @@ uhci_control(u32 endp, int dir, const void *cmd, int cmdsize return 0; } -void * +struct usb_pipe * uhci_alloc_intr_pipe(u32 endp, int period) { if (! CONFIG_USB_UHCI) @@ -259,23 +260,24 @@ uhci_alloc_intr_pipe(u32 endp, int period) } qh->next_td = &tds[0]; + qh->pipe.endp = endp; // XXX - need schedule - just add to primary list for now. - struct uhci_qh *data_qh = cntl->qh; + struct uhci_qh *data_qh = cntl->uhci.qh; qh->link = data_qh->link; data_qh->link = (u32)qh | UHCI_PTR_QH; - return qh; + return &qh->pipe; } int -uhci_poll_intr(void *pipe, void *data) +uhci_poll_intr(struct usb_pipe *pipe, void *data) { ASSERT16(); if (! CONFIG_USB_UHCI) return -1; - struct uhci_qh *qh = pipe; + struct uhci_qh *qh = container_of(pipe, struct uhci_qh, pipe); struct uhci_td *td = GET_FLATPTR(qh->next_td); u32 status = GET_FLATPTR(td->status); u32 token = GET_FLATPTR(td->token); diff --git a/src/usb-uhci.h b/src/usb-uhci.h index 6ad7e15..b284fcc 100644 --- a/src/usb-uhci.h +++ b/src/usb-uhci.h @@ -1,13 +1,15 @@ #ifndef __USB_UHCI_H #define __USB_UHCI_H +#include "usb.h" // struct usb_pipe + // usb-uhci.c struct usb_s; int uhci_init(struct usb_s *cntl); int uhci_control(u32 endp, int dir, const void *cmd, int cmdsize , void *data, int datasize); -void *uhci_alloc_intr_pipe(u32 endp, int period); -int uhci_poll_intr(void *pipe, void *data); +struct usb_pipe *uhci_alloc_intr_pipe(u32 endp, int period); +int uhci_poll_intr(struct usb_pipe *pipe, void *data); /**************************************************************** @@ -119,7 +121,7 @@ struct uhci_qh { // Software fields struct uhci_td *next_td; - u32 reserved; + struct usb_pipe pipe; } PACKED; #define UHCI_PTR_BITS 0x000F diff --git a/src/usb.c b/src/usb.c index 8e14b8e..edaef11 100644 --- a/src/usb.c +++ b/src/usb.c @@ -10,6 +10,7 @@ #include "pci_regs.h" // PCI_CLASS_REVISION #include "pci_ids.h" // PCI_CLASS_SERIAL_USB_UHCI #include "usb-uhci.h" // uhci_init +#include "usb-ohci.h" // ohci_init #include "usb-hid.h" // usb_keyboard_setup #include "usb.h" // struct usb_s @@ -19,19 +20,40 @@ static int send_control(u32 endp, int dir, const void *cmd, int cmdsize , void *data, int datasize) { - return uhci_control(endp, dir, cmd, cmdsize, data, datasize); + struct usb_s *cntl = endp2cntl(endp); + switch (cntl->type) { + default: + case USB_TYPE_UHCI: + return uhci_control(endp, dir, cmd, cmdsize, data, datasize); + case USB_TYPE_OHCI: + return ohci_control(endp, dir, cmd, cmdsize, data, datasize); + } } -void * +struct usb_pipe * alloc_intr_pipe(u32 endp, int period) { - return uhci_alloc_intr_pipe(endp, period); + struct usb_s *cntl = endp2cntl(endp); + switch (cntl->type) { + default: + case USB_TYPE_UHCI: + return uhci_alloc_intr_pipe(endp, period); + case USB_TYPE_OHCI: + return ohci_alloc_intr_pipe(endp, period); + } } int -usb_poll_intr(void *pipe, void *data) +usb_poll_intr(struct usb_pipe *pipe, void *data) { - return uhci_poll_intr(pipe, data); + struct usb_s *cntl = endp2cntl(pipe->endp); + switch (cntl->type) { + default: + case USB_TYPE_UHCI: + return uhci_poll_intr(pipe, data); + case USB_TYPE_OHCI: + return ohci_poll_intr(pipe, data); + } } int @@ -195,6 +217,8 @@ usb_setup() int devcount = 0; if (code == PCI_CLASS_SERIAL_USB_UHCI) devcount = uhci_init(cntl); + else if (code == PCI_CLASS_SERIAL_USB_OHCI) + devcount = ohci_init(cntl); if (devcount > 0) { // Success diff --git a/src/usb.h b/src/usb.h index e8d7455..36fde59 100644 --- a/src/usb.h +++ b/src/usb.h @@ -4,14 +4,30 @@ // Local information for a usb controller. struct usb_s { - u16 bdf; - u16 iobase; + u8 type; u8 maxaddr; - void *qh; + u16 bdf; + + union { + struct { + u16 iobase; + void *qh; + } uhci; + struct { + struct ohci_regs *regs; + } ohci; + }; }; +#define USB_TYPE_UHCI 1 +#define USB_TYPE_OHCI 2 + extern struct usb_s USBControllers[]; +struct usb_pipe { + u32 endp; +}; + #define USB_MAXADDR 127 // usb.c @@ -20,8 +36,8 @@ int configure_usb_device(struct usb_s *cntl, int lowspeed); struct usb_ctrlrequest; int send_default_control(u32 endp, const struct usb_ctrlrequest *req , void *data); -void *alloc_intr_pipe(u32 endp, int period); -int usb_poll_intr(void *pipe, void *data); +struct usb_pipe *alloc_intr_pipe(u32 endp, int period); +int usb_poll_intr(struct usb_pipe *pipe, void *data); /****************************************************************