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

📄 mem_tty.c

📁 LINUX内核编程的一些程序例子
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Mem TTY driver * * Copyright (C) 2003 marco corvi <marco_corvi@geocities.com> *  *	This program is free software; you can redistribute it and/or modify *	it under the terms of the GNU General Public License as published by *	the Free Software Foundation; either version 2 of the License, or *	(at your option) any later version. * * This driver has been adapted from the tiny_tty driver by * Greg Kroah-Hartman (greg@kroah.com) * * This driver shows how to create a minimal tty driver.  i * It relies on a memory buffer acting as backing hardware,  * it uses a timer to emulate delay in receiving the data. */#include <asm/uaccess.h>#include <linux/config.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/tty.h>#include <linux/tty_driver.h>#include <linux/tty_flip.h>#include <linux/module.h>#include <linux/sched.h>#include <linux/serial.h>#include <linux/serial_reg.h>#define DRIVER_VERSION "v1.0"#define DRIVER_AUTHOR "marco corvi <marco_corvi@geocities.com>"#define DRIVER_DESC "Memory TTY driver"/* Module information */MODULE_AUTHOR( DRIVER_AUTHOR );MODULE_DESCRIPTION( DRIVER_DESC );MODULE_LICENSE("GPL");#define MEM_TTY_MAJOR	240	/* experimental range */#define MEM_TTY_MINORS	255	/* use the whole major up */#define MEM_HW_SIZE    128struct mem_tty_serial {  struct tty_struct *tty;  /* pointer to the tty for this device */  struct file * filp;  int    open_count;       /* number of times this port has been opened */  struct semaphore sem;    /* locks this structure */  struct timer_list	*timer;  char * hw_buffer;  int    head;  int    tail;  int    throttling;  wait_queue_head_t   wait;    /* wait_queue */  int mcr;                     /* modem control register */  int msr;                     /* modem status register */  struct serial_struct serial; /* serial_struct data */  struct async_icount  icount; /* intr. count */};static int			mem_tty_refcount;static struct tty_driver	mem_tty_driver;static struct tty_struct	*mem_tty[MEM_TTY_MINORS];static struct termios		*mem_tty_termios[MEM_TTY_MINORS];static struct termios		*mem_tty_termios_locked[MEM_TTY_MINORS];static struct mem_tty_serial	*mem_tty_table[MEM_TTY_MINORS];	/* initially all NULL */// #define DELAY_TIME		HZ /* 1 second per character */#define DELAY_TIME 2 /* 2 jiffies */static void mem_tty_timer (unsigned long data){  struct mem_tty_serial *mem = (struct mem_tty_serial *)data;  struct tty_struct *tty;  if (!mem)    return;  printk(KERN_ALERT "mem_tty_timer head %d tail %d\n", mem->head, mem->tail );  if ( mem->tail == mem->head )     return;  tty = mem->tty;  if (tty->flip.count >= TTY_FLIPBUF_SIZE) {    tty_flip_buffer_push(tty);  }  tty_insert_flip_char(tty, mem->hw_buffer[mem->tail], 0);  tty_flip_buffer_push(tty);  mem->tail = ( mem->tail + 1) % MEM_HW_SIZE;  // tty_schedule_flip (tty); // This is not necessary  // printk(KERN_ALERT "mem_tty_timer ok %c\n", mem_tty_data_char);    if ( mem->tail != mem->head ) {      /* resubmit the timer again */    mem->timer->expires = jiffies + DELAY_TIME;    add_timer (mem->timer);  }}static int mem_tty_ioctl (struct tty_struct *tty, struct file * file,                          unsigned int cmd, unsigned long arg ){  struct mem_tty_serial *mem = tty->driver_data;  struct serial_struct          tmp_serial;  struct serial_icounter_struct tmp_icount;  unsigned int value;  if ( ! mem )     return -ENODEV;  down (&mem->sem);  if (!mem->open_count) { /* port was not opened */    up (&mem->sem);    return -EINVAL;  }  switch ( cmd ) {    case TIOCMGET:       value = ( (mem->mcr & UART_MCR_DTR) ? TIOCM_DTR : 0 )            | ( (mem->mcr & UART_MCR_RTS) ? TIOCM_RTS : 0 )            | ( (mem->msr & UART_MSR_CTS) ? TIOCM_CTS : 0 )            | ( (mem->msr & UART_MSR_DCD) ? TIOCM_CAR : 0 )            | ( (mem->msr & UART_MSR_RI)  ? TIOCM_RI  : 0 )            | ( (mem->msr & UART_MSR_DSR) ? TIOCM_DSR : 0 );      if ( copy_to_user( (unsigned int *)arg, &value, sizeof(unsigned int)))        return -EFAULT;      return 0;    case TIOCMBIS:      if ( copy_from_user( &value, (unsigned int *)arg, sizeof(unsigned int)))        return -EFAULT;      if ( value & TIOCM_RTS ) mem->mcr |= UART_MCR_RTS;      if ( value & TIOCM_DTR ) mem->mcr |= UART_MCR_DTR;      if ( value & TIOCM_LOOP ) mem->mcr |= UART_MCR_LOOP;      return 0;    case TIOCMBIC:      if ( copy_from_user( &value, (unsigned int *)arg, sizeof(unsigned int)))        return -EFAULT;      if ( value & TIOCM_RTS ) mem->mcr &= ~UART_MCR_RTS;      if ( value & TIOCM_DTR ) mem->mcr &= ~UART_MCR_DTR;      if ( value & TIOCM_LOOP ) mem->mcr &= ~UART_MCR_LOOP;      return 0;    case TIOCMSET:      if ( copy_from_user( &value, (unsigned int *)arg, sizeof(unsigned int)))        return -EFAULT;      mem->mcr &= ~( UART_MCR_RTS | UART_MCR_DTR | UART_MCR_LOOP);      if ( value & TIOCM_RTS ) mem->mcr |= UART_MCR_RTS;      if ( value & TIOCM_DTR ) mem->mcr |= UART_MCR_DTR;      if ( value & TIOCM_LOOP ) mem->mcr |= UART_MCR_LOOP;      return 0;    case TIOCGSERIAL:      memset( &tmp_serial, 0, sizeof(struct serial_struct) );      // copy all the fields except for reserved and not-used      tmp_serial.type = mem->serial.type;      tmp_serial.line = mem->serial.line;      tmp_serial.port = mem->serial.port;      tmp_serial.irq  = mem->serial.irq ;      tmp_serial.flags = mem->serial.flags;      tmp_serial.xmit_fifo_size = mem->serial.xmit_fifo_size;      tmp_serial.baud_base = mem->serial.baud_base;      tmp_serial.close_delay = mem->serial.close_delay;      tmp_serial.closing_wait = mem->serial.closing_wait;      tmp_serial.custom_divisor = mem->serial.custom_divisor;      tmp_serial.hub6 = mem->serial.hub6;      tmp_serial.io_type = mem->serial.io_type;      tmp_serial.port_high = mem->serial.port_high;      tmp_serial.iomem_reg_shift = mem->serial.iomem_reg_shift;      tmp_serial.iomem_base = mem->serial.iomem_base;      if ( copy_to_user( (struct serial_struct *)arg, &tmp_serial,                         sizeof(struct serial_struct) ) )        return -EFAULT;      return 0;    case TIOCSSERIAL:      if ( copy_from_user( &mem->serial, (struct serial_struct *)arg,                           sizeof(struct serial_struct)))        return -EFAULT;      return 0;    case TIOCMIWAIT:      if ( copy_from_user( &value, (unsigned int *)arg, sizeof(unsigned int)))        return -EFAULT;      {        DECLARE_WAITQUEUE(wait, current);        struct async_icount ic_now;        struct async_icount ic_prev = mem->icount;        while (1) {          add_wait_queue( &mem->wait, &wait);          set_current_state( TASK_INTERRUPTIBLE );          schedule();          remove_wait_queue( &mem->wait, &wait);          if ( signal_pending( current ) )            return -ERESTARTSYS;          ic_now = mem->icount;          if ( ic_now.rng == ic_prev.rng   /* ring */            && ic_now.dsr == ic_prev.dsr   /* data set ready */            && ic_now.dcd == ic_prev.dcd   /* data carrier detect */            && ic_now.cts == ic_prev.cts ) /* clear to send */            return -EIO;          if ( ( (value & TIOCM_RNG ) && ( ic_now.rng != ic_prev.rng) )            || ( (value & TIOCM_DSR ) && ( ic_now.dsr != ic_prev.dsr) )            || ( (value & TIOCM_CD  ) && ( ic_now.dcd != ic_prev.dcd) )            || ( (value & TIOCM_CTS ) && ( ic_now.cts != ic_prev.cts) ) )            return 0;        }      }      break;    case TIOCGICOUNT:      tmp_icount.cts = mem->icount.cts;      tmp_icount.dsr = mem->icount.dsr;      tmp_icount.rng = mem->icount.rng;      tmp_icount.dcd = mem->icount.dcd;      tmp_icount.rx = mem->icount.rx;      tmp_icount.tx = mem->icount.tx;      tmp_icount.frame = mem->icount.frame;      tmp_icount.overrun = mem->icount.overrun;      tmp_icount.parity = mem->icount.parity;      tmp_icount.brk = mem->icount.brk;      tmp_icount.buf_overrun = mem->icount.buf_overrun;      if ( copy_to_user( ( struct serial_icounter_struct *) arg, &tmp_icount,                           sizeof( struct serial_icounter_struct ) ) )        return -EFAULT;      return 0;  }  return -ENOIOCTLCMD;}static int mem_tty_open (struct tty_struct *tty, struct file * filp){  struct mem_tty_serial *mem;  struct timer_list *timer;  MOD_INC_USE_COUNT;  /* initialize the pointer in case something fails */  tty->driver_data = NULL;  /* get the serial object associated with this tty pointer */  // mem = mem_tty_table[minor(tty->device)];  mem = mem_tty_table[MINOR(tty->device)];  if (mem == NULL) {    /* first time accessing this device, let's create it */    mem = kmalloc (sizeof (*mem), GFP_KERNEL);    if (!mem) {      MOD_DEC_USE_COUNT;      return -ENOMEM;    }    // create hardware buffer    mem->hw_buffer = kmalloc( MEM_HW_SIZE, GFP_KERNEL);    if ( ! mem->hw_buffer ) {      kfree( mem );      MOD_DEC_USE_COUNT;      return -ENOMEM;    }    init_MUTEX (&mem->sem);    mem->open_count = 0;    mem->timer = NULL;    // connection state information    init_waitqueue_head( & mem->wait );    // mem_tty_table[minor(tty->device)] = mem;    mem_tty_table[MINOR(tty->device)] = mem;  }  down (&mem->sem);  /* save our structure within the tty structure */  tty->driver_data = mem;  mem->tty = tty;  mem->filp = filp;  ++mem->open_count;  if (mem->open_count == 1) {    /* this is the first time this port is opened */    /* do any hardware initialization needed here */    mem->head = 0;    mem->tail = 0;    mem->throttling = 0;    /* reset connection state information */    mem->mcr = TIOCM_DTR | TIOCM_RTS ;    mem->msr = TIOCM_CTS | TIOCM_CAR | TIOCM_RI | TIOCM_DSR ;    memset( & mem->serial, 0, sizeof( struct serial_struct ) );    mem->serial.type = PORT_UNKNOWN;    mem->serial.port = SERIAL_IO_PORT;    mem->serial.line = 1;    mem->serial.closing_wait = ASYNC_CLOSING_WAIT_INF;    mem->serial.irq   = 0;    mem->serial.flags = 0x0;    mem->serial.xmit_fifo_size = MEM_HW_SIZE;       mem->serial.baud_base = 9600;    mem->serial.close_delay = 0*HZ;    mem->serial.custom_divisor = 0;    mem->serial.hub6 = 1;    mem->serial.io_type = SERIAL_IO_HUB6;    memset( & mem->icount, 0, sizeof(struct async_icount) );    /* create our timer and submit it */

⌨️ 快捷键说明

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