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

📄 sab82532.c

📁 移植到2410开发板上的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		*tty->flip.char_buf_ptr++ = 0;		info->icount.brk++;	}	if (!tty)		return;	if (stat->sreg.isr0 & SAB82532_ISR0_RFO) {		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {			info->icount.buf_overrun++;			goto check_modem;		}		tty->flip.count++;		*tty->flip.flag_buf_ptr++ = TTY_PARITY;		*tty->flip.char_buf_ptr++ = 0;		info->icount.overrun++;	}check_modem:	if (stat->sreg.isr0 & SAB82532_ISR0_CDSC) {		info->dcd = (readb(&info->regs->r.vstr) & SAB82532_VSTR_CD) ? 0 : 1;		info->icount.dcd++;		modem_change++;#ifdef SERIAL_DEBUG_MODEM		printk("DCD change: %d\n", info->icount.dcd);#endif	}	if (stat->sreg.isr1 & SAB82532_ISR1_CSC) {		info->cts = readb(&info->regs->r.star) & SAB82532_STAR_CTS;		info->icount.cts++;		modem_change++;#ifdef SERIAL_DEBUG_MODEM		printk("CTS change: %d, CTS %s\n", info->icount.cts, info->cts ? "on" : "off");#endif	}	if ((readb(&info->regs->r.pvr) & info->pvr_dsr_bit) ^ info->dsr) {		info->dsr = (readb(&info->regs->r.pvr) & info->pvr_dsr_bit) ? 0 : 1;		info->icount.dsr++;		modem_change++;#ifdef SERIAL_DEBUG_MODEM		printk("DSR change: %d\n", info->icount.dsr);#endif	}	if (modem_change)		wake_up_interruptible(&info->delta_msr_wait);	if ((info->flags & ASYNC_CHECK_CD) &&	    (stat->sreg.isr0 & SAB82532_ISR0_CDSC)) {#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))		printk("ttys%d CD now %s...", info->line,		       (info->dcd) ? "on" : "off");#endif				if (info->dcd)			wake_up_interruptible(&info->open_wait);		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&			   (info->flags & ASYNC_CALLOUT_NOHUP))) {#ifdef SERIAL_DEBUG_OPEN			printk("scheduling hangup...");#endif			MOD_INC_USE_COUNT;			if (schedule_task(&info->tqueue_hangup) == 0)				MOD_DEC_USE_COUNT;		}	}	if (info->flags & ASYNC_CTS_FLOW) {		if (info->tty->hw_stopped) {			if (info->cts) {#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))				printk("CTS tx start...");#endif				info->tty->hw_stopped = 0;				sab82532_sched_event(info,						     RS_EVENT_WRITE_WAKEUP);				info->interrupt_mask1 &= ~(SAB82532_IMR1_XPR);				writeb(info->interrupt_mask1, &info->regs->w.imr1);				sab82532_start_tx(info);			}		} else {			if (!(info->cts)) {#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))				printk("CTS tx stop...");#endif				info->tty->hw_stopped = 1;			}		}	}}/* * This is the serial driver's generic interrupt routine */static void sab82532_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct sab82532 *info = dev_id;	union sab82532_irq_status status;#ifdef SERIAL_DEBUG_INTR	printk("sab82532_interrupt(%d)...", irq);#endif	status.stat = 0;	if (readb(&info->regs->r.gis) & SAB82532_GIS_ISA0)		status.sreg.isr0 = readb(&info->regs->r.isr0);	if (readb(&info->regs->r.gis) & SAB82532_GIS_ISA1)		status.sreg.isr1 = readb(&info->regs->r.isr1);#ifdef SERIAL_DEBUG_INTR	printk("%d<%02x.%02x>", info->line,	       status.sreg.isr0, status.sreg.isr1);#endif	if (!status.stat)		goto next;	if (status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |				SAB82532_ISR0_RFO | SAB82532_ISR0_RPF))		receive_chars(info, &status);	if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) ||	    (status.sreg.isr1 & (SAB82532_ISR1_BRK | SAB82532_ISR1_CSC)))		check_status(info, &status);	if (status.sreg.isr1 & (SAB82532_ISR1_ALLS | SAB82532_ISR1_XPR))		transmit_chars(info, &status);next:	info = info->next;	status.stat = 0;	if (readb(&info->regs->r.gis) & SAB82532_GIS_ISB0)		status.sreg.isr0 = readb(&info->regs->r.isr0);	if (readb(&info->regs->r.gis) & SAB82532_GIS_ISB1)		status.sreg.isr1 = readb(&info->regs->r.isr1);#ifdef SERIAL_DEBUG_INTR	printk("%d<%02x.%02x>", info->line,	       status.sreg.isr0, status.sreg.isr1);#endif	if (!status.stat)		goto done;	if (status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |				SAB82532_ISR0_RFO | SAB82532_ISR0_RPF))		receive_chars(info, &status);	if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) ||	    (status.sreg.isr1 & (SAB82532_ISR1_BRK | SAB82532_ISR1_CSC)))		check_status(info, &status);	if (status.sreg.isr1 & (SAB82532_ISR1_ALLS | SAB82532_ISR1_XPR))		transmit_chars(info, &status);done:	;#ifdef SERIAL_DEBUG_INTR	printk("end.\n");#endif}/* * ------------------------------------------------------------------- * Here ends the serial interrupt routines. * ------------------------------------------------------------------- *//* * This routine is used to handle the "bottom half" processing for the * serial driver, known also the "software interrupt" processing. * This processing is done at the kernel interrupt level, after the * sab82532_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This * is where time-consuming activities which can not be done in the * interrupt driver proper are done; the interrupt driver schedules * them using sab82532_sched_event(), and they get done here. */static void do_serial_bh(void){	run_task_queue(&tq_serial);}static void do_softint(void *private_){	struct sab82532	*info = (struct sab82532 *)private_;	struct tty_struct *tty;	tty = info->tty;	if (!tty)		return;	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&		    tty->ldisc.write_wakeup)			(tty->ldisc.write_wakeup)(tty);		wake_up_interruptible(&tty->write_wait);	}}/* * This routine is called from the scheduler tqueue when the interrupt * routine has signalled that a hangup has occurred.  The path of * hangup processing is: * * 	serial interrupt routine -> (scheduler tqueue) -> * 	do_serial_hangup() -> tty->hangup() -> sab82532_hangup() *  */static void do_serial_hangup(void *private_){	struct sab82532	*info = (struct sab82532 *) private_;	struct tty_struct *tty;	tty = info->tty;	if (tty)		tty_hangup(tty);	MOD_DEC_USE_COUNT;}static voidsab82532_init_line(struct sab82532 *info){	unsigned char stat, tmp;	/*	 * Wait for any commands or immediate characters	 */	sab82532_cec_wait(info);	sab82532_tec_wait(info);	/*	 * Clear the FIFO buffers.	 */	writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr);	sab82532_cec_wait(info);	writeb(SAB82532_CMDR_XRES, &info->regs->w.cmdr);	/*	 * Clear the interrupt registers.	 */	stat = readb(&info->regs->r.isr0);	stat = readb(&info->regs->r.isr1);	/*	 * Now, initialize the UART 	 */	writeb(0, &info->regs->w.ccr0);				/* power-down */	writeb(SAB82532_CCR0_MCE | SAB82532_CCR0_SC_NRZ |	       SAB82532_CCR0_SM_ASYNC, &info->regs->w.ccr0);	writeb(SAB82532_CCR1_ODS | SAB82532_CCR1_BCR | 7, &info->regs->w.ccr1);	writeb(SAB82532_CCR2_BDF | SAB82532_CCR2_SSEL |	       SAB82532_CCR2_TOE, &info->regs->w.ccr2);	writeb(0, &info->regs->w.ccr3);	writeb(SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG, &info->regs->w.ccr4);	writeb(SAB82532_MODE_RTS | SAB82532_MODE_FCTS |	       SAB82532_MODE_RAC, &info->regs->w.mode);	writeb(SAB82532_RFC_DPS | SAB82532_RFC_RFDF, &info->regs->w.rfc);	switch (info->recv_fifo_size) {		case 1:			tmp = readb(&info->regs->w.rfc);			tmp |= SAB82532_RFC_RFTH_1;			writeb(tmp, &info->regs->w.rfc);			break;		case 4:			tmp = readb(&info->regs->w.rfc);			tmp |= SAB82532_RFC_RFTH_4;			writeb(tmp, &info->regs->w.rfc);			break;		case 16:			tmp = readb(&info->regs->w.rfc);			tmp |= SAB82532_RFC_RFTH_16;			writeb(tmp, &info->regs->w.rfc);			break;		default:			info->recv_fifo_size = 32;			/* fall through */		case 32:			tmp = readb(&info->regs->w.rfc);			tmp |= SAB82532_RFC_RFTH_32;			writeb(tmp, &info->regs->w.rfc);			break;	}	tmp = readb(&info->regs->rw.ccr0);	tmp |= SAB82532_CCR0_PU;	/* power-up */	writeb(tmp, &info->regs->rw.ccr0);}static int startup(struct sab82532 *info){	unsigned long flags;	unsigned long page;	int retval = 0;	page = get_free_page(GFP_KERNEL);	if (!page)		return -ENOMEM;	save_flags(flags); cli();	if (info->flags & ASYNC_INITIALIZED) {		free_page(page);		goto errout;	}	if (!info->regs) {		if (info->tty)			set_bit(TTY_IO_ERROR, &info->tty->flags);		free_page(page);		retval = -ENODEV;		goto errout;	}	if (info->xmit.buf)		free_page(page);	else		info->xmit.buf = (unsigned char *)page;#ifdef SERIAL_DEBUG_OPEN	printk("starting up serial port %d...", info->line);#endif	/*	 * Initialize the Hardware	 */	sab82532_init_line(info);	if (info->tty->termios->c_cflag & CBAUD) {		u8 tmp;		tmp = readb(&info->regs->rw.mode);		tmp &= ~(SAB82532_MODE_FRTS);		tmp |= SAB82532_MODE_RTS;		writeb(tmp, &info->regs->rw.mode);		tmp = readb(&info->regs->rw.pvr);		tmp &= ~(info->pvr_dtr_bit);		writeb(tmp, &info->regs->rw.pvr);	}	/*	 * Finally, enable interrupts	 */	info->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR |				SAB82532_IMR0_PLLA;	writeb(info->interrupt_mask0, &info->regs->w.imr0);	info->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS |				SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN |				SAB82532_IMR1_CSC | SAB82532_IMR1_XON |				SAB82532_IMR1_XPR;	writeb(info->interrupt_mask1, &info->regs->w.imr1);	set_bit(SAB82532_ALLS, &info->irqflags);	if (info->tty)		clear_bit(TTY_IO_ERROR, &info->tty->flags);	info->xmit.head = info->xmit.tail = 0;	set_bit(SAB82532_XPR, &info->irqflags);	/*	 * and set the speed of the serial port	 */	change_speed(info);	info->flags |= ASYNC_INITIALIZED;	restore_flags(flags);	return 0;	errout:	restore_flags(flags);	return retval;}/* * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */static void shutdown(struct sab82532 *info){	unsigned long flags;	u8 tmp;	if (!(info->flags & ASYNC_INITIALIZED))		return;#ifdef SERIAL_DEBUG_OPEN	printk("Shutting down serial port %d...", info->line);#endif	save_flags(flags); cli(); /* Disable interrupts */	/*	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq	 * here so the queue might never be waken up	 */	wake_up_interruptible(&info->delta_msr_wait);	if (info->xmit.buf) {		free_page((unsigned long)info->xmit.buf);		info->xmit.buf = 0;	}#ifdef CONFIG_SERIAL_CONSOLE	if (info->is_console) {		info->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR |					SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC;		writeb(info->interrupt_mask0, &info->regs->w.imr0);		info->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS |					SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN |					SAB82532_IMR1_CSC | SAB82532_IMR1_XON |					SAB82532_IMR1_XPR;		writeb(info->interrupt_mask1, &info->regs->w.imr1);		if (info->tty)			set_bit(TTY_IO_ERROR, &info->tty->flags);		info->flags &= ~ASYNC_INITIALIZED;		restore_flags(flags);		return;	}#endif	/* Disable Interrupts */	info->interrupt_mask0 = 0xff;	writeb(info->interrupt_mask0, &info->regs->w.imr0);	info->interrupt_mask1 = 0xff;	writeb(info->interrupt_mask1, &info->regs->w.imr1);	if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {		tmp = readb(&info->regs->r.mode);		tmp |= (SAB82532_MODE_FRTS | SAB82532_MODE_RTS);		writeb(tmp, &info->regs->rw.mode);		writeb(readb(&info->regs->rw.pvr) | info->pvr_dtr_bit,		       &info->regs->rw.pvr);	}	/* Disable break condition */	tmp = readb(&info->regs->rw.dafo);	tmp &= ~(SAB82532_DAFO_XBRK);	writeb(tmp, &info->regs->rw.dafo);	/* Disable Receiver */		tmp = readb(&info->regs->rw.mode);	tmp &= ~(SAB82532_MODE_RAC);	writeb(tmp, &info->regs->rw.mode);	/* Power Down */		tmp = readb(&info->regs->rw.ccr0);	tmp &= ~(SAB82532_CCR0_PU);	writeb(tmp, &info->regs->rw.ccr0);	if (info->tty)		set_bit(TTY_IO_ERROR, &info->tty->flags);	info->flags &= ~ASYNC_INITIALIZED;	restore_flags(flags);}/* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */static void change_speed(struct sab82532 *info){	unsigned long	flags;	unsigned int	ebrg;	tcflag_t	cflag;	unsigned char	dafo;	int		bits, n, m;	if (!info->tty || !info->tty->termios)		return;	cflag = info->tty->termios->c_cflag;	/* Byte size and parity */	switch (cflag & CSIZE) {	      case CS5: dafo = SAB82532_DAFO_CHL5; bits = 7; break;	      case CS6: dafo = SAB82532_DAFO_CHL6; bits = 8; break;	      case CS7: dafo = SAB82532_DAFO_CHL7; bits = 9; break;	      case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break;	      /* Never happens, but GCC is too dumb to figure it out */	      default:  dafo = SAB82532_DAFO_CHL5; bits = 7; break;	}	if (cflag & CSTOPB) {		dafo |= SAB82532_DAFO_STOP;		bits++;	}

⌨️ 快捷键说明

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