⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 si.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Device driver for Specialix range (SI/XIO) of serial line multiplexors. * * Copyright (C) 1990, 1992 Specialix International, * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk> * Copyright (C) 1995, Peter Wemm <peter@haywire.dialix.com> * * Originally derived from:	SunOS 4.x version * Ported from BSDI version to FreeBSD by Peter Wemm. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notices, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notices, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by Andy Rutter of *	Advanced Methods and Tools Ltd. based on original information *	from Specialix International. * 4. Neither the name of Advanced Methods and Tools, nor Specialix *    International may be used to endorse or promote products derived from *    this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL THE AUTHORS BE LIABLE. * *	$\Id: si.c,v 1.9.2.5 1996/07/01 11:01:58 peter Exp $ */#ifndef lintstatic char si_copyright1[] =  "@(#) (C) Specialix International, 1990,1992",            si_copyright2[] =  "@(#) (C) Andy Rutter 1993",            si_copyright3[] =  "@(#) (C) Peter Wemm 1995";#endif	/* not lint */#include <sys/param.h>#include <sys/systm.h>#include <sys/ioctl.h>#include <sys/tty.h>#include <sys/ttydefaults.h>#include <sys/proc.h>#include <sys/user.h>#include <sys/conf.h>#include <sys/file.h>#include <sys/uio.h>#include <sys/dkstat.h>#include <sys/kernel.h>#include <sys/syslog.h>#include <sys/malloc.h>#include <sys/devconf.h>#include <machine/clock.h>#include <i386/isa/icu.h>#include <i386/isa/isa.h>#include <i386/isa/isa_device.h>#include <i386/isa/sireg.h>#include <machine/si.h>#include "si.h"/* * This device driver is designed to interface the Specialix International * range of serial multiplexor cards (SI/XIO) to BSDI/386 on an ISA bus machine. * * The controller is interfaced to the host via dual port ram * and a (programmable - SIHOST2) interrupt at IRQ 11,12 or 15. */#define	POLL		/* turn on poller to generate buffer empty interrupt */#undef	FASTPOLL	/* turn on 100Hz poller, (XXX: NOTYET!) */#define SI_DEF_HWFLOW	/* turn on default CRTSCTS flow control */#define SI_I_HIGH_WATER	(TTYHOG - 2 * SI_BUFFERSIZE)#define INT_COUNT 25000	/* max of 125 ints per second */#define RXINT_COUNT 1	/* one rxint per 10 milliseconds */enum si_mctl { GET, SET, BIS, BIC };static void si_command __P((struct si_port *, int, int));static int si_modem __P((struct si_port *, enum si_mctl, int));static void si_write_enable __P((struct si_port *, int));static int si_Sioctl __P((dev_t, int, caddr_t, int, struct proc *));static void si_start __P((struct tty *));static void si_lstart __P((struct si_port *));static void si_disc_optim __P((struct tty *tp, struct termios *t,					struct si_port *pp));static void sihardclose __P((struct si_port *pp));static void sidtrwakeup __P((void *chan));void	sistop	__P((struct tty *tp, int rw));void	siintr	__P((int unit));int	siparam __P((struct tty *, struct termios *));extern	void	si_registerdev __P((struct isa_device *id));extern	int	siprobe __P((struct isa_device *id));extern	int	siattach __P((struct isa_device *id));static	void	si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip));#ifdef SI_DEBUG		/* use: ``options "SI_DEBUG"'' in your config file *//* XXX: should be varargs, I know.. but where's vprintf()? */static	void	si_dprintf __P((/* struct si_port *pp, int flags, char *str, int a1, int a2, int a3, int a4, int a5, int a6 */));static	char	*si_mctl2str __P((enum si_mctl cmd));#define	DPRINT(x)	si_dprintf x#else#define	DPRINT(x)	/* void */#endifstatic int si_Nports;static int si_Nmodules;static int si_debug = 0;	/* data, not bss, so it's patchable */static struct tty *si_tty;/* where the firmware lives; defined in si_code.c */extern int si_dsize;extern unsigned char si_download[];struct si_softc {	int 		sc_type;	/* adapter type */	char 		*sc_typename;	/* adapter type string */	struct si_port	*sc_ports;	/* port structures for this card */	caddr_t		sc_paddr;	/* physical addr of iomem */	caddr_t		sc_maddr;	/* kvaddr of iomem */	int		sc_nport;	/* # ports on this card */	int		sc_irq;		/* copy of attach irq */	int		sc_eisa_iobase;	/* EISA io port address */	int		sc_eisa_irqbits;	struct kern_devconf sc_kdc;};struct si_softc si_softc[NSI];		/* up to 4 elements */#ifndef B2000	/* not standard, but the hardware knows it. */# define B2000 2000#endifstatic struct speedtab bdrates[] = {	B75,	CLK75,		/* 0x0 */	B110,	CLK110,		/* 0x1 */	B150,	CLK150,		/* 0x3 */	B300,	CLK300,		/* 0x4 */	B600,	CLK600,		/* 0x5 */	B1200,	CLK1200,	/* 0x6 */	B2000,	CLK2000,	/* 0x7 */	B2400,	CLK2400,	/* 0x8 */	B4800,	CLK4800,	/* 0x9 */	B9600,	CLK9600,	/* 0xb */	B19200,	CLK19200,	/* 0xc */	B38400, CLK38400,	/* 0x2 (out of order!) */	B57600, CLK57600,	/* 0xd */	B115200, CLK110,	/* 0x1 (dupe!, 110 baud on "si") */	-1,	-1};/* populated with approx character/sec rates - translated at card * initialisation time to chars per tick of the clock */static int done_chartimes = 0;static struct speedtab chartimes[] = {	B75,	8,	B110,	11,	B150,	15,	B300,	30,	B600,	60,	B1200,	120,	B2000,	200,	B2400,	240,	B4800,	480,	B9600,	960,	B19200,	1920,	B38400, 3840,	B57600, 5760,	B115200, 11520,	-1,	-1};static volatile int in_intr = 0;	/* Inside interrupt handler? */static int si_default_rate =	TTYDEF_SPEED;static int si_default_iflag =	0;static int si_default_oflag =	0;static int si_default_lflag =	0;#ifdef SI_DEF_HWFLOWstatic int si_default_cflag =	TTYDEF_CFLAG | CRTSCTS;#elsestatic int si_default_cflag =	TTYDEF_CFLAG;#endif#ifdef POLL#define	POLL_INTERVAL	(hz/2)static int init_finished = 0;static int fastpoll = 0;static void si_poll __P((void *));#endif/* * Array of adapter types and the corresponding RAM size. The order of * entries here MUST match the ordinal of the adapter type. */static char *si_type[] = {	"EMPTY",	"SIHOST",	"SI2",				/* MCA */	"SIHOST2",	"SIEISA",};static struct kern_devconf si_kdc[NSI] = { {	0, 0, 0,		/* filled in by dev_attach */	"si", 0, { MDDT_ISA, 0, "tty" },	isa_generic_externalize, 0, 0, ISA_EXTERNALLEN,	&kdc_isa0,		/* parent */	0,			/* parent data */	DC_UNCONFIGURED,	/* state */	"Specialix SI/XIO Host adapter",	DC_CLS_SERIAL,		/* class */} };voidsi_registerdev(id)	struct isa_device *id;{	if (id->id_unit != 0) {		si_kdc[id->id_unit] = si_kdc[0];	/* struct copy */	}	si_kdc[id->id_unit].kdc_unit = id->id_unit;	si_kdc[id->id_unit].kdc_isa = id;	si_kdc[id->id_unit].kdc_state = DC_UNCONFIGURED;	dev_attach(&si_kdc[id->id_unit]);}/* Look for a valid board at the given mem addr */intsiprobe(id)	struct isa_device *id;{	struct si_softc *sc;	int type;	u_int i, ramsize;	volatile BYTE was, *ux;	volatile unsigned char *maddr;	unsigned char *paddr;	si_registerdev(id);	maddr = id->id_maddr;		/* virtual address... */	paddr = (caddr_t)vtophys(id->id_maddr);	/* physical address... */	DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n",		id->id_unit, id->id_maddr, paddr));	/*	 * this is a lie, but it's easier than trying to handle caching	 * and ram conflicts in the >1M and <16M region.	 */	if ((caddr_t)paddr < (caddr_t)IOM_BEGIN ||	    (caddr_t)paddr >= (caddr_t)IOM_END) {		printf("si%d: iomem (%lx) out of range\n",			id->id_unit, (long)paddr);		return(0);	}	if (id->id_unit >= NSI) {		/* THIS IS IMPOSSIBLE */		return(0);	}	if (((u_int)paddr & 0x7fff) != 0) {		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,			"si%d: iomem (%x) not on 32k boundary\n",			id->id_unit, paddr));		return(0);	}	for (i=0; i < NSI; i++) {		if ((sc = &si_softc[i]) == NULL)			continue;		if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) {			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,				"si%d: iomem (%x) already configured to si%d\n",				id->id_unit, sc->sc_paddr, i));			return(0);		}	}#if NEISA > 0	if (id->id_iobase > 0x0fff) {	/* EISA card */		int irq, port;		unsigned long base;		int eisa_irqs[] = { 0,IRQ1,IRQ2,IRQ3,IRQ4,IRQ5,IRQ6,IRQ7,			IRQ8,IRQ9,IRQ10,IRQ11,IRQ12,IRQ13,IRQ14,IRQ15 };		port = id->id_iobase;		base = (inb(port+1) << 24) | (inb(port) << 16);		irq  = ((inb(port+2) >> 4) & 0xf);		id->id_irq = eisa_irqs[irq];		DPRINT((0, DBG_AUTOBOOT,		    "si%d: EISA base %x, irq %x, id_irq %x, port %x\n",		    id->id_unit, base, irq, id->id_irq, port));		if ((id->id_irq&(IRQ1|IRQ2|IRQ8|IRQ13)) != 0)			goto bad_irq;		id->id_iobase &= 0xf000;		id->id_iosize  = 0x0fff;		type = EISA;		outb(p+2, (BYTE)irq << 4);		sc->sc_eisa_iobase = p;		sc->sc_eisa_irqbits = irq << 4;		ramsize = SIEISA_RAMSIZE;		goto got_card;	}#endif	/* Is there anything out there? (0x17 is just an arbitrary number) */	*maddr = 0x17;	if (*maddr != 0x17) {		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,			"si%d: 0x17 check fail at phys 0x%x\n",			id->id_unit, paddr));fail:		return(0);	}	/*	 * OK, now to see if whatever responded is really an SI card.	 * Try for a MK II first (SIHOST2)	 */	for (i=SIPLSIG; i<SIPLSIG+8; i++)		if ((*(maddr+i) & 7) != (~(BYTE)i & 7))			goto try_mk1;	/* It must be an SIHOST2 */	*(maddr + SIPLRESET) = 0;	*(maddr + SIPLIRQCLR) = 0;	*(maddr + SIPLIRQSET) = 0x10;	type = SIHOST2;	ramsize = SIHOST2_RAMSIZE;	goto got_card;	/*	 * Its not a MK II, so try for a MK I (SIHOST)	 */try_mk1:	*(maddr+SIRESET) = 0x0;		/* reset the card */	*(maddr+SIINTCL) = 0x0;		/* clear int */	*(maddr+SIRAM) = 0x17;	if (*(maddr+SIRAM) != (BYTE)0x17)		goto fail;	*(maddr+0x7ff8) = 0x17;	if (*(maddr+0x7ff8) != (BYTE)0x17) {		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,			"si%d: 0x17 check fail at phys 0x%x = 0x%x\n",			id->id_unit, paddr+0x77f8, *(maddr+0x77f8)));		goto fail;	}	/* It must be an SIHOST (maybe?) - there must be a better way XXXX */	type = SIHOST;	ramsize = SIHOST_RAMSIZE;got_card:	DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n",		id->id_unit, type));	/* Try the acid test */	ux = (BYTE *)(maddr + SIRAM);	for (i=0; i<ramsize; i++, ux++)		*ux = (BYTE)(i&0xff);	ux = (BYTE *)(maddr + SIRAM);	for (i=0; i<ramsize; i++, ux++) {		if ((was = *ux) != (BYTE)(i&0xff)) {			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,				"si%d: match fail at phys 0x%x, was %x should be %x\n",				id->id_unit, paddr+i, was, i&0xff));			goto fail;		}	}	/* clear out the RAM */	ux = (BYTE *)(maddr + SIRAM);	for (i=0; i<ramsize; i++)		*ux++ = 0;	ux = (BYTE *)(maddr + SIRAM);	for (i=0; i<ramsize; i++) {		if ((was = *ux++) != 0) {			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,				"si%d: clear fail at phys 0x%x, was %x\n",				id->id_unit, paddr+i, was));			goto fail;		}	}	/*	 * Success, we've found a valid board, now fill in	 * the adapter structure.	 */	switch (type) {	case SIHOST2:		if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) {bad_irq:			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,				"si%d: bad IRQ value - %d\n",				id->id_unit, id->id_irq));			return(0);		}		id->id_msize = SIHOST2_MEMSIZE;		break;	case SIHOST:		if ((id->id_irq&(IRQ11|IRQ12|IRQ15)) == 0) {			goto bad_irq;		}		id->id_msize = SIHOST_MEMSIZE;		break;	case SIEISA:		id->id_msize = SIEISA_MEMSIZE;		break;	case SI2:		/* MCA */	default:		printf("si%d: %s not supported\n", id->id_unit, si_type[type]);		return(0);	}	si_softc[id->id_unit].sc_type = type;	si_softc[id->id_unit].sc_typename = si_type[type];	return(-1);	/* -1 == found */}/* * Attach the device.  Initialize the card. */intsiattach(id)	struct isa_device *id;{	int unit = id->id_unit;	struct si_softc *sc = &si_softc[unit];	struct si_port *pp;	volatile struct si_channel *ccbp;	volatile struct si_reg *regp;	volatile caddr_t maddr;	struct si_module *modp;	struct tty *tp;	struct speedtab *spt;	int nmodule, nport, x, y;	int uart_type;	DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit));	sc->sc_paddr = (caddr_t)vtophys(id->id_maddr);	sc->sc_maddr = id->id_maddr;	sc->sc_irq = id->id_irq;	sc->sc_ports = NULL;			/* mark as uninitialised */	maddr = sc->sc_maddr;	/*	 * OK, now lets download the firmware and try and boot the CPU..	 */	DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n",		id->id_unit, si_dsize));	bcopy(si_download, maddr, si_dsize);	switch (sc->sc_type) {	case SIEISA:#if NEISA > 0		/* modify the Z280 firmware to tell it that it's on an EISA */		*(maddr+0x42) = 1;		outb(sc->sc_eisa_iobase+2, sc->sc_eisa_irqbits | 4);		(void)inb(sc->sc_eisa_iobase+3); /* reset interrupt */		break;#endif	/* fall-through if not EISA */	case SI2:		/*		 * must get around to converting the code for		 * these one day, if FreeBSD ever supports it.		 */		return 0;	case SIHOST:		*(maddr+SIRESET_CL) = 0;		*(maddr+SIINTCL_CL) = 0;		break;	case SIHOST2:		*(maddr+SIPLRESET) = 0x10;		switch (sc->sc_irq) {		case IRQ11:			*(maddr+SIPLIRQ11) = 0x10;			break;		case IRQ12:			*(maddr+SIPLIRQ12) = 0x10;			break;		case IRQ15:			*(maddr+SIPLIRQ15) = 0x10;			break;		}		*(maddr+SIPLIRQCLR) = 0x10;		break;	}	DELAY(1000000);			/* wait around for a second */	regp = (struct si_reg *)maddr;	y = 0;					/* wait max of 5 sec for init OK */	while (regp->initstat == 0 && y++ < 10) {		DELAY(500000);	}	switch (regp->initstat) {	case 0:		printf("si%d: startup timeout - aborting\n", unit);		sc->sc_type = SIEMPTY;		return 0;	case 1:			/* set throttle to 125 intr per second */		regp->int_count = INT_COUNT;			/* rx intr max of 25 timer per second */		regp->rx_int_count = RXINT_COUNT;		regp->int_pending = 0;		/* no intr pending */		regp->int_scounter = 0;	/* reset counter */		break;	case 0xff:		/*		 * No modules found, so give up on this one.		 */		printf("si%d: %s - no ports found\n", unit,			si_type[sc->sc_type]);		return 0;	default:		printf("si%d: Z280 version error - initstat %x\n",			unit, regp->initstat);		return 0;	}	/*	 * First time around the ports just count them in order	 * to allocate some memory.	 */	nport = 0;	modp = (struct si_module *)(maddr + 0x80);	for (;;) {		DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp));		switch (modp->sm_type & (~MMASK)) {		case M232:		case M422:			DPRINT((0, DBG_DOWNLOAD,				"si%d: Found 232/422 module, %d ports\n",				unit, (int)(modp->sm_type & MMASK)));			/* this is a firmware issue */			if (si_Nports == SI_MAXPORTPERCARD) {				printf("si%d: extra ports ignored\n", unit);				continue;			}			x = modp->sm_type & MMASK;			nport += x;			si_Nports += x;			si_Nmodules++;			break;		default:			printf("si%d: unknown module type %d\n",				unit, modp->sm_type);			break;		}		if (modp->sm_next == 0)			break;		modp = (struct si_module *)			(maddr + (unsigned)(modp->sm_next & 0x7fff));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -