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

📄 pcxx.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
		bd = &boards[crd];		outb(FEPRST, bd->port);		pcxxdelay(1);		for(i=0; (inb(bd->port) & FEPMASK) != FEPRST; i++) {			if(i > 100) {				printk("PC/Xx: Board not found at port 0x%x! Check switch settings.\n",					bd->port);				bd->status = DISABLED;				break;			}#ifdef MODULE			schedule();#endif			pcxxdelay(10);		}		if(bd->status == DISABLED)			continue;		v = inb(bd->port);		if((v & 0x1) == 0x1) {			if((v & 0x30) == 0) {        /* PC/Xi 64K card */				memory_seg = 0xf000;				memory_size = 0x10000;			} 			if((v & 0x30) == 0x10) {     /* PC/Xi 128K card */				memory_seg = 0xe000;				memory_size = 0x20000;			}						if((v & 0x30) == 0x20) {     /* PC/Xi 256K card */				memory_seg = 0xc000;				memory_size = 0x40000;			}			if((v & 0x30) == 0x30) {     /* PC/Xi 512K card */				memory_seg = 0x8000;				memory_size = 0x80000;			}			bd->type = PCXI;		} else {			if((v & 0x1) == 0x1) {				bd->status = DISABLED;   /* PC/Xm unsupported card */				printk("PC/Xx: PC/Xm at 0x%x not supported!!\n", bd->port);				continue;			} else {				if(v & 0xC0) {    					topwin = 0x1f00L;					outb((((ulong)bd->membase>>8) & 0xe0) | 0x10, bd->port+2);					outb(((ulong)bd->membase>>16) & 0xff, bd->port+3);					bd->type = PCXEVE; /* PC/Xe 8K card */				} else { 					bd->type = PCXE;    /* PC/Xe 64K card */				}									memory_seg = 0xf000;				memory_size = 0x10000;			}		}		if (verbose)			printk("Configuring card %d as a %s %ldK card. io=0x%x, mem=%lx-%lx\n",				crd+1, board_desc[bd->type], memory_size/1024,				bd->port,bd->membase,bd->membase+memory_size-1);		if (boards[crd].memsize == 0)			boards[crd].memsize = memory_size;		else			if (boards[crd].memsize != memory_size) {			    printk("PC/Xx: memory size mismatch:supplied=%lx(%ldK) probed=%ld(%ldK)\n",				    boards[crd].memsize, boards[crd].memsize / 1024,				    memory_size, memory_size / 1024);			    continue;			}		memaddr = (unchar *)phys_to_virt(bd->membase);		if (verbose)			printk("Resetting board and testing memory access:");		outb(FEPRST|FEPMEM, bd->port);		for(i=0; (inb(bd->port) & FEPMASK) != (FEPRST|FEPMEM); i++) {			if(i > 1000) {				printk("\nPC/Xx: %s not resetting at port 0x%x! Check switch settings.\n",					board_desc[bd->type], bd->port);				bd->status = DISABLED;				break;			}#ifdef MODULE			schedule();#endif			pcxxdelay(1);		}		if(bd->status == DISABLED)			continue;		memwinon(bd,0);		*(ulong *)(memaddr + botwin) = 0xa55a3cc3;		*(ulong *)(memaddr + topwin) = 0x5aa5c33c;		if(*(ulong *)(memaddr + botwin) != 0xa55a3cc3 ||					*(ulong *)(memaddr + topwin) != 0x5aa5c33c) {			printk("PC/Xx: Failed memory test at %lx for %s at port %x, check switch settings.\n",				bd->membase, board_desc[bd->type], bd->port);			bd->status = DISABLED;			continue;		}		if (verbose)			printk(" done.\n");		for(i=0; i < 16; i++) {			memaddr[MISCGLOBAL+i] = 0;		}		if(bd->type == PCXI || bd->type == PCXE) {			bios = memaddr + BIOSCODE + ((0xf000 - memory_seg) << 4);			if (verbose)				printk("Downloading BIOS to 0x%lx:", virt_to_phys(bios));			memcpy(bios, pcxx_bios, pcxx_nbios);			if (verbose)				printk(" done.\n");			outb(FEPMEM, bd->port);			if (verbose)				printk("Waiting for BIOS to become ready");			for(i=1; i <= 30; i++) {				if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {					goto load_fep;				}				if (verbose) {					printk(".");					if (i % 50 == 0)						printk("\n");				}#ifdef MODULE				schedule();#endif				pcxxdelay(50);			}			printk("\nPC/Xx: BIOS download failed for board at 0x%x(addr=%lx-%lx)!\n",							bd->port, bd->membase, bd->membase+bd->memsize);			bd->status = DISABLED;			continue;		}		if(bd->type == PCXEVE) {			bios = memaddr + (BIOSCODE & 0x1fff);			memwinon(bd,0xff);						memcpy(bios, pcxx_bios, pcxx_nbios);			outb(FEPCLR, bd->port);			memwinon(bd,0);			for(i=0; i <= 1000; i++) {				if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {					goto load_fep;				}				if (verbose) {					printk(".");					if (i % 50 == 0)						printk("\n");				}#ifdef MODULE				schedule();#endif				pcxxdelay(10);			}			printk("\nPC/Xx: BIOS download failed on the %s at 0x%x!\n",				board_desc[bd->type], bd->port);			bd->status = DISABLED;			continue;		}load_fep:		fepos = memaddr + FEPCODE;		if(bd->type == PCXEVE)			fepos = memaddr + (FEPCODE & 0x1fff);		if (verbose)			printk(" ok.\nDownloading FEP/OS to 0x%lx:", virt_to_phys(fepos));		memwinon(bd, (FEPCODE >> 13));		memcpy(fepos, pcxx_cook, pcxx_ncook);		memwinon(bd, 0);		if (verbose)			printk(" done.\n");		*(ushort *)((ulong)memaddr + MBOX +  0) = 2;		*(ushort *)((ulong)memaddr + MBOX +  2) = memory_seg + FEPCODESEG;		*(ushort *)((ulong)memaddr + MBOX +  4) = 0;		*(ushort *)((ulong)memaddr + MBOX +  6) = FEPCODESEG;		*(ushort *)((ulong)memaddr + MBOX +  8) = 0;		*(ushort *)((ulong)memaddr + MBOX + 10) = pcxx_ncook;		outb(FEPMEM|FEPINT, bd->port);		outb(FEPMEM, bd->port);		for(i=0; *(ushort *)((ulong)memaddr + MBOX); i++) {			if(i > 2000) {				printk("PC/Xx: Command failed for the %s at 0x%x!\n",					board_desc[bd->type], bd->port);				bd->status = DISABLED;				break;			}#ifdef MODULE			schedule();#endif			pcxxdelay(1);		}		if(bd->status == DISABLED)			continue;		if (verbose)			printk("Waiting for FEP/OS to become ready");		*(ushort *)(memaddr + FEPSTAT) = 0;		*(ushort *)(memaddr + MBOX + 0) = 1;		*(ushort *)(memaddr + MBOX + 2) = FEPCODESEG;		*(ushort *)(memaddr + MBOX + 4) = 0x4L;		outb(FEPINT, bd->port);		outb(FEPCLR, bd->port);		memwinon(bd, 0);		for(i=1; *(ushort *)((ulong)memaddr + FEPSTAT) != *(ushort *)"OS"; i++) {			if(i > 1000) {				printk("\nPC/Xx: FEP/OS download failed on the %s at 0x%x!\n",					board_desc[bd->type], bd->port);				bd->status = DISABLED;				break;			}			if (verbose) {				printk(".");				if (i % 50 == 0)					printk("\n%5d",i/50);			}#ifdef MODULE			schedule();#endif			pcxxdelay(1);		}		if(bd->status == DISABLED)			continue;		if (verbose)			printk(" ok.\n");		ch = digi_channels+bd->first_minor;		pcxxassert(ch < digi_channels+nbdevs, "ch out of range");		bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT);		gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL);		if((bd->type == PCXEVE) && (*(ushort *)((ulong)memaddr+NPORT) < 3))			shrinkmem = 1;		request_region(bd->port, 4, "PC/Xx");		for(i=0; i < bd->numports; i++, ch++, bc++) {			if(((ushort *)((ulong)memaddr + PORTBASE))[i] == 0) {				ch->brdchan = 0;				continue;			}			ch->brdchan = bc;			ch->mailbox = gd;			ch->tqueue.routine = do_softint;			ch->tqueue.data = ch;			ch->board = &boards[crd];#ifdef DEFAULT_HW_FLOW			ch->digiext.digi_flags = RTSPACE|CTSPACE;#endif			if(boards[crd].altpin) {				ch->dsr = CD;				ch->dcd = DSR;				ch->digiext.digi_flags |= DIGI_ALTPIN;			} else { 				ch->dcd = CD;				ch->dsr = DSR;			}			ch->magic = PCXX_MAGIC;			ch->boardnum = crd;			ch->channelnum = i;			ch->dev = bd->first_minor + i;			ch->tty = 0;			if(shrinkmem) {				fepcmd(ch, SETBUFFER, 32, 0, 0, 0);				shrinkmem = 0;			}						if(bd->type != PCXEVE) {				ch->txptr = memaddr+((bc->tseg-memory_seg) << 4);				ch->rxptr = memaddr+((bc->rseg-memory_seg) << 4);				ch->txwin = ch->rxwin = 0;			} else {				ch->txptr = memaddr+(((bc->tseg-memory_seg) << 4) & 0x1fff);				ch->txwin = FEPWIN | ((bc->tseg-memory_seg) >> 9);				ch->rxptr = memaddr+(((bc->rseg-memory_seg) << 4) & 0x1fff);				ch->rxwin = FEPWIN | ((bc->rseg-memory_seg) >>9 );			}			ch->txbufsize = bc->tmax + 1;			ch->rxbufsize = bc->rmax + 1;			ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);			lowwater = ch->txbufsize >= 2000 ? 1024 : ch->txbufsize/2;			fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);			fepcmd(ch, SRXLWATER, ch->rxbufsize/4, 0, 10, 0);			fepcmd(ch, SRXHWATER, 3 * ch->rxbufsize/4, 0, 10, 0);			bc->edelay = 100;			bc->idata = 1;			ch->startc = bc->startc;			ch->stopc = bc->stopc;			ch->startca = bc->startca;			ch->stopca = bc->stopca;			ch->fepcflag = 0;			ch->fepiflag = 0;			ch->fepoflag = 0;			ch->fepstartc = 0;			ch->fepstopc = 0;			ch->fepstartca = 0;			ch->fepstopca = 0;			ch->close_delay = 50;			ch->count = 0;			ch->blocked_open = 0;			ch->callout_termios = pcxe_callout.init_termios;			ch->normal_termios = pcxe_driver.init_termios;			ch->open_wait = 0;			ch->close_wait = 0;			ch->asyncflags = 0;		}		if (verbose)		    printk("Card No. %d ready: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n", 			    crd+1, board_desc[bd->type], board_mem[bd->type], bd->port, 			    bd->membase, bd->numports);		else		    printk("PC/Xx: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n", 			    board_desc[bd->type], board_mem[bd->type], bd->port, 			    bd->membase, bd->numports);		memwinoff(bd, 0);		enabled_cards++;	}	if (enabled_cards <= 0) {		printk(KERN_NOTICE "PC/Xx: No cards enabled, no driver.\n");		return -EIO;	}	if(tty_register_driver(&pcxe_driver))		panic("Couldn't register PC/Xe driver");	if(tty_register_driver(&pcxe_callout))		panic("Couldn't register PC/Xe callout");	/*	 * Start up the poller to check for events on all enabled boards	 */	timer_active |= 1 << DIGI_TIMER;	if (verbose)		printk(KERN_NOTICE "PC/Xx: Driver with %d card(s) ready.\n", enabled_cards);	return 0;}static void pcxxpoll(void){	unsigned long flags;	int crd;	volatile unsigned int head, tail;	struct channel *ch;	struct board_info *bd;	save_flags(flags);	cli();	for(crd=0; crd < numcards; crd++) {		bd = &boards[crd];		ch = digi_channels+bd->first_minor;		if(bd->status == DISABLED)			continue;		assertmemoff(ch);		globalwinon(ch);		head = ch->mailbox->ein;		tail = ch->mailbox->eout;		if(head != tail)			doevent(crd);		memoff(ch);	}	timer_table[DIGI_TIMER].fn = pcxxpoll;	timer_table[DIGI_TIMER].expires = jiffies + HZ/25;	timer_active |= 1 << DIGI_TIMER;	restore_flags(flags);}static void doevent(int crd){	volatile struct board_info *bd;	static struct tty_struct *tty;	volatile struct board_chan *bc;	volatile unchar *eventbuf;	volatile unsigned int head;	volatile unsigned int tail;	struct channel *ch;	struct channel *chan0;	int channel, event, mstat, lstat;	bd = &boards[crd];	chan0 = digi_channels+bd->first_minor;	pcxxassert(chan0 < digi_channels+nbdevs, "ch out of range");	assertgwinon(chan0);	while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein)) {		assertgwinon(chan0);		eventbuf = (volatile unchar *)phys_to_virt(bd->membase + tail + ISTART);		channel = eventbuf[0];		event = eventbuf[1];		mstat = eventbuf[2];		lstat = eventbuf[3];		ch=chan0+channel;		if ((unsigned)channel >= bd->numports || !ch) { 			printk("physmem=%lx, tail=%x, head=%x\n", bd->membase, tail, head);			printk("doevent(%x) channel %x, event %x, mstat %x, lstat %x\n",					crd, (unsigned)channel, event, (unsigned)mstat, lstat);			if(channel >= bd->numports)				ch = chan0;			bc = ch->brdchan;			goto next;		}		if ((bc = ch->brdchan) == NULL)			goto next;		if (event & DATA_IND) {			receive_data(ch);			assertgwinon(ch);		}		if (event & MODEMCHG_IND) {			ch->imodem = mstat;			if (ch->asyncflags & (ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE)) {				if (ch->asyncflags & ASYNC_CHECK_CD) {					if (mstat & ch->dcd) {						wake_up_interruptible(&ch->open_wait);					} else {						pcxe_sched_event(ch, PCXE_EVENT_HANGUP);					}				}			}		}		tty = ch->tty;		if (tty) {			if (event & BREAK_IND) {				tty->flip.count++;				*tty->flip.flag_buf_ptr++ = TTY_BREAK;				*tty->flip.char_buf_ptr++ = 0;#if 0				if (ch->asyncflags & ASYNC_SAK)					do_SAK(tty);#endif				tty_schedule_flip(tty); 			}			if (event & LOWTX_IND) {				if (ch->statusflags & LOWWAIT) {					ch->statusflags &= ~LOWWAIT;					if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&						tty->ldisc.write_wakeup)						(tty->ldisc.write_wakeup)(tty);					wake_up_interruptible(&tty->write_wait);				}			}			if (event & EMPTYTX_IND) {				ch->statusflags &= ~TXBUSY;				if (ch->statusflags & EMPTYWAIT) {					ch->statusflags &= ~EMPTYWAIT;					if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&						tty->ldisc.write_wakeup)						(tty->ldisc.write_wakeup)(tty);					wake_up_interruptible(&tty->write_wait);				}			}		}	next:		globalwinon(ch);		if(!bc) printk("bc == NULL in doevent!\n");		else bc->idata = 1;		chan0->mailbox->eout = (tail+4) & (IMAX-ISTART-4);		globalwinon(chan0);	}}/* * pcxxdelay - delays a specified number of milliseconds */static void pcxxdelay(int msec){	while(msec-- > 0)		__delay(loops_per_sec/1000);}static void fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds,						int bytecmd){	unchar *memaddr;	unsigned int head, tail;	long count;	int n;	if(ch->board->status == DISABLED)		return;	assertgwinon(ch);	memaddr = (unchar *)phys_to_virt(ch->board->membase);	head = ch->mailbox->cin;	if(head >= (CMAX-CSTART) || (head & 03)) {		printk("line %d: Out of range, cmd=%x, head=%x\n", __LINE__, cmd, head);		return;	}	if(bytecmd) {		*(unchar *)(memaddr+head+CSTART+0) = cmd;		*(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor;		*(unchar *)(memaddr+head+CSTART+2) = word_or_byte;		*(unchar *)(memaddr+head+CSTART+3) = byte2;	} else {		*(unchar *)(memaddr+head+CSTART+0) = cmd;		*(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor;		*(ushort*)(memaddr+head+CSTART+2) = word_or_byte;	}	head = (head+4) & (CMAX-CSTART-4);	ch->mailbox->cin = head;	count = FEPTIMEOUT;	while(1) {		count--;		if(count == 0) {			printk("Fep not responding in fepcmd()\n");			return;		}		head = ch->mailbox->cin;		tail = ch->mailbox->cout;		n = (head-tail) & (CMAX-CSTART-4);		if(n <= ncmds * (sizeof(short)*4))			break;		/* Seems not to be good here: schedule(); */	}}static unsigned termios2digi_c(struct channel *ch, unsigned cflag){	unsigned res = 0;#ifdef SPEED_HACK	/* CL: HACK to force 115200 at 38400 and 57600 at 19200 Baud */	if ((cflag & CBAUD)== B38400) cflag=cflag - B38400 + B115200;	if ((cflag & CBAUD)== B19200) cflag=cflag - B19200 + B57600;#endif	if (cflag & CBAUDEX)	{		ch->digiext.digi_flags |= DIGI_FAST;		res |= FEP_HUPCL;		/* This gets strange but if we don't do this we will get 78600		 * instead of 115200. 57600 is mapped to 50 baud yielding 57600 in		 * FAST mode. 115200 is mapped to 75. We need to map it to 110 to		 * do 115K		 */		if (cflag & B115200) res|=1;	}	else ch->digiext.digi_flags &= ~DIGI_FAST;	res |= cflag & (CBAUD | PARODD | PARENB | CSTOPB | CSIZE | CLOCAL);	return res;

⌨️ 快捷键说明

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