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

📄 specialix.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
	unsigned long flags;		board = SX_BOARD(MINOR(tty->device));	if (board > SX_NBOARD || !(sx_board[board].flags & SX_BOARD_PRESENT))		return -ENODEV;		bp = &sx_board[board];	port = sx_port + board * SX_NPORT + SX_PORT(MINOR(tty->device));#ifdef DEBUG_SPECIALIX	printk (KERN_DEBUG "Board = %d, bp = %p, port = %p, portno = %d.\n", 	        board, bp, port, SX_PORT(MINOR(tty->device)));#endif	if (sx_paranoia_check(port, tty->device, "sx_open"))		return -ENODEV;	if ((error = sx_setup_board(bp)))		return error;	port->count++;	tty->driver_data = port;	port->tty = tty;	if ((error = sx_setup_port(bp, port))) 		return error;		if ((error = block_til_ready(tty, filp, port)))		return error;	if ((port->count == 1) && (port->flags & ASYNC_SPLIT_TERMIOS)) {		if (tty->driver.subtype == SPECIALIX_TYPE_NORMAL)			*tty->termios = port->normal_termios;		else			*tty->termios = port->callout_termios;		save_flags(flags); cli();		sx_change_speed(bp, port);		restore_flags(flags);	}	port->session = current->session;	port->pgrp = current->pgrp;	return 0;}static void sx_close(struct tty_struct * tty, struct file * filp){	struct specialix_port *port = (struct specialix_port *) tty->driver_data;	struct specialix_board *bp;	unsigned long flags;	unsigned long timeout;		if (!port || sx_paranoia_check(port, tty->device, "close"))		return;		save_flags(flags); cli();	if (tty_hung_up_p(filp)) {		restore_flags(flags);		return;	}		bp = port_Board(port);	if ((tty->count == 1) && (port->count != 1)) {		printk(KERN_ERR "sx%d: sx_close: bad port count;"		       " tty->count is 1, port count is %d\n",		       board_No(bp), port->count);		port->count = 1;	}	if (--port->count < 0) {		printk(KERN_ERR "sx%d: sx_close: bad port count for tty%d: %d\n",		       board_No(bp), port_No(port), port->count);		port->count = 0;	}	if (port->count) {		restore_flags(flags);		return;	}	port->flags |= ASYNC_CLOSING;	/*	 * Save the termios structure, since this port may have	 * separate termios for callout and dialin.	 */	if (port->flags & ASYNC_NORMAL_ACTIVE)		port->normal_termios = *tty->termios;	if (port->flags & ASYNC_CALLOUT_ACTIVE)		port->callout_termios = *tty->termios;	/*	 * Now we wait for the transmit buffer to clear; and we notify 	 * the line discipline to only process XON/XOFF characters.	 */	tty->closing = 1;	if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)		tty_wait_until_sent(tty, port->closing_wait);	/*	 * At this point we stop accepting input.  To do this, we	 * disable the receive line status interrupts, and tell the	 * interrupt driver to stop checking the data ready bit in the	 * line status register.	 */	port->IER &= ~IER_RXD;	if (port->flags & ASYNC_INITIALIZED) {		port->IER &= ~IER_TXRDY;		port->IER |= IER_TXEMPTY;		sx_out(bp, CD186x_CAR, port_No(port));		sx_out(bp, CD186x_IER, port->IER);		/*		 * Before we drop DTR, make sure the UART transmitter		 * has completely drained; this is especially		 * important if there is a transmit FIFO!		 */		timeout = jiffies+HZ;		while(port->IER & IER_TXEMPTY) {			current->state = TASK_INTERRUPTIBLE; 			schedule_timeout(port->timeout);			if (time_after(jiffies, timeout)) {				printk (KERN_INFO "Timeout waiting for close\n");				break;			}		}	}	sx_shutdown_port(bp, port);	if (tty->driver.flush_buffer)		tty->driver.flush_buffer(tty);	if (tty->ldisc.flush_buffer)		tty->ldisc.flush_buffer(tty);	tty->closing = 0;	port->event = 0;	port->tty = 0;	if (port->blocked_open) {		if (port->close_delay) {			current->state = TASK_INTERRUPTIBLE;			schedule_timeout(port->close_delay);		}		wake_up_interruptible(&port->open_wait);	}	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|			 ASYNC_CLOSING);	wake_up_interruptible(&port->close_wait);	restore_flags(flags);}static int sx_write(struct tty_struct * tty, int from_user,                     const unsigned char *buf, int count){	struct specialix_port *port = (struct specialix_port *)tty->driver_data;	struct specialix_board *bp;	int c, total = 0;	unsigned long flags;					if (sx_paranoia_check(port, tty->device, "sx_write"))		return 0;		bp = port_Board(port);	if (!tty || !port->xmit_buf || !tmp_buf)		return 0;	if (from_user)		down(&tmp_buf_sem);	save_flags(flags);	while (1) {		cli();				c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,		                   SERIAL_XMIT_SIZE - port->xmit_head));		if (c <= 0)			break;		if (from_user) {			copy_from_user(tmp_buf, buf, c);			c = MIN(c, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,			               SERIAL_XMIT_SIZE - port->xmit_head));			memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c);		} else			memcpy(port->xmit_buf + port->xmit_head, buf, c);		port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);		port->xmit_cnt += c;		restore_flags(flags);		buf += c;		count -= c;		total += c;	}	if (from_user)		up(&tmp_buf_sem);	if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&	    !(port->IER & IER_TXRDY)) {		port->IER |= IER_TXRDY;		sx_out(bp, CD186x_CAR, port_No(port));		sx_out(bp, CD186x_IER, port->IER);	}	restore_flags(flags);	return total;}static void sx_put_char(struct tty_struct * tty, unsigned char ch){	struct specialix_port *port = (struct specialix_port *)tty->driver_data;	unsigned long flags;	if (sx_paranoia_check(port, tty->device, "sx_put_char"))		return;	if (!tty || !port->xmit_buf)		return;	save_flags(flags); cli();		if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {		restore_flags(flags);		return;	}	port->xmit_buf[port->xmit_head++] = ch;	port->xmit_head &= SERIAL_XMIT_SIZE - 1;	port->xmit_cnt++;	restore_flags(flags);}static void sx_flush_chars(struct tty_struct * tty){	struct specialix_port *port = (struct specialix_port *)tty->driver_data;	unsigned long flags;					if (sx_paranoia_check(port, tty->device, "sx_flush_chars"))		return;		if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||	    !port->xmit_buf)		return;	save_flags(flags); cli();	port->IER |= IER_TXRDY;	sx_out(port_Board(port), CD186x_CAR, port_No(port));	sx_out(port_Board(port), CD186x_IER, port->IER);	restore_flags(flags);}static int sx_write_room(struct tty_struct * tty){	struct specialix_port *port = (struct specialix_port *)tty->driver_data;	int	ret;					if (sx_paranoia_check(port, tty->device, "sx_write_room"))		return 0;	ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;	if (ret < 0)		ret = 0;	return ret;}static int sx_chars_in_buffer(struct tty_struct *tty){	struct specialix_port *port = (struct specialix_port *)tty->driver_data;					if (sx_paranoia_check(port, tty->device, "sx_chars_in_buffer"))		return 0;		return port->xmit_cnt;}static void sx_flush_buffer(struct tty_struct *tty){	struct specialix_port *port = (struct specialix_port *)tty->driver_data;	unsigned long flags;					if (sx_paranoia_check(port, tty->device, "sx_flush_buffer"))		return;	save_flags(flags); cli();	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;	restore_flags(flags);		wake_up_interruptible(&tty->write_wait);	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&	    tty->ldisc.write_wakeup)		(tty->ldisc.write_wakeup)(tty);}static int sx_get_modem_info(struct specialix_port * port, unsigned int *value){	struct specialix_board * bp;	unsigned char status;	unsigned int result;	unsigned long flags;	bp = port_Board(port);	save_flags(flags); cli();	sx_out(bp, CD186x_CAR, port_No(port));	status = sx_in(bp, CD186x_MSVR);	restore_flags(flags);#ifdef DEBUG_SPECIALIX	printk (KERN_DEBUG "Got msvr[%d] = %02x, car = %d.\n", 		port_No(port), status, sx_in (bp, CD186x_CAR));	printk (KERN_DEBUG "sx_port = %p, port = %p\n", sx_port, port);#endif	if (SX_CRTSCTS(port->tty)) {		result  = /*   (status & MSVR_RTS) ? */ TIOCM_DTR /* : 0) */ 		          |   ((status & MSVR_DTR) ? TIOCM_RTS : 0)		          |   ((status & MSVR_CD)  ? TIOCM_CAR : 0)		          |/* ((status & MSVR_DSR) ? */ TIOCM_DSR /* : 0) */		          |   ((status & MSVR_CTS) ? TIOCM_CTS : 0);	} else {		result  = /*   (status & MSVR_RTS) ? */ TIOCM_RTS /* : 0) */ 		          |   ((status & MSVR_DTR) ? TIOCM_DTR : 0)		          |   ((status & MSVR_CD)  ? TIOCM_CAR : 0)		          |/* ((status & MSVR_DSR) ? */ TIOCM_DSR /* : 0) */		          |   ((status & MSVR_CTS) ? TIOCM_CTS : 0);	}	put_user(result,(unsigned int *) value);	return 0;}static int sx_set_modem_info(struct specialix_port * port, unsigned int cmd,                             unsigned int *value){	int error;	unsigned int arg;	unsigned long flags;	struct specialix_board *bp = port_Board(port);	error = verify_area(VERIFY_READ, value, sizeof(int));	if (error) 		return error;	Get_user(arg, (unsigned long *) value);	switch (cmd) {	case TIOCMBIS: 	   /*	if (arg & TIOCM_RTS) 			port->MSVR |= MSVR_RTS; */	   /*   if (arg & TIOCM_DTR)			port->MSVR |= MSVR_DTR; */		if (SX_CRTSCTS(port->tty)) {			if (arg & TIOCM_RTS)				port->MSVR |= MSVR_DTR; 		} else {			if (arg & TIOCM_DTR)				port->MSVR |= MSVR_DTR; 		}	     		break;	case TIOCMBIC:	  /*	if (arg & TIOCM_RTS)			port->MSVR &= ~MSVR_RTS; */	  /*    if (arg & TIOCM_DTR)			port->MSVR &= ~MSVR_DTR; */		if (SX_CRTSCTS(port->tty)) {			if (arg & TIOCM_RTS)				port->MSVR &= ~MSVR_DTR;		} else {			if (arg & TIOCM_DTR)				port->MSVR &= ~MSVR_DTR;		}		break;	case TIOCMSET:	  /* port->MSVR = (arg & TIOCM_RTS) ? (port->MSVR | MSVR_RTS) : 						 (port->MSVR & ~MSVR_RTS); */	  /* port->MSVR = (arg & TIOCM_DTR) ? (port->MSVR | MSVR_DTR) : 						 (port->MSVR & ~MSVR_DTR); */		if (SX_CRTSCTS(port->tty)) {	  		port->MSVR = (arg & TIOCM_RTS) ? 			                         (port->MSVR |  MSVR_DTR) : 			                         (port->MSVR & ~MSVR_DTR);		} else {			port->MSVR = (arg & TIOCM_DTR) ?			                         (port->MSVR |  MSVR_DTR):			                         (port->MSVR & ~MSVR_DTR);		}		break;	default:		return -EINVAL;	}	save_flags(flags); cli();	sx_out(bp, CD186x_CAR, port_No(port));	sx_out(bp, CD186x_MSVR, port->MSVR);	restore_flags(flags);	return 0;}extern inline void sx_send_break(struct specialix_port * port, unsigned long length){	struct specialix_board *bp = port_Board(port);	unsigned long flags;		save_flags(flags); cli();	port->break_length = SPECIALIX_TPS / HZ * length;	port->COR2 |= COR2_ETC;	port->IER  |= IER_TXRDY;	sx_out(bp, CD186x_CAR, port_No(port));	sx_out(bp, CD186x_COR2, port->COR2);	sx_out(bp, CD186x_IER, port->IER);	sx_wait_CCR(bp);	sx_out(bp, CD186x_CCR, CCR_CORCHG2);	sx_wait_CCR(bp);	restore_flags(flags);}extern inline int sx_set_serial_info(struct specialix_port * port,                                     struct serial_struct * newinfo){	struct serial_struct tmp;	struct specialix_board *bp = port_Board(port);	int change_speed;	unsigned long flags;	int error;		error = verify_area(VERIFY_READ, (void *) newinfo, sizeof(tmp));	if (error)		return error;	if (copy_from_user(&tmp, newinfo, sizeof(tmp)))		return -EFAULT;	#if 0		if ((tmp.irq != bp->irq) ||	    (tmp.port != bp->base) ||	    (tmp.type != PORT_CIRRUS) ||	    (tmp.baud_base != (SX_OSCFREQ + CD186x_TPC/2) / CD186x_TPC) ||	    (tmp.custom_divisor != 0) ||	    (tmp.xmit_fifo_size != CD186x_NFIFO) ||	    (tmp.flags & ~SPECIALIX_LEGAL_FLAGS))		return -EINVAL;#endif		change_speed = ((port->flags & ASYNC_SPD_MASK) !=			(tmp.flags & ASYNC_SPD_MASK));	change_speed |= (tmp.custom_divisor != port->custom_divisor);		if (!capable(CAP_SYS_ADMIN)) {		if ((tmp.close_delay != port->close_delay) ||		    (tmp.closing_wait != port->closing_wait) ||		    ((tmp.flags & ~ASYNC_USR_MASK) !=		     (port->flags & ~ASYNC_USR_MASK)))			return -EPERM;		port->flags = ((port->flags & ~ASYNC_USR_MASK) |		                  (tmp.flags & ASYNC_USR_MASK));		port->custom_divisor = tmp.custom_divisor;	} else {		port->flags = ((port->flags & ~ASYNC_FLAGS) |		                  (tmp.flags & ASYNC_FLAGS));		port->close_delay = tmp.close_delay;		port->closing_wait = tmp.closing_wait;		port->custom_divisor = tmp.custom_divisor;	}	if (change_speed) {		save_flags(flags); cli();		sx_change_speed(bp, port);		restore_flags(flags);	}	return 0;}extern inline int sx_get_serial_info(struct specialix_port * port,				     struct serial_struct * retinfo){	struct serial_struct tmp;	struct specialix_board *bp = port_Board(port);	int error;		error = verify_area(VERIFY_WRITE, (void *) retinfo, sizeof(tmp));	if (error)		return error;	memset(&tmp, 0, sizeof(tmp));	tmp.type = PORT_CIRRUS;	tmp.line = port - sx_port;	tmp.port = bp->base;	tmp.irq  = bp->irq;	tmp.flags = port->flags;	tmp.baud_base = (SX_OSCFREQ + CD186x_TPC/2) / CD186x_TPC;

⌨️ 快捷键说明

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