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

📄 generic_serial.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 2 页
字号:
	struct gs_port   *port;	func_enter ();	if (!tty) return;	port = tty->driver_data;	tty = port->tty;	if (!tty) 		return;	gs_shutdown_port (port);	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE |GS_ACTIVE);	port->tty = NULL;	port->count = 0;	wake_up_interruptible(&port->open_wait);	func_exit ();}void gs_do_softint(void *private_){	struct gs_port *port = private_;	struct tty_struct *tty;	func_enter ();	if (!port) return;	tty = port->tty;	if (!tty) return;	if (test_and_clear_bit(RS_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);	}	func_exit ();}int gs_block_til_ready(void *port_, struct file * filp){	struct gs_port *port = port_;	DECLARE_WAITQUEUE(wait, current);	int    retval;	int    do_clocal = 0;	int    CD;	struct tty_struct *tty;	func_enter ();	if (!port) return 0;	tty = port->tty;	if (!tty) return 0;	gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n"); 	/*	 * If the device is in the middle of being closed, then block	 * until it's done, and then try again.	 */	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {	  interruptible_sleep_on(&port->close_wait);		if (port->flags & ASYNC_HUP_NOTIFY)			return -EAGAIN;		else			return -ERESTARTSYS;	}	gs_dprintk (GS_DEBUG_BTR, "after hung up\n"); 	/*	 * If this is a callout device, then just make sure the normal	 * device isn't being used.	 */	if (tty->driver.subtype == GS_TYPE_CALLOUT) {		if (port->flags & ASYNC_NORMAL_ACTIVE)			return -EBUSY;		if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&		    (port->flags & ASYNC_SESSION_LOCKOUT) &&		    (port->session != current->session))			return -EBUSY;		if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&		    (port->flags & ASYNC_PGRP_LOCKOUT) &&		    (port->pgrp != current->pgrp))			return -EBUSY;		port->flags |= ASYNC_CALLOUT_ACTIVE;		return 0;	}	gs_dprintk (GS_DEBUG_BTR, "after subtype\n");	/*	 * If non-blocking mode is set, or the port is not enabled,	 * then make the check up front and then exit.	 */	if ((filp->f_flags & O_NONBLOCK) ||	    (tty->flags & (1 << TTY_IO_ERROR))) {		if (port->flags & ASYNC_CALLOUT_ACTIVE)			return -EBUSY;		port->flags |= ASYNC_NORMAL_ACTIVE;		return 0;	}	gs_dprintk (GS_DEBUG_BTR, "after nonblock\n");  	if (port->flags & ASYNC_CALLOUT_ACTIVE) {		if (port->normal_termios.c_cflag & CLOCAL) 			do_clocal = 1;	} else {		if (C_CLOCAL(tty))			do_clocal = 1;	}	/*	 * Block waiting for the carrier detect and the line to become	 * free (i.e., not in use by the callout).  While we are in	 * this loop, port->count is dropped by one, so that	 * rs_close() knows when to free things.  We restore it upon	 * exit, either normal or abnormal.	 */	retval = 0;	add_wait_queue(&port->open_wait, &wait);	gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); 	cli();	if (!tty_hung_up_p(filp))		port->count--;	sti();	port->blocked_open++;	while (1) {		CD = port->rd->get_CD (port);		gs_dprintk (GS_DEBUG_BTR, "CD is now %d.\n", CD);		set_current_state (TASK_INTERRUPTIBLE);		if (tty_hung_up_p(filp) ||		    !(port->flags & ASYNC_INITIALIZED)) {			if (port->flags & ASYNC_HUP_NOTIFY)				retval = -EAGAIN;			else				retval = -ERESTARTSYS;			break;		}		if (!(port->flags & ASYNC_CALLOUT_ACTIVE) &&		    !(port->flags & ASYNC_CLOSING) &&		    (do_clocal || CD))			break;		gs_dprintk (GS_DEBUG_BTR, "signal_pending is now: %d (%lx)\n", 		(int)signal_pending (current), *(long*)(&current->blocked)); 		if (signal_pending(current)) {			retval = -ERESTARTSYS;			break;		}		schedule();	}	gs_dprintk (GS_DEBUG_BTR, "Got out of the loop. (%d)\n",		    port->blocked_open);	set_current_state (TASK_RUNNING);	remove_wait_queue(&port->open_wait, &wait);	if (!tty_hung_up_p(filp))		port->count++;	port->blocked_open--;	if (retval)		return retval;	port->flags |= ASYNC_NORMAL_ACTIVE;	func_exit ();	return 0;}			 void gs_close(struct tty_struct * tty, struct file * filp){	unsigned long flags;	struct gs_port *port;	func_enter ();	if (!tty) return;	port = (struct gs_port *) tty->driver_data;	if (!port) return;	if (!port->tty) {		/* This seems to happen when this is called from vhangup. */		gs_dprintk (GS_DEBUG_CLOSE, "gs: Odd: port->tty is NULL\n");		port->tty = tty;	}	save_flags(flags); cli();	if (tty_hung_up_p(filp)) {		restore_flags(flags);		port->rd->hungup (port);		func_exit ();		return;	}	if ((tty->count == 1) && (port->count != 1)) {		printk(KERN_ERR "gs: gs_close: bad port count;"		       " tty->count is 1, port count is %d\n", port->count);		port->count = 1;	}	if (--port->count < 0) {		printk(KERN_ERR "gs: gs_close: bad port count: %d\n", port->count);		port->count = 0;	}	if (port->count) {		gs_dprintk(GS_DEBUG_CLOSE, "gs_close: count: %d\n", port->count);		restore_flags(flags);		func_exit ();		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->rd->disable_rx_interrupts (port);	/* close has no way of returning "EINTR", so discard return value */	if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)		gs_wait_tx_flushed (port, port->closing_wait); 	port->flags &= ~GS_ACTIVE;	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->rd->close (port);	port->rd->shutdown_port (port);	port->tty = 0;	if (port->blocked_open) {		if (port->close_delay) {			set_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 | ASYNC_INITIALIZED);	wake_up_interruptible(&port->close_wait);	restore_flags(flags);	func_exit ();}static unsigned int     gs_baudrates[] = {  0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,  9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600};void gs_set_termios (struct tty_struct * tty,                      struct termios * old_termios){	struct gs_port *port;	int baudrate, tmp, rv;	struct termios *tiosp;	func_enter();	if (!tty) return;	port = tty->driver_data;	if (!port) return;	tiosp = tty->termios;	if (gs_debug & GS_DEBUG_TERMIOS) {		gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp);	}#if 0	/* This is an optimization that is only allowed for dumb cards */	/* Smart cards require knowledge of iflags and oflags too: that 	   might change hardware cooking mode.... */#endif	if (old_termios) {		if(   (tiosp->c_iflag == old_termios->c_iflag)		   && (tiosp->c_oflag == old_termios->c_oflag)		   && (tiosp->c_cflag == old_termios->c_cflag)		   && (tiosp->c_lflag == old_termios->c_lflag)		   && (tiosp->c_line  == old_termios->c_line)		   && (memcmp(tiosp->c_cc, old_termios->c_cc, NCC) == 0)) {			gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: optimized away\n");			return /* 0 */;		}	} else 		gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: no old_termios: "		           "no optimization\n");	if(old_termios && (gs_debug & GS_DEBUG_TERMIOS)) {		if(tiosp->c_iflag != old_termios->c_iflag)  printk("c_iflag changed\n");		if(tiosp->c_oflag != old_termios->c_oflag)  printk("c_oflag changed\n");		if(tiosp->c_cflag != old_termios->c_cflag)  printk("c_cflag changed\n");		if(tiosp->c_lflag != old_termios->c_lflag)  printk("c_lflag changed\n");		if(tiosp->c_line  != old_termios->c_line)   printk("c_line changed\n");		if(!memcmp(tiosp->c_cc, old_termios->c_cc, NCC)) printk("c_cc changed\n");	}	baudrate = tiosp->c_cflag & CBAUD;	if (baudrate & CBAUDEX) {		baudrate &= ~CBAUDEX;		if ((baudrate < 1) || (baudrate > 4))			tiosp->c_cflag &= ~CBAUDEX;		else			baudrate += 15;	}	baudrate = gs_baudrates[baudrate];	if ((tiosp->c_cflag & CBAUD) == B38400) {		if (     (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)			baudrate = 57600;		else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)			baudrate = 115200;		else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)			baudrate = 230400;		else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)			baudrate = 460800;		else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)			baudrate = (port->baud_base / port->custom_divisor);	}	/* I recommend using THIS instead of the mess in termios (and	   duplicating the above code). Next we should create a clean	   interface towards this variable. If your card supports arbitrary	   baud rates, (e.g. CD1400 or 16550 based cards) then everything	   will be very easy..... */	port->baud = baudrate;	/* Two timer ticks seems enough to wakeup something like SLIP driver */	/* Baudrate/10 is cps. Divide by HZ to get chars per tick. */	tmp = (baudrate / 10 / HZ) * 2;			 	if (tmp <                 0) tmp = 0;	if (tmp >= SERIAL_XMIT_SIZE) tmp = SERIAL_XMIT_SIZE-1;	port->wakeup_chars = tmp;	/* We should really wait for the characters to be all sent before	   changing the settings. -- CAL */	rv = gs_wait_tx_flushed (port, MAX_SCHEDULE_TIMEOUT);	if (rv < 0) return /* rv */;	rv = port->rd->set_real_termios(port);	if (rv < 0) return /* rv */;	if ((!old_termios || 	     (old_termios->c_cflag & CRTSCTS)) &&	    !(      tiosp->c_cflag & CRTSCTS)) {		tty->stopped = 0;		gs_start(tty);	}#ifdef tytso_patch_94Nov25_1726	/* This "makes sense", Why is it commented out? */	if (!(old_termios->c_cflag & CLOCAL) &&	    (tty->termios->c_cflag & CLOCAL))		wake_up_interruptible(&info->open_wait);#endif	func_exit();	return /* 0 */;}/* Must be called with interrupts enabled */int gs_init_port(struct gs_port *port){	unsigned long flags;	unsigned long page;	save_flags (flags);	if (!tmp_buf) {		page = get_free_page(GFP_KERNEL);		cli (); /* Don't expect this to make a difference. */ 		if (tmp_buf)			free_page(page);		else			tmp_buf = (unsigned char *) page;		restore_flags (flags);		if (!tmp_buf) {			return -ENOMEM;		}	}	if (port->flags & ASYNC_INITIALIZED)		return 0;	if (!port->xmit_buf) {		/* We may sleep in get_free_page() */		unsigned long tmp;		tmp = get_free_page(GFP_KERNEL);		/* Spinlock? */		cli ();		if (port->xmit_buf) 			free_page (tmp);		else			port->xmit_buf = (unsigned char *) tmp;		restore_flags (flags);		if (!port->xmit_buf)			return -ENOMEM;	}	cli();	if (port->tty) 		clear_bit(TTY_IO_ERROR, &port->tty->flags);	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;	gs_set_termios(port->tty, NULL);	port->flags |= ASYNC_INITIALIZED;	port->flags &= ~GS_TX_INTEN;	restore_flags(flags);	return 0;}int gs_setserial(struct gs_port *port, struct serial_struct *sp){	struct serial_struct sio;	copy_from_user(&sio, sp, sizeof(struct serial_struct));	if (!capable(CAP_SYS_ADMIN)) {		if ((sio.baud_base != port->baud_base) ||		    (sio.close_delay != port->close_delay) ||		    ((sio.flags & ~ASYNC_USR_MASK) !=		     (port->flags & ~ASYNC_USR_MASK)))			return(-EPERM);	} 	port->flags = (port->flags & ~ASYNC_USR_MASK) |		(sio.flags & ASYNC_USR_MASK);  	port->baud_base = sio.baud_base;	port->close_delay = sio.close_delay;	port->closing_wait = sio.closing_wait;	port->custom_divisor = sio.custom_divisor;	gs_set_termios (port->tty, NULL);	return 0;}/*****************************************************************************//* *      Generate the serial struct info. */void gs_getserial(struct gs_port *port, struct serial_struct *sp){	struct serial_struct    sio;	memset(&sio, 0, sizeof(struct serial_struct));	sio.flags = port->flags;	sio.baud_base = port->baud_base;	sio.close_delay = port->close_delay;	sio.closing_wait = port->closing_wait;	sio.custom_divisor = port->custom_divisor;	sio.hub6 = 0;	/* If you want you can override these. */	sio.type = PORT_UNKNOWN;	sio.xmit_fifo_size = -1;	sio.line = -1;	sio.port = -1;	sio.irq = -1;	if (port->rd->getserial)		port->rd->getserial (port, &sio);	copy_to_user(sp, &sio, sizeof(struct serial_struct));}EXPORT_SYMBOL(gs_put_char);EXPORT_SYMBOL(gs_write);EXPORT_SYMBOL(gs_write_room);EXPORT_SYMBOL(gs_chars_in_buffer);EXPORT_SYMBOL(gs_flush_buffer);EXPORT_SYMBOL(gs_flush_chars);EXPORT_SYMBOL(gs_stop);EXPORT_SYMBOL(gs_start);EXPORT_SYMBOL(gs_hangup);EXPORT_SYMBOL(gs_do_softint);EXPORT_SYMBOL(gs_block_til_ready);EXPORT_SYMBOL(gs_close);EXPORT_SYMBOL(gs_set_termios);EXPORT_SYMBOL(gs_init_port);EXPORT_SYMBOL(gs_setserial);EXPORT_SYMBOL(gs_getserial);

⌨️ 快捷键说明

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