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

📄 aurora.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
/*	$Id: aurora.c,v 1.19 2002/01/08 16:00:16 davem Exp $ *	linux/drivers/sbus/char/aurora.c -- Aurora multiport driver * *	Copyright (c) 1999 by Oliver Aldulea (oli at bv dot ro) * *	This code is based on the RISCom/8 multiport serial driver written *	by Dmitry Gorodchanin (pgmdsg@ibi.com), based on the Linux serial *	driver, written by Linus Torvalds, Theodore T'so and others. *	The Aurora multiport programming info was obtained mainly from the *	Cirrus Logic CD180 documentation (available on the web), and by *	doing heavy tests on the board. Many thanks to Eddie C. Dost for the *	help on the sbus interface. * *	This program is free software; you can redistribute it and/or modify *	it under the terms of the GNU General Public License as published by *	the Free Software Foundation; either version 2 of the License, or *	(at your option) any later version. * *	This program is distributed in the hope that it will be useful, *	but WITHOUT ANY WARRANTY; without even the implied warranty of *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *	GNU General Public License for more details. * *	You should have received a copy of the GNU General Public License *	along with this program; if not, write to the Free Software *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *	Revision 1.0 * *	This is the first public release. * *	Most of the information you need is in the aurora.h file. Please *	read that file before reading this one. * *	Several parts of the code do not have comments yet. *  * n.b.  The board can support 115.2 bit rates, but only on a few * ports. The total badwidth of one chip (ports 0-7 or 8-15) is equal * to OSC_FREQ div 16. In case of my board, each chip can take 6 * channels of 115.2 kbaud.  This information is not well-tested. *  * Fixed to use tty_get_baud_rate(). *   Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12 */#include <linux/module.h>#include <linux/errno.h>#include <linux/sched.h>#ifdef AURORA_INT_DEBUG#include <linux/timer.h>#endif#include <linux/interrupt.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/major.h>#include <linux/string.h>#include <linux/fcntl.h>#include <linux/mm.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/bitops.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/oplib.h>#include <asm/system.h>#include <asm/kdebug.h>#include <asm/sbus.h>#include <asm/uaccess.h>#include "aurora.h"#include "cd180.h"unsigned char irqs[4] = {	0, 0, 0, 0};#ifdef AURORA_INT_DEBUGint irqhit=0;#endifstatic struct tty_driver *aurora_driver;static struct Aurora_board aurora_board[AURORA_NBOARD] = {	{0,},};static struct Aurora_port aurora_port[AURORA_TNPORTS] =  {	{ 0, },};/* no longer used. static struct Aurora_board * IRQ_to_board[16] = { NULL, } ;*/static unsigned char * tmp_buf = NULL;static DECLARE_MUTEX(tmp_buf_sem);DECLARE_TASK_QUEUE(tq_aurora);static inline int aurora_paranoia_check(struct Aurora_port const * port,				    char *name, const char *routine){#ifdef AURORA_PARANOIA_CHECK	static const char *badmagic =		KERN_DEBUG "aurora: Warning: bad aurora port magic number for device %s in %s\n";	static const char *badinfo =		KERN_DEBUG "aurora: Warning: null aurora port for device %s in %s\n";	if (!port) {		printk(badinfo, name, routine);		return 1;	}	if (port->magic != AURORA_MAGIC) {		printk(badmagic, name, routine);		return 1;	}#endif	return 0;}/* *  *  Service functions for aurora driver. *  *//* Get board number from pointer */static inline int board_No (struct Aurora_board const * bp){	return bp - aurora_board;}/* Get port number from pointer */static inline int port_No (struct Aurora_port const * port){	return AURORA_PORT(port - aurora_port); }/* Get pointer to board from pointer to port */static inline struct Aurora_board * port_Board(struct Aurora_port const * port){	return &aurora_board[AURORA_BOARD(port - aurora_port)];}/* Wait for Channel Command Register ready */static inline void aurora_wait_CCR(struct aurora_reg128 * r){	unsigned long delay;#ifdef AURORA_DEBUGprintk("aurora_wait_CCR\n");#endif	/* FIXME: need something more descriptive than 100000 :) */	for (delay = 100000; delay; delay--) 		if (!sbus_readb(&r->r[CD180_CCR]))			return;	printk(KERN_DEBUG "aurora: Timeout waiting for CCR.\n");}/* *  aurora probe functions. *//* Must be called with enabled interrupts */static inline void aurora_long_delay(unsigned long delay){	unsigned long i;#ifdef AURORA_DEBUG	printk("aurora_long_delay: start\n");#endif	for (i = jiffies + delay; time_before(jiffies, i); ) ;#ifdef AURORA_DEBUG	printk("aurora_long_delay: end\n");#endif}/* Reset and setup CD180 chip */static int aurora_init_CD180(struct Aurora_board * bp, int chip){	unsigned long flags;	int id;	#ifdef AURORA_DEBUG	printk("aurora_init_CD180: start %d:%d\n",	       board_No(bp), chip);#endif	save_flags(flags); cli();	sbus_writeb(0, &bp->r[chip]->r[CD180_CAR]);	sbus_writeb(0, &bp->r[chip]->r[CD180_GSVR]);	/* Wait for CCR ready        */	aurora_wait_CCR(bp->r[chip]);	/* Reset CD180 chip          */	sbus_writeb(CCR_HARDRESET, &bp->r[chip]->r[CD180_CCR]);	udelay(1);	sti();	id=1000;	while((--id) &&	      (sbus_readb(&bp->r[chip]->r[CD180_GSVR])!=0xff))udelay(100);	if(!id) {		printk(KERN_ERR "aurora%d: Chip %d failed init.\n",		       board_No(bp), chip);		restore_flags(flags);		return(-1);	}	cli();	sbus_writeb((board_No(bp)<<5)|((chip+1)<<3),		    &bp->r[chip]->r[CD180_GSVR]); /* Set ID for this chip      */	sbus_writeb(0x80|bp->ACK_MINT,		    &bp->r[chip]->r[CD180_MSMR]); /* Prio for modem intr       */	sbus_writeb(0x80|bp->ACK_TINT,		    &bp->r[chip]->r[CD180_TSMR]); /* Prio for transmitter intr */	sbus_writeb(0x80|bp->ACK_RINT,		    &bp->r[chip]->r[CD180_RSMR]); /* Prio for receiver intr    */	/* Setting up prescaler. We need 4 tick per 1 ms */	sbus_writeb((bp->oscfreq/(1000000/AURORA_TPS)) >> 8,		    &bp->r[chip]->r[CD180_PPRH]);	sbus_writeb((bp->oscfreq/(1000000/AURORA_TPS)) & 0xff,		    &bp->r[chip]->r[CD180_PPRL]);	sbus_writeb(SRCR_AUTOPRI|SRCR_GLOBPRI,		    &bp->r[chip]->r[CD180_SRCR]);	id = sbus_readb(&bp->r[chip]->r[CD180_GFRCR]);	printk(KERN_INFO "aurora%d: Chip %d id %02x: ",	       board_No(bp), chip,id);	if(sbus_readb(&bp->r[chip]->r[CD180_SRCR]) & 128) {		switch (id) {			case 0x82:printk("CL-CD1864 rev A\n");break;			case 0x83:printk("CL-CD1865 rev A\n");break;			case 0x84:printk("CL-CD1865 rev B\n");break;			case 0x85:printk("CL-CD1865 rev C\n");break;			default:printk("Unknown.\n");		};	} else {		switch (id) {			case 0x81:printk("CL-CD180 rev B\n");break;			case 0x82:printk("CL-CD180 rev C\n");break;			default:printk("Unknown.\n");		};	}	restore_flags(flags);#ifdef AURORA_DEBUG	printk("aurora_init_CD180: end\n");#endif	return 0;}static int valid_irq(unsigned char irq){int i;for(i=0;i<TYPE_1_IRQS;i++)	if (type_1_irq[i]==irq) return 1;return 0;}static irqreturn_t aurora_interrupt(int irq, void * dev_id, struct pt_regs * regs);/* Main probing routine, also sets irq. */static int aurora_probe(void){	struct sbus_bus *sbus;	struct sbus_dev *sdev;	int grrr;	char buf[30];	int bn = 0;	struct Aurora_board *bp;	for_each_sbus(sbus) {		for_each_sbusdev(sdev, sbus) {/*			printk("Try: %x %s\n",sdev,sdev->prom_name);*/			if (!strcmp(sdev->prom_name, "sio16")) {#ifdef AURORA_DEBUG				printk(KERN_INFO "aurora: sio16 at %p\n",sdev);#endif				if((sdev->reg_addrs[0].reg_size!=1) &&				   (sdev->reg_addrs[1].reg_size!=128) &&				   (sdev->reg_addrs[2].reg_size!=128) &&				   (sdev->reg_addrs[3].reg_size!=4)) {				   	printk(KERN_ERR "aurora%d: registers' sizes "					       "do not match.\n", bn);				   	break;				}				bp = &aurora_board[bn];				bp->r0 = (struct aurora_reg1 *)					sbus_ioremap(&sdev->resource[0], 0,						     sdev->reg_addrs[0].reg_size,						     "sio16");				if (bp->r0 == NULL) {					printk(KERN_ERR "aurora%d: can't map "					       "reg_addrs[0]\n", bn);					break;				}#ifdef AURORA_DEBUG				printk("Map reg 0: %p\n", bp->r0);#endif				bp->r[0] = (struct aurora_reg128 *)					sbus_ioremap(&sdev->resource[1], 0,						     sdev->reg_addrs[1].reg_size,						     "sio16");				if (bp->r[0] == NULL) {					printk(KERN_ERR "aurora%d: can't map "					       "reg_addrs[1]\n", bn);					break;				}#ifdef AURORA_DEBUG				printk("Map reg 1: %p\n", bp->r[0]);#endif				bp->r[1] = (struct aurora_reg128 *)					sbus_ioremap(&sdev->resource[2], 0,						     sdev->reg_addrs[2].reg_size,						     "sio16");				if (bp->r[1] == NULL) {					printk(KERN_ERR "aurora%d: can't map "					       "reg_addrs[2]\n", bn);					break;				}#ifdef AURORA_DEBUG				printk("Map reg 2: %p\n", bp->r[1]);#endif				bp->r3 = (struct aurora_reg4 *)					sbus_ioremap(&sdev->resource[3], 0,						     sdev->reg_addrs[3].reg_size,						     "sio16");				if (bp->r3 == NULL) {					printk(KERN_ERR "aurora%d: can't map "					       "reg_addrs[3]\n", bn);					break;				}#ifdef AURORA_DEBUG				printk("Map reg 3: %p\n", bp->r3);#endif				/* Variables setup */				bp->flags = 0;#ifdef AURORA_DEBUG				grrr=prom_getint(sdev->prom_node,"intr");				printk("intr pri %d\n", grrr);#endif				if ((bp->irq=irqs[bn]) && valid_irq(bp->irq) &&				    !request_irq(bp->irq|0x30, aurora_interrupt, SA_SHIRQ, "sio16", bp)) {					free_irq(bp->irq|0x30, bp);				} else				if ((bp->irq=prom_getint(sdev->prom_node, "bintr")) && valid_irq(bp->irq) &&				    !request_irq(bp->irq|0x30, aurora_interrupt, SA_SHIRQ, "sio16", bp)) {					free_irq(bp->irq|0x30, bp);				} else				if ((bp->irq=prom_getint(sdev->prom_node, "intr")) && valid_irq(bp->irq) &&				    !request_irq(bp->irq|0x30, aurora_interrupt, SA_SHIRQ, "sio16", bp)) {					free_irq(bp->irq|0x30, bp);				} else				for(grrr=0;grrr<TYPE_1_IRQS;grrr++) {					if ((bp->irq=type_1_irq[grrr])&&!request_irq(bp->irq|0x30, aurora_interrupt, SA_SHIRQ, "sio16", bp)) {						free_irq(bp->irq|0x30, bp);						break;					} else {					printk(KERN_ERR "aurora%d: Could not get an irq for this board !!!\n",bn);					bp->flags=0xff;					}				}				if(bp->flags==0xff)break;				printk(KERN_INFO "aurora%d: irq %d\n",bn,bp->irq&0x0f);				buf[0]=0;				grrr=prom_getproperty(sdev->prom_node,"dtr_rts",buf,sizeof(buf));				if(!strcmp(buf,"swapped")){					printk(KERN_INFO "aurora%d: Swapped DTR and RTS\n",bn);					bp->DTR=MSVR_RTS;					bp->RTS=MSVR_DTR;					bp->MSVDTR=CD180_MSVRTS;					bp->MSVRTS=CD180_MSVDTR;					bp->flags|=AURORA_BOARD_DTR_FLOW_OK;					}else{					#ifdef AURORA_FORCE_DTR_FLOW					printk(KERN_INFO "aurora%d: Forcing swapped DTR-RTS\n",bn);					bp->DTR=MSVR_RTS;					bp->RTS=MSVR_DTR;					bp->MSVDTR=CD180_MSVRTS;					bp->MSVRTS=CD180_MSVDTR;					bp->flags|=AURORA_BOARD_DTR_FLOW_OK;					#else					printk(KERN_INFO "aurora%d: Normal DTR and RTS\n",bn);					bp->DTR=MSVR_DTR;					bp->RTS=MSVR_RTS;					bp->MSVDTR=CD180_MSVDTR;					bp->MSVRTS=CD180_MSVRTS;					#endif				}				bp->oscfreq=prom_getint(sdev->prom_node,"clk")*100;				printk(KERN_INFO "aurora%d: Oscillator: %d Hz\n",bn,bp->oscfreq);				grrr=prom_getproperty(sdev->prom_node,"chip",buf,sizeof(buf));				printk(KERN_INFO "aurora%d: Chips: %s\n",bn,buf);				grrr=prom_getproperty(sdev->prom_node,"manu",buf,sizeof(buf));				printk(KERN_INFO "aurora%d: Manufacturer: %s\n",bn,buf);				grrr=prom_getproperty(sdev->prom_node,"model",buf,sizeof(buf));				printk(KERN_INFO "aurora%d: Model: %s\n",bn,buf);				grrr=prom_getproperty(sdev->prom_node,"rev",buf,sizeof(buf));				printk(KERN_INFO "aurora%d: Revision: %s\n",bn,buf);				grrr=prom_getproperty(sdev->prom_node,"mode",buf,sizeof(buf));				printk(KERN_INFO "aurora%d: Mode: %s\n",bn,buf);				#ifdef MODULE				bp->count=0;				#endif				bp->flags = AURORA_BOARD_PRESENT;				/* hardware ack */				bp->ACK_MINT=1;				bp->ACK_TINT=2;				bp->ACK_RINT=3;				bn++;			}		}	}	return bn;}static void aurora_release_io_range(struct Aurora_board *bp){	sbus_iounmap((unsigned long)bp->r0, 1);	sbus_iounmap((unsigned long)bp->r[0], 128);	sbus_iounmap((unsigned long)bp->r[1], 128);	sbus_iounmap((unsigned long)bp->r3, 4);}static inline void aurora_mark_event(struct Aurora_port * port, int event){#ifdef AURORA_DEBUG	printk("aurora_mark_event: start\n");#endif	set_bit(event, &port->event);	queue_task(&port->tqueue, &tq_aurora);	mark_bh(AURORA_BH);#ifdef AURORA_DEBUG	printk("aurora_mark_event: end\n");#endif}static __inline__ struct Aurora_port * aurora_get_port(struct Aurora_board const * bp,						       int chip,						       unsigned char const *what){	unsigned char channel;	struct Aurora_port * port;	channel = ((chip << 3) |		   ((sbus_readb(&bp->r[chip]->r[CD180_GSCR]) & GSCR_CHAN) >> GSCR_CHAN_OFF));	port = &aurora_port[board_No(bp) * AURORA_NPORT * AURORA_NCD180 + channel];	if (port->flags & ASYNC_INITIALIZED)		return port;	printk(KERN_DEBUG "aurora%d: %s interrupt from invalid port %d\n",	       board_No(bp), what, channel);	return NULL;}static void aurora_receive_exc(struct Aurora_board const * bp, int chip){	struct Aurora_port *port;	struct tty_struct *tty;	unsigned char status;	unsigned char ch;		if (!(port = aurora_get_port(bp, chip, "Receive_x")))		return;	tty = port->tty;	if (tty->flip.count >= TTY_FLIPBUF_SIZE)  {#ifdef AURORA_INTNORM		printk("aurora%d: port %d: Working around flip buffer overflow.\n",		       board_No(bp), port_No(port));#endif		return;	}	#ifdef AURORA_REPORT_OVERRUN		status = sbus_readb(&bp->r[chip]->r[CD180_RCSR]);	if (status & RCSR_OE)  {		port->overrun++;#if 1		printk("aurora%d: port %d: Overrun. Total %ld overruns.\n",		       board_No(bp), port_No(port), port->overrun);#endif			}	status &= port->mark_mask;#else		status = sbus_readb(&bp->r[chip]->r[CD180_RCSR]) & port->mark_mask;#endif		ch = sbus_readb(&bp->r[chip]->r[CD180_RDR]);	if (!status)		return;	if (status & RCSR_TOUT)  {/*		printk("aurora%d: port %d: Receiver timeout. Hardware problems ?\n",		       board_No(bp), port_No(port));*/		return;			} else if (status & RCSR_BREAK)  {		printk(KERN_DEBUG "aurora%d: port %d: Handling break...\n",		       board_No(bp), port_No(port));		*tty->flip.flag_buf_ptr++ = TTY_BREAK;		if (port->flags & ASYNC_SAK)			do_SAK(tty);			} else if (status & RCSR_PE) 		*tty->flip.flag_buf_ptr++ = TTY_PARITY;		else if (status & RCSR_FE) 		*tty->flip.flag_buf_ptr++ = TTY_FRAME;	        else if (status & RCSR_OE)		*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;		else		*tty->flip.flag_buf_ptr++ = 0;		*tty->flip.char_buf_ptr++ = ch;	tty->flip.count++;	queue_task(&tty->flip.tqueue, &tq_timer);}static void aurora_receive(struct Aurora_board const * bp, int chip){	struct Aurora_port *port;	struct tty_struct *tty;	unsigned char count,cnt;	if (!(port = aurora_get_port(bp, chip, "Receive")))		return;		tty = port->tty;		count = sbus_readb(&bp->r[chip]->r[CD180_RDCR]);#ifdef AURORA_REPORT_FIFO	port->hits[count > 8 ? 9 : count]++;#endif	while (count--)  {		if (tty->flip.count >= TTY_FLIPBUF_SIZE)  {#ifdef AURORA_INTNORM			printk("aurora%d: port %d: Working around flip buffer overflow.\n",			       board_No(bp), port_No(port));#endif			break;		}		cnt = sbus_readb(&bp->r[chip]->r[CD180_RDR]);		*tty->flip.char_buf_ptr++ = cnt;		*tty->flip.flag_buf_ptr++ = 0;		tty->flip.count++;	}	queue_task(&tty->flip.tqueue, &tq_timer);}static void aurora_transmit(struct Aurora_board const * bp, int chip){	struct Aurora_port *port;	struct tty_struct *tty;	unsigned char count;		if (!(port = aurora_get_port(bp, chip, "Transmit")))		return;			tty = port->tty;		if (port->SRER & SRER_TXEMPTY)  {		/* FIFO drained */		sbus_writeb(port_No(port) & 7,			    &bp->r[chip]->r[CD180_CAR]);		udelay(1);		port->SRER &= ~SRER_TXEMPTY;		sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);		return;	}		if ((port->xmit_cnt <= 0 && !port->break_length)	    || tty->stopped || tty->hw_stopped)  {		sbus_writeb(port_No(port) & 7,			    &bp->r[chip]->r[CD180_CAR]);		udelay(1);		port->SRER &= ~SRER_TXRDY;		sbus_writeb(port->SRER,			    &bp->r[chip]->r[CD180_SRER]);		return;	}		if (port->break_length)  {		if (port->break_length > 0)  {			if (port->COR2 & COR2_ETC)  {				sbus_writeb(CD180_C_ESC,					    &bp->r[chip]->r[CD180_TDR]);				sbus_writeb(CD180_C_SBRK,					    &bp->r[chip]->r[CD180_TDR]);				port->COR2 &= ~COR2_ETC;			}

⌨️ 快捷键说明

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