diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/9/pc/uartpci.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/9/pc/uartpci.c')
-rwxr-xr-x | sys/src/9/pc/uartpci.c | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/sys/src/9/pc/uartpci.c b/sys/src/9/pc/uartpci.c new file mode 100755 index 000000000..d86acf50f --- /dev/null +++ b/sys/src/9/pc/uartpci.c @@ -0,0 +1,219 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +extern PhysUart i8250physuart; +extern PhysUart pciphysuart; +extern void* i8250alloc(int, int, int); + +static Uart *perlehead, *perletail; + +static Uart* +uartpci(int ctlrno, Pcidev* p, int barno, int n, int freq, char* name, + int iosize) +{ + int i, io; + void *ctlr; + char buf[64]; + Uart *head, *uart; + + io = p->mem[barno].bar & ~0x01; + snprint(buf, sizeof(buf), "%s%d", pciphysuart.name, ctlrno); + if(ioalloc(io, p->mem[barno].size, 0, buf) < 0){ + print("uartpci: I/O 0x%uX in use\n", io); + return nil; + } + + head = uart = malloc(sizeof(Uart)*n); + for(i = 0; i < n; i++){ + ctlr = i8250alloc(io, p->intl, p->tbdf); + io += iosize; + if(ctlr == nil) + continue; + + uart->regs = ctlr; + snprint(buf, sizeof(buf), "%s.%8.8uX", name, p->tbdf); + kstrdup(&uart->name, buf); + uart->freq = freq; + uart->phys = &i8250physuart; + if(uart != head) + (uart-1)->next = uart; + uart++; + } + + if (head) { + if(perlehead != nil) + perletail->next = head; + else + perlehead = head; + for(perletail = head; perletail->next != nil; + perletail = perletail->next) + ; + } + return head; +} + +static Uart * +ultraport16si(int ctlrno, Pcidev *p, ulong freq) +{ + int io, i; + char *name; + Uart *uart; + + name = "Ultraport16si"; /* 16L788 UARTs */ + io = p->mem[4].bar & ~1; + if (ioalloc(io, p->mem[4].size, 0, name) < 0) { + print("uartpci: can't get IO space to set %s to rs-232\n", name); + return nil; + } + for (i = 0; i < 16; i++) { + outb(io, i << 4); + outb(io, (i << 4) + 1); /* set to RS232 mode (Don't ask!) */ + } + + uart = uartpci(ctlrno, p, 2, 8, freq, name, 16); + if(uart) + uart = uartpci(ctlrno, p, 3, 8, freq, name, 16); + return uart; +} + +static Uart* +uartpcipnp(void) +{ + Pcidev *p; + char *name; + int ctlrno, subid; + ulong freq; + Uart *uart; + + /* + * Loop through all PCI devices looking for simple serial + * controllers (ccrb == Pcibccomm (7)) and configure the ones which + * are familiar. All suitable devices are configured to + * simply point to the generic i8250 driver. + */ + perlehead = perletail = nil; + ctlrno = 0; + for(p = pcimatch(nil, 0, 0); p != nil; p = pcimatch(p, 0, 0)){ + if(p->ccrb != Pcibccomm || p->ccru > 2) + continue; + + switch(p->did<<16 | p->vid){ + default: + continue; + case (0x9835<<16)|0x9710: /* StarTech PCI2S550 */ + uart = uartpci(ctlrno, p, 0, 1, 1843200, "PCI2S550-0", 8); + if(uart == nil) + continue; + uart->next = uartpci(ctlrno, p, 1, 1, 1843200, + "PCI2S550-1", 8); + if(uart->next == nil) + continue; + break; + case (0x950A<<16)|0x1415: /* Oxford Semi OX16PCI954 */ + case (0x9501<<16)|0x1415: + case (0x9521<<16)|0x1415: + /* + * These are common devices used by 3rd-party + * manufacturers. + * Must check the subsystem VID and DID for correct + * match. + */ + subid = pcicfgr16(p, PciSVID); + subid |= pcicfgr16(p, PciSID)<<16; + switch(subid){ + default: + print("oxsemi uart %.8#ux of vid %#ux did %#ux unknown\n", + subid, p->vid, p->did); + continue; + case (0<<16)|0x1415: + uart = uartpci(ctlrno, p, 0, 4, 1843200, + "starport-pex4s", 8); + break; + case (1<<16)|0x1415: + uart = uartpci(ctlrno, p, 0, 2, 14745600, + "starport-pex2s", 8); + break; + case (0x2000<<16)|0x131F:/* SIIG CyberSerial PCIe */ + uart = uartpci(ctlrno, p, 0, 1, 18432000, + "CyberSerial-1S", 8); + break; + } + break; + case (0x9505<<16)|0x1415: /* Oxford Semi OXuPCI952 */ + name = "SATAGear-IOI-102"; /* PciSVID=1415, PciSID=0 */ + if (uartpci(ctlrno, p, 0, 1, 14745600, name, 8) != nil) + ctlrno++; + if (uartpci(ctlrno, p, 1, 1, 14745600, name, 8) != nil) + ctlrno++; + uart = nil; /* don't ctlrno++ below */ + break; + case (0x9050<<16)|0x10B5: /* Perle PCI-Fast4 series */ + case (0x9030<<16)|0x10B5: /* Perle Ultraport series */ + /* + * These devices consists of a PLX bridge (the above + * PCI VID+DID) behind which are some 16C654 UARTs. + * Must check the subsystem VID and DID for correct + * match. + */ + subid = pcicfgr16(p, PciSVID); + subid |= pcicfgr16(p, PciSID)<<16; + freq = 7372800; + switch(subid){ + default: + continue; + case (0x0011<<16)|0x12E0: /* Perle PCI-Fast16 */ + name = "PCI-Fast16"; + uart = uartpci(ctlrno, p, 2, 16, freq, name, 8); + break; + case (0x0021<<16)|0x12E0: /* Perle PCI-Fast8 */ + name = "PCI-Fast8"; + uart = uartpci(ctlrno, p, 2, 8, freq, name, 8); + break; + case (0x0031<<16)|0x12E0: /* Perle PCI-Fast4 */ + name = "PCI-Fast4"; + uart = uartpci(ctlrno, p, 2, 4, freq, name, 8); + break; + case (0x0021<<16)|0x155F: /* Perle Ultraport8 */ + name = "Ultraport8"; /* 16C754 UARTs */ + uart = uartpci(ctlrno, p, 2, 8, freq, name, 8); + break; + case (0x0041<<16)|0x155F: /* Perle Ultraport16 */ + name = "Ultraport16"; + uart = uartpci(ctlrno, p, 2, 16, 2 * freq, + name, 8); + break; + case (0x0241<<16)|0x155F: /* Perle Ultraport16 */ + uart = ultraport16si(ctlrno, p, 4 * freq); + break; + } + break; + } + if(uart) + ctlrno++; + } + + return perlehead; +} + +PhysUart pciphysuart = { + .name = "UartPCI", + .pnp = uartpcipnp, + .enable = nil, + .disable = nil, + .kick = nil, + .dobreak = nil, + .baud = nil, + .bits = nil, + .stop = nil, + .parity = nil, + .modemctl = nil, + .rts = nil, + .dtr = nil, + .status = nil, + .fifo = nil, +}; |