static int citty_ioctl_tiocgicount(struct tty_struct *tty, struct file *file,
				   unsigned int cmd, unsigned long arg)
{
	struct citty_port *citty = tty->driver_data;

	F_ENTER();
	if (cmd == TIOCGICOUNT) {
		struct async_icount cnow = citty->icount;
		struct serial_icounter_struct icount;

		icount.cts      = cnow.cts;
		icount.dsr      = cnow.dsr;
		icount.rng      = cnow.rng;
		icount.dcd      = cnow.dcd;
		icount.rx       = cnow.rx;
		icount.tx       = cnow.tx;
		icount.frame    = cnow.frame;
		icount.overrun  = cnow.overrun;
		icount.parity   = cnow.parity;
		icount.brk      = cnow.brk;
		icount.buf_overrun = cnow.buf_overrun;

		if (copy_to_user((void __user *)arg, &icount, sizeof(icount)))
			return -EFAULT;
		return 0;
	}

	F_LEAVE();
	return -ENOIOCTLCMD;
}
static void citty_close(struct tty_struct *tty, struct file *file)
{
	struct citty_port *citty = NULL;
	int index = tty->index;

	F_ENTER();

	down(&sem_lock_tty[index]);
	citty = citty_table[index];
	/* Modified by Rovin Yu: release citty and related resource */
	if (citty) {
		if (!citty->port->count) {
			/* port was never opened */
			goto exit;
		}
		--citty->port->count;
		PDEBUG("citty_close: index is %d, count is %d\n",
				index, citty->port->count);
		if (citty->port->count <= 0) {
			citty_table[index] = NULL;
			kfree(citty);
		}
	}
exit:
	up(&sem_lock_tty[index]);
	F_LEAVE();
}
/* the real citty_ioctl function.
 * The above is done to get the small functions*/
static int citty_ioctl(struct tty_struct *tty,
		       unsigned int cmd, unsigned long arg)
{
	struct file *file = NULL;
	F_ENTER();

	switch (cmd) {
	case TIOCGSERIAL:
		return citty_ioctl_tiocgserial(tty, file, cmd, arg);
	case TIOCMIWAIT:
		return citty_ioctl_tiocmiwait(tty, file, cmd, arg);
	case TIOCGICOUNT:
		return citty_ioctl_tiocgicount(tty, file, cmd, arg);
	case TCSETS:
		return citty_ioctl_tcsets(tty, file, cmd, arg);
	case TCGETS:              /* 0x5401 ioctls.h */
		return citty_ioctl_tcgets(tty, file, cmd, arg);
	case TCSETSF:             /* 0x5404 */
	case TCSETAF:             /* 0x5408 */

		return 0;         /* has to return zero for qtopia to work */
	default:
		PDEBUG("citty_ioctl cmd: %d.\n", cmd);
		return -ENOIOCTLCMD;           /* for PPPD to work? */

		break;
	}

	F_LEAVE();

}
int cctdev_open(struct inode *inode, struct file *filp)
{
	struct cctdev_dev *dev;	/* device information */

	F_ENTER();

	dev = container_of(inode->i_cdev, struct cctdev_dev, cdev);

	filp->private_data = dev;	/* for other methods */

	/* now trim to 0 the length of the device if open was write-only */
	/*
	   if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) {

	   if (down_interruptible(&dev->sem))
	   return -ERESTARTSYS;

	   up(&dev->sem);
	   }
	 */

	/* used to keep track of how many readers */
	down(&dev->sem);
	if (filp->f_mode & FMODE_READ)
		dev->nreaders++;
	if (filp->f_mode & FMODE_WRITE)
		dev->nwriters++;
	up(&dev->sem);

	F_LEAVE();

	return nonseekable_open(inode, filp);	/* success */
}
static int citty_write_room(struct tty_struct *tty)
{
	struct citty_port *citty = NULL;
	int index = tty->index;
	int room = -EINVAL;

	F_ENTER();

	down(&sem_lock_tty[index]);
	citty = citty_table[index];
	if (!citty) {
		up(&sem_lock_tty[index]);
		return -ENODEV;
	}

	if (!citty->port->count) {
		PDEBUG("citty_write_room: no port is open.");
		/* port was not opened */
		goto exit;
	}

	/* calculate how much room is left in the device */
	/* CHECKPOINT */
	/* room = CITTY_BUF_SIZE * spacefree(  &txCittyBuf ); */
	room = CITTY_BUF_SIZE * spacefree(&txCittyBuf[tty->index]);

exit:
	up(&sem_lock_tty[index]);

	F_LEAVE();

	return room;
}
void cci_init_buffer(struct buf_struct *buffer)
{
	int i;

	F_ENTER();

	for (i = 0; i < NUM_CITTY_BUF; i++) {
		buffer->pBuf[i] = kmalloc(CITTY_BUF_SIZE, GFP_KERNEL);
		if (!buffer->pBuf[i])
			printk(KERN_ERR "Failed to allocate memory.\n");

		buffer->iBufIn = 0;
		buffer->iBufOut = 0;

	}

	sema_init(&(buffer->gSem), 1);

	/* init the queue */
	init_waitqueue_head(&(buffer->gInq));
	init_waitqueue_head(&(buffer->gOutq));

	F_LEAVE();

}
static void do_close(struct cidatatty_port *cidatatty)
{
	unsigned long flags;

	F_ENTER();

	down(&cidatatty->sem_lock_tty);
	spin_lock_irqsave(&cidatatty->port_lock, flags);
	if (!cidatatty->port.count) {
		/* port was never opened */
		goto exit;
	}

	--cidatatty->port.count;
	if (cidatatty->port.count <= 0) {
		/* The port is being closed by the last user. */
		/* Do any hardware specific stuff here */
		if (cidatatty->port.tty->index == PSDTTYINDEX)
			unregisterRxCallBack(PDP_PPP);
		else if (cidatatty->port.tty->index == CSDTTYINDEX)
			unregisterRxCallBack(CSD_RAW);
		else if (cidatatty->port.tty->index == IMSTTYINDEX)
			unregisterRxCallBack(IMS_RAW);
	}
exit:
	spin_unlock_irqrestore(&cidatatty->port_lock, flags);
	up(&cidatatty->sem_lock_tty);

	PDEBUG("Leaving do_close: ");
}
static void __exit citty_exit(void)
{
	struct citty_serial *citty;
	int i;

	F_ENTER();
	for (i = 0; i < CITTY_TTY_MINORS; ++i)
		tty_unregister_device(citty_tty_driver, i);

	tty_unregister_driver(citty_tty_driver);
	put_tty_driver(citty_tty_driver);

	/*  free the memory */
	for (i = 0; i < CITTY_TTY_MINORS; ++i)
	{
		down(&sem[i]);
		citty = citty_table[i];
		if (citty)
		{
			kfree(citty);
			citty_table[i] = NULL;

			//cci_free_buffer(&txCittyBuf[i]);

		}
		up(&sem[i]);
		cci_free_buffer(&txCittyBuf[i]); //Modified by Rovin to move here
	}

	/* clean up for the cctdev stuff */
	cctdev_cleanup_module();

	F_LEAVE();
}
static void __exit cidatatty_exit(void)
{
	struct cidatatty_port *cidatatty;
	int i;

	F_ENTER();

	/* unregister device */
	for (i = 0; i < CIDATATTY_TTY_MINORS; ++i) {
		cidatatty = cidatatty_table[i].data_port;
		if (cidatatty) {
			/* close the port */
			while (cidatatty->port.count)
				do_close(cidatatty);

			cidatatty_table[i].data_port = NULL;
			tty_port_destroy(&cidatatty->port);
			kfree(cidatatty);
		}
		tty_unregister_device(cidatatty_tty_driver, i);
	}

	/* unregister driver */
	tty_unregister_driver(cidatatty_tty_driver);

	cctdatadev_cleanup_module();
	F_LEAVE();
}
static int citty_ioctl(struct tty_struct *tty, struct file *file,
		       unsigned int cmd, unsigned long arg)
#endif
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
	struct file *file = NULL;
#endif
	F_ENTER();

	switch (cmd)
	{
	case TIOCGSERIAL:
		return citty_ioctl_tiocgserial(tty, file, cmd, arg);
	case TIOCMIWAIT:
		return citty_ioctl_tiocmiwait(tty, file, cmd, arg);
	case TIOCGICOUNT:
		return citty_ioctl_tiocgicount(tty, file, cmd, arg);
	case TCSETS:
		return citty_ioctl_tcsets(tty, file, cmd, arg);
	case TCGETS:                    //0x5401 ioctls.h
		return citty_ioctl_tcgets(tty, file, cmd, arg);
	case TCSETSF:                   //0x5404
	case TCSETAF:                   //0x5408

		return 0;               //has to return zero for qtopia to work
	default:
		PDEBUG("citty_ioctl cmd: %d.\n", cmd);
		return -ENOIOCTLCMD;           // for PPPD to work?

		break;
	}

	F_LEAVE();

}
static void __exit citty_exit(void)
{
	struct citty_port *citty = NULL;
	int i;

	F_ENTER();

	/* unregister devices  */
	for (i = 0; i < CITTY_TTY_MINORS; ++i) {
		down(&sem_lock_tty[i]);
		citty = citty_table[i];
		if (citty) {
			citty_table[i] = NULL;
			kfree(citty);
		}
		up(&sem_lock_tty[i]);
		tty_port_destroy(&citty_port_table[i]);
		tty_unregister_device(citty_tty_driver, i);
		cci_free_buffer(&txCittyBuf[i]);
	}

	/* unregister driver */
	tty_unregister_driver(citty_tty_driver);
	put_tty_driver(citty_tty_driver);

	/* clean up for the cctdev stuff */
	cctdev_cleanup_module();

	F_LEAVE();
}
unsigned int cctdev_poll(struct file *filp, poll_table *wait)
{
	struct cctdev_dev *dev = filp->private_data;
	int minor_num;
	unsigned int mask = 0;

	F_ENTER();

	minor_num = MINOR(dev->cdev.dev);

	down(&txCittyBuf[minor_num].gSem);

	poll_wait(filp, &txCittyBuf[minor_num].gInq, wait);

	if (txCittyBuf[minor_num].iBufOut != txCittyBuf[minor_num].iBufIn)
		mask |= POLLIN | POLLRDNORM;

	mask |= POLLOUT | POLLWRNORM;

	up(&txCittyBuf[minor_num].gSem);

	F_LEAVE();

	return mask;

}
static int __init citty_init(void)
{
	int retval;
	int i;

	F_ENTER();

	/* allocate the tty driver */
	citty_tty_driver = alloc_tty_driver(CITTY_TTY_MINORS);
	if (!citty_tty_driver)
		return -ENOMEM;

	/* initialize the tty driver */
	citty_tty_driver->owner = THIS_MODULE;
	citty_tty_driver->driver_name = "citty_tty";
	citty_tty_driver->name = "citty";
	citty_tty_driver->major = CITTY_TTY_MAJOR;
	citty_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
	citty_tty_driver->subtype = SERIAL_TYPE_NORMAL;
	citty_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
	citty_tty_driver->init_termios = tty_std_termios;
	/* B115200 | CS8 | CREAD | HUPCL | CLOCAL; */
	citty_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL;
	citty_tty_driver->init_termios.c_iflag = IGNBRK | IGNCR | IGNPAR;
	citty_tty_driver->init_termios.c_oflag = 0;
	citty_tty_driver->init_termios.c_lflag = 0;

	tty_set_operations(citty_tty_driver, &serial_ops);

	/* register the tty driver */
	retval = tty_register_driver(citty_tty_driver);
	if (retval) {
		printk(KERN_ERR "failed to register citty tty driver");
		put_tty_driver(citty_tty_driver);
		citty_tty_driver = NULL;
		return retval;
	}

	/* register tty devices */
	for (i = 0; i < CITTY_TTY_MINORS; ++i) {
		/* Init buffer */
		cci_init_buffer(&txCittyBuf[i]);
		sema_init(&sem_lock_tty[i], 1);

		tty_port_init(&citty_port_table[i]);
		tty_port_register_device(&citty_port_table[i],
				citty_tty_driver, i, NULL);
	}

	printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION "\n");

	cctdev_init_module();

	F_LEAVE();
	return retval;
}
示例#14
0
/*******************************************************************
*  FUNCTION: cctdev_write
*
*  DESCRIPTION: Once data come, push it to the tty port
*
*
*  RETURNS: utlFAILED or utlSUCCESS
*
*******************************************************************/
ssize_t cctdev_write(struct file *filp, const char __user *buf, size_t count,
		     loff_t *f_pos)
{
	struct cctdev_dev *dev = filp->private_data;
	int minor_num;
	int c;
	char *tbuf = NULL;

	/* send the data to the tty layer for users to read.
	 * This doesn't
	 * actually push the data through unless tty->low_latency is set */
	struct citty_port *citty = NULL;
	struct tty_struct *tty = NULL;

	F_ENTER();
	/* Extract Minor Number */
	minor_num = MINOR(dev->cdev.dev);
	PDEBUG("cctdev_write: minor_num:%d\n", minor_num);

	mutex_lock(&mutex_lock_tty[minor_num]);

	/*
	 *   get the serial object associated with this tty pointer
	 *   always give the data to the first open Dev.
	 */
	citty = citty_table[minor_num];
	PDEBUG("cctdev_write: citty: 0x%x, minor_num:%d\n",
		(unsigned long)citty, minor_num);

	if (!citty) {
		PDEBUG("Warning: citty is NULL.\n");
		mutex_unlock(&mutex_lock_tty[minor_num]);
		return -ENODEV;
	}

	tty = citty->port->tty;

	if (!tty) {
		mutex_unlock(&mutex_lock_tty[minor_num]);
		return -ENODEV;
	}

	tbuf = memdup_user(buf, count);
	if (IS_ERR(tbuf)) {
		pr_warn("%s: memdup_user returned error[%ld]\n",
			__func__, PTR_ERR(tbuf));
		mutex_unlock(&mutex_lock_tty[minor_num]);
		return PTR_ERR(tbuf);
	}

	c = tty->ldisc->ops->receive_buf2(tty, tbuf, NULL, count);
	kfree(tbuf);
	mutex_unlock(&mutex_lock_tty[minor_num]);
	return c;
}
static void cidatatty_close(struct tty_struct *tty, struct file *file)
{
	struct cidatatty_port *cidatatty = tty->driver_data;

	F_ENTER();

	if (cidatatty)
		do_close(cidatatty);

	F_LEAVE();
}
static int citty_open(struct tty_struct *tty, struct file *file)
{
	struct citty_serial *citty;
	int index;

	F_ENTER();
	schedule();
	/* initialize the pointer in case something fails */
	tty->driver_data = NULL;

	/* get the serial object associated with this tty pointer */
	index = tty->index;
	if (!cctdev_ready || (cctdev_devices[index].nreaders == 0 && cctdev_devices[index].nwriters == 0))
		return -EAGAIN;

	down(&sem[index]);
	citty = citty_table[index];
	if (citty == NULL)
	{
		/* first time accessing this device, let's create it */
		citty = kmalloc(sizeof(*citty), GFP_KERNEL);
		if (!citty)
		{
			up(&sem[index]);
			return -ENOMEM;
		}
		citty->open_count = 0;

		citty_table[index] = citty;
	}

	/* save our structure within the tty structure */
	tty->driver_data = citty;

	/* vcy */
	tty->flags = TTY_NO_WRITE_SPLIT | tty->flags;

	citty->tty = tty;

	++citty->open_count;
	if (citty->open_count == 1)
	{
		/* this is the first time this port is opened */
		/* do any hardware initialization needed here */


	}

	up(&sem[index]);

	F_LEAVE();
	return 0;
}
int data_rx_csd(char *packet, int len, unsigned char cid)
{
	struct tty_struct *tty = NULL;
	struct cidatatty_port *cidatatty;
	int ret;

	F_ENTER();

	if (!cidatatty_table[CSDTTYINDEX].data_port
	    || cidatatty_table[CSDTTYINDEX].data_port->cid != cid
	    || cidatatty_table[CSDTTYINDEX].data_port->devinuse != 1) {
		printk(KERN_ERR "data_rx_csd: not found tty device. cid = %d\n",
		       cid);
		return 0;
	} else {
		tty = cidatatty_table[CSDTTYINDEX].data_port->port.tty;
	}

	if (!tty) {
		printk(KERN_ERR "data_rx_csd: tty device is null. cid = %d\n",
		       cid);
		return 0;
	}
	cidatatty = tty->driver_data;
	/* drop packets if nobody uses cidatatty */
	if (cidatatty == NULL) {
		printk(KERN_ERR
		       "data_rx_csd: drop packets if nobody uses cidatatty. cid = %d\n",
		       cid);
		return 0;
	}

	down(&cidatatty->sem_lock_tty);

	if (cidatatty->port.count == 0) {
		up(&cidatatty->sem_lock_tty);
		printk(KERN_ERR "data_rx_csd: cidatatty device is closed\n");
		return 0;
	}

	ret = tty_insert_flip_string(&cidatatty->port, packet, len);
	tty_flip_buffer_push(&cidatatty->port);

	up(&cidatatty->sem_lock_tty);

	if (ret < len)
		printk(KERN_ERR
		       "data_rx_csd: give up because receive_room left\n");

	return ret;
}
static int citty_write(struct tty_struct *tty, const unsigned char *buffer,
		       int count)
{
	struct citty_port *citty = NULL;
	int index = tty->index;
	int retval = -EINVAL;

	F_ENTER();
	/* for some reason, this function is called with count == 0 */
	if (count <= 0) {
		printk(KERN_ERR "Error: count is %d.\n", count);
		return 0;
	}

	down(&sem_lock_tty[index]);
	citty = citty_table[index];
	if (!citty) {
		up(&sem_lock_tty[index]);
		PDEBUG("Warning: citty_write: citty is NULL\n");
		return -ENODEV;
	}

	if (!citty->port->count) {
		printk(KERN_ERR "Error: citty_write: port was not open\n");
		/* port was not opened */
		goto exit;
	}
#ifdef DEBUG_BUF_CONTENT
	/* int i; */
	printk(KERN_DEBUG "CITTY Tx Buffer datalen is %d\n data:", count);
	for (i = 0; i < count; i++)
		printk(KERN_DEBUG "%02x(%c)", buffer[i]&0xff, buffer[i]&0xff);
	/*    printk(KERN_DEBUG " %02x", buffer[i]&0xff ); */
	printk(KERN_DEBUG "\n");
#endif

	/*
	 * packet is ready for transmission:
	 * write the packet to TxCitty buffer
	 */
	retval =
	    write_citty_buffer(&txCittyBuf[tty->index], buffer, count,
			       COPY_FROM_CITTY);

exit:
	up(&sem_lock_tty[index]);

	F_LEAVE();

	return retval;
}
示例#19
0
static int citty_open(struct tty_struct *tty, struct file *file)
{
	struct citty_port *citty = NULL;
	int index = tty->index;

	F_ENTER();
	schedule();
	/* initialize the pointer in case something fails */
	tty->driver_data = NULL;

	/* get the serial object associated with this tty pointer */
	if (!cctdev_ready
	    || (cctdev_devices[index].nreaders == 0
		&& cctdev_devices[index].nwriters == 0))
		return -EAGAIN;

	mutex_lock(&mutex_lock_tty[index]);
	citty = citty_table[index];
	if (!citty) {
		citty = kmalloc(sizeof(*citty), GFP_KERNEL);
		if (!citty) {
			mutex_unlock(&mutex_lock_tty[index]);
			return -ENOMEM;
		}
		/* save tty_port structure within the our structure */
		citty_table[index] = citty;
		citty->port = &citty_port_table[index];
		citty->port->count = 0;
	}

	/* do the real open operation */
	/* save our structure within the tty structure */
	tty->driver_data = citty;

	/* vcy */
	tty->flags = TTY_NO_WRITE_SPLIT | tty->flags;

	/* save tty_struct within the tty_port structure */
	citty->port->tty = tty;

	++citty->port->count;
	if (citty->port->count == 1) {
		/* this is the first time this port is opened */
		/* do any hardware initialization needed here */
	}

	mutex_unlock(&mutex_lock_tty[index]);

	F_LEAVE();
	return 0;
}
static int citty_ioctl_tcgets(struct tty_struct *tty, struct file *file,
			      unsigned int cmd, unsigned long arg)
{
	F_ENTER();

	if (copy_to_user((void *)arg, tty->termios, sizeof(struct termios)))
	{
		printk("Failed to copy to user for tcgets.\n");
		return -EFAULT;
	}
	F_LEAVE();

	return 0;
}
/*******************************************************************
*  FUNCTION: cctdev_write
*
*  DESCRIPTION: Once data come, push it to the tty port
*
*
*  RETURNS: utlFAILED or utlSUCCESS
*
*******************************************************************/
ssize_t cctdev_write(struct file *filp, const char __user *buf, size_t count,
		     loff_t *f_pos)
{
	struct cctdev_dev *dev = filp->private_data;
	int minor_num;
	int c;

	/* send the data to the tty layer for users to read.
	 * This doesn't
	 * actually push the data through unless tty->low_latency is set */
	struct citty_port *citty = NULL;
	struct tty_struct *tty = NULL;

	F_ENTER();
	/* Extract Minor Number */
	minor_num = MINOR(dev->cdev.dev);
	PDEBUG("cctdev_write: minor_num:%d\n", minor_num);

	down(&sem_lock_tty[minor_num]);

	/*
	 *   get the serial object associated with this tty pointer
	 *   always give the data to the first open Dev.
	 */
	citty = citty_table[minor_num];
	PDEBUG("cctdev_write: citty: 0x%x, minor_num:%d\n",
		(unsigned long)citty, minor_num);

	if (!citty) {
		PDEBUG("Warning: citty is NULL.\n");
		up(&sem_lock_tty[minor_num]);
		return 0;
	}

	tty = citty->port->tty;

	if (!tty) {
		up(&sem_lock_tty[minor_num]);
		return 0;
	}
	c = tty->receive_room;
	if (c > count)
		c = count;

	tty->ldisc->ops->receive_buf(tty, buf, NULL, c);
	up(&sem_lock_tty[minor_num]);
	return c;
}
/*
 * Set up the char_dev structure for this device.
 */
static void cctdev_setup_cdev(struct cctdev_dev *dev, int index)
{
	int err, devno = MKDEV(cctdev_major, cctdev_minor + index);

	F_ENTER();

	cdev_init(&dev->cdev, &cctdev_fops);
	dev->cdev.owner = THIS_MODULE;
	dev->cdev.ops = &cctdev_fops;
	err = cdev_add(&dev->cdev, devno, 1);
	/* Fail gracefully if need be */
	if (err)
		printk(KERN_NOTICE "Error %d adding cctdev%d", err, index);

	F_LEAVE();

}
static int citty_tiocmset(struct tty_struct *tty, struct file *file,
			  unsigned int set, unsigned int clear)
#endif
{
	struct citty_serial *citty = tty->driver_data;
	unsigned int mcr = citty->mcr;

	F_ENTER();
	if (set & TIOCM_RTS)
		mcr |= MCR_RTS;
	if (set & TIOCM_DTR)
		mcr |= MCR_RTS;
	if (set & TIOCM_LOOP)
		mcr |= MCR_RTS;
	if (set & TIOCM_CTS)
		mcr |= MCR_RTS;
	if (set & TIOCM_RI)
		mcr |= MCR_RTS;
	if (set & TIOCM_DSR)
		mcr |= MCR_RTS;
	if (set & TIOCM_CAR)
		mcr |= MCR_RTS;

	if (clear & TIOCM_RTS)
		mcr &= ~MCR_RTS;
	if (clear & TIOCM_DTR)
		mcr &= ~MCR_RTS;
	if (clear & TIOCM_LOOP)
		mcr &= ~MCR_RTS;
	if (clear & TIOCM_CTS)
		mcr &= ~MCR_RTS;
	if (clear & TIOCM_CAR)
		mcr &= ~MCR_RTS;
	if (clear & TIOCM_RI)
		mcr &= ~MCR_RTS;
	if (clear & TIOCM_DSR)
		mcr &= ~MCR_RTS;

	/* set the new MCR value in the device */
	citty->mcr = mcr;

	F_LEAVE();
	return 0;
}
static int citty_ioctl_tiocmiwait(struct tty_struct *tty, struct file *file,
				  unsigned int cmd, unsigned long arg)
{
	struct citty_serial *citty = tty->driver_data;

	F_ENTER();

	if (cmd == TIOCMIWAIT)
	{
		DECLARE_WAITQUEUE(wait, current);
		struct async_icount cnow;
		struct async_icount cprev;

		cprev = citty->icount;
		while (1)
		{
			add_wait_queue(&citty->wait, &wait);
			set_current_state(TASK_INTERRUPTIBLE);
			schedule();
			remove_wait_queue(&citty->wait, &wait);

			/* see if a signal woke us up */
			if (signal_pending(current))
				return -ERESTARTSYS;

			cnow = citty->icount;
			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;
		}

	}

	F_LEAVE();
	return -ENOIOCTLCMD;
}
int cctdatadev_open(struct inode *inode, struct file *filp)
{
	struct cctdatadev_dev *dev;
	F_ENTER();
#if 1
	dev = container_of(inode->i_cdev, struct cctdatadev_dev, cdev);

	filp->private_data = dev;	/* for other methods */

	/* used to keep track of how many readers */
	if (filp->f_mode & FMODE_READ)
		dev->nreaders++;
	if (filp->f_mode & FMODE_WRITE)
		dev->nwriters++;
#endif
	F_LEAVE();

	return nonseekable_open(inode, filp);	/* success */
}
/*******************************************************************
*  FUNCTION: cctdev_read
*
*  DESCRIPTION: To pass the data from TxBuffer to CI
*
*  RETURNS: utlFAILED or utlSUCCESS
*
*******************************************************************/
ssize_t cctdev_read(struct file *filp, char __user *buf, size_t count,
		    loff_t *f_pos)
{
	struct cctdev_dev *dev = filp->private_data;
	ssize_t retval = 0;
	int minor_num;

	F_ENTER();

	/* Extract Minor Number*/
	minor_num = MINOR(dev->cdev.dev);

	PDEBUG("txCittyBuf[%d].iBufOut: %d, iBufIn: %d\n", minor_num, txCittyBuf[minor_num].iBufOut, txCittyBuf[minor_num].iBufIn);

	retval = read_citty_buffer( buf, &txCittyBuf[minor_num], COPY_TO_USER);

	F_LEAVE();

	return retval;
}
static int citty_tiocmget(struct tty_struct *tty)
{
	struct citty_port *citty = tty->driver_data;
	unsigned int result = 0;
	unsigned int msr = citty->msr;
	unsigned int mcr = citty->mcr;

	F_ENTER();

	result = ((mcr & MCR_DTR)  ? TIOCM_DTR  : 0) |  /* DTR is set */
		 ((mcr & MCR_RTS)  ? TIOCM_RTS  : 0) |  /* RTS is set */
		 ((mcr & MCR_LOOP) ? TIOCM_LOOP : 0) |  /* LOOP is set */
		 ((msr & MSR_CTS)  ? TIOCM_CTS  : 0) |  /* CTS is set */
		 ((msr & MSR_CD)   ? TIOCM_CAR  : 0) |  /* CD is set */
		 ((msr & MSR_RI)   ? TIOCM_RI   : 0) |  /* RI is set */
		 ((msr & MSR_DSR)  ? TIOCM_DSR  : 0);   /* DSR is set */

	F_LEAVE();
	return result;
}
static int citty_tiocmget(struct tty_struct *tty, struct file *file)
#endif
{
	struct citty_serial *citty = tty->driver_data;
	unsigned int result = 0;
	unsigned int msr = citty->msr;
	unsigned int mcr = citty->mcr;

	F_ENTER();

	result = ((mcr & MCR_DTR)  ? TIOCM_DTR  : 0) |  /* DTR is set */
		 ((mcr & MCR_RTS)  ? TIOCM_RTS  : 0) |  /* RTS is set */
		 ((mcr & MCR_LOOP) ? TIOCM_LOOP : 0) |  /* LOOP is set */
		 ((msr & MSR_CTS)  ? TIOCM_CTS  : 0) |  /* CTS is set */
		 ((msr & MSR_CD)   ? TIOCM_CAR  : 0) |  /* Carrier detect is set*/
		 ((msr & MSR_RI)   ? TIOCM_RI   : 0) |  /* Ring Indicator is set */
		 ((msr & MSR_DSR)  ? TIOCM_DSR  : 0);   /* DSR is set */

	F_LEAVE();
	return result;
}
示例#29
0
int cctdev_open(struct inode *inode, struct file *filp)
{
	struct cctdev_dev *dev;	/* device information */

	F_ENTER();

	dev = container_of(inode->i_cdev, struct cctdev_dev, cdev);

	filp->private_data = dev;	/* for other methods */

	/* used to keep track of how many readers */
	mutex_lock(&dev->lock);
	if (filp->f_mode & FMODE_READ)
		dev->nreaders++;
	if (filp->f_mode & FMODE_WRITE)
		dev->nwriters++;
	mutex_unlock(&dev->lock);

	F_LEAVE();

	return nonseekable_open(inode, filp);	/* success */
}
static int cidatatty_ioctl_tiocgserial(struct tty_struct *tty,
				       struct file *file, unsigned int cmd,
				       unsigned long arg)
{
	struct cidatatty_port *cidatatty = tty->driver_data;

	F_ENTER();

	if (cmd == TIOCGSERIAL) {
		struct serial_struct tmp;

		if (!arg)
			return -EFAULT;

		memset(&tmp, 0, sizeof(tmp));

		tmp.type                = cidatatty->serial.type;
		tmp.line                = cidatatty->serial.line;
		tmp.port                = cidatatty->serial.port;
		tmp.irq                 = cidatatty->serial.irq;
		tmp.flags               = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
		tmp.xmit_fifo_size      = cidatatty->serial.xmit_fifo_size;
		tmp.baud_base           = cidatatty->serial.baud_base;
		tmp.close_delay         = 5 * HZ;
		tmp.closing_wait        = 30 * HZ;
		tmp.custom_divisor      = cidatatty->serial.custom_divisor;
		tmp.hub6                = cidatatty->serial.hub6;
		tmp.io_type             = cidatatty->serial.io_type;

		if (copy_to_user
		    ((void __user *)arg, &tmp, sizeof(struct serial_struct)))
			return -EFAULT;
		return 0;
	}

	F_LEAVE();
	return -ENOIOCTLCMD;
}