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

📄 serial_netarm.c

📁 这是一个SIGMA方案的PMP播放器的UCLINUX程序,可播放DVD,VCD,CD MP3...有很好的参考价值.
💻 C
📖 第 1 页 / 共 5 页
字号:
	return;}/* Write a number of characters (polled) */static intrs_write(struct tty_struct * tty, int from_user,         const unsigned char *buf, int count){	struct netarm_async_struct *info = (struct netarm_async_struct *)tty->driver_data;	volatile netarm_serial_channel_t *regs;	unsigned int *buf32;	unsigned int *fifo;	unsigned char *bytefifo;	int acount;	int scount = 0;#ifdef	NAS_DEBUG_VERBOSE	printk(" rs_write: called with %d chars\n", count);#endif					if (serial_paranoia_check(info, tty->device, "rs_write"))		return 0;	if (!tty || !info->xmit.buf || !tmp_buf)		return 0;	regs = info->registers;	fifo = (unsigned int *)&(regs->fifo);	bytefifo = (unsigned char *)&(regs->fifo);	/* count to align */	acount = (4 - (((unsigned int)buf) & 0x3)) & 0x03;	if ( acount > count ) acount = count;	count -= acount;	/* word align */	if ( acount > 0 )	{		while ( acount > 0 )		{			NAS_TX_WAIT_RDY(regs);			*bytefifo = *buf;		      		buf++;	      		acount--;	      		scount++;		}  	}	buf32 = (unsigned int *)buf;	while ( count > 3 )  	{		NAS_TX_WAIT_RDY(regs);    		*fifo = *buf32;		buf32++;		count  -= 4;		scount += 4;	}	if ( count > 0 )  	{  		buf = (unsigned char *)buf32;  		while ( count > 0 )		{			NAS_TX_WAIT_RDY(regs);			*bytefifo = *buf;			buf++;			count--;			scount++;		}  	}	return scount;}static intrs_write_room(struct tty_struct *tty){	struct netarm_async_struct *info = (struct netarm_async_struct *)tty->driver_data;	if (serial_paranoia_check(info, tty->device, "rs_write_room"))		return 0;	return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);}static int rs_chars_in_buffer(struct tty_struct *tty){	struct netarm_async_struct *info = (struct netarm_async_struct *)tty->driver_data;					if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))		return 0;	return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);}/* not needed in polled output: */static void rs_flush_buffer(struct tty_struct *tty){	struct netarm_async_struct *info = (struct netarm_async_struct *)tty->driver_data;		serial_paranoia_check(info, tty->device, "rs_flush_buffer");	return;}/* * This function is used to send a high-priority XON/XOFF character to * the device */static voidrs_send_xchar(struct tty_struct *tty, char ch){	rs_put_char( tty, ch );}/* * ------------------------------------------------------------ * rs_throttle() *  * This routine is called by the upper-layer tty layer to signal that * incoming characters should be throttled. * ------------------------------------------------------------ */static voidrs_throttle(struct tty_struct * tty){	struct netarm_async_struct *info = (struct netarm_async_struct *)tty->driver_data;#ifdef SERIAL_DEBUG_THROTTLE	char	buf[64];		printk("throttle %s: %d....\n", tty_name(tty, buf),	       tty->ldisc.chars_in_buffer(tty));#endif	if (serial_paranoia_check(info, tty->device, "rs_throttle"))		return;		if (I_IXOFF(tty))		rs_send_xchar(tty, STOP_CHAR(tty));	if (tty->termios->c_cflag & CRTSCTS)		info->registers->ctrl_a &= ~NETARM_SER_CTLA_RTS_EN;}static voidrs_unthrottle(struct tty_struct * tty){	struct netarm_async_struct *info = (struct netarm_async_struct *)tty->driver_data;#ifdef SERIAL_DEBUG_THROTTLE	char	buf[64];		printk("unthrottle %s: %d....\n", tty_name(tty, buf),	       tty->ldisc.chars_in_buffer(tty));#endif	if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))		return;		if (I_IXOFF(tty)) {		if (info->x_char)			info->x_char = 0;		else			rs_send_xchar(tty, START_CHAR(tty));	}	if (tty->termios->c_cflag & CRTSCTS)		info->registers->ctrl_a |= NETARM_SER_CTLA_RTS_EN;}/* * ------------------------------------------------------------ * rs_ioctl() and friends * ------------------------------------------------------------ */static intget_serial_info(struct netarm_async_struct * info, struct serial_struct * retinfo){	struct serial_struct tmp;	struct serial_state *state = info->state;   	if (!retinfo)		return -EFAULT;	memset(&tmp, 0, sizeof(tmp));	tmp.type = state->type;	tmp.line = state->line;	tmp.port = state->port;	if (HIGH_BITS_OFFSET)		tmp.port_high = state->port >> HIGH_BITS_OFFSET;	else		tmp.port_high = 0;	tmp.irq = state->irq;	tmp.flags = state->flags;	tmp.xmit_fifo_size = state->xmit_fifo_size;	tmp.baud_base = state->baud_base;	tmp.close_delay = state->close_delay;	tmp.closing_wait = state->closing_wait;	tmp.custom_divisor = state->custom_divisor;	tmp.hub6 = state->hub6;	tmp.io_type = state->io_type;	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))		return -EFAULT;	return 0;}static intset_serial_info(struct netarm_async_struct * info, struct serial_struct * new_info){	struct serial_struct new_serial; 	struct serial_state old_state, *state;	unsigned int		i,change_irq,change_port;	int 			retval = 0;	unsigned long		new_port;	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))		return -EFAULT;	state = info->state;	old_state = *state;	new_port = new_serial.port;	if (HIGH_BITS_OFFSET)		new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;	change_irq = new_serial.irq != state->irq;	change_port = (new_port != ((int) state->port)) ||		(new_serial.hub6 != state->hub6);  	if (!capable(CAP_SYS_ADMIN)) {		if (change_irq || change_port ||		    (new_serial.baud_base != state->baud_base) ||		    (new_serial.type != state->type) ||		    (new_serial.close_delay != state->close_delay) ||		    (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||		    ((new_serial.flags & ~ASYNC_USR_MASK) !=		     (state->flags & ~ASYNC_USR_MASK)))			return -EPERM;		state->flags = ((state->flags & ~ASYNC_USR_MASK) |			       (new_serial.flags & ASYNC_USR_MASK));		info->flags = ((info->flags & ~ASYNC_USR_MASK) |			       (new_serial.flags & ASYNC_USR_MASK));		state->custom_divisor = new_serial.custom_divisor;		goto check_and_exit;	}	new_serial.irq = irq_cannonicalize(new_serial.irq);	if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) || 	    (new_serial.baud_base < 9600)|| (new_serial.type != PORT_NETARM))	{		return -EINVAL;	}	if (new_serial.type == PORT_NETARM)		new_serial.xmit_fifo_size = NETARM_SER_FIFO_SIZE;	/* Make sure address is not already in use */	if (new_serial.type) {		for (i = 0 ; i < NR_NAS_PORTS; i++)			if ((state != &rs_table[i]) &&			    (rs_table[i].port == new_port) &&			    rs_table[i].type)				return -EADDRINUSE;	}	if ((change_port || change_irq) && (state->count > 1))		return -EBUSY;	/*	 * OK, past this point, all the error checking has been done.	 * At this point, we start making changes.....	 */	state->baud_base = new_serial.baud_base;	state->flags = ((state->flags & ~ASYNC_FLAGS) |			(new_serial.flags & ASYNC_FLAGS));	info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |		       (info->flags & ASYNC_INTERNAL_FLAGS));	state->custom_divisor = new_serial.custom_divisor;	state->close_delay = new_serial.close_delay * HZ/100;	state->closing_wait = new_serial.closing_wait * HZ/100;#if (LINUX_VERSION_CODE > 0x20100)	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;#endif	info->xmit_fifo_size = state->xmit_fifo_size =		new_serial.xmit_fifo_size;	if ((state->type != PORT_UNKNOWN) && state->port) {		release_region(state->port,8);	}	state->type = new_serial.type;	if (change_port || change_irq) {		/*		 * We need to shutdown the serial port at the old		 * port/irq combination.		 */		shutdown(info);		state->irq = new_serial.irq;		info->port = state->port = new_port;	}	if ((state->type != PORT_UNKNOWN) && state->port) {		request_region(state->port,8,"serial(set)");	}	check_and_exit:	if (!state->port || !state->type)		return 0;	if (info->flags & ASYNC_INITIALIZED) {		if (((old_state.flags & ASYNC_SPD_MASK) !=		     (state->flags & ASYNC_SPD_MASK)) ||		    (old_state.custom_divisor != state->custom_divisor)) {			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)				info->tty->alt_speed = 57600;			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)				info->tty->alt_speed = 115200;			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)				info->tty->alt_speed = 230400;			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)				info->tty->alt_speed = 460800;			change_speed(info, 0);		}	} else		retval = startup(info);	return retval;}/* * get_lsr_info - get line status register info * * Purpose: Let user call ioctl() to get info when the UART physically * 	    is emptied.  On bus types like RS485, the transmitter must * 	    release the bus after transmitting. This must be done when * 	    the transmit shift register is empty, not be done when the * 	    transmit holding register is empty.  This functionality * 	    allows an RS485 driver to be written in user space.  */static intget_lsr_info(struct netarm_async_struct * info, unsigned int *value){	unsigned char status;	unsigned int result;	unsigned long flags;	save_flags(flags); cli();	status = info->registers->status_a;	restore_flags(flags);	result = ((status & NETARM_SER_STATA_TX_FULL) ? TIOCSER_TEMT : 0);	/*	 * If we're about to load something into the transmit	 * register, we'll pretend the transmitter isn't empty to	 * avoid a race condition (depending on when the transmit	 * interrupt happens).	 */	if (info->x_char || 	    ((CIRC_CNT(info->xmit.head, info->xmit.tail,		       SERIAL_XMIT_SIZE) > 0) &&	     !info->tty->stopped && !info->tty->hw_stopped))		result &= TIOCSER_TEMT;	if (copy_to_user(value, &result, sizeof(int)))		return -EFAULT;	return 0;}static intdo_autoconfig(struct netarm_async_struct * info){	if (!capable(CAP_SYS_ADMIN))		return -EPERM;		if (info->state->count > 1)		return -EBUSY;		shutdown(info);	autoconfig(info->state);	return startup(info);}/* * rs_break() --- routine which turns the break handling on or off */static voidrs_break(struct tty_struct *tty, int break_state){	struct netarm_async_struct * info = (struct netarm_async_struct *)tty->driver_data;	unsigned long flags, control;		if (serial_paranoia_check(info, tty->device, "rs_break"))		return;	if (!CONFIGURED_NAS_PORT(info))		return;	save_flags(flags); cli();	control = info->registers->ctrl_a;	if (break_state == -1)		control |= NETARM_SER_CTLA_BRK;	else		control &= ~NETARM_SER_CTLA_BRK;	info->registers->ctrl_a = control;	restore_flags(flags);}static intrs_ioctl(struct tty_struct *tty, struct file * file,         unsigned int cmd, unsigned long arg){	struct netarm_async_struct * info = (struct netarm_async_struct *)tty->driver_data;	struct async_icount cprev, cnow;	/* kernel counter temps */	struct serial_icounter_struct icount;	unsigned long flags, control;		if (serial_paranoia_check(info, tty->device, "rs_ioctl"))		return -ENODEV;	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {		if (tty->flags & (1 << TTY_IO_ERROR))		    return -EIO;	}		switch (cmd) {/*		case TIOCMGET:			return get_modem_info(info, (unsigned int *) arg);		case TIOCMBIS:		case TIOCMBIC:		case TIOCMSET:			return set_modem_info(info, cmd, (unsigned int *) arg);*/		case TIOCGSERIAL:			return get_serial_info(info,					       (struct serial_struct *) arg);		case TIOCSSERIAL:			return set_serial_info(info,					       (struct serial_struct *) arg);		case TIOCSERCONFIG:			return do_autoconfig(info);		case TIOCSERGETLSR: /* Get line status register */			return get_lsr_info(info, (unsigned int *) arg);		case TIOCSERGSTRUCT:			if (copy_to_user((struct netarm_async_struct *) arg,					 info, sizeof(struct netarm_async_struct)))				return -EFAULT;			return 0;									/*		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change		 * - mask passed in arg for lines of interest 		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)		 * Caller should use TIOCGICOUNT to see which one it was		 */		case TIOCMIWAIT:			save_flags(flags); cli();			/* note the counters on entry */			cprev = info->state->icount;			restore_flags(flags);			/* Force modem status interrupts on */			control = info->registers->ctrl_a;			control |= NETARM_SER_CTLA_IE_RX_DCD |			           NETARM_SER_CTLA_IE_RX_RI |				   NETARM_SER_CTLA_IE_RX_DSR |				   NETARM_SER_CTLA_IE_TX_CTS;			info->registers->ctrl_a = control;			while (1)			{				interruptible_sleep_on(&info->delta_msr_wait);				/* see if a signal did it */				if (signal_pending(current))					return -ERESTARTSYS;				save_flags(flags); cli();				cnow = info->state->icount; /* atomic copy */				restore_flags(flags);				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)					return -EIO; /* no change => error */				if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||				     ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||				     ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||				     ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {					return 0;				}				cprev = cnow;			}			/* NOTREACHED */		/* 		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)		 * Return: write counters to the user passed counter struct		 * NB: both 1->0 and 0->1 transitions are counted except for		 *     RI where only 0->1 is counted.		 */

⌨️ 快捷键说明

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