Plan 9 from Bell Labs’s /usr/web/sources/patch/applied/perle-ultraport16/uartpci.c.new

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#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*
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++;
	}

	return head;
}

static void
ultraport16si(Pcidev *p)
{
	int io, i;
	
	io = p->mem[4].bar & ~1;
	if (ioalloc(io, p->mem[4].size, 0, "Ultraport16si") < 0) {
		print("Can't get space to set Ultraport16si to rs-232\n");
		return;
	}
	for (i = 0; i < 16; i++) {
		outb(io, i << 4);
		outb(io, (i << 4) +1);	/* set to RS232 mode  (Don't ask!) */
	}
}

static Uart*
uartpcipnp(void)
{
	Pcidev *p;
	char *name;
	int ctlrno, n, subid, freq, iosize;
	Uart *head, *tail, *uart;

	/*
	 * Loop through all PCI devices looking for simple serial
	 * controllers (ccrb == 0x07) and configure the ones which
	 * are familiar. All suitable devices are configured to
	 * simply point to the generic i8250 driver.
	 */
	head = tail = nil;
	ctlrno = 0;
	for(p = pcimatch(nil, 0, 0); p != nil; p = pcimatch(p, 0, 0)){
		if(p->ccrb != 0x07 || 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);
			break;
		case (0x950A<<16)|0x1415:	/* Oxford Semi OX16PCI954 */
			/*
			 * 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:
				continue;
			case (0x2000<<16)|0x131F:/* SIIG CyberSerial PCIe */
				uart = uartpci(ctlrno, p, 0, 1, 18432000, "CyberSerial-1S", 8);
					if(uart == nil)
						continue;
				break;
			}
			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;
			iosize = 8;
			switch(subid){
			default:
				continue;
			case (0x0011<<16)|0x12E0:	/* Perle PCI-Fast16 */
				n = 16;
				name = "PCI-Fast16";
				uart = uartpci(ctlrno, p, 2, n, freq, name, iosize);
				if(uart == nil)
					continue;
				break;
			case (0x0021<<16)|0x12E0:	/* Perle PCI-Fast8 */
				n = 8;
				name = "PCI-Fast8";
				uart = uartpci(ctlrno, p, 2, n, freq, name, iosize);
				if(uart == nil)
					continue;
				break;
			case (0x0031<<16)|0x12E0:	/* Perle PCI-Fast4 */
				n = 4;
				name = "PCI-Fast4";
				uart = uartpci(ctlrno, p, 2, n, freq, name, iosize);
				if(uart == nil)
					continue;
				break;
			case (0x0021<<16)|0x155F:	/* Perle Ultraport8 */
				n = 8;
				name = "Ultraport8";	/* 16C754 UARTs */
				uart = uartpci(ctlrno, p, 2, n, freq, name, iosize);
				if(uart == nil)
					continue;
				break;
			case (0x0241<<16)|0x155F:	/* Perle Ultraport16 */
				name = "Ultraport16si";	/* 16L788 UARTs */
				freq *= 4;
				iosize = 16;
				ultraport16si(p);
				uart = uartpci(ctlrno, p, 2, 8, freq, name, iosize);
				if(uart == nil)
					continue;
				if(head != nil)
					tail->next = uart;
				else
					head = uart;
				for(tail = uart; tail->next != nil; tail = tail->next)
					;
				uart = uartpci(ctlrno, p, 3, 8, freq, name, iosize);
				if(uart == nil)
					continue;
				break;
			}
			break;
		}

		if(head != nil)
			tail->next = uart;
		else
			head = uart;
		for(tail = uart; tail->next != nil; tail = tail->next)
			;
		ctlrno++;
	}

	return head;
}

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,
};

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].