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

📄 si.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Device driver for Specialix range (SI/XIO) of serial line multiplexors. * * Copyright (C) 1990, 1992, 1998 Specialix International, * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk> * Copyright (C) 1995, Peter Wemm <peter@netplex.com.au> * * 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.78 1999/01/12 00:36:35 eivind Exp $ */#ifndef lintstatic const char si_copyright1[] =  "@(#) Copyright (C) Specialix International, 1990,1992,1998",		  si_copyright2[] =  "@(#) Copyright (C) Andy Rutter 1993",		  si_copyright3[] =  "@(#) Copyright (C) Peter Wemm 1995";#endif	/* not lint */#include "opt_compat.h"#include "opt_debug_si.h"#include "opt_devfs.h"#include <sys/param.h>#include <sys/systm.h>#if defined(COMPAT_43) || defined(COMPAT_SUNOS)#include <sys/ioctl_compat.h>#endif#include <sys/tty.h>#include <sys/proc.h>#include <sys/conf.h>#include <sys/fcntl.h>#include <sys/dkstat.h>#include <sys/kernel.h>#include <sys/malloc.h>#include <sys/sysctl.h>#ifdef DEVFS#include <sys/devfsext.h>#endif /*DEVFS*/#include <machine/clock.h>#include <vm/vm.h>#include <vm/pmap.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 <machine/stdarg.h>#include "pci.h"#if NPCI > 0#include <pci/pcivar.h>#endif#include "eisa.h"#if NEISA > 0#include <i386/eisa/eisaconf.h>#include <i386/isa/icu.h>#endif#include "si.h"/* * This device driver is designed to interface the Specialix International * SI, XIO and SX range of serial multiplexor cards to FreeBSD on an ISA, * EISA or PCI bus machine. * * The controller is interfaced to the host via dual port RAM * and an interrupt. * * The code for the Host 1 (very old ISA cards) has not been tested. */#define	POLL		/* turn on poller to scan for lost interrupts */#define REALPOLL	/* on each poll, scan for work regardless */#define POLLHZ	(hz/10)	/* 10 times per second */#define SI_I_HIGH_WATER	(TTYHOG - 2 * SI_BUFFERSIZE)#define INT_COUNT 25000		/* max of 125 ints per second */#define JET_INT_COUNT 100	/* max of 100 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, u_long, caddr_t, int, struct proc *));static void si_start __P((struct tty *));static timeout_t si_lstart;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));static int	siparam __P((struct tty *, struct termios *));static	int	siprobe __P((struct isa_device *id));static	int	siattach __P((struct isa_device *id));static	void	si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip));static void	si_intr __P((int unit));static char *	si_modulename __P((int host_type, int uart_type));struct isa_driver sidriver =	{ siprobe, siattach, "si" };static u_long sipcieisacount = 0;#if NPCI > 0static const char *sipciprobe __P((pcici_t, pcidi_t));static void sipciattach __P((pcici_t, int));static struct pci_device sipcidev = {	"si",	sipciprobe,	sipciattach,	&sipcieisacount,	NULL,};DATA_SET (pcidevice_set, sipcidev);#endif#if NEISA > 0static int si_eisa_probe __P((void));static int si_eisa_attach __P((struct eisa_device *ed));static struct eisa_driver si_eisa_driver = {	"si",	si_eisa_probe,	si_eisa_attach,	NULL,	&sipcieisacount,};DATA_SET(eisadriver_set, si_eisa_driver);#endifstatic	d_open_t	siopen;static	d_close_t	siclose;static	d_read_t	siread;static	d_write_t	siwrite;static	d_ioctl_t	siioctl;static	d_stop_t	sistop;static	d_devtotty_t	sidevtotty;#define	CDEV_MAJOR	68static	struct cdevsw	si_cdevsw = {	siopen,		siclose,	siread,		siwrite,	siioctl,	sistop,		noreset,	sidevtotty,	ttpoll,		nommap,		NULL,		"si",	NULL,		-1,		nodump,		nopsize,	D_TTY,};#ifdef SI_DEBUG		/* use: ``options "SI_DEBUG"'' in your config file */static	void	si_dprintf __P((struct si_port *pp, int flags, const char *fmt,				...));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 */SYSCTL_INT(_machdep, OID_AUTO, si_debug, CTLFLAG_RW, &si_debug, 0, "");static struct tty *si_tty;/* where the firmware lives; defined in si2_z280.c and si3_t225.c *//* old: si2_z280.c */extern unsigned char si2_z280_download[];extern unsigned short si2_z280_downloadaddr;extern int si2_z280_dsize;/* new: si3_t225.c */extern unsigned char si3_t225_download[];extern unsigned short si3_t225_downloadaddr;extern int si3_t225_dsize;extern unsigned char si3_t225_bootstrap[];extern unsigned short si3_t225_bootloadaddr;extern int si3_t225_bsize;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 */#if NEISA > 0	int		sc_eisa_iobase;	/* EISA io port address */	int		sc_eisa_irq;	/* EISA irq number */#endif#ifdef	DEVFS	struct {		void	*ttya;		void	*cuaa;		void	*ttyl;		void	*cual;		void	*ttyi;		void	*cuai;	} devfs_token[32]; /* what is the max per card? */	void	*control_token;#endif};static 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? */#ifdef POLLstatic int si_pollrate;			/* in addition to irq */static int si_realpoll;			/* poll HW on timer */SYSCTL_INT(_machdep, OID_AUTO, si_pollrate, CTLFLAG_RW, &si_pollrate, 0, "");SYSCTL_INT(_machdep, OID_AUTO, si_realpoll, CTLFLAG_RW, &si_realpoll, 0, "");		 static int init_finished = 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",	"SIMCA",		/* FreeBSD does not support Microchannel */	"SIHOST2",	"SIEISA",	"SIPCI",	"SXPCI",	"SXISA",};#if NPCI > 0static const char *sipciprobe(configid, deviceid)pcici_t configid;pcidi_t deviceid;{	switch (deviceid)	{		case 0x400011cb:			return("Specialix SI/XIO PCI host card");			break;		case 0x200011cb:			if (pci_conf_read(configid, SIJETSSIDREG) == 0x020011cb)				return("Specialix SX PCI host card");			else				return NULL;			break;		default:			return NULL;	}	/*NOTREACHED*/}voidsipciattach(configid, unit)pcici_t configid;int unit;{	struct isa_device id;	vm_offset_t vaddr,paddr;	u_long mapval = 0;	/* shut up gcc, should not be needed */	switch ( pci_conf_read(configid, 0) >> 16 )	{		case 0x4000:			si_softc[unit].sc_type = SIPCI;			mapval = SIPCIBADR;			break;		case 0x2000:			si_softc[unit].sc_type = SIJETPCI;			mapval = SIJETBADR;			break;	}	if (!pci_map_mem(configid, mapval, &vaddr, &paddr))	{		printf("si%d: couldn't map memory\n", unit);	}	/*	 * We're cheating here a little bit. The argument to an ISA	 * interrupt routine is the unit number. The argument to a	 * PCI interrupt handler is a void *, but we're simply going	 * to be lazy and hand it the unit number.	 */	if (!pci_map_int(configid, (pci_inthand_t *) si_intr, (void *)unit, &tty_imask)) {		printf("si%d: couldn't map interrupt\n", unit);	}	si_softc[unit].sc_typename = si_type[si_softc[unit].sc_type];	/*	 * More cheating: We're going to dummy up a struct isa_device	 * and call the other attach routine. We don't really have to	 * fill in very much of the structure, since we filled in a	 * little of the soft state already.	 */	id.id_unit = unit;	id.id_maddr = (caddr_t) vaddr;	siattach(&id);}#endif#if NEISA > 0static const char *si_eisa_match __P((eisa_id_t id));static const char *si_eisa_match(id)	eisa_id_t id;{	if (id == SIEISADEVID)		return ("Specialix SI/XIO EISA host card");	return (NULL);}static intsi_eisa_probe(void){	struct eisa_device *ed = NULL;	int count, irq;	for (count=0; (ed = eisa_match_dev(ed, si_eisa_match)) != NULL; count++)	{		u_long port,maddr;		port = (ed->ioconf.slot * EISA_SLOT_SIZE) + SIEISABASE;		eisa_add_iospace(ed, port, SIEISAIOSIZE, RESVADDR_NONE);		maddr = (inb(port+1) << 24) | (inb(port) << 16);		irq  = ((inb(port+2) >> 4) & 0xf);		eisa_add_mspace(ed, maddr, SIEISA_MEMSIZE, RESVADDR_NONE);		eisa_add_intr(ed, irq);		eisa_registerdev(ed, &si_eisa_driver);		count++;	}	return count;}static intsi_eisa_attach(ed)	struct eisa_device *ed;{	struct isa_device id;	resvaddr_t *maddr,*iospace;	u_int irq;	struct si_softc *sc;	sc = &si_softc[ed->unit];	sc->sc_type = SIEISA;	sc->sc_typename = si_type[sc->sc_type];	if ((iospace = ed->ioconf.ioaddrs.lh_first) == NULL) {		printf("si%lu: no iospace??\n", ed->unit);		return -1;	}	sc->sc_eisa_iobase = iospace->addr;	irq  = ((inb(iospace->addr + 2) >> 4) & 0xf);	sc->sc_eisa_irq = irq;	if ((maddr = ed->ioconf.maddrs.lh_first) == NULL) {		printf("si%lu: where am I??\n", ed->unit);		return -1;	}	eisa_reg_start(ed);	if (eisa_reg_iospace(ed, iospace)) {		printf("si%lu: failed to register iospace %p\n",			ed->unit, (void *)iospace);		return -1;	}	if (eisa_reg_mspace(ed, maddr)) {		printf("si%lu: failed to register memspace %p\n",			ed->unit, (void *)maddr);		return -1;	}	/*	 * We're cheating here a little bit. The argument to an ISA	 * interrupt routine is the unit number. The argument to a	 * EISA interrupt handler is a void *, but we're simply going	 * to be lazy and hand it the unit number.	 */	if (eisa_reg_intr(ed, irq, (void (*)(void *)) si_intr,		(void *)(intptr_t)(ed->unit), &tty_imask, 1)) {		printf("si%lu: failed to register interrupt %d\n",			ed->unit, irq);		return -1;	}	eisa_reg_end(ed);	if (eisa_enable_intr(ed, irq)) {		return -1;	}	/*	 * More cheating: We're going to dummy up a struct isa_device	 * and call the other attach routine. We don't really have to	 * fill in very much of the structure, since we filled in a	 * little of the soft state already.	 */	id.id_unit = ed->unit;	id.id_maddr = (caddr_t) pmap_mapdev(maddr->addr, SIEISA_MEMSIZE);	return (siattach(&id));}#endif/* Look for a valid board at the given mem addr */static 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_pollrate = POLLHZ;		/* default 10 per second */#ifdef REALPOLL	si_realpoll = 1;		/* scan always */#endif	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 (%p) out of range\n",			id->id_unit, (void *)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);	}	if (si_softc[id->id_unit].sc_typename) {		/* EISA or PCI has taken this unit, choose another */		for (i=0; i < NSI; i++) {			if (si_softc[i].sc_typename == NULL) {				id->id_unit = i;				break;			}		}		if (i >= NSI) {			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,				"si%d: cannot realloc unit\n", id->id_unit));			return (0);		}

⌨️ 快捷键说明

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