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

📄 trioserial.c

📁 arm平台上的uclinux系统全部源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		}		wake_up_interruptible(&info->open_wait);	}	info->flags &= ~(S_NORMAL_ACTIVE|S_CALLOUT_ACTIVE|			 S_CLOSING);	wake_up_interruptible(&info->close_wait);	restore_flags(flags);}/* * rs_hangup() --- called by tty_hangup() when a hangup is signaled. */void rs_hangup(struct tty_struct *tty){	struct trio_serial * info = (struct trio_serial *)tty->driver_data;		if (serial_paranoia_check(info, tty->device, "rs_hangup"))		return;		rs_flush_buffer(tty);	shutdown(info);	info->event = 0;	info->count = 0;	info->flags &= ~(S_NORMAL_ACTIVE|S_CALLOUT_ACTIVE);	info->tty = 0;	wake_up_interruptible(&info->open_wait);}/* * ------------------------------------------------------------ * rs_open() and friends * ------------------------------------------------------------ */static int block_til_ready(struct tty_struct *tty, struct file * filp,			   struct trio_serial *info){	struct wait_queue wait = { current, NULL };	int		retval;	int		do_clocal = 0;	/*	 * If the device is in the middle of being closed, then block	 * until it's done, and then try again.	 */	if (info->flags & S_CLOSING) {		interruptible_sleep_on(&info->close_wait);#ifdef SERIAL_DO_RESTART		if (info->flags & S_HUP_NOTIFY)			return -EAGAIN;		else			return -ERESTARTSYS;#else		return -EAGAIN;#endif	}	/*	 * If this is a callout device, then just make sure the normal	 * device isn't being used.	 */	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {		if (info->flags & S_NORMAL_ACTIVE)			return -EBUSY;		if ((info->flags & S_CALLOUT_ACTIVE) &&		    (info->flags & S_SESSION_LOCKOUT) &&		    (info->session != current->session))		    return -EBUSY;		if ((info->flags & S_CALLOUT_ACTIVE) &&		    (info->flags & S_PGRP_LOCKOUT) &&		    (info->pgrp != current->pgrp))		    return -EBUSY;		info->flags |= S_CALLOUT_ACTIVE;		return 0;	}		/*	 * 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 (info->flags & S_CALLOUT_ACTIVE)			return -EBUSY;		info->flags |= S_NORMAL_ACTIVE;		return 0;	}	if (info->flags & S_CALLOUT_ACTIVE) {		if (info->normal_termios.c_cflag & CLOCAL)			do_clocal = 1;	} else {		if (tty->termios->c_cflag & CLOCAL)			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, info->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(&info->open_wait, &wait);#ifdef SERIAL_DEBUG_OPEN	printk("block_til_ready before block: ttyS%d, count = %d\n",	       info->line, info->count);#endif	info->count--;	info->blocked_open++;	while (1) {		cli();		if (!(info->flags & S_CALLOUT_ACTIVE))			trio_rtsdtr(info, 1);		sti();		current->state = TASK_INTERRUPTIBLE;		if (tty_hung_up_p(filp) ||		    !(info->flags & S_INITIALIZED)) {#ifdef SERIAL_DO_RESTART			if (info->flags & S_HUP_NOTIFY)				retval = -EAGAIN;			else				retval = -ERESTARTSYS;	#else			retval = -EAGAIN;#endif			break;		}		if (!(info->flags & S_CALLOUT_ACTIVE) &&		    !(info->flags & S_CLOSING) && do_clocal)			break;		if (current->signal & ~current->blocked) {			retval = -ERESTARTSYS;			break;		}#ifdef SERIAL_DEBUG_OPEN		printk("block_til_ready blocking: ttyS%d, count = %d\n",		       info->line, info->count);#endif		schedule();	}	current->state = TASK_RUNNING;	remove_wait_queue(&info->open_wait, &wait);	if (!tty_hung_up_p(filp))		info->count++;	info->blocked_open--;#ifdef SERIAL_DEBUG_OPEN	printk("block_til_ready after blocking: ttyS%d, count = %d\n",	       info->line, info->count);#endif	if (retval)		return retval;	info->flags |= S_NORMAL_ACTIVE;	if(!info->use_ints){			serialpoll.data = (void *)info;				queue_task(&serialpoll, &tq_timer);	}	return 0;}	/* * This routine is called whenever a serial port is opened.  It * enables interrupts for a serial port, linking in its S structure into * the IRQ chain.   It also performs the serial-specific * initialization for the tty structure. */int rs_open(struct tty_struct *tty, struct file * filp){	struct trio_serial	*info;	int 			retval, line;	line = MINOR(tty->device) - tty->driver.minor_start;		if (line != 0) /* we have exactly one */		return -ENODEV;	info = &trio_info[0];#if 0	/* Is the kgdb running over this line? */	if (info->kgdb_channel)		return -ENODEV;#endif	if (serial_paranoia_check(info, tty->device, "rs_open"))		return -ENODEV;#ifdef SERIAL_DEBUG_OPEN	printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,	       info->count);#endif	info->count++;	tty->driver_data = info;	info->tty = tty;	/*	 * Start up serial port	 */	retval = startup(info);	if (retval)		return retval;		retval = block_til_ready(tty, filp, info);	if (retval) {#ifdef SERIAL_DEBUG_OPEN		printk("rs_open returning after block_til_ready with %d\n",		       retval);#endif		return retval;	}	if ((info->count == 1) && (info->flags & S_SPLIT_TERMIOS)) {		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)			*tty->termios = info->normal_termios;		else 			*tty->termios = info->callout_termios;		change_speed(info);	}	info->session = current->session;	info->pgrp = current->pgrp;#ifdef SERIAL_DEBUG_OPEN	printk("rs_open ttyS%d successful...\n", info->line);#endif	return 0;}extern void register_console(void (*proc)(const char *));#if 0static inline voidrs_cons_check(struct trio_serial *ss, int channel){	int i, o, io;	static consout_registered = 0;	static msg_printed = 0;	i = o = io = 0;	/* Is this one of the serial console lines? */	if((trio_cons_chanout != channel) &&	   (trio_cons_chanin != channel))		return;	trio_conschan = ss->trio_channel;	trio_consinfo = ss;	/* Register the console output putchar, if necessary */	if((trio_cons_chanout == channel)) {		o = 1;		/* double whee.. */		if(!consout_registered) {			register_console(trio_console_print);			consout_registered = 1;		}	}	/* If this is console input, we handle the break received	 * status interrupt on this line to mean prom_halt().	 */	if(trio_cons_chanin == channel) {		ss->break_abort = 1;		i = 1;	}	if(o && i)		io = 1;	if(ss->baud != 9600)		panic("Console baud rate weirdness");	/* Set flag variable for this port so that it cannot be	 * opened for other uses by accident.	 */	ss->is_cons = 1;	if(io) {		if(!msg_printed) {			printk("zs%d: console I/O\n", ((channel>>1)&1));			msg_printed = 1;		}	} else {		printk("zs%d: console %s\n", ((channel>>1)&1),		       (i==1 ? "input" : (o==1 ? "output" : "WEIRD")));	}}#endifstatic struct irqaction irq_usarta = { rs_interrupta, 0, 0, "usarta", NULL, NULL};static struct irqaction irq_usartb = { rs_interruptb, 0, 0, "usartb", NULL, NULL};extern int setup_arm_irq(int, struct irqaction *);void interrupts_init(void){	setup_arm_irq(IRQ_USARTA, &irq_usarta);	setup_arm_irq(IRQ_USARTB, &irq_usartb);}/* rs_init inits the driver */int rs_trio_init(void){	int flags,i;	struct trio_serial *info;	/* Setup base handler, and timer table. */	init_bh(SERIAL_BH, do_serial_bh);	timer_table[RS_TIMER].fn = rs_timer;	timer_table[RS_TIMER].expires = 0;	/* Initialize the tty_driver structure */		memset(&serial_driver, 0, sizeof(struct tty_driver));	serial_driver.magic = TTY_DRIVER_MAGIC;	serial_driver.name = "ttyS";	serial_driver.major = TTY_MAJOR;	serial_driver.minor_start = 64;	serial_driver.num = 1;	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;	serial_driver.subtype = SERIAL_TYPE_NORMAL;	serial_driver.init_termios = tty_std_termios;	serial_driver.init_termios.c_cflag =		B9600 | CS8 | CREAD | HUPCL | CLOCAL;	serial_driver.flags = TTY_DRIVER_REAL_RAW;	serial_driver.refcount = &serial_refcount;	serial_driver.table = serial_table;	serial_driver.termios = serial_termios;	serial_driver.termios_locked = serial_termios_locked;	serial_driver.open = rs_open;	serial_driver.close = rs_close;	serial_driver.write = rs_write;	serial_driver.flush_chars = rs_flush_chars;	serial_driver.write_room = rs_write_room;	serial_driver.chars_in_buffer = rs_chars_in_buffer;	serial_driver.flush_buffer = rs_flush_buffer;	serial_driver.ioctl = rs_ioctl;	serial_driver.throttle = rs_throttle;	serial_driver.unthrottle = rs_unthrottle;	serial_driver.set_termios = rs_set_termios;	serial_driver.stop = rs_stop;	serial_driver.start = rs_start;	serial_driver.hangup = rs_hangup;	serial_driver.set_ldisc = rs_set_ldisc;	/*	 * The callout device is just like normal device except for	 * major number and the subtype code.	 */	callout_driver = serial_driver;	callout_driver.name = "cua";	callout_driver.major = TTYAUX_MAJOR;	callout_driver.subtype = SERIAL_TYPE_CALLOUT;	if (tty_register_driver(&serial_driver))		panic("Couldn't register serial driver\n");	if (tty_register_driver(&callout_driver))		panic("Couldn't register callout driver\n");		save_flags(flags); cli();	i=0;	while(i<US_NB){		info = &trio_info[i];		info->magic = SERIAL_MAGIC;		info->uart = uarts[i];		info->tty = 0;		info->irqmask = (i)?AIC_UB:AIC_UA;		info->irq = (i)?IRQ_USARTB:IRQ_USARTA;		info->port = i+1;		set_ints_mode(0,info);		info->custom_divisor = 16;		info->close_delay = 50;		info->closing_wait = 3000;		info->x_char = 0;		info->event = 0;		info->count = 0;		info->blocked_open = 0;		info->tqueue.routine = do_softint;		info->tqueue.data = info;		info->tqueue_hangup.routine = do_serial_hangup;		info->tqueue_hangup.data = info;		info->callout_termios =callout_driver.init_termios;		info->normal_termios = serial_driver.init_termios;		info->open_wait = 0;		info->close_wait = 0;		info->line = 0;		info->is_cons = (i)?0:1; /* Means shortcuts work */		i++;	}	interrupts_init();	restore_flags(flags);// hack to do polling	serialpoll.routine = serpoll;	serialpoll.data = 0;		return 0;}/* * register_serial and unregister_serial allows for serial ports to be * configured at run-time, to support PCMCIA modems. *//* SPARC: Unused at this time, just here to make things link. */int register_serial(struct serial_struct *req){	return -1;}void unregister_serial(int line){	return;}#if 0/* Hooks for running a serial console.  con_init() calls this if the * console is being run over one of the ttya/ttyb serial ports. * 'chip' should be zero, as chip 1 drives the mouse/keyboard. * 'channel' is decoded as 0=TTYA 1=TTYB, note that the channels * are addressed backwards, channel B is first, then channel A. */voidrs_cons_hook(int chip, int out, int channel){	if(chip)		panic("rs_cons_hook called with chip not zero");	if(!trio_chips[chip]) {		trio_chips[chip] = get_zs(chip);		/* Two channels per chip */		trio_channels[(chip*2)] = &trio_chips[chip]->channelA;		trio_channels[(chip*2)+1] = &trio_chips[chip]->channelB;	}	trio_info[channel].trio_channel = trio_channels[channel];	trio_info[channel].change_needed = 0;	trio_info[channel].clk_divisor = 16;	trio_info[channel].trio_baud = get_zsbaud(&trio_info[channel]);	rs_cons_check(&trio_info[channel], channel);	if(out)		trio_cons_chanout = ((chip * 2) + channel);	else		trio_cons_chanin = ((chip * 2) + channel);}/* This is called at boot time to prime the kgdb serial debugging * serial line.  The 'tty_num' argument is 0 for /dev/ttya and 1 * for /dev/ttyb which is determined in setup_arch() from the * boot command line flags. */voidrs_kgdb_hook(int tty_num){	int chip = 0;	if(!trio_chips[chip]) {		trio_chips[chip] = get_zs(chip);		/* Two channels per chip */		trio_channels[(chip*2)] = &trio_chips[chip]->channelA;		trio_channels[(chip*2)+1] = &trio_chips[chip]->channelB;	}	trio_info[tty_num].trio_channel = trio_channels[tty_num];	trio_kgdbchan = trio_info[tty_num].trio_channel;	trio_info[tty_num].change_needed = 0;	trio_info[tty_num].clk_divisor = 16;	trio_info[tty_num].trio_baud = get_zsbaud(&trio_info[tty_num]);	trio_info[tty_num].kgdb_channel = 1;     /* This runs kgdb */	trio_info[tty_num ^ 1].kgdb_channel = 0; /* This does not */	/* Turn on transmitter/receiver at 8-bits/char */	kgdb_chaninit(&trio_info[tty_num], 0, 9600);	ZS_CLEARERR(trio_kgdbchan);	udelay(5);	ZS_CLEARFIFO(trio_kgdbchan);}#endif

⌨️ 快捷键说明

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