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

📄 8253xtty.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 5 页
字号:
		{			skb_unlink(port->active2.receive->HostVaddr);			skb_queue_tail(port->sab8253xc_rcvbuflist, port->active2.receive->HostVaddr);			skb_queue_head(port->sab8253xbuflist, skb);			port->active2.receive->HostVaddr = skb;			port->active2.receive->Count = (port->recv_fifo_size|OWN_SAB);		}		queue_task(&tty->flip.tqueue, &tq_timer);		port->icount.brk++;	}		if (stat->images[ISR0_IDX] & SAB82532_ISR0_RFO) 	{		port->active2.receive->HostVaddr->tail[0] = 0;		port->active2.receive->HostVaddr->tail[1] = TTY_PARITY;		port->active2.receive->HostVaddr->tail += 2;		port->active2.receive->HostVaddr->data_len = 2;		port->active2.receive->HostVaddr->len = 2;		if(skb = dev_alloc_skb(port->recv_fifo_size), skb == NULL)		{			port->icount.buf_overrun++;			port->active2.receive->HostVaddr->tail = port->active2.receive->HostVaddr->data; 				/* clear the buffer */			port->active2.receive->Count = (port->recv_fifo_size|OWN_SAB);			port->active2.receive->HostVaddr->data_len = 0;			port->active2.receive->HostVaddr->len = 0;		}		else		{			skb_unlink(port->active2.receive->HostVaddr);			skb_queue_tail(port->sab8253xc_rcvbuflist, port->active2.receive->HostVaddr);			skb_queue_head(port->sab8253xbuflist, skb);			port->active2.receive->HostVaddr = skb;			port->active2.receive->Count = (port->recv_fifo_size|OWN_SAB);		}		queue_task(&tty->flip.tqueue, &tq_timer);		port->icount.overrun++;	}	 check_modem:	/* Checking DCD */	sig = &port->dcd;	if (stat->images[sig->irq] & sig->irqmask) 	{		sig->val = ISON(port,dcd);		port->icount.dcd++;		modem_change++;	}	/* Checking CTS */	sig = &port->cts;	if (stat->images[sig->irq] & sig->irqmask) 	{		sig->val = ISON(port,cts);		port->icount.cts++;		modem_change++;	}	/* Checking DSR */	sig = &port->dsr;	if (stat->images[sig->irq] & sig->irqmask) 	{		sig->val = ISON(port,dsr);		port->icount.dsr++;		modem_change++;	}	if (modem_change)	{		wake_up_interruptible(&port->delta_msr_wait); /* incase kernel proc level was waiting on modem change */	}		sig = &port->dcd;	if ((port->flags & FLAG8253X_CHECK_CD) &&	    (stat->images[sig->irq] & sig->irqmask)) 	{				if (sig->val)		{			wake_up_interruptible(&port->open_wait); /* in case waiting in block_til_ready */		}		else if (!((port->flags & FLAG8253X_CALLOUT_ACTIVE) &&			   (port->flags & FLAG8253X_CALLOUT_NOHUP))) 		{						MOD_INC_USE_COUNT;	/* in case a close is already in progress						   don't want structures to vanish during						   late processing of hangup */			if (schedule_task(&port->tqueue_hangup) == 0)			{				MOD_DEC_USE_COUNT; /* task schedule failed */			}		}	}		sig = &port->cts;	if (port->flags & FLAG8253X_CTS_FLOW) 	{		if (port->tty->hw_stopped) 		{			if (sig->val) 			{								port->tty->hw_stopped = 0;				sab8253x_sched_event(port, SAB8253X_EVENT_WRITE_WAKEUP);				sab8253x_start_tx(port);			}		} 		else 		{			if (!(sig->val)) 			{				port->tty->hw_stopped = 1;			}		}	}}/* * 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 * sab8253x_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 sab8253x_sched_event(), and they get done here. */				/* The following routine is installed */				/* in the bottom half -- just search */				/* for the init_bh() call */				/* The logic: sab8253x_sched_event() */				/* enqueues the tqueue port entry on */				/* the tq_8253x_serial task list -- */				/* whenever the bottom half is run */				/* sab8253x_do_softint is invoked for */				/* every port that has invoked the bottom */				/* half via sab8253x_sched_event(). */				/* currently only a write wakeevent */				/* wakeup is scheduled -- to tell the */				/* tty driver to send more chars */				/* down to the serial driver.*/static void sab8253x_do_serial_bh(void){	run_task_queue(&tq_8253x_serial);}				/* I believe the reason for the */				/* bottom half processing below is */				/* the length of time needed to transfer */				/* characters to the TTY driver. */static void sab8253x_do_softint(void *private_){	struct sab_port	*port = (struct sab_port *)private_;	struct tty_struct *tty;		tty = port->tty;	if (!tty)	{		return;	}		port->DoingInterrupt = 1;	if (test_and_clear_bit(SAB8253X_EVENT_WRITE_WAKEUP, &port->event)) 	{		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&		    tty->ldisc.write_wakeup)			(tty->ldisc.write_wakeup)(tty);		wake_up_interruptible(&tty->write_wait); /* in case tty driver waiting on write */	}	port->DoingInterrupt = 0;}/* * 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() -> sab8253x_hangup() *  *//* This logic takes place at kernel *//* process context through the scheduler*//* schedule_task(tqueue_hangup) *//* takes place in the interrupt handler*/static void sab8253x_do_serial_hangup(void *private_){	struct sab_port *port = (struct sab_port *) private_;	struct tty_struct *tty;		tty = port->tty;	if (tty)	{		tty_hangup(tty);	}	MOD_DEC_USE_COUNT;		/* in case busy waiting to unload module */}static voidsab8253x_init_line(struct sab_port *port){	unsigned char stat;	if(port->chip->c_cim)	{		if(port->chip->c_cim->ci_type == CIM_SP502)		{			aura_sp502_program(port, SP502_OFF_MODE);		}	}		/*	 * Wait for any commands or immediate characters	 */	sab8253x_cec_wait(port);	sab8253x_tec_wait(port);		/*	 * Clear the FIFO buffers.	 */		WRITEB(port, cmdr, SAB82532_CMDR_RRES);	sab8253x_cec_wait(port);	WRITEB(port, cmdr, SAB82532_CMDR_XRES);			/*	 * Clear the interrupt registers.	 */	stat = READB(port, isr0);	stat = READB(port, isr1);		/*	 * Now, initialize the UART 	 */	WRITEB(port, ccr0, 0);	  /* power-down */	WRITEB(port, ccr0,	       SAB82532_CCR0_MCE | SAB82532_CCR0_SC_NRZ | SAB82532_CCR0_SM_ASYNC);	WRITEB(port, ccr1,	       SAB82532_CCR1_ODS | SAB82532_CCR1_BCR | 7);	WRITEB(port, ccr2,	       SAB82532_CCR2_BDF | SAB82532_CCR2_SSEL | SAB82532_CCR2_TOE);	WRITEB(port, ccr3, 0);	WRITEB(port, ccr4,	       SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG);	WRITEB(port, mode,	       SAB82532_MODE_RTS | SAB82532_MODE_FCTS | SAB82532_MODE_RAC);	WRITEB(port, rfc,	       SAB82532_RFC_DPS | SAB82532_RFC_RFDF);	switch (port->recv_fifo_size) 	{	case 1:		SET_REG_BIT(port,rfc,SAB82532_RFC_RFTH_1);		break;	case 4:		SET_REG_BIT(port,rfc,SAB82532_RFC_RFTH_4);		break;	case 16:		SET_REG_BIT(port,rfc,SAB82532_RFC_RFTH_16);		break;	default:		port->recv_fifo_size = 32;	case 32:		SET_REG_BIT(port,rfc,SAB82532_RFC_RFTH_32);		break;	}	/* power-up */	SET_REG_BIT(port, ccr0, SAB82532_CCR0_PU);	if(port->chip->c_cim)	{		if(port->chip->c_cim->ci_type == CIM_SP502)		{			aura_sp502_program(port, port->sigmode);		}	}}static int sab8253x_startup(struct sab_port *port){	unsigned long flags;		int retval = 0;		save_flags(flags); cli();		if (port->flags & FLAG8253X_INITIALIZED) 	{		goto errout;	}		port->msgbufindex = 0;	port->xmit_buf = NULL;	port->buffergreedy = 0;		if (!port->regs) 	{		if (port->tty)		{			set_bit(TTY_IO_ERROR, &port->tty->flags);		}		retval = -ENODEV;		goto errout;	}		/*	 * Initialize the Hardware	 */	sab8253x_init_line(port);		if (port->tty->termios->c_cflag & CBAUD) 	{		/* Activate RTS */		RAISE(port,rts);				/* Activate DTR */		RAISE(port,dtr);	}		/*	 * Initialize the modem signals values	 */	port->dcd.val=ISON(port,dcd);	port->cts.val=ISON(port,cts);	port->dsr.val=ISON(port,dsr);		/*	 * Finally, enable interrupts	 */		port->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR |		SAB82532_IMR0_PLLA;	WRITEB(port, imr0, port->interrupt_mask0);	port->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_XOFF |		SAB82532_IMR1_TIN | SAB82532_IMR1_XON |		SAB82532_IMR1_XPR;	WRITEB(port, imr1, port->interrupt_mask1);	port->all_sent = 1;		if (port->tty)	{		clear_bit(TTY_IO_ERROR, &port->tty->flags);	}	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;		/*	 * and set the speed of the serial port	 */	sab8253x_change_speed(port);		port->flags |= FLAG8253X_INITIALIZED;	port->receive_chars = sab8253x_receive_chars;	port->transmit_chars = sab8253x_transmit_chars;	port->check_status = sab8253x_check_status;	port->receive_test = (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |			      SAB82532_ISR0_RFO | SAB82532_ISR0_RPF);	port->transmit_test = (SAB82532_ISR1_ALLS | SAB82532_ISR1_XPR);	port->check_status_test = SAB82532_ISR1_BRK;		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 sab8253x_shutdown(struct sab_port *port){	unsigned long flags;		if (!(port->flags & FLAG8253X_INITIALIZED))	{		return;	}		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(&port->delta_msr_wait);	/* shutting down port modem status is pointless */		if (port->xmit_buf) 	{		port->xmit_buf = NULL;	}	#ifdef XCONFIG_SERIAL_CONSOLE	if (port->is_console) 	{		port->interrupt_mask0 = 			SAB82532_IMR0_PERR | SAB82532_IMR0_FERR |			/*SAB82532_IMR0_TIME |*/			SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC;		WRITEB(port,imr0,port->interrupt_mask0);		port->interrupt_mask1 = 			SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS |			SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN |			SAB82532_IMR1_CSC | SAB82532_IMR1_XON |			SAB82532_IMR1_XPR;		WRITEB(port,imr1,port->interrupt_mask1);		if (port->tty)		{			set_bit(TTY_IO_ERROR, &port->tty->flags);		}		port->flags &= ~FLAG8253X_INITIALIZED;		restore_flags(flags);		return;	}#endif		/* Disable Interrupts */		port->interrupt_mask0 = 0xff;	WRITEB(port, imr0, port->interrupt_mask0);	port->interrupt_mask1 = 0xff;	WRITEB(port, imr1, port->interrupt_mask1);		if (!port->tty || (port->tty->termios->c_cflag & HUPCL)) 	{		LOWER(port,rts);		LOWER(port,dtr);	}		/* Disable break condition */	CLEAR_REG_BIT(port,dafo,SAB82532_DAFO_XBRK);		/* Disable Receiver */		CLEAR_REG_BIT(port,mode,SAB82532_MODE_RAC);		/* Power Down */		CLEAR_REG_BIT(port,ccr0,SAB82532_CCR0_PU);		if (port->tty)	{		set_bit(TTY_IO_ERROR, &port->tty->flags);	}		port->flags &= ~FLAG8253X_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 sab8253x_change_speed(struct sab_port *port){	unsigned long	flags,baud;	tcflag_t	cflag;	u8	        dafo,ccr2=0,ccr4=0,ebrg=0,mode;	int		i, bits;#ifdef DEBUGGING	printk("Change speed!  ");#endif	if (!port->tty || !port->tty->termios) 	{#ifdef DEBUGGING		printk("NOT!\n");#endif		return;	}	#ifdef DEBUGGING	printk(" for real.\n");#endif		cflag = port->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;	default:	case CS8: 		dafo = SAB82532_DAFO_CHL8; 		bits = 10; 		break;	}		if (cflag & CSTOPB) 	{		dafo |= SAB82532_DAFO_STOP;		bits++;	}		if (cflag & PARENB) 	{		dafo |= SAB82532_DAFO_PARE;		bits++;	}		if (cflag & PARODD) 	{#ifdef CMSPAR		if (cflag & CMSPAR)			dafo |= SAB82532_DAFO_PAR_MARK;		else#endif			dafo |= SAB82532_DAFO_PAR_ODD;	} 	else 	{#ifdef CMSPAR		if (cflag & CMSPAR)			dafo |= SAB82532_DAFO_PAR_SPACE;		else#endif			dafo |= SAB82532_DAFO_PAR_EVEN;	}

⌨️ 快捷键说明

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