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 inline ssize_t spidev_sync_write(struct spidev_data *spidev, size_t len) 
  62.     struct spi_transfer t = { 
  63.             .tx_buf     = spidev->buffer,    //發送緩沖區 
  64.             .len        = len,  //發送數據長度 
  65.         }; 
  66.     struct spi_message  m; 
  67.  
  68.     spi_message_init(&m);   //初始化spi消息(初始化spi傳遞事務隊列) 
  69.     spi_message_add_tail(&t, &m);   //添加spr傳遞到該隊列 
  70.     return spidev_sync(spidev, &m); //同步讀寫 
  71.  
  72. static inline ssize_t spidev_sync_read(struct spidev_data *spidev, size_t len) 
  73.     struct spi_transfer t = { 
  74.             .rx_buf     = spidev->buffer,    //接收緩沖區 
  75.             .len        = len,  //接收數據長度 
  76.         }; 
  77.     struct spi_message  m; 
  78.  
  79.     spi_message_init(&m);   //初始化spi消息(初始化spi傳遞事務隊列) 
  80.     spi_message_add_tail(&t, &m);   //添加spr傳遞到該隊列 
  81.     return spidev_sync(spidev, &m); //同步讀寫 
  82.  
  83. static ssize_t spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) 
  84.     struct spidev_data  *spidev; 
  85.     ssize_t status = 0; 
  86.  
  87.     if (count > bufsiz)  //傳輸數據大於緩沖區容量 
  88.         return -EMSGSIZE; 
  89.     spidev = filp->private_data; //從文件私有數據指針獲取spidev_data 
  90.     mutex_lock(&spidev->buf_lock);   //上互斥鎖 
  91.     status = spidev_sync_read(spidev, count);   //同步讀,返回傳輸數據長度 
  92.     if (status > 0) { 
  93.         unsigned long   missing;    //丟失的數據個數 
  94.         missing = copy_to_user(buf, spidev->buffer, status); //內核空間復制到用戶空間 
  95.         if (missing == status)      //丟失的數據個數等於要傳輸的數據個數 
  96.             status = -EFAULT; 
  97.         else 
  98.             status = status - missing;  //傳輸成功的數據個數 
  99.     } 
  100.     mutex_unlock(&spidev->buf_lock);//解互斥鎖 
  101.     return status;  //返回讀取成功的數據個數 
  102.  
  103. static ssize_t spidev_write(struct file *filp, const char __user *buf,size_t count, loff_t *f_pos) 
  104.     struct spidev_data  *spidev; 
  105.     ssize_t         status = 0; 
  106.     unsigned long       missing; 
  107.  
  108.     if (count > bufsiz)  //傳輸數據大於緩沖區容量 
  109.         return -EMSGSIZE; 
  110.     spidev = filp->private_data; //從文件私有數據指針獲取spidev_data 
  111.     mutex_lock(&spidev->buf_lock);   //上互斥鎖 
  112.     missing = copy_from_user(spidev->buffer, buf, count);    //用戶空間復制到內核空間 
  113.     if (missing == 0) { //傳輸失敗個數為0 
  114.         status = spidev_sync_write(spidev, count);  //同步寫,返回傳輸數據長度 
  115.     }  
  116.     else 
  117.         status = -EFAULT; 
  118.     mutex_unlock(&spidev->buf_lock);//解互斥鎖 
  119.     return status;  //返回寫數據的實際個數 
  120.  
  121. static int spidev_message(struct spidev_data *spidev,struct spi_ioc_transfer *u_xfers, unsigned n_xfers) 
  122.     struct spi_message  msg; 
  123.     struct spi_transfer *k_xfers; 
  124.     struct spi_transfer *k_tmp; 
  125.     struct spi_ioc_transfer *u_tmp; 
  126.     unsigned    n, total; 
  127.     u8  *buf; 
  128.     int status = -EFAULT; 
  129.  
  130.     spi_message_init(&msg); //初始化spi消息(初始化spi傳遞事務隊列) 
  131.     k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL); //分配spi傳輸指針內存 
  132.     if (k_xfers == NULL) 
  133.         return -ENOMEM; 
  134.     buf = spidev->buffer;    //獲取spidev_data的緩沖區 
  135.     total = 0; 
  136.     //n=xfers為spi_ioc_transfer個數,u_tmp = u_xfers為要處理的spi_ioc_transfer指針 
  137.     for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;n;n--, k_tmp++, u_tmp++) { 
  138.         k_tmp->len = u_tmp->len;  //設置傳輸信息的長度 
  139.         total += k_tmp->len; //累加傳輸信息的總長度 
  140.         if (total > bufsiz) {    //信息量超過bufsiz緩沖區最大容量 
  141.             status = -EMSGSIZE; 
  142.             goto done; 
  143.         } 
  144.         if (u_tmp->rx_buf) { //接收緩沖區指針不為空 
  145.             k_tmp->rx_buf = buf; //緩沖區指向buf 
  146.             if (!access_ok(VERIFY_WRITE, (u8 __user *)(uintptr_t) u_tmp->rx_buf,u_tmp->len)) 
  147.                 goto done; 
  148.         } 
  149.         if (u_tmp->tx_buf) { //發送緩沖區指針不為空 
  150.             k_tmp->tx_buf = buf; //緩沖區指針指向buf 
  151.             if (copy_from_user(buf, (const u8 __user *)(uintptr_t) u_tmp->tx_buf,u_tmp->len)) //用戶空間復制數據到buf 
  152.                 goto done; 
  153.         } 
  154.         buf += k_tmp->len;   //緩沖區指針移動一個傳輸信息的長度 
  155.         k_tmp->cs_change = !!u_tmp->cs_change;    //設置cs_change 
  156.         k_tmp->bits_per_word = u_tmp->bits_per_word;  //設置bits_per_word 一個字多少位 
  157.         k_tmp->delay_usecs = u_tmp->delay_usecs;  //設置delay_usecs 毫秒級延時 
  158.         k_tmp->speed_hz = u_tmp->speed_hz;    //設置speed_hz 速率 
  159. #ifdef VERBOSE 
  160.         dev_dbg(&spidev->spi->dev,"  xfer len %zd %s%s%s%dbits %u usec %uHz\n", 
  161.             u_tmp->len,u_tmp->rx_buf ? "rx " : "",u_tmp->tx_buf ? "tx " : "",u_tmp->cs_change ? "cs " : "", 
  162.             u_tmp->bits_per_word ? : spidev->spi->bits_per_word,u_tmp->delay_usecs,u_tmp->speed_hz ? : spidev->spi->max_speed_hz); 
  163. #endif 
  164.         spi_message_add_tail(k_tmp, &msg);  //添加spr傳遞到該隊列 
  165.     } 
  166.     //for循環的作用是將spi_ioc_transfer批量轉換為spi傳遞結構體spi_transfer,然后添加進spi傳遞事務隊列 
  167.     status = spidev_sync(spidev, &msg);     //同步讀寫 
  168.     if (status < 0) 
  169.         goto done; 
  170.     buf = spidev->buffer;    //獲取spidev_data緩沖區指針 
  171.     for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {   //批量從內核空間復制spi_ioc_transfer到用戶空間 
  172.         if (u_tmp->rx_buf) { //判斷是否存在接收緩沖區 
  173.             if (__copy_to_user((u8 __user *)(uintptr_t) u_tmp->rx_buf, buf,u_tmp->len)) { 
  174.                 status = -EFAULT; 
  175.                 goto done; 
  176.             } 
  177.         } 
  178.         buf += u_tmp->len;   //buf指針位置調整指向下一個spi_ioc_transfer 
  179.     } 
  180.     status = total; //status等於實際傳輸的數據長度 
  181. done: 
  182.     kfree(k_xfers); //釋放k_xfers 
  183.     return status;  //返回實際傳輸的數據長度 
  184.  
  185. static long spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 
  186.     int err = 0; 
  187.     int retval = 0; 
  188.     struct spidev_data  *spidev; 
  189.     struct spi_device   *spi; 
  190.     u32 tmp; 
  191.     unsigned    n_ioc; 
  192.     struct spi_ioc_transfer *ioc; 
  193.  
  194.     if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)    //判斷控制命令的類型 
  195.         return -ENOTTY; 
  196.     if (_IOC_DIR(cmd) & _IOC_READ)  //判斷控制命令的方向是否為讀read 
  197.         err = !access_ok(VERIFY_WRITE,(void __user *)arg, _IOC_SIZE(cmd));  //判斷傳輸數據大小 
  198.     if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE) //判斷控制命令的方向是否為寫write 
  199.         err = !access_ok(VERIFY_READ,(void __user *)arg, _IOC_SIZE(cmd));   //判斷傳輸數據大小 
  200.     if (err) 
  201.         return -EFAULT; 
  202.  
  203.     spidev = filp->private_data; //從文件私有數據中獲取spidev_data 
  204.     spin_lock_irq(&spidev->spi_lock);    //上自旋鎖 
  205.     spi = spi_dev_get(spidev->spi);          //獲取spi設備 
  206.     spin_unlock_irq(&spidev->spi_lock);  //解自旋鎖 
  207.     if (spi == NULL)    //獲取spi設備失敗 
  208.         return -ESHUTDOWN;  //則返回錯誤 
  209.     mutex_lock(&spidev->buf_lock);   //上互斥鎖 
  210.      
  211.     switch (cmd) { 
  212.     case SPI_IOC_RD_MODE:   //設置spi讀模式  (此處原作者的理解與我不同,這里應該是應用程序獲取數據)
  213.         retval = __put_user(spi->mode & SPI_MODE_MASK,(__u8 __user *)arg); 
  214.         break; 
  215.     case SPI_IOC_RD_LSB_FIRST:  //設置spi讀最低有效位  (此處原作者的理解與我不同,這里應該是應用程序獲取數據)
  216.         retval = __put_user((spi->mode & SPI_LSB_FIRST) ?  1 : 0,(__u8 __user *)arg); 
  217.         break; 
  218.     case SPI_IOC_RD_BITS_PER_WORD:  //設置spi讀每個字含多個個位  (此處原作者的理解與我不同,這里應該是應用程序獲取數據)
  219.         retval = __put_user(spi->bits_per_word, (__u8 __user *)arg); 
  220.         break; 
  221.     case SPI_IOC_RD_MAX_SPEED_HZ:   //設置spi讀最大速率  (此處原作者的理解與我不同,這里應該是應用程序獲取數據)
  222.         retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg); 
  223.         break; 
  224.     case SPI_IOC_WR_MODE:   //設置spi寫模式 
  225.         retval = __get_user(tmp, (u8 __user *)arg); 
  226.         if (retval == 0) { 
  227.             u8  save = spi->mode;    //獲取spi設備模式 
  228.  
  229.             if (tmp & ~SPI_MODE_MASK) { 
  230.                 retval = -EINVAL; 
  231.                 break; 
  232.             } 
  233.  
  234.             tmp |= spi->mode & ~SPI_MODE_MASK; 
  235.             spi->mode = (u8)tmp; 
  236.             retval = spi_setup(spi);    //配置spi設備 
  237.             if (retval < 0) 
  238.                 spi->mode = save; 
  239.             else 
  240.                 dev_dbg(&spi->dev, "spi mode %02x\n", tmp); 
  241.         } 
  242.         break; 
  243.     case SPI_IOC_WR_LSB_FIRST:  //設置spi寫最低有效位 
  244.         retval = __get_user(tmp, (__u8 __user *)arg); 
  245.         if (retval == 0) { 
  246.             u8  save = spi->mode;    //獲取spi設備模式 
  247.  
  248.             if (tmp) 
  249.                 spi->mode |= SPI_LSB_FIRST; 
  250.             else 
  251.                 spi->mode &= ~SPI_LSB_FIRST; 
  252.             retval = spi_setup(spi);    //配置spi設備 
  253.             if (retval < 0) 
  254.                 spi->mode = save; 
  255.             else 
  256.                 dev_dbg(&spi->dev, "%csb first\n",tmp ? 'l' : 'm'); 
  257.         } 
  258.         break; 
  259.     case SPI_IOC_WR_BITS_PER_WORD:  //設置spi寫每個字含多個個位 
  260.         retval = __get_user(tmp, (__u8 __user *)arg);   //用戶空間獲取數據 
  261.         if (retval == 0) { 
  262.             u8  save = spi->bits_per_word;   //獲取spi設備 每個字含多少位 
  263.  
  264.             spi->bits_per_word = tmp;    //更新新的spi設備 每個字含多少位 
  265.             retval = spi_setup(spi);    //配置spi設備 
  266.             if (retval < 0)  //配置失敗 
  267.                 spi->bits_per_word = save;   //還原spi設備 每個字含多少位 
  268.             else 
  269.                 dev_dbg(&spi->dev, "%d bits per word\n", tmp); 
  270.         } 
  271.         break; 
  272.     case SPI_IOC_WR_MAX_SPEED_HZ:       //設置spi寫最大速率 
  273.         retval = __get_user(tmp, (__u32 __user *)arg);  //用戶空間獲取數據 
  274.         if (retval == 0) { 
  275.             u32 save = spi->max_speed_hz;    //獲取spi設備最大速率 
  276.  
  277.             spi->max_speed_hz = tmp; //更新新的spi設備最大速率 
  278.             retval = spi_setup(spi);    //配置spi設備 
  279.             if (retval < 0)  //配置失敗 
  280.                 spi->max_speed_hz = save;    //還原spi設備最大速率 
  281.             else 
  282.                 dev_dbg(&spi->dev, "%d Hz (max)\n", tmp); 
  283.         } 
  284.         break; 
  285.  
  286.     default: 
  287.         //命令必須為寫方向的命令,且傳輸數據必須是SPI_IOC_MESSAGE()修飾的命令 
  288.         if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))|| _IOC_DIR(cmd) != _IOC_WRITE) { 
  289.             retval = -ENOTTY; 
  290.             break; 
  291.         } 
  292.  
  293.         tmp = _IOC_SIZE(cmd);   //計算傳輸數據大小 
  294.         if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) { //判斷是否為spi_ioc_transfer對齊 
  295.             retval = -EINVAL; 
  296.             break; 
  297.         } 
  298.         n_ioc = tmp / sizeof(struct spi_ioc_transfer);  //計算出spi_ioc_transfer數據的個數 
  299.         if (n_ioc == 0) 
  300.             break; 
  301.  
  302.         ioc = kmalloc(tmp, GFP_KERNEL); //分配spi_ioc_transfer指針ioc內存 
  303.         if (!ioc) { 
  304.             retval = -ENOMEM; 
  305.             break; 
  306.         } 
  307.         if (__copy_from_user(ioc, (void __user *)arg, tmp)) {   //從用戶空間復制到內核空間 
  308.             kfree(ioc); //復制失敗則釋放ioc內存 
  309.             retval = -EFAULT; 
  310.             break; 
  311.         } 
  312.  
  313.         retval = spidev_message(spidev, ioc, n_ioc);    //spidev消息處理 
  314.         kfree(ioc); //釋放ioc內存 
  315.         break; 
  316.     } 
  317.  
  318.     mutex_unlock(&spidev->buf_lock); //解互斥鎖 
  319.     spi_dev_put(spi);   //增加spi設備的引用計數 
  320.     return retval; 
  321.  
  322. static int spidev_open(struct inode *inode, struct file *filp) 
  323.     struct spidev_data  *spidev; 
  324.     int status = -ENXIO; 
  325.  
  326.     mutex_lock(&device_list_lock);  //上互斥鎖 
  327.     list_for_each_entry(spidev, &device_list, device_entry) {   //遍歷device_list 
  328.         if (spidev->devt == inode->i_rdev) {  //判斷設備號找到對應的設備 
  329.             status = 0; //設置狀態為0 
  330.             break; 
  331.         } 
  332.     } 
  333.     if (status == 0) {  //找得到對應的設備 
  334.         if (!spidev->buffer) {   //spidev_data緩沖區為空 
  335.             spidev->buffer = kmalloc(bufsiz, GFP_KERNEL);    //則分配內存 
  336.             if (!spidev->buffer) {   //還空 
  337.                 dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");  //申請內存失敗 
  338.                 status = -ENOMEM; 
  339.             } 
  340.         } 
  341.         if (status == 0) {  //找得到對應的設備 
  342.             spidev->users++; //spidev_data使用者計數++ 
  343.             filp->private_data = spidev; //spidev_data放在文件的私有數據里 
  344.             nonseekable_open(inode, filp);  //設置文件的打開模式(文件讀寫指針不會跟隨讀寫操作移動) 
  345.         } 
  346.     }  
  347.     else 
  348.         pr_debug("spidev: nothing for minor %d\n", iminor(inode)); 
  349.     mutex_unlock(&device_list_lock);    //接互斥鎖 
  350.     return status; 
  351.  
  352. static int spidev_release(struct inode *inode, struct file *filp) 
  353.     struct spidev_data  *spidev; 
  354.     int status = 0; 
  355.  
  356.     mutex_lock(&device_list_lock); 
  357.     spidev = filp->private_data; //獲取spidev_data 
  358.     filp->private_data = NULL;       //清除文件的私有數據指針 
  359.     spidev->users--;             //使用者個數-- 
  360.     if (!spidev->users) {    //如果使用者個數為0 
  361.         int     dofree; 
  362.         kfree(spidev->buffer);   //釋放spidev_data的緩沖區內存 
  363.         spidev->buffer = NULL;   //清除spidev_data緩沖區指針 
  364.         spin_lock_irq(&spidev->spi_lock);    //上自旋鎖 
  365.         dofree = (spidev->spi == NULL);  //判斷spi設備是否與spidev_data解綁了 
  366.         spin_unlock_irq(&spidev->spi_lock);  //解自旋鎖 
  367.         if (dofree)         //沒有捆綁的spi設備 
  368.             kfree(spidev);  //則是否spidev_data內存 
  369.     } 
  370.     mutex_unlock(&device_list_lock); 
  371.     return status; 
  372.  
  373. static const struct file_operations spidev_fops = {     //文件操作函數集 
  374.     .owner =    THIS_MODULE, 
  375.     .write =    spidev_write,       //寫write 
  376.     .read =     spidev_read,        //讀read 
  377.     .unlocked_ioctl = spidev_ioctl, //控制ioctl 
  378.     .open =     spidev_open,        //打開open 
  379.     .release =  spidev_release,     //釋放release 
  380.     .llseek =   no_llseek,          //文件指針移動 no_llseek表示沒有移動 
  381. }; 
  382.  
  383. static struct class *spidev_class; 
  384.  
  385. static int __devinit spidev_probe(struct spi_device *spi) 
  386.     struct spidev_data  *spidev; 
  387.     int status; 
  388.     unsigned long   minor; 
  389.  
  390.     spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);  //分配spidev_data內存 
  391.     if (!spidev) 
  392.         return -ENOMEM; 
  393.     spidev->spi = spi;   //設置spidev_data->spi(spi設備) 
  394.     spin_lock_init(&spidev->spi_lock); 
  395.     mutex_init(&spidev->buf_lock); 
  396.     INIT_LIST_HEAD(&spidev->device_entry);   //初始化spidev_data入口鏈表 
  397.     mutex_lock(&device_list_lock); 
  398.     minor = find_first_zero_bit(minors, N_SPI_MINORS);  //查找次設備位圖分配次設備號 
  399.     if (minor < N_SPI_MINORS) { 
  400.         struct device *dev; 
  401.         spidev->devt = MKDEV(SPIDEV_MAJOR, minor);   //計算出設備號 
  402.         //創建設備/dev/spidev%d.%d(spidev總線號.片選號) 
  403.         dev = device_create(spidev_class, &spi->dev, spidev->devt,spidev, "spidev%d.%d",spi->master->bus_num, spi->chip_select); 
  404.         status = IS_ERR(dev) ? PTR_ERR(dev) : 0; 
  405.     }  
  406.     else { 
  407.         dev_dbg(&spi->dev, "no minor number available!\n"); 
  408.         status = -ENODEV; 
  409.     } 
  410.     if (status == 0) {  //分配設備號成功 
  411.         set_bit(minor, minors); //更新次設備位圖 
  412.         list_add(&spidev->device_entry, &device_list);   //添加進設備鏈表 
  413.     } 
  414.     mutex_unlock(&device_list_lock); 
  415.  
  416.     if (status == 0) 
  417.         spi_set_drvdata(spi, spidev);   //spi->dev->p->driver_data=spidev  
  418.     else 
  419.         kfree(spidev); 
  420.  
  421.     return status; 
  422.  
  423. static int __devexit spidev_remove(struct spi_device *spi) 
  424.     struct spidev_data  *spidev = spi_get_drvdata(spi);     //根據spi設備獲取spidev_data 
  425.     spin_lock_irq(&spidev->spi_lock);            //上自旋鎖 
  426.     spidev->spi = NULL;                              //清空spidev_data->spi指針 
  427.     spi_set_drvdata(spi, NULL);                     //spi->dev->p->driver_data=NULL 
  428.     spin_unlock_irq(&spidev->spi_lock);          //解自旋鎖 
  429.     mutex_lock(&device_list_lock);              //上互斥鎖 
  430.     list_del(&spidev->device_entry);             //刪除spidev_data入口鏈表 
  431.     device_destroy(spidev_class, spidev->devt);      //銷毀/dev/spidev%d.%d 
  432.     clear_bit(MINOR(spidev->devt), minors);          //清除次設備位圖對應位 
  433.     if (spidev->users == 0)                          //使用者個數為0 
  434.         kfree(spidev);                              //釋放spidev_data內存 
  435.     mutex_unlock(&device_list_lock);            //解互斥鎖 
  436.     return 0; 
  437.  
  438. static struct spi_driver spidev_spi_driver = {  //spi設備驅動 
  439.     .driver = { 
  440.         .name =     "spidev", 
  441.         .owner =    THIS_MODULE, 
  442.     }, 
  443.     .probe =    spidev_probe,   //spidev的probe方法(當注冊了modalias域為"spidev"的spi設備或板級設備,則會調用probe方法) 
  444.     .remove =   __devexit_p(spidev_remove), //spidev的remove方法 
  445. }; 
  446.  
  447. static int __init spidev_init(void)     //spidev接口初始化 
  448.     int status; 
  449.     BUILD_BUG_ON(N_SPI_MINORS > 256); 
  450.     //注冊字符設備,主設備號SPIDEV_MAJOR=153,捆綁的設備操作函數集為spidev_fops 
  451.     status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops); 
  452.     if (status < 0) 
  453.         return status; 
  454.     spidev_class = class_create(THIS_MODULE, "spidev"); //創建設備類spidev_class 
  455.     if (IS_ERR(spidev_class)) { 
  456.         unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name); 
  457.         return PTR_ERR(spidev_class); 
  458.     } 
  459.     status = spi_register_driver(&spidev_spi_driver);   //注冊spi設備驅動spidev_spi_driver 
  460.     if (status < 0) { 
  461.         class_destroy(spidev_class); 
  462.         unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name); 
  463.     } 
  464.     return status; 
  465. module_init(spidev_init);   //聲明初始化入口 
  466.  
  467. static void __exit spidev_exit(void)            //spidev接口銷毀 
  468.     spi_unregister_driver(&spidev_spi_driver);  //注銷spi設備驅動spidev_spi_driver 
  469.     class_destroy(spidev_class);                //注銷設備類spidev_class 
  470.     unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name); //注銷字符設備 
  471. module_exit(spidev_exit);   //聲明初始化出口 
  472.  
  473. MODULE_AUTHOR("Andrea Paterniani, <a.paterniani@swapp-eng.it>"); 
  474. MODULE_DESCRIPTION("User mode SPI device interface"); 
  475. MODULE_LICENSE("GPL"); 
  476. MODULE_ALIAS("spi:spidev"); 


二.用戶空間例子(spidev_test.c)

[cpp]  view plain copy
 
  1. #include <stdint.h> 
  2. #include <unistd.h> 
  3. #include <stdio.h> 
  4. #include <stdlib.h> 
  5. #include <getopt.h> 
  6. #include <fcntl.h> 
  7. #include <sys/ioctl.h> 
  8. #include <linux/types.h> 
  9. #include <linux/spi/spidev.h> 
  10.  
  11. #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 
  12.  
  13. static void pabort(const char *s) 
  14.     perror(s); 
  15.     abort(); 
  16.  
  17. static const char *device = "/dev/spidev1.1"; 
  18. static uint8_t mode; 
  19. static uint8_t bits = 8; 
  20. static uint32_t speed = 500000; 
  21. static uint16_t delay; 
  22.  
  23. static void transfer(int fd) 
  24.     int ret; 
  25.     uint8_t tx[] = {    //要發送的數據數組 
  26.         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  27.         0x40, 0x00, 0x00, 0x00, 0x00, 0x95, 
  28.         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  29.         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  30.         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  31.         0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD, 
  32.         0xF0, 0x0D, 
  33.     }; 
  34.     uint8_t rx[ARRAY_SIZE(tx)] = {0, }; //接收的數據數據 
  35.     struct spi_ioc_transfer tr = {  //聲明並初始化spi_ioc_transfer結構體 
  36.         .tx_buf = (unsigned long)tx, 
  37.         .rx_buf = (unsigned long)rx, 
  38.         .len = ARRAY_SIZE(tx), 
  39.         .delay_usecs = delay, 
  40.         .speed_hz = speed, 
  41.         .bits_per_word = bits, 
  42.     }; 
  43.     //SPI_IOC_MESSAGE(1)的1表示spi_ioc_transfer的數量 
  44.     ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);   //ioctl默認操作,傳輸數據 
  45.     if (ret < 1) 
  46.         pabort("can't send spi message"); 
  47.  
  48.     for (ret = 0; ret < ARRAY_SIZE(tx); ret++) { //打印接收緩沖區 
  49.         if (!(ret % 6))     //6個數據為一簇打印 
  50.             puts(""); 
  51.         printf("%.2X ", rx[ret]); 
  52.     } 
  53.     puts(""); 
  54.  
  55. static void print_usage(const char *prog)   //參數錯誤則打印幫助信息 
  56.     printf("Usage: %s [-DsbdlHOLC3]\n", prog); 
  57.     puts("  -D --device   device to use (default /dev/spidev1.1)\n" 
  58.          "  -s --speed    max speed (Hz)\n" 
  59.          "  -d --delay    delay (usec)\n" 
  60.          "  -b --bpw      bits per word \n" 
  61.          "  -l --loop     loopback\n" 
  62.          "  -H --cpha     clock phase\n" 
  63.          "  -O --cpol     clock polarity\n" 
  64.          "  -L --lsb      least significant bit first\n" 
  65.          "  -C --cs-high  chip select active high\n" 
  66.          "  -3 --3wire    SI/SO signals shared\n"); 
  67.     exit(1); 
  68.  
  69. static void parse_opts(int argc, char *argv[]) 
  70.     while (1) { 
  71.         static const struct option lopts[] = {  //參數命令表 
  72.             { "device",  1, 0, 'D' }, 
  73.             { "speed",   1, 0, 's' }, 
  74.             { "delay",   1, 0, 'd' }, 
  75.             { "bpw",     1, 0, 'b' }, 
  76.             { "loop",    0, 0, 'l' }, 
  77.             { "cpha",    0, 0, 'H' }, 
  78.             { "cpol",    0, 0, 'O' }, 
  79.             { "lsb",     0, 0, 'L' }, 
  80.             { "cs-high", 0, 0, 'C' }, 
  81.             { "3wire",   0, 0, '3' }, 
  82.             { "no-cs",   0, 0, 'N' }, 
  83.             { "ready",   0, 0, 'R' }, 
  84.             { NULL, 0, 0, 0 }, 
  85.         }; 
  86.         int c; 
  87.  
  88.         c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL); 
  89.  
  90.         if (c == -1) 
  91.             break; 
  92.  
  93.         switch (c) { 
  94.         case 'D':   //設備名 
  95.             device = optarg; 
  96.             break; 
  97.         case 's':   //速率 
  98.             speed = atoi(optarg); 
  99.             break; 
  100.         case 'd':   //延時時間 
  101.             delay = atoi(optarg); 
  102.             break; 
  103.         case 'b':   //每字含多少位 
  104.             bits = atoi(optarg); 
  105.             break; 
  106.         case 'l':   //回送模式 
  107.             mode |= SPI_LOOP; 
  108.             break; 
  109.         case 'H':   //時鍾相位 
  110.             mode |= SPI_CPHA; 
  111.             break; 
  112.         case 'O':   //時鍾極性 
  113.             mode |= SPI_CPOL; 
  114.             break; 
  115.         case 'L':   //lsb 最低有效位 
  116.             mode |= SPI_LSB_FIRST; 
  117.             break; 
  118.         case 'C':   //片選高電平 
  119.             mode |= SPI_CS_HIGH; 
  120.             break; 
  121.         case '3':   //3線傳輸模式 
  122.             mode |= SPI_3WIRE; 
  123.             break; 
  124.         case 'N':   //沒片選 
  125.             mode |= SPI_NO_CS; 
  126.             break; 
  127.         case 'R':   //從機拉低電平停止數據傳輸 
  128.             mode |= SPI_READY; 
  129.             break; 
  130.         default:    //錯誤的參數 
  131.             print_usage(argv[0]); 
  132.             break; 
  133.         } 
  134.     } 
  135.  
  136. int main(int argc, char *argv[]) 
  137.     int ret = 0; 
  138.     int fd; 
  139.  
  140.     parse_opts(argc, argv); //解析傳遞進來的參數 
  141.  
  142.     fd = open(device, O_RDWR);  //打開設備文件 
  143.     if (fd < 0) 
  144.         pabort("can't open device"); 
  145.  
  146.     /*
  147.      * spi mode //設置spi設備模式
  148.      */ 
  149.     ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);    //寫模式 
  150.     if (ret == -1) 
  151.         pabort("can't set spi mode"); 
  152.  
  153.     ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);    //讀模式 
  154.     if (ret == -1) 
  155.         pabort("can't get spi mode"); 
  156.  
  157.     /*
  158.      * bits per word    //設置每個字含多少位
  159.      */ 
  160.     ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);   //寫 每個字含多少位 
  161.     if (ret == -1) 
  162.         pabort("can't set bits per word"); 
  163.  
  164.     ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);   //讀 每個字含多少位 
  165.     if (ret == -1) 
  166.         pabort("can't get bits per word"); 
  167.  
  168.     /*
  169.      * max speed hz     //設置速率
  170.      */ 
  171.     ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);   //寫速率 
  172.     if (ret == -1) 
  173.         pabort("can't set max speed hz"); 
  174.  
  175.     ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);   //讀速率 
  176.     if (ret == -1) 
  177.         pabort("can't get max speed hz"); 
  178.     //打印模式,每字多少位和速率信息 
  179.     printf("spi mode: %d\n", mode); 
  180.     printf("bits per word: %d\n", bits); 
  181.     printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); 
  182.  
  183.     transfer(fd);   //傳輸測試 
  184.  
  185.     close(fd);  //關閉設備 
  186.  
  187.     return ret; 


這里整理下ioctl的命令:

[cpp]  view plain copy
 
    1. SPI_IOC_RD_MODE     //讀 模式 
    2. SPI_IOC_RD_LSB_FIRST    //讀 LSB 
    3. SPI_IOC_RD_BITS_PER_WORD    //讀 每字多少位 
    4. SPI_IOC_RD_MAX_SPEED_HZ //讀 最大速率 
    5. SPI_IOC_WR_MODE     //寫 模式 
    6. SPI_IOC_WR_LSB_FIRST    //寫 LSB 
    7. SPI_IOC_WR_BITS_PER_WORD    //寫 每字多少位 
    8. SPI_IOC_WR_MAX_SPEED_HZ //寫 最大速率 
    9. SPI_IOC_MESSAGE(n)      //傳輸n個數據包 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM