6.1.1Drv/Serial(Character Device Drv)

转载请注明出处http://blog.csdn.net/alvin_jack/article/details/70665371

在Nuttx中,字符型设备具有以下的属性(以串口为例):

文章均出自个人理解,错误之处敬请指出;

 

Nuttx的驱动主要分为两层,向上为抽象为文件的接口层,具体接口如下,向下为驱动接口层,通过dev、ops实现对底层寄存器的操作,以及对驱动模块的配置;

    1)include/nuttx/fs/fs.h所有的结构和API接口需要以字符型设备正常运行,具体的定义在该头文件中;每个设备驱动必须实现struct file_operations这个数据结构的实例,具体如下:

struct file_operations{
     int open (FAR struct file *filep);
     int close (FAR struct file *filep);
     ssize_t read(FAR struct file *filep, FAR char *buffer, size_t buflen);
     ssize_t write(FAR struct file *filep, FAR const char *buffer, size_t buflen);
     off_t seek(FAR struct file *filep, off_t offset, int whence);
     int ioctl(FAR struct file *filep,int cmd, unsigned long arg);
     int poll(FAR struct file *filep, struct pollfd *fds, bool setup);
}

 

      2)drivers/serial/serial.c,这里就是用来填充之前已经定义的file_operations结构,换句话说就是对该结构的实现;

而实现函数,例如uart_open(FAR struct file *filep):

static int uart_open(FAR struct file *filep)
{
  //获取设备的路径,并根据路径在虚拟文件系统中找到该设备驱动结构体变量(即dev)
  FAR struct inode *inode = filep->f_inode;
  FAR uart_dev_t *dev = inode->i_private;
  uint8_t tmp;
  int ret;

  /* If the port is the middle of closing, wait until the close is finished.
  * If a signal is received while we are waiting, then return EINTR.
  */

  ret = uart_takesem(&dev->closesem, true);
  if (ret < 0)
  {
  /* A signal received while waiting for the last close operation. */

  return ret;
  }

#ifdef CONFIG_SERIAL_REMOVABLE
  /* If the removable device is no longer connected, refuse to open the
  * device. We check this after obtaining the close semaphore because
  * we might have been waiting when the device was disconnected.
  */

  if (dev->disconnected)
  {
  ret = -ENOTCONN;
  goto errout_with_sem;
  }
#endif

  /* Start up serial port */
  /* Increment the count of references to the device. */

  tmp = dev->open_count + 1;
  if (tmp == 0)
  {
  /* More than 255 opens; uint8_t overflows to zero */

  ret = -EMFILE;
  goto errout_with_sem;
  }

  /* Check if this is the first time that the driver has been opened. */

  if (tmp == 1)
  {
  irqstate_t flags = enter_critical_section();

  /* If this is the console, then the UART has already been initialized. */

  if (!dev->isconsole)
  {
  /* Perform one time hardware initialization */

  ret = uart_setup(dev);
  if (ret < 0)
  {
  leave_critical_section(flags);
  goto errout_with_sem;
  }
  }

  /* In any event, we do have to configure for interrupt driven mode of
  * operation. Attach the hardware IRQ(s). Hmm.. should shutdown() the
  * the device in the rare case that uart_attach() fails, tmp==1, and
  * this is not the console.
  */

  ret = uart_attach(dev);
  if (ret < 0)
  {
  uart_shutdown(dev);
  leave_critical_section(flags);
  goto errout_with_sem;
  }

  /* Mark the io buffers empty */

  dev->xmit.head = 0;
  dev->xmit.tail = 0;
  dev->recv.head = 0;
  dev->recv.tail = 0;

  /* Initialize termios state */

#ifdef CONFIG_SERIAL_TERMIOS
  dev->tc_iflag = 0;
  if (dev->isconsole)
  {
  /* Enable \n -> \r\n translation for the console */

  dev->tc_oflag = OPOST | ONLCR;
  }
  else
  {
  dev->tc_oflag = 0;
  }
#endif

#ifdef CONFIG_SERIAL_DMA
  /* Notify DMA that there is free space in the RX buffer */

  uart_dmarxfree(dev);
#endif

  /* Enable the RX interrupt */

  uart_enablerxint(dev);
  leave_critical_section(flags);
  }

  /* Save the new open count on success */

  dev->open_count = tmp;

errout_with_sem:
  uart_givesem(&dev->closesem);
  return ret;
}

 

     里面调用的函数例如uart_setup、uart_givesem、uart_dmarxfree都是来自于uart_ops_s的数据结构中的,而uart_ops_s中的数据结构则是对uart的外设寄存器组进行操作,从而实现串口的功能;

#define uart_setup(dev) 	dev->ops->setup(dev)
#define uart_shutdown(dev) 	dev->ops->shutdown(dev)
#define uart_attach(dev) 	dev->ops->attach(dev)
#define uart_detach(dev) 	dev->ops->detach(dev)
#define uart_enabletxint(dev) 	dev->ops->txint(dev, true)
#define uart_disabletxint(dev) 	dev->ops->txint(dev, false)
#define uart_enablerxint(dev) 	dev->ops->rxint(dev, true)
#define uart_disablerxint(dev) 	dev->ops->rxint(dev, false)
#define uart_rxavailable(dev) 	dev->ops->rxavailable(dev)
#define uart_txready(dev) 	dev->ops->txready(dev)
#define uart_txempty(dev) 	dev->ops->txempty(dev)
#define uart_send(dev,ch) 	dev->ops->send(dev,ch)
#define uart_receive(dev,s) 	dev->ops->receive(dev,s)

 

         3)uart_dev_s,包含了uart_ops_s以及串口的状态值(如中断信号量、传输标志位...),uart_dev_s是需要被系统的驱动调用的,也就是说在初始化的时候会通过(uart_register())进行注册,将之前的填充好的数据结构与虚拟文件系统进行关联;

struct uart_dev_s
{
  /* State data */
  uint8_t open_count;               /* Number of times the device has been opened */
  volatile bool xmitwaiting;       /* true: User waiting for space in xmit.buffer */
  volatile bool recvwaiting;       /* true: User waiting for data in recv.buffer */

#ifdef CONFIG_SERIAL_REMOVABLE
  volatile bool disconnected;    /* true: Removable device is not connected */
#endif
  bool isconsole; /* true: This is the serial console */

#ifdef CONFIG_SERIAL_TERMIOS
  /* Terminal control flags */
  tcflag_t tc_iflag; /* Input modes */
  tcflag_t tc_oflag; /* Output modes */
  tcflag_t tc_lflag; /* Local modes */
#endif

  /* Semaphores */
  sem_t closesem; /* Locks out new open while close is in progress */
  sem_t xmitsem; /* Wakeup user waiting for space in xmit.buffer */
  sem_t recvsem; /* Wakeup user waiting for data in recv.buffer */
#ifndef CONFIG_DISABLE_POLL
  sem_t pollsem; /* Manages exclusive access to fds[] */
#endif

  /* I/O buffers */
  struct uart_buffer_s xmit; /* Describes transmit buffer */
  struct uart_buffer_s recv; /* Describes receive buffer */

#ifdef CONFIG_SERIAL_DMA
  /* DMA transfers */
  struct uart_dmaxfer_s dmatx; /* Describes transmit DMA transfer */
  struct uart_dmaxfer_s dmarx; /* Describes receive DMA transfer */
#endif

  /* Driver interface */
  FAR const struct uart_ops_s *ops; /* Arch-specific operations */
  FAR void *priv; /* Used by the arch-specific logic */

  /* The following is a list if poll structures of threads waiting for
  * driver events. The 'struct pollfd' reference for each open is also
  * retained in the f_priv field of the 'struct file'.
  */
#ifndef CONFIG_DISABLE_POLL
  struct pollfd *fds[CONFIG_SERIAL_NPOLLWAITERS];
#endif
};

 

     4)register_driver,串口注册函数,完成之前所填充的数据结构uart_dev_suart_ops_s与虚拟文件系统关联

int register_driver( FAR const char *path, \
                     FAR const struct file_operations *fops,\
                     mode_t mode,\
                     FAR void *priv);
eg:
register_driver(/dev/ttyS0, 	\注册到系统虚拟文件系统的地址
                &g_serialops,	\填充的file_operations数据结构
                0666,		\端口的权限
                dev);		\填充的uart_dev_s数据结构

 

     到这里一个串口的驱动就算完成了,对应用层来说,所调用file_operations中的函数去驱动的硬件,是已经在初始化的时候就做好了的;基于串口的应用开发也就不需要再去关心硬件驱动层面的开发了;

     一般来说,file_operationsdev(uart_dev_s)之间的关系也就是从注册开始建立起联系的,一般的板卡会存在多个dev(uart_dev_s),而file_operations针对同一类设备来说只会是存在一个实例,这些驱动一般OS都会事先写好,然后用户通过配置文件进行选择;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值