原创 tty(2)

2012-6-11 00:18 1209 5 5 分类: MCU/ 嵌入式

static int tiny_tiocmget(struct tty_struct *tty, struct file *file)
{
 struct tiny_serial *tiny = tty->driver_data;

 unsigned int result = 0;
 unsigned int msr = tiny->msr;
 unsigned int mcr = tiny->mcr;

 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 */

 return result;
}

static int tiny_tiocmset(struct tty_struct *tty, struct file *file,
                         unsigned int set, unsigned int clear)
{
 struct tiny_serial *tiny = tty->driver_data;
 unsigned int mcr = tiny->mcr;

 if (set & TIOCM_RTS)
  mcr |= MCR_RTS;
 if (set & TIOCM_DTR)
  mcr |= MCR_RTS;

 if (clear & TIOCM_RTS)
  mcr &= ~MCR_RTS;
 if (clear & TIOCM_DTR)
  mcr &= ~MCR_RTS;

 /* set the new MCR value in the device */
 tiny->mcr = mcr;
 return 0;
}

static int tiny_read_proc(char *page, char **start, off_t off, int count,
                          int *eof, void *data)
{
 struct tiny_serial *tiny;
 off_t begin = 0;
 int length = 0;
 int i;

 length += sprintf(page, "tinyserinfo:1.0 driver:%s\n", DRIVER_VERSION);
 for (i = 0; i < TINY_TTY_MINORS && length < PAGE_SIZE; ++i) {
  tiny = tiny_table;
  if (tiny == NULL)
   continue;

  length += sprintf(page+length, "%d\n", i);
  if ((length + begin) > (off + count))
   goto done;
  if ((length + begin) < off) {
   begin += length;
   length = 0;
  }
 }
 *eof = 1;
done:
 if (off >= (length + begin))
  return 0;
 *start = page + (off-begin);
 return (count < begin+length-off) ? count : begin + length-off;
}

#define tiny_ioctl tiny_ioctl_tiocgserial
static int tiny_ioctl(struct tty_struct *tty, struct file *file,
                      unsigned int cmd, unsigned long arg)
{
 struct tiny_serial *tiny = tty->driver_data;

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

  if (!arg)
   return -EFAULT;

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

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

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

#define tiny_ioctl tiny_ioctl_tiocmiwait
static int tiny_ioctl(struct tty_struct *tty, struct file *file,
                      unsigned int cmd, unsigned long arg)
{
/*
 struct tiny_serial *tiny = tty->driver_data;

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

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

  
   if (signal_pending(current))
    return -ERESTARTSYS;

   cnow = tiny->icount;
   if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
       cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
    return -EIO;
   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;
  }

 }
*/
 return -ENOIOCTLCMD;
}
#undef tiny_ioctl

#define tiny_ioctl tiny_ioctl_tiocgicount
static int tiny_ioctl(struct tty_struct *tty, struct file *file,
                      unsigned int cmd, unsigned long arg)
{
 struct tiny_serial *tiny = tty->driver_data;

 if (cmd == TIOCGICOUNT) {
  struct async_icount cnow = tiny->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;
 }
 return -ENOIOCTLCMD;
}
#undef tiny_ioctl

/* the real tiny_ioctl function.  The above is done to get the small functions in the book */
static int tiny_ioctl(struct tty_struct *tty, struct file *file,
                      unsigned int cmd, unsigned long arg)
{
 switch (cmd) {
 case TIOCGSERIAL:
  return tiny_ioctl_tiocgserial(tty, file, cmd, arg);
 case TIOCMIWAIT:
  return tiny_ioctl_tiocmiwait(tty, file, cmd, arg);
 case TIOCGICOUNT:
  return tiny_ioctl_tiocgicount(tty, file, cmd, arg);
 }

 return -ENOIOCTLCMD;
}

static struct tty_operations serial_ops = {
 .open = tiny_open,
 .close = tiny_close,
 .write = tiny_write,
 .write_room = tiny_write_room,
 .set_termios = tiny_set_termios,
};

static struct tty_driver *tiny_tty_driver;

static int __init tiny_init(void)
{
 int retval;
 int i;

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

 /* initialize the tty driver */
 tiny_tty_driver->owner = THIS_MODULE;
 tiny_tty_driver->driver_name = "tiny_tty";
 tiny_tty_driver->name = "ttty";
// tiny_tty_driver->devfs_name = "tts/ttty%d";
 tiny_tty_driver->major = TINY_TTY_MAJOR,
 tiny_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
 tiny_tty_driver->subtype = SERIAL_TYPE_NORMAL;
// tiny_tty_driver->flags =  TTY_DRIVER_REAL_RAW;
 tiny_tty_driver->init_termios = tty_std_termios;
 tiny_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD;
 tty_set_operations(tiny_tty_driver, &serial_ops);

 /* hack to make the book purty, yet still use these functions in the
  * real driver.  They really should be set up in the serial_ops
  * structure above... */
// tiny_tty_driver->read_proc = tiny_read_proc;
// tiny_tty_driver->tiocmget = tiny_tiocmget;
// tiny_tty_driver->tiocmset = tiny_tiocmset;
// tiny_tty_driver->ioctl = tiny_ioctl;

 /* register the tty driver */
 retval = tty_register_driver(tiny_tty_driver);
 if (retval) {
  printk(KERN_ERR "failed to register tiny tty driver");
  put_tty_driver(tiny_tty_driver);
  return retval;
 }
/* //不需要注册device吗?
 for (i = 0; i < TINY_TTY_MINORS; ++i)
  tty_register_device(tiny_tty_driver, i, NULL);
*/
 printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION);
 return retval;
}

static void __exit tiny_exit(void)
{
 struct tiny_serial *tiny;
 int i;

 for (i = 0; i < TINY_TTY_MINORS; ++i)
  tty_unregister_device(tiny_tty_driver, i);
 tty_unregister_driver(tiny_tty_driver);

 /* shut down all of the timers and free the memory */
 for (i = 0; i < TINY_TTY_MINORS; ++i) {
  tiny = tiny_table;
  if (tiny) {
   /* close the port */
   while (tiny->open_count)
    do_close(tiny);

   /* shut down our timer and free the memory */
   del_timer(tiny->timer);
   kfree(tiny->timer);
   kfree(tiny);
   tiny_table = NULL;
  }
 }
}

module_init(tiny_init);

module_exit(tiny_exit);
 

 

arm
PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
我要评论
0
5
关闭 站长推荐上一条 /3 下一条