linux spi驱动开发学习-----spidev.c和spi test app

一.spidev.c文件

看一个设备驱动的方法:

module_init标识的入口初始化函数spidev_init,(module_exit标识的出口函数)

设备与设备驱动匹配时候调用的probe方法spidev_probe

设备驱动的操作函数集file_operations--->spidev_fops

@@open方法spidev_open
进行检查, 重点是以后三条语句,其他的见下面代码注释:

  1. spidev->users++; //spidev_data使用者计数++ 
  2. filp->private_data = spidev; //spidev_data放在文件的私有数据里 
  3. nonseekable_open(inode, filp);  //设置文件的打开模式(文件读写指针不会跟随读写操作移动)

 


@@read方法spidev_read
spidev = filp->private_data;=========>>status = spidev_sync_read(spidev, count);===========>>
spidev_sync(spidev, &m);==========>>status = spi_async(spidev->spi, message);===========>>
wait_for_completion(&done);========>>到了这一步是重点,在spi_async()方法中,使用以下语句将要做的事情加到workqueue中
list_add_tail(&m->queue, &bitbang->queue);
queue_work(bitbang->workqueue, &bitbang->work);
此后所有的处理程序便转移到在之前初始化的work方法中看以下代码:

点击(此处)折叠或打开

  1. static void bitbang_work(struct work_struct *work)
  2. {
  3.     struct spi_bitbang    *bitbang =
  4.         container_of(work, struct spi_bitbang, work);
  5.     unsigned long        flags;
  6.     int            do_setup = -1;
  7.     int            (*setup_transfer)(struct spi_device *,
  8.                     struct spi_transfer *);
  9.     setup_transfer = bitbang->setup_transfer;
  10.     spin_lock_irqsave(&bitbang->lock, flags);
  11.     bitbang->busy = 1;
  12.     while (!list_empty(&bitbang->queue)) {
  13.         struct spi_message    *m;
  14.         struct spi_device    *spi;
  15.         unsigned        nsecs;
  16.         struct spi_transfer    *t = NULL;
  17.         unsigned        tmp;
  18.         unsigned        cs_change;
  19.         int            status;
  20.         m = container_of(bitbang->queue.next, struct spi_message,
  21.                 queue);
  22.         list_del_init(&m->queue);
  23.         spin_unlock_irqrestore(&bitbang->lock, flags);
  24.         /* FIXME this is made-up ... the correct value is known to
  25.          * word-at-a-time bitbang code, and presumably chipselect()
  26.          * should enforce these requirements too?
  27.          */
  28.         nsecs = 100;
  29.         spi = m->spi;
  30.         tmp = 0;
  31.         cs_change = 1;
  32.         status = 0;
  33.         list_for_each_entry (t, &m->transfers, transfer_list) {
  34.             /* override speed or wordsize? */
  35.             if (t->speed_hz || t->bits_per_word)
  36.                 do_setup = 1;
  37.             /* init (-1) or override (1) transfer params */
  38.             if (do_setup != 0) {
  39.                 if (!setup_transfer) {
  40.                     status = -ENOPROTOOPT;
  41.                     break;
  42.                 }
  43.                 status = setup_transfer(spi, t);
  44.                 if (status < 0)
  45.                     break;
  46.             }
  47.             /* set up default clock polarity, and activate chip;
  48.              * this implicitly updates clock and spi modes as
  49.              * previously recorded for this device via setup().
  50.              * (and also deselects any other chip that might be
  51.              * selected ...)
  52.              */
  53.             if (cs_change) {
  54.                 bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
  55.                 ndelay(nsecs);
  56.             }
  57.             cs_change = t->cs_change;
  58.             if (!t->tx_buf && !t->rx_buf && t->len) {
  59.                 status = -EINVAL;
  60.                 break;
  61.             }
  62.             /* transfer data. the lower level code handles any
  63.              * new dma mappings it needs. our caller always gave
  64.              * us dma-safe buffers.
  65.              */
  66.             if (t->len) {
  67.                 /* REVISIT dma API still needs a designated
  68.                  * DMA_ADDR_INVALID; ~0 might be better.
  69.                  */
  70.                 if (!m->is_dma_mapped)
  71.                     t->rx_dma = t->tx_dma = 0;
  72.                 status = bitbang->txrx_bufs(spi, t);
  73.             }
  74.             if (status > 0)
  75.                 m->actual_length += status;
  76.             if (status != t->len) {
  77.                 /* always report some kind of error */
  78.                 if (status >= 0)
  79.                     status = -EREMOTEIO;
  80.                 break;
  81.             }
  82.             status = 0;
  83.             /* protocol tweaks before next transfer */
  84.             if (t->delay_usecs)
  85.                 udelay(t->delay_usecs);
  86.             if (!cs_change)
  87.                 continue;
  88.             if (t->transfer_list.next == &m->transfers)
  89.                 break;
  90.             /* sometimes a short mid-message deselect of the chip
  91.              * may be needed to terminate a mode or command
  92.              */
  93.             ndelay(nsecs);
  94.             bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
  95.             ndelay(nsecs);
  96.         }
  97.         m->status = status;
  98.         m->complete(m->context);
  99.         /* restore speed and wordsize if it was overridden */
  100.         if (do_setup == 1)
  101.             setup_transfer(spi, NULL);
  102.         do_setup = 0;
  103.         /* normally deactivate chipselect ... unless no error and
  104.          * cs_change has hinted that the next message will probably
  105.          * be for this chip too.
  106.          */
  107.         if (!(status == 0 && cs_change)) {
  108.             ndelay(nsecs);
  109.             bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
  110.             ndelay(nsecs);
  111.         }
  112.         spin_lock_irqsave(&bitbang->lock, flags);
  113.     }
  114.     bitbang->busy = 0;
  115.     spin_unlock_irqrestore(&bitbang->lock, flags);
  116. }

结束处理所有任务后,见上面红色底纹部分解除wait_for_completion(&done);
最后missing = copy_to_user(buf, spidev->buffer, status);将数据发送到用户空间

@@write方法spidev_write
与上面open方式基本相同

@@ioctl方法spidev_ioctl
具体的详解见下面章节(三,四)

下面是spidev.c添加注释部分

 

 

[cpp]  view plain copy
 
  1. #include <linux/init.h> 
  2. #include <linux/module.h> 
  3. #include <linux/ioctl.h> 
  4. #include <linux/fs.h> 
  5. #include <linux/device.h> 
  6. #include <linux/err.h> 
  7. #include <linux/list.h> 
  8. #include <linux/errno.h> 
  9. #include <linux/mutex.h> 
  10. #include <linux/slab.h> 
  11. #include <linux/spi/spi.h> 
  12. #include <linux/spi/spidev.h> 
  13. #include <asm/uaccess.h> 
  14.  
  15. #define SPIDEV_MAJOR            153 //spidev主设备号 
  16. #define N_SPI_MINORS            32  /* ... up to 256 */ 
  17. static DECLARE_BITMAP(minors, N_SPI_MINORS);    //声明次设备位图 
  18. #define SPI_MODE_MASK (SPI_CPHA|SPI_CPOL|SPI_CS_HIGH|SPI_LSB_FIRST|SPI_3WIRE|SPI_LOOP|SPI_NO_CS|SPI_READY) 
  19.  
  20. struct spidev_data { 
  21.     dev_t   devt;               //设备号 
  22.     spinlock_t  spi_lock;       //自旋锁 
  23.     struct spi_device   *spi;   //spi设备结构体 
  24.     struct list_head    device_entry; 
  25.     struct mutex    buf_lock;   //互斥锁 
  26.     unsigned        users;      //使用者计数 
  27.     u8          *buffer;        //缓冲区 
  28. }; 
  29.  
  30. static LIST_HEAD(device_list);  //声明spi设备链表 
  31. static DEFINE_MUTEX(device_list_lock);  //定义互斥锁 
  32. static unsigned bufsiz = 4096;  //最大传输缓冲区大小 
  33. module_param(bufsiz, uint, S_IRUGO); 
  34. MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message"); 
  35.  
  36. static void spidev_complete(void *arg) 
  37.     complete(arg);  //调用complete 
  38.  
  39. static ssize_t spidev_sync(struct spidev_data *spidev, struct spi_message *message) 
  40.     DECLARE_COMPLETION_ONSTACK(done); 
  41.     int status; 
  42.  
  43.     message->complete = spidev_complete; //设置spi消息的complete方法 回调函数 
  44.     message->context = &done; 
  45.  
  46.     spin_lock_irq(&spidev->spi_lock); 
  47.     if (spidev->spi == NULL) //判断是否有指定对应的spi设备 
  48.         status = -ESHUTDOWN; 
  49.     else 
  50.         status = spi_async(spidev->spi, message);    //spi异步同步 
  51.     spin_unlock_irq(&spidev->spi_lock); 
  52.  
  53.     if (status == 0) { 
  54.         wait_for_completion(&done); //等待传输完成 
  55.         status = message->status;    //获取spi消息传输事务状态 
  56.         if (status == 0) 
  57.             status = message->actual_length; //status等于传输的实际长度 
  58.     } 
  59.     return status;  //返回实际传输长度 
  60.  
  61. static inli
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值