6.1.1Drv/Serial(Character Device Drv)

来源:互联网 发布:java邮箱格式验证方法 编辑:程序博客网 时间:2024/06/05 05:11
转载请注明出处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 0
原创粉丝点击