rocket.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,368 行 · 第 1/5 页

C
2,368
字号
#ifdef ROCKET_DEBUG_THROTTLE	printk(KERN_INFO "throttle %s: %d....\n", tty->name,	       tty->ldisc.chars_in_buffer(tty));#endif	if (rocket_paranoia_check(info, "rp_throttle"))		return;	cp = &info->channel;	if (I_IXOFF(tty))		rp_send_xchar(tty, STOP_CHAR(tty));	sClrRTS(&info->channel);}static void rp_unthrottle(struct tty_struct *tty){	struct r_port *info = (struct r_port *) tty->driver_data;	CHANNEL_t *cp;#ifdef ROCKET_DEBUG_THROTTLE	printk(KERN_INFO "unthrottle %s: %d....\n", tty->name,	       tty->ldisc.chars_in_buffer(tty));#endif	if (rocket_paranoia_check(info, "rp_throttle"))		return;	cp = &info->channel;	if (I_IXOFF(tty))		rp_send_xchar(tty, START_CHAR(tty));	sSetRTS(&info->channel);}/* * ------------------------------------------------------------ * rp_stop() and rp_start() * * This routines are called before setting or resetting tty->stopped. * They enable or disable transmitter interrupts, as necessary. * ------------------------------------------------------------ */static void rp_stop(struct tty_struct *tty){	struct r_port *info = (struct r_port *) tty->driver_data;#ifdef ROCKET_DEBUG_FLOW	printk(KERN_INFO "stop %s: %d %d....\n", tty->name,	       info->xmit_cnt, info->xmit_fifo_room);#endif	if (rocket_paranoia_check(info, "rp_stop"))		return;	if (sGetTxCnt(&info->channel))		sDisTransmit(&info->channel);}static void rp_start(struct tty_struct *tty){	struct r_port *info = (struct r_port *) tty->driver_data;#ifdef ROCKET_DEBUG_FLOW	printk(KERN_INFO "start %s: %d %d....\n", tty->name,	       info->xmit_cnt, info->xmit_fifo_room);#endif	if (rocket_paranoia_check(info, "rp_stop"))		return;	sEnTransmit(&info->channel);	set_bit((info->aiop * 8) + info->chan,		(void *) &xmit_flags[info->board]);}/* * rp_wait_until_sent() --- wait until the transmitter is empty */static void rp_wait_until_sent(struct tty_struct *tty, int timeout){	struct r_port *info = (struct r_port *) tty->driver_data;	CHANNEL_t *cp;	unsigned long orig_jiffies;	int check_time, exit_time;	int txcnt;	if (rocket_paranoia_check(info, "rp_wait_until_sent"))		return;	cp = &info->channel;	orig_jiffies = jiffies;#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT	printk(KERN_INFO "In RP_wait_until_sent(%d) (jiff=%lu)...", timeout,	       jiffies);	printk(KERN_INFO "cps=%d...", info->cps);#endif	while (1) {		txcnt = sGetTxCnt(cp);		if (!txcnt) {			if (sGetChanStatusLo(cp) & TXSHRMT)				break;			check_time = (HZ / info->cps) / 5;		} else {			check_time = HZ * txcnt / info->cps;		}		if (timeout) {			exit_time = orig_jiffies + timeout - jiffies;			if (exit_time <= 0)				break;			if (exit_time < check_time)				check_time = exit_time;		}		if (check_time == 0)			check_time = 1;#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT		printk(KERN_INFO "txcnt = %d (jiff=%lu,check=%d)...", txcnt, jiffies, check_time);#endif		current->state = TASK_INTERRUPTIBLE;		schedule_timeout(check_time);		if (signal_pending(current))			break;	}	current->state = TASK_RUNNING;#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT	printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies);#endif}/* * rp_hangup() --- called by tty_hangup() when a hangup is signaled. */static void rp_hangup(struct tty_struct *tty){	CHANNEL_t *cp;	struct r_port *info = (struct r_port *) tty->driver_data;	if (rocket_paranoia_check(info, "rp_hangup"))		return;#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP))	printk(KERN_INFO "rp_hangup of ttyR%d...", info->line);#endif	rp_flush_buffer(tty);	if (info->flags & ROCKET_CLOSING)		return;	if (info->count) 		atomic_dec(&rp_num_ports_open);	clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);	info->count = 0;	info->flags &= ~ROCKET_NORMAL_ACTIVE;	info->tty = NULL;	cp = &info->channel;	sDisRxFIFO(cp);	sDisTransmit(cp);	sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));	sDisCTSFlowCtl(cp);	sDisTxSoftFlowCtl(cp);	sClrTxXOFF(cp);	info->flags &= ~ROCKET_INITIALIZED;	wake_up_interruptible(&info->open_wait);}/* *  Exception handler - write char routine.  The RocketPort driver uses a *  double-buffering strategy, with the twist that if the in-memory CPU *  buffer is empty, and there's space in the transmit FIFO, the *  writing routines will write directly to transmit FIFO. *  Write buffer and counters protected by spinlocks */static void rp_put_char(struct tty_struct *tty, unsigned char ch){	struct r_port *info = (struct r_port *) tty->driver_data;	CHANNEL_t *cp;	unsigned long flags;	if (rocket_paranoia_check(info, "rp_put_char"))		return;	/*  Grab the port write semaphore, locking out other processes that try to write to this port */	down(&info->write_sem);#ifdef ROCKET_DEBUG_WRITE	printk(KERN_INFO "rp_put_char %c...", ch);#endif	spin_lock_irqsave(&info->slock, flags);	cp = &info->channel;	if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0)		info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);	if (tty->stopped || tty->hw_stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) {		info->xmit_buf[info->xmit_head++] = ch;		info->xmit_head &= XMIT_BUF_SIZE - 1;		info->xmit_cnt++;		set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);	} else {		sOutB(sGetTxRxDataIO(cp), ch);		info->xmit_fifo_room--;	}	spin_unlock_irqrestore(&info->slock, flags);	up(&info->write_sem);}/* *  Exception handler - write routine, called when user app writes to the device. *  A per port write semaphore is used to protect from another process writing to *  this port at the same time.  This other process could be running on the other CPU *  or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out).  *  Spinlocks protect the info xmit members. */static int rp_write(struct tty_struct *tty, int from_user,		    const unsigned char *buf, int count){	struct r_port *info = (struct r_port *) tty->driver_data;	CHANNEL_t *cp;	const unsigned char *b;	int c, retval = 0;	unsigned long flags;	if (count <= 0 || rocket_paranoia_check(info, "rp_write"))		return 0;	down_interruptible(&info->write_sem);#ifdef ROCKET_DEBUG_WRITE	printk(KERN_INFO "rp_write %d chars...", count);#endif	cp = &info->channel;	if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room < count)		info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);        /*	 *  If the write queue for the port is empty, and there is FIFO space, stuff bytes 	 *  into FIFO.  Use the write queue for temp storage.         */	if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) {		c = min(count, info->xmit_fifo_room);		b = buf;		if (from_user) {			if (copy_from_user(info->xmit_buf, buf, c)) {				retval = -EFAULT;				goto end;			}			if (info->tty == 0)				goto end;			b = info->xmit_buf;			c = min(c, info->xmit_fifo_room);		}		/*  Push data into FIFO, 2 bytes at a time */		sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) b, c / 2);		/*  If there is a byte remaining, write it */		if (c & 1)			sOutB(sGetTxRxDataIO(cp), b[c - 1]);		retval += c;		buf += c;		count -= c;		spin_lock_irqsave(&info->slock, flags);		info->xmit_fifo_room -= c;		spin_unlock_irqrestore(&info->slock, flags);	}	/* If count is zero, we wrote it all and are done */	if (!count)		goto end;	/*  Write remaining data into the port's xmit_buf */	while (1) {		if (info->tty == 0)	/*   Seemingly obligatory check... */			goto end;		c = min(count, min(XMIT_BUF_SIZE - info->xmit_cnt - 1, XMIT_BUF_SIZE - info->xmit_head));		if (c <= 0)			break;		b = buf;		if (from_user) {			if (copy_from_user(info->xmit_buf + info->xmit_head, b, c)) {				retval = -EFAULT;				goto end_intr;			} else {				memcpy(info->xmit_buf + info->xmit_head, b, c);			}		}		spin_lock_irqsave(&info->slock, flags);		info->xmit_head =		    (info->xmit_head + c) & (XMIT_BUF_SIZE - 1);		info->xmit_cnt += c;		spin_unlock_irqrestore(&info->slock, flags);		buf += c;		count -= c;		retval += c;	}end_intr:	if ((retval > 0) && !tty->stopped && !tty->hw_stopped)		set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);	end: 	if (info->xmit_cnt < WAKEUP_CHARS) { 		tty_wakeup(tty);		wake_up_interruptible(&tty->write_wait);#ifdef ROCKETPORT_HAVE_POLL_WAIT		wake_up_interruptible(&tty->poll_wait);#endif	}	up(&info->write_sem);	return retval;}/* * Return the number of characters that can be sent.  We estimate * only using the in-memory transmit buffer only, and ignore the * potential space in the transmit FIFO. */static int rp_write_room(struct tty_struct *tty){	struct r_port *info = (struct r_port *) tty->driver_data;	int ret;	if (rocket_paranoia_check(info, "rp_write_room"))		return 0;	ret = XMIT_BUF_SIZE - info->xmit_cnt - 1;	if (ret < 0)		ret = 0;#ifdef ROCKET_DEBUG_WRITE	printk(KERN_INFO "rp_write_room returns %d...", ret);#endif	return ret;}/* * Return the number of characters in the buffer.  Again, this only * counts those characters in the in-memory transmit buffer. */static int rp_chars_in_buffer(struct tty_struct *tty){	struct r_port *info = (struct r_port *) tty->driver_data;	CHANNEL_t *cp;	if (rocket_paranoia_check(info, "rp_chars_in_buffer"))		return 0;	cp = &info->channel;#ifdef ROCKET_DEBUG_WRITE	printk(KERN_INFO "rp_chars_in_buffer returns %d...", info->xmit_cnt);#endif	return info->xmit_cnt;}/* *  Flushes the TX fifo for a port, deletes data in the xmit_buf stored in the *  r_port struct for the port.  Note that spinlock are used to protect info members, *  do not call this function if the spinlock is already held. */static void rp_flush_buffer(struct tty_struct *tty){	struct r_port *info = (struct r_port *) tty->driver_data;	CHANNEL_t *cp;	unsigned long flags;	if (rocket_paranoia_check(info, "rp_flush_buffer"))		return;	spin_lock_irqsave(&info->slock, flags);	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;	spin_unlock_irqrestore(&info->slock, flags);	wake_up_interruptible(&tty->write_wait);#ifdef ROCKETPORT_HAVE_POLL_WAIT	wake_up_interruptible(&tty->poll_wait);#endif	tty_wakeup(tty);	cp = &info->channel;	sFlushTxFIFO(cp);}#ifdef CONFIG_PCI/* *  Called when a PCI card is found.  Retrieves and stores model information, *  init's aiopic and serial port hardware. *  Inputs:  i is the board number (0-n) */__init int register_PCI(int i, struct pci_dev *dev){	int num_aiops, aiop, max_num_aiops, num_chan, chan;	unsigned int aiopio[MAX_AIOPS_PER_BOARD];	char *str, *board_type;	CONTROLLER_t *ctlp;	int fast_clock = 0;	int altChanRingIndicator = 0;	int ports_per_aiop = 8;	int ret;	unsigned int class_rev;	WordIO_t ConfigIO = 0;	ByteIO_t UPCIRingInd = 0;	if (!dev || pci_enable_device(dev))		return 0;	rcktpt_io_addr[i] = pci_resource_start(dev, 0);	ret = pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);	if (ret) {		printk(KERN_INFO "  Error during register_PCI(), unable to read config dword \n");		return 0;	}	rcktpt_type[i] = ROCKET_TYPE_NORMAL;	rocketModel[i].loadrm2 = 0;	rocketModel[i].startingPortNumber = nextLineNumber;	/*  Depending on the model, set up some config variables */	switch (dev->device) {	case PCI_DEVICE_ID_RP4QUAD:		str = "Quadcable";		max_num_aiops = 1;		ports_per_aiop = 4;		rocketModel[i].model = MODEL_RP4QUAD;		strcpy(rocketModel[i].modelString, "RocketPort 4 port w/quad cable");		rocketModel[i].numPorts = 4;		break;	case PCI_DEVICE_ID_RP8OCTA:		str = "Octacable";		max_num_aiops = 1;		rocketModel[i].model = MODEL_RP8OCTA;		strcpy(rocketModel[i].modelString, "RocketPort 8 port w/octa cable");		rocketModel[i].numPorts = 8;		break;	case PCI_DEVICE_ID_URP8OCTA:		str = "Octacable";		max_num_aiops = 1;		rocketModel[i].model = MODEL_UPCI_RP8OCTA;		strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/octa cable");		rocketModel[i].numPorts = 8;		break;	case PCI_DEVICE_ID_RP8INTF:		str = "8";		max_num_aiops = 1;		rocketModel[i].model = MODEL_RP8INTF;		strcpy(rocketModel[i].modelString, "RocketPort 8 port w/external I/F");		rocketModel[i].numPorts = 8;		break;	case PCI_DEVICE_ID_URP8INTF:		str = "8";		max_num_aiops = 1;		rocketModel[i].model = MODEL_UPCI_RP8INTF;		strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/external I/F");		rocketModel[i].numPorts = 8;		break;	case PCI_DEVICE_ID_RP8J:		str = "8J";		max_num_aiops = 1;		rocketModel[i].model = MODEL_RP8J;		strcpy(rocketModel[i].modelString, "RocketPort 8 port w/RJ11 connectors");		rocketModel[i].numPorts = 8;		break;	case PCI_DEVICE_ID_RP4J:

⌨️ 快捷键说明

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