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

📄 su.c

📁 自己根据lkd和情境分析
💻 C
📖 第 1 页 / 共 5 页
字号:
		if (--info->xmit_cnt <= 0)			break;	} while (--count > 0);		if (info->xmit_cnt < WAKEUP_CHARS)		su_sched_event(info, RS_EVENT_WRITE_WAKEUP);#ifdef SERIAL_DEBUG_INTR	printk("T%d...", info->xmit_cnt);#endif	if (intr_done)		*intr_done = 0;	if (info->xmit_cnt <= 0) {		info->IER &= ~UART_IER_THRI;		serial_out(info, UART_IER, info->IER);	}}static voidcheck_modem_status(struct su_struct *info){	int	status;	struct	async_icount *icount;	status = serial_in(info, UART_MSR);	if (status & UART_MSR_ANY_DELTA) {		icount = &info->icount;		/* update input line counters */		if (status & UART_MSR_TERI)			icount->rng++;		if (status & UART_MSR_DDSR)			icount->dsr++;		if (status & UART_MSR_DDCD) {			icount->dcd++;#ifdef CONFIG_HARD_PPS			if ((info->flags & ASYNC_HARDPPS_CD) &&			    (status & UART_MSR_DCD))				hardpps();#endif		}		if (status & UART_MSR_DCTS)			icount->cts++;		wake_up_interruptible(&info->delta_msr_wait);	}	if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))		printk("ttys%d CD now %s...", info->line,		       (status & UART_MSR_DCD) ? "on" : "off");#endif				if (status & UART_MSR_DCD)			wake_up_interruptible(&info->open_wait);		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&			   (info->flags & ASYNC_CALLOUT_NOHUP))) {#ifdef SERIAL_DEBUG_OPEN			printk("doing serial hangup...");#endif			if (info->tty)				tty_hangup(info->tty);	}	}	if (info->flags & ASYNC_CTS_FLOW) {		if (info->tty->hw_stopped) {			if (status & UART_MSR_CTS) {#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))				printk("CTS tx start...");#endif				info->tty->hw_stopped = 0;				info->IER |= UART_IER_THRI;				serial_out(info, UART_IER, info->IER);				su_sched_event(info, RS_EVENT_WRITE_WAKEUP);				return;			}		} else {			if (!(status & UART_MSR_CTS)) {#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))				printk("CTS tx stop...");#endif				info->tty->hw_stopped = 1;				info->IER &= ~UART_IER_THRI;				serial_out(info, UART_IER, info->IER);			}		}	}}/* * This is the kbd/mouse serial driver's interrupt routine */static voidsu_kbd_ms_interrupt(int irq, void *dev_id, struct pt_regs * regs){	struct su_struct *info = (struct su_struct *)dev_id;	unsigned char status;#ifdef SERIAL_DEBUG_INTR	printk("su_kbd_ms_interrupt(%s)...", __irq_itoa(irq));#endif	if (!info)		return;	if (serial_in(info, UART_IIR) & UART_IIR_NO_INT)		return;	status = serial_inp(info, UART_LSR);#ifdef SERIAL_DEBUG_INTR	printk("status = %x...", status);#endif	if ((status & UART_LSR_DR) || (status & UART_LSR_BI))		receive_kbd_ms_chars(info, regs,				     (status & UART_LSR_BI) != 0);#ifdef SERIAL_DEBUG_INTR	printk("end.\n");#endif}/* * This is the serial driver's generic interrupt routine */static voidsu_serial_interrupt(int irq, void *dev_id, struct pt_regs * regs){	int status;	struct su_struct *info;	int pass_counter = 0;#ifdef SERIAL_DEBUG_INTR	printk("su_serial_interrupt(%s)...", __irq_itoa(irq));#endif	info = (struct su_struct *)dev_id;	if (!info || !info->tty) {#ifdef SERIAL_DEBUG_INTR		printk("strain\n");#endif		return;	}	do {		status = serial_inp(info, UART_LSR);#ifdef SERIAL_DEBUG_INTR		printk("status = %x...", status);#endif		if (status & UART_LSR_DR)			receive_serial_chars(info, &status, regs);		check_modem_status(info);		if (status & UART_LSR_THRE)			transmit_chars(info, 0);		if (pass_counter++ > RS_ISR_PASS_LIMIT) {#ifdef SERIAL_DEBUG_INTR			printk("rs loop break");#endif			break; 	/* Prevent infinite loops */		}	} while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));	info->last_active = jiffies;#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 * su_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 su_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 su_struct	*info = (struct su_struct *) 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);	}}/* * --------------------------------------------------------------- * Low level utility subroutines for the serial driver:  routines to * figure out the appropriate timeout for an interrupt chain, routines * to initialize and startup a serial port, and routines to shutdown a * serial port.  Useful stuff like that. * --------------------------------------------------------------- */static intstartup(struct su_struct *info){	unsigned long flags;	int	retval=0;	unsigned long page;	save_flags(flags);	if (info->tty) {		page = get_free_page(GFP_KERNEL);		if (!page)			return -ENOMEM;		cli();		if (info->flags & ASYNC_INITIALIZED) {			free_page(page);			goto errout;		}		if (info->port == 0 || info->type == PORT_UNKNOWN) {			set_bit(TTY_IO_ERROR, &info->tty->flags);			free_page(page);			goto errout;		}		if (info->xmit_buf)			free_page(page);		else			info->xmit_buf = (unsigned char *) page;	}	cli();#ifdef SERIAL_DEBUG_OPEN	printk("starting up ttys%d (irq %s)...", info->line,	       __irq_itoa(info->irq));#endif	if (uart_config[info->type].flags & UART_STARTECH) {		/* Wake up UART */		serial_outp(info, UART_LCR, 0xBF);		serial_outp(info, UART_EFR, UART_EFR_ECB);		serial_outp(info, UART_IER, 0);		serial_outp(info, UART_EFR, 0);		serial_outp(info, UART_LCR, 0);	}	if (info->type == PORT_16750) {		/* Wake up UART */		serial_outp(info, UART_IER, 0);	}	/*	 * Clear the FIFO buffers and disable them	 * (they will be reenabled in change_speed())	 */	if (uart_config[info->type].flags & UART_CLEAR_FIFO)		serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |					     UART_FCR_CLEAR_XMIT));	/*	 * At this point there's no way the LSR could still be 0xFF;	 * if it is, then bail out, because there's likely no UART	 * here.	 */	if (serial_inp(info, UART_LSR) == 0xff) {		if (capable(CAP_SYS_ADMIN)) {			if (info->tty)				set_bit(TTY_IO_ERROR, &info->tty->flags);		} else			retval = -ENODEV;		goto errout;	}	/*	 * Allocate the IRQ if necessary	 */	if (info->port_type != SU_PORT_PORT) {		retval = request_irq(info->irq, su_kbd_ms_interrupt,				     SA_SHIRQ, info->name, info);	} else {		retval = request_irq(info->irq, su_serial_interrupt,				     SA_SHIRQ, info->name, info);	}	if (retval) {		if (capable(CAP_SYS_ADMIN)) {			if (info->tty)				set_bit(TTY_IO_ERROR, &info->tty->flags);			retval = 0;		}		goto errout;	}	/*	 * Clear the interrupt registers.	 */	(void) serial_inp(info, UART_RX);	(void) serial_inp(info, UART_IIR);	(void) serial_inp(info, UART_MSR);	/*	 * Now, initialize the UART 	 */	serial_outp(info, UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */	info->MCR = 0;	if (info->tty && info->tty->termios->c_cflag & CBAUD)		info->MCR = UART_MCR_DTR | UART_MCR_RTS;	if (info->irq != 0)		info->MCR |= UART_MCR_OUT2;	serial_outp(info, UART_MCR, info->MCR);	/*	 * Finally, enable interrupts	 */	info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;	serial_outp(info, UART_IER, info->IER);	/* enable interrupts */	/*	 * And clear the interrupt registers again for luck.	 */	(void)serial_inp(info, UART_LSR);	(void)serial_inp(info, UART_RX);	(void)serial_inp(info, UART_IIR);	(void)serial_inp(info, UART_MSR);	if (info->tty)		clear_bit(TTY_IO_ERROR, &info->tty->flags);	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;	/*	 * Set up the tty->alt_speed kludge	 */	if (info->tty) {		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)			info->tty->alt_speed = 57600;		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)			info->tty->alt_speed = 115200;		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)			info->tty->alt_speed = 230400;		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)			info->tty->alt_speed = 460800;	}	/*	 * and set the speed of the serial port	 */	change_speed(info, 0);	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 voidshutdown(struct su_struct *info){	unsigned long	flags;	if (!(info->flags & ASYNC_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(&info->delta_msr_wait);		/*	 * Free the IRQ, if necessary	 */	free_irq(info->irq, info);	if (info->xmit_buf) {		free_page((unsigned long) info->xmit_buf);		info->xmit_buf = 0;	}	info->IER = 0;	serial_outp(info, UART_IER, 0x00);	/* disable all intrs */	info->MCR &= ~UART_MCR_OUT2;	/* disable break condition */	serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);	serial_outp(info, UART_MCR, info->MCR);	/* disable FIFO's */		serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |				     UART_FCR_CLEAR_XMIT));	(void)serial_in(info, UART_RX);    /* read data port to reset things */	if (info->tty)		set_bit(TTY_IO_ERROR, &info->tty->flags);	if (uart_config[info->type].flags & UART_STARTECH) {		/* Arrange to enter sleep mode */		serial_outp(info, UART_LCR, 0xBF);		serial_outp(info, UART_EFR, UART_EFR_ECB);		serial_outp(info, UART_IER, UART_IERX_SLEEP);		serial_outp(info, UART_LCR, 0);	}	if (info->type == PORT_16750) {		/* Arrange to enter sleep mode */		serial_outp(info, UART_IER, UART_IERX_SLEEP);	}	info->flags &= ~ASYNC_INITIALIZED;	restore_flags(flags);}static intsu_get_baud_rate(struct su_struct *info){	static struct tty_struct c_tty;	static struct termios c_termios;	if (info->tty)		return tty_get_baud_rate(info->tty);	memset(&c_tty, 0, sizeof(c_tty));	memset(&c_termios, 0, sizeof(c_termios));	c_tty.termios = &c_termios;	c_termios.c_cflag = info->cflag;	return tty_get_baud_rate(&c_tty);}/* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */static voidchange_speed(struct su_struct *info,	     struct termios *old_termios){	int		quot = 0, baud;	unsigned int	cval, fcr = 0;	int		bits;	unsigned long	flags;	if (info->port_type == SU_PORT_PORT) {		if (!info->tty || !info->tty->termios)			return;		if (!info->port)			return;		info->cflag = info->tty->termios->c_cflag;	}	/* byte size and parity */	switch (info->cflag & CSIZE) {	      case CS5: cval = 0x00; bits = 7; break;	      case CS6: cval = 0x01; bits = 8; break;	      case CS7: cval = 0x02; bits = 9; break;	      case CS8: cval = 0x03; bits = 10; break;		/* Never happens, but GCC is too dumb to figure it out */	      default:  cval = 0x00; bits = 7; break;	}	if (info->cflag & CSTOPB) {		cval |= 0x04;		bits++;	}	if (info->cflag & PARENB) {		cval |= UART_LCR_PARITY;		bits++;	}	if (!(info->cflag & PARODD))		cval |= UART_LCR_EPAR;#ifdef CMSPAR	if (info->cflag & CMSPAR)		cval |= UART_LCR_SPAR;#endif	/* Determine divisor based on baud rate */	baud = su_get_baud_rate(info);	if (baud == 38400 &&	    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))		quot = info->custom_divisor;	else {		if (baud == 134)			/* Special case since 134 is really 134.5 */			quot = (2 * info->baud_base / 269);

⌨️ 快捷键说明

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