当前位置:   article > 正文

SPI驱动之SPI设备驱动程序

SPI驱动之SPI设备驱动程序


前篇文章分析了SPI主控制器驱动,也就是SPI总线驱动,既然总线有了,根据Linux设备驱动模型,还得有SPI设备和SPI设备驱动。SPI设备是在板级文件中注册,SPI设备驱动需要用户自己实现,好在内核为我们提供了一个通用的SPI设备驱动spidev.c,下面就来分析一下这个文件,该文件位于kernel3.0.15/drivers/spi/spidev.c。

1. 模块初始化和注销:spidev_init & spidev_exit

  1. static const struct file_operations spidev_fops = {  
  2.     .owner =    THIS_MODULE,  
  3.     /* REVISIT switch to aio primitives, so that userspace 
  4.      * gets more complete API coverage.  It'll simplify things 
  5.      * too, except for the locking. 
  6.      */  
  7.     .write =    spidev_write,  
  8.     .read =     spidev_read,  
  9.     .unlocked_ioctl = spidev_ioctl,  
  10.     .compat_ioctl = spidev_compat_ioctl,  
  11.     .open =     spidev_open,  
  12.     .release =  spidev_release,  
  13.     .llseek =   no_llseek,  
  14. };  
  1. static const struct file_operations spidev_fops = {
  2. .owner = THIS_MODULE,
  3. /* REVISIT switch to aio primitives, so that userspace
  4. * gets more complete API coverage. It'll simplify things
  5. * too, except for the locking.
  6. */
  7. .write = spidev_write,
  8. .read = spidev_read,
  9. .unlocked_ioctl = spidev_ioctl,
  10. .compat_ioctl = spidev_compat_ioctl,
  11. .open = spidev_open,
  12. .release = spidev_release,
  13. .llseek = no_llseek,
  14. };

  1. static struct spi_driver spidev_spi_driver = {  
  2.     .driver = {  
  3.         .name =     "spidev",  
  4.         .owner =    THIS_MODULE,  
  5.     },  
  6.     .probe =    spidev_probe,  
  7.     .remove =   __devexit_p(spidev_remove),  
  8.   
  9.     /* NOTE:  suspend/resume methods are not necessary here. 
  10.      * We don't do anything except pass the requests to/from 
  11.      * the underlying controller.  The refrigerator handles 
  12.      * most issues; the controller driver handles the rest. 
  13.      */  
  14. };  
  15.   
  16. /*-------------------------------------------------------------------------*/  
  17.   
  18. static int __init spidev_init(void)  
  19. {  
  20.     int status;  
  21.   
  22.     /* Claim our 256 reserved device numbers.  Then register a class 
  23.      * that will key udev/mdev to add/remove /dev nodes.  Last, register 
  24.      * the driver which manages those device numbers. 
  25.      */  
  26.     BUILD_BUG_ON(N_SPI_MINORS > 256);  
  27.     //注册字符设备,参数spidev_fops是struct file_operations的实例,这里就可以知道,用户程序的open、write等操作最终会调用这里面的函数  
  28.     status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);  
  29.     if (status < 0)  
  30.         return status;  
  31.   
  32.     spidev_class = class_create(THIS_MODULE, "spidev"); //创建spidev这一类设备,为后面自动生成设备节点做准备  
  33.     if (IS_ERR(spidev_class)) {  
  34.         unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);  
  35.         return PTR_ERR(spidev_class);  
  36.     }  
  37.   
  38.     status = spi_register_driver(&spidev_spi_driver); //注册spi设备驱动  
  39.     if (status < 0) {  
  40.         class_destroy(spidev_class);  
  41.         unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);  
  42.     }  
  43.     return status;  
  44. }  
  45. module_init(spidev_init);  
  46.   
  47. static void __exit spidev_exit(void)  
  48. {  
  49.     spi_unregister_driver(&spidev_spi_driver);  
  50.     class_destroy(spidev_class);  
  51.     unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);  
  52. }  
  53. module_exit(spidev_exit);  
  54.   
  55. MODULE_AUTHOR("Andrea Paterniani, <a.paterniani@swapp-eng.it>");  
  56. MODULE_DESCRIPTION("User mode SPI device interface");  
  57. MODULE_LICENSE("GPL");  
  58. MODULE_ALIAS("spi:spidev");  
  1. static struct spi_driver spidev_spi_driver = {
  2. .driver = {
  3. .name = "spidev",
  4. .owner = THIS_MODULE,
  5. },
  6. .probe = spidev_probe,
  7. .remove = __devexit_p(spidev_remove),
  8. /* NOTE: suspend/resume methods are not necessary here.
  9. * We don't do anything except pass the requests to/from
  10. * the underlying controller. The refrigerator handles
  11. * most issues; the controller driver handles the rest.
  12. */
  13. };
  14. /*-------------------------------------------------------------------------*/
  15. static int __init spidev_init(void)
  16. {
  17. int status;
  18. /* Claim our 256 reserved device numbers. Then register a class
  19. * that will key udev/mdev to add/remove /dev nodes. Last, register
  20. * the driver which manages those device numbers.
  21. */
  22. BUILD_BUG_ON(N_SPI_MINORS > 256);
  23. //注册字符设备,参数spidev_fops是struct file_operations的实例,这里就可以知道,用户程序的open、write等操作最终会调用这里面的函数
  24. status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
  25. if (status < 0)
  26. return status;
  27. spidev_class = class_create(THIS_MODULE, "spidev"); //创建spidev这一类设备,为后面自动生成设备节点做准备
  28. if (IS_ERR(spidev_class)) {
  29. unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
  30. return PTR_ERR(spidev_class);
  31. }
  32. status = spi_register_driver(&spidev_spi_driver); //注册spi设备驱动
  33. if (status < 0) {
  34. class_destroy(spidev_class);
  35. unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
  36. }
  37. return status;
  38. }
  39. module_init(spidev_init);
  40. static void __exit spidev_exit(void)
  41. {
  42. spi_unregister_driver(&spidev_spi_driver);
  43. class_destroy(spidev_class);
  44. unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
  45. }
  46. module_exit(spidev_exit);
  47. MODULE_AUTHOR("Andrea Paterniani, <a.paterniani@swapp-eng.it>");
  48. MODULE_DESCRIPTION("User mode SPI device interface");
  49. MODULE_LICENSE("GPL");
  50. MODULE_ALIAS("spi:spidev");

在模块初始化函数中,创建了一个字符设备以提供API给用户层,同时创建了一个spidev类,最后注册spi_driver到内核中。在这里我们看到了SPI设备驱动是如何提供API给用户层的,那就是通过再熟悉不过的字符设备。通过字符设备,给用户层提供了5个API:open,release,write,read和ioctl。

接下来分析一下spi_register_driver函数,该函数位于kernel3.0.15/drivers/spi/spi.c

  1. int spi_register_driver(struct spi_driver *sdrv)  
  2. {  
  3.     sdrv->driver.bus = &spi_bus_type; //该驱动所属的总线  
  4.     if (sdrv->probe)  
  5.         sdrv->driver.probe = spi_drv_probe;  
  6.     if (sdrv->remove)  
  7.         sdrv->driver.remove = spi_drv_remove;  
  8.     if (sdrv->shutdown)  
  9.         sdrv->driver.shutdown = spi_drv_shutdown;  
  10.     //将驱动注册进设备模型,注册成功的话就会在总线上寻找设备,调用总线上的match函数,看能否与之匹配起来,匹配成功的话,驱动中的probe函数就会被调用  
  11.     return driver_register(&sdrv->driver);  
  12. }  
  1. int spi_register_driver(struct spi_driver *sdrv)
  2. {
  3. sdrv->driver.bus = &spi_bus_type; //该驱动所属的总线
  4. if (sdrv->probe)
  5. sdrv->driver.probe = spi_drv_probe;
  6. if (sdrv->remove)
  7. sdrv->driver.remove = spi_drv_remove;
  8. if (sdrv->shutdown)
  9. sdrv->driver.shutdown = spi_drv_shutdown;
  10. //将驱动注册进设备模型,注册成功的话就会在总线上寻找设备,调用总线上的match函数,看能否与之匹配起来,匹配成功的话,驱动中的probe函数就会被调用
  11. return driver_register(&sdrv->driver);
  12. }

在调用driver_register的过程中,将用driver.name和spi_device的modalias字段进行比较,两者相等则将该spi_driver和spi_device进行绑定。当spi_driver注册成功以后,将调用probe方法:spidev_probe函数。

2. 探测和移除函数:spidev_probe & spidev_remove

  1. static int __devinit spidev_probe(struct spi_device *spi)  
  2. {  
  3.     struct spidev_data  *spidev;  
  4.     int         status;  
  5.     unsigned long       minor;  
  6.   
  7.     /* Allocate driver data */  
  8.     spidev = kzalloc(sizeof(*spidev), GFP_KERNEL); //分配内存,注意对象的类型是struct spidev_data  
  9.     if (!spidev)  
  10.         return -ENOMEM;  
  11.   
  12.     /* Initialize the driver data */  
  13.     spidev->spi = spi;  
  14.     spin_lock_init(&spidev->spi_lock); //一些锁和链表的初始化  
  15.     mutex_init(&spidev->buf_lock);  
  16.   
  17.     INIT_LIST_HEAD(&spidev->device_entry);  
  18.   
  19.     /* If we can allocate a minor number, hook up this device. 
  20.      * Reusing minors is fine so long as udev or mdev is working. 
  21.      */  
  22.     mutex_lock(&device_list_lock);  
  23.     minor = find_first_zero_bit(minors, N_SPI_MINORS); //从名字上就可以知道,就是找到第一个为0的位,分析见下面  
  24.     if (minor < N_SPI_MINORS) {  
  25.         struct device *dev;  
  26.   
  27.         spidev->devt = MKDEV(SPIDEV_MAJOR, minor); //如果找到了非0位,就将它作为次设备号与之前注册的主设备号生成设备号  
  28.         dev = device_create(spidev_class, &spi->dev, spidev->devt,//创建设备,并生成设备节点,设备节点在/dev目录下,名字的形式为“spidevx.x”  
  29.                     spidev, "spidev%d.%d",  
  30.                     spi->master->bus_num, spi->chip_select);  
  31.         status = IS_ERR(dev) ? PTR_ERR(dev) : 0;  
  32.     } else {  
  33.         dev_dbg(&spi->dev, "no minor number available!\n");  
  34.         status = -ENODEV;  
  35.     }  
  36.     if (status == 0) { //创建设备成功后,将相应的位置1,表示该次设备号已经被使用,同时将该设备加入到设备链表  
  37.         set_bit(minor, minors);  
  38.         list_add(&spidev->device_entry, &device_list);  
  39.     }  
  40.     mutex_unlock(&device_list_lock);  
  41.   
  42.     if (status == 0)  
  43.         spi_set_drvdata(spi, spidev); //将设备的私有数据指针指向该设备  
  44.     else  
  45.         kfree(spidev);  
  46.   
  47.     return status;  
  48. }  
  49.   
  50. static int __devexit spidev_remove(struct spi_device *spi)  
  51. {  
  52.     struct spidev_data  *spidev = spi_get_drvdata(spi);  
  53.   
  54.     /* make sure ops on existing fds can abort cleanly */  
  55.     spin_lock_irq(&spidev->spi_lock);  
  56.     spidev->spi = NULL;  
  57.     spi_set_drvdata(spi, NULL);  
  58.     spin_unlock_irq(&spidev->spi_lock);  
  59.   
  60.     /* prevent new opens */  
  61.     mutex_lock(&device_list_lock);  
  62.     list_del(&spidev->device_entry);  
  63.     device_destroy(spidev_class, spidev->devt);  
  64.     clear_bit(MINOR(spidev->devt), minors);  
  65.     if (spidev->users == 0)  
  66.         kfree(spidev);  
  67.     mutex_unlock(&device_list_lock);  
  68.   
  69.     return 0;  
  70. }  
  1. static int __devinit spidev_probe(struct spi_device *spi)
  2. {
  3. struct spidev_data *spidev;
  4. int status;
  5. unsigned long minor;
  6. /* Allocate driver data */
  7. spidev = kzalloc(sizeof(*spidev), GFP_KERNEL); //分配内存,注意对象的类型是struct spidev_data
  8. if (!spidev)
  9. return -ENOMEM;
  10. /* Initialize the driver data */
  11. spidev->spi = spi;
  12. spin_lock_init(&spidev->spi_lock); //一些锁和链表的初始化
  13. mutex_init(&spidev->buf_lock);
  14. INIT_LIST_HEAD(&spidev->device_entry);
  15. /* If we can allocate a minor number, hook up this device.
  16. * Reusing minors is fine so long as udev or mdev is working.
  17. */
  18. mutex_lock(&device_list_lock);
  19. minor = find_first_zero_bit(minors, N_SPI_MINORS); //从名字上就可以知道,就是找到第一个为0的位,分析见下面
  20. if (minor < N_SPI_MINORS) {
  21. struct device *dev;
  22. spidev->devt = MKDEV(SPIDEV_MAJOR, minor); //如果找到了非0位,就将它作为次设备号与之前注册的主设备号生成设备号
  23. dev = device_create(spidev_class, &spi->dev, spidev->devt,//创建设备,并生成设备节点,设备节点在/dev目录下,名字的形式为“spidevx.x”
  24. spidev, "spidev%d.%d",
  25. spi->master->bus_num, spi->chip_select);
  26. status = IS_ERR(dev) ? PTR_ERR(dev) : 0;
  27. } else {
  28. dev_dbg(&spi->dev, "no minor number available!\n");
  29. status = -ENODEV;
  30. }
  31. if (status == 0) { //创建设备成功后,将相应的位置1,表示该次设备号已经被使用,同时将该设备加入到设备链表
  32. set_bit(minor, minors);
  33. list_add(&spidev->device_entry, &device_list);
  34. }
  35. mutex_unlock(&device_list_lock);
  36. if (status == 0)
  37. spi_set_drvdata(spi, spidev); //将设备的私有数据指针指向该设备
  38. else
  39. kfree(spidev);
  40. return status;
  41. }
  42. static int __devexit spidev_remove(struct spi_device *spi)
  43. {
  44. struct spidev_data *spidev = spi_get_drvdata(spi);
  45. /* make sure ops on existing fds can abort cleanly */
  46. spin_lock_irq(&spidev->spi_lock);
  47. spidev->spi = NULL;
  48. spi_set_drvdata(spi, NULL);
  49. spin_unlock_irq(&spidev->spi_lock);
  50. /* prevent new opens */
  51. mutex_lock(&device_list_lock);
  52. list_del(&spidev->device_entry);
  53. device_destroy(spidev_class, spidev->devt);
  54. clear_bit(MINOR(spidev->devt), minors);
  55. if (spidev->users == 0)
  56. kfree(spidev);
  57. mutex_unlock(&device_list_lock);
  58. return 0;
  59. }

spidev_data(kernel3.0.15/driver/spi/spidev.c)

  1. struct spidev_data {  
  2.     dev_t           devt; //设备号  
  3.     spinlock_t      spi_lock;  
  4.     struct spi_device   *spi;  
  5.     struct list_head    device_entry; //设备链表,所有采用此驱动的设备将连成一个链表  
  6.   
  7.     /* buffer is NULL unless this device is open (users > 0) */  
  8.     struct mutex        buf_lock;  
  9.     unsigned        users; //计数,也即是此设备被open的次数  
  10.     u8          *buffer;  
  11. };  
  1. struct spidev_data {
  2. dev_t devt; //设备号
  3. spinlock_t spi_lock;
  4. struct spi_device *spi;
  5. struct list_head device_entry; //设备链表,所有采用此驱动的设备将连成一个链表
  6. /* buffer is NULL unless this device is open (users > 0) */
  7. struct mutex buf_lock;
  8. unsigned users; //计数,也即是此设备被open的次数
  9. u8 *buffer;
  10. };
find_first_zero_bit(minors, N_SPI_MINORS)
第一个参数minors的定义:

kernel3.0.15/driver/spi/spidev.c

  1. #define N_SPI_MINORS            32  /* ... up to 256 */  
  2.   
  3. static DECLARE_BITMAP(minors, N_SPI_MINORS);  
  1. #define N_SPI_MINORS 32 /* ... up to 256 */
  2. static DECLARE_BITMAP(minors, N_SPI_MINORS);
DECLARE_BITMAP是一个宏,定义如下:

kernel3.0.15/include/linux/types.h

  1. #define DECLARE_BITMAP(name,bits) \  
  2.     unsigned long name[BITS_TO_LONGS(bits)]  
  1. #define DECLARE_BITMAP(name,bits) \
  2. unsigned long name[BITS_TO_LONGS(bits)]
将宏展开后是这样的,unsigned long minors[1],其实就是定义一个只有一个元素的无符号长整形数组miniors。

3. 打开和释放函数:spidev_open & spidev_release

  1. static int spidev_open(struct inode *inode, struct file *filp)  
  2. {  
  3.     struct spidev_data  *spidev;  
  4.     int         status = -ENXIO;  
  5.   
  6.     mutex_lock(&device_list_lock);  
  7.   
  8.     list_for_each_entry(spidev, &device_list, device_entry) {  
  9.         if (spidev->devt == inode->i_rdev) { //遍历设备链表,每找到一个设备就将它的设备号与打开文件的设备号进行比较,相等的话表示查找成功  
  10.             status = 0;  
  11.             break;  
  12.         }  
  13.     }  
  14.     //查找成功后就分配读写数据内存,使用计数加1,设置文件私有数据指针指向查找到的设备,以后在驱动的write、read函数里就可以把它取出来  
  15.     if (status == 0) {  
  16.         if (!spidev->buffer) {  
  17.             spidev->buffer = kmalloc(bufsiz, GFP_KERNEL);  
  18.             if (!spidev->buffer) {  
  19.                 dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");  
  20.                 status = -ENOMEM;  
  21.             }  
  22.         }  
  23.         if (status == 0) {  
  24.             spidev->users++;  
  25.             filp->private_data = spidev;  
  26.             nonseekable_open(inode, filp);  
  27.         }  
  28.     } else  
  29.         pr_debug("spidev: nothing for minor %d\n", iminor(inode));  
  30.   
  31.     mutex_unlock(&device_list_lock);  
  32.     return status;  
  33. }  
  34.   
  35. static int spidev_release(struct inode *inode, struct file *filp)  
  36. {  
  37.     struct spidev_data  *spidev;  
  38.     int         status = 0;  
  39.   
  40.     mutex_lock(&device_list_lock);  
  41.     spidev = filp->private_data;  
  42.     filp->private_data = NULL;  
  43.   
  44.     /* last close? */  
  45.     spidev->users--;  
  46.     if (!spidev->users) {  
  47.         int     dofree;  
  48.   
  49.         kfree(spidev->buffer);  
  50.         spidev->buffer = NULL;  
  51.   
  52.         /* ... after we unbound from the underlying device? */  
  53.         spin_lock_irq(&spidev->spi_lock);  
  54.         dofree = (spidev->spi == NULL);  
  55.         spin_unlock_irq(&spidev->spi_lock);  
  56.   
  57.         if (dofree)  
  58.             kfree(spidev);  
  59.     }  
  60.     mutex_unlock(&device_list_lock);  
  61.   
  62.     return status;  
  63. }  
  1. static int spidev_open(struct inode *inode, struct file *filp)
  2. {
  3. struct spidev_data *spidev;
  4. int status = -ENXIO;
  5. mutex_lock(&device_list_lock);
  6. list_for_each_entry(spidev, &device_list, device_entry) {
  7. if (spidev->devt == inode->i_rdev) { //遍历设备链表,每找到一个设备就将它的设备号与打开文件的设备号进行比较,相等的话表示查找成功
  8. status = 0;
  9. break;
  10. }
  11. }
  12. //查找成功后就分配读写数据内存,使用计数加1,设置文件私有数据指针指向查找到的设备,以后在驱动的write、read函数里就可以把它取出来
  13. if (status == 0) {
  14. if (!spidev->buffer) {
  15. spidev->buffer = kmalloc(bufsiz, GFP_KERNEL);
  16. if (!spidev->buffer) {
  17. dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");
  18. status = -ENOMEM;
  19. }
  20. }
  21. if (status == 0) {
  22. spidev->users++;
  23. filp->private_data = spidev;
  24. nonseekable_open(inode, filp);
  25. }
  26. } else
  27. pr_debug("spidev: nothing for minor %d\n", iminor(inode));
  28. mutex_unlock(&device_list_lock);
  29. return status;
  30. }
  31. static int spidev_release(struct inode *inode, struct file *filp)
  32. {
  33. struct spidev_data *spidev;
  34. int status = 0;
  35. mutex_lock(&device_list_lock);
  36. spidev = filp->private_data;
  37. filp->private_data = NULL;
  38. /* last close? */
  39. spidev->users--;
  40. if (!spidev->users) {
  41. int dofree;
  42. kfree(spidev->buffer);
  43. spidev->buffer = NULL;
  44. /* ... after we unbound from the underlying device? */
  45. spin_lock_irq(&spidev->spi_lock);
  46. dofree = (spidev->spi == NULL);
  47. spin_unlock_irq(&spidev->spi_lock);
  48. if (dofree)
  49. kfree(spidev);
  50. }
  51. mutex_unlock(&device_list_lock);
  52. return status;
  53. }

4. 读和写函数:spidev_read & spidev_write

  1. /* Read-only message with current device setup */  
  2. static ssize_t  
  3. spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)  
  4. {  
  5.     struct spidev_data  *spidev;  
  6.     ssize_t         status = 0;  
  7.   
  8.     /* chipselect only toggles at start or end of operation */  
  9.     if (count > bufsiz)  
  10.         return -EMSGSIZE;  
  11.   
  12.     spidev = filp->private_data;  
  13.   
  14.     mutex_lock(&spidev->buf_lock);  
  15.     status = spidev_sync_read(spidev, count);  
  16.     if (status > 0) {  
  17.         unsigned long   missing;  
  18.   
  19.         missing = copy_to_user(buf, spidev->buffer, status);  
  20.         if (missing == status)  
  21.             status = -EFAULT;  
  22.         else  
  23.             status = status - missing;  
  24.     }  
  25.     mutex_unlock(&spidev->buf_lock);  
  26.   
  27.     return status;  
  28. }  
  29.   
  30. /* Write-only message with current device setup */  
  31. static ssize_t  
  32. spidev_write(struct file *filp, const char __user *buf,  
  33.         size_t count, loff_t *f_pos)  
  34. {  
  35.     struct spidev_data  *spidev;  
  36.     ssize_t         status = 0;  
  37.     unsigned long       missing;  
  38.   
  39.     /* chipselect only toggles at start or end of operation */  
  40.     if (count > bufsiz) //应用程序写入的数据不能大于驱动中缓冲区的大小,默认为4096个字节  
  41.         return -EMSGSIZE;  
  42.   
  43.     spidev = filp->private_data; //指向文件的私有数据  
  44.   
  45.     mutex_lock(&spidev->buf_lock);  
  46.     missing = copy_from_user(spidev->buffer, buf, count); //拷贝用户空间的数据到内核空间  
  47.     if (missing == 0) {  
  48.         status = spidev_sync_write(spidev, count);  
  49.     } else  
  50.         status = -EFAULT;  
  51.     mutex_unlock(&spidev->buf_lock);  
  52.   
  53.     return status;  
  54. }  
  1. /* Read-only message with current device setup */
  2. static ssize_t
  3. spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
  4. {
  5. struct spidev_data *spidev;
  6. ssize_t status = 0;
  7. /* chipselect only toggles at start or end of operation */
  8. if (count > bufsiz)
  9. return -EMSGSIZE;
  10. spidev = filp->private_data;
  11. mutex_lock(&spidev->buf_lock);
  12. status = spidev_sync_read(spidev, count);
  13. if (status > 0) {
  14. unsigned long missing;
  15. missing = copy_to_user(buf, spidev->buffer, status);
  16. if (missing == status)
  17. status = -EFAULT;
  18. else
  19. status = status - missing;
  20. }
  21. mutex_unlock(&spidev->buf_lock);
  22. return status;
  23. }
  24. /* Write-only message with current device setup */
  25. static ssize_t
  26. spidev_write(struct file *filp, const char __user *buf,
  27. size_t count, loff_t *f_pos)
  28. {
  29. struct spidev_data *spidev;
  30. ssize_t status = 0;
  31. unsigned long missing;
  32. /* chipselect only toggles at start or end of operation */
  33. if (count > bufsiz) //应用程序写入的数据不能大于驱动中缓冲区的大小,默认为4096个字节
  34. return -EMSGSIZE;
  35. spidev = filp->private_data; //指向文件的私有数据
  36. mutex_lock(&spidev->buf_lock);
  37. missing = copy_from_user(spidev->buffer, buf, count); //拷贝用户空间的数据到内核空间
  38. if (missing == 0) {
  39. status = spidev_sync_write(spidev, count);
  40. } else
  41. status = -EFAULT;
  42. mutex_unlock(&spidev->buf_lock);
  43. return status;
  44. }

5.ioctl函数:spidev_ioctl

  1. static long  
  2. spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  
  3. {  
  4.     int         err = 0;  
  5.     int         retval = 0;  
  6.     struct spidev_data  *spidev;  
  7.     struct spi_device   *spi;  
  8.     u32         tmp;  
  9.     unsigned        n_ioc;  
  10.     struct spi_ioc_transfer *ioc;  
  11.   
  12.     /* Check type and command number */  
  13.     if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)  
  14.         return -ENOTTY;  
  15.   
  16.     /* Check access direction once here; don't repeat below. 
  17.      * IOC_DIR is from the user perspective, while access_ok is 
  18.      * from the kernel perspective; so they look reversed. 
  19.      */  
  20.     if (_IOC_DIR(cmd) & _IOC_READ)  
  21.         err = !access_ok(VERIFY_WRITE,  
  22.                 (void __user *)arg, _IOC_SIZE(cmd));  
  23.     if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)  
  24.         err = !access_ok(VERIFY_READ,  
  25.                 (void __user *)arg, _IOC_SIZE(cmd));  
  26.     if (err)  
  27.         return -EFAULT;  
  28.   
  29.     /* guard against device removal before, or while, 
  30.      * we issue this ioctl. 
  31.      */  
  32.     spidev = filp->private_data;  
  33.     spin_lock_irq(&spidev->spi_lock);  
  34.     spi = spi_dev_get(spidev->spi);  
  35.     spin_unlock_irq(&spidev->spi_lock);  
  36.   
  37.     if (spi == NULL)  
  38.         return -ESHUTDOWN;  
  39.   
  40.     /* use the buffer lock here for triple duty: 
  41.      *  - prevent I/O (from us) so calling spi_setup() is safe; 
  42.      *  - prevent concurrent SPI_IOC_WR_* from morphing 
  43.      *    data fields while SPI_IOC_RD_* reads them; 
  44.      *  - SPI_IOC_MESSAGE needs the buffer locked "normally". 
  45.      */  
  46.     mutex_lock(&spidev->buf_lock);  
  47.   
  48.     switch (cmd) {  
  49.     /* read requests */  
  50.     case SPI_IOC_RD_MODE:  
  51.         retval = __put_user(spi->mode & SPI_MODE_MASK,  
  52.                     (__u8 __user *)arg);  
  53.         break;  
  54.     case SPI_IOC_RD_LSB_FIRST:  
  55.         retval = __put_user((spi->mode & SPI_LSB_FIRST) ?  1 : 0,  
  56.                     (__u8 __user *)arg);  
  57.         break;  
  58.     case SPI_IOC_RD_BITS_PER_WORD:  
  59.         retval = __put_user(spi->bits_per_word, (__u8 __user *)arg);  
  60.         break;  
  61.     case SPI_IOC_RD_MAX_SPEED_HZ:  
  62.         retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg);  
  63.         break;  
  64.   
  65.     /* write requests */  
  66.     case SPI_IOC_WR_MODE:  
  67.         retval = __get_user(tmp, (u8 __user *)arg);  
  68.         if (retval == 0) {  
  69.             u8  save = spi->mode;  
  70.   
  71.             if (tmp & ~SPI_MODE_MASK) {  
  72.                 retval = -EINVAL;  
  73.                 break;  
  74.             }  
  75.   
  76.             tmp |= spi->mode & ~SPI_MODE_MASK;  
  77.             spi->mode = (u8)tmp;  
  78.             retval = spi_setup(spi);  
  79.             if (retval < 0)  
  80.                 spi->mode = save;  
  81.             else  
  82.                 dev_dbg(&spi->dev, "spi mode %02x\n", tmp);  
  83.         }  
  84.         break;  
  85.     case SPI_IOC_WR_LSB_FIRST:  
  86.         retval = __get_user(tmp, (__u8 __user *)arg);  
  87.         if (retval == 0) {  
  88.             u8  save = spi->mode;  
  89.   
  90.             if (tmp)  
  91.                 spi->mode |= SPI_LSB_FIRST;  
  92.             else  
  93.                 spi->mode &= ~SPI_LSB_FIRST;  
  94.             retval = spi_setup(spi);  
  95.             if (retval < 0)  
  96.                 spi->mode = save;  
  97.             else  
  98.                 dev_dbg(&spi->dev, "%csb first\n",  
  99.                         tmp ? 'l' : 'm');  
  100.         }  
  101.         break;  
  102.     case SPI_IOC_WR_BITS_PER_WORD:  
  103.         retval = __get_user(tmp, (__u8 __user *)arg);  
  104.         if (retval == 0) {  
  105.             u8  save = spi->bits_per_word;  
  106.   
  107.             spi->bits_per_word = tmp;  
  108.             retval = spi_setup(spi);  
  109.             if (retval < 0)  
  110.                 spi->bits_per_word = save;  
  111.             else  
  112.                 dev_dbg(&spi->dev, "%d bits per word\n", tmp);  
  113.         }  
  114.         break;  
  115.     case SPI_IOC_WR_MAX_SPEED_HZ:  
  116.         retval = __get_user(tmp, (__u32 __user *)arg);  
  117.         if (retval == 0) {  
  118.             u32 save = spi->max_speed_hz;  
  119.   
  120.             spi->max_speed_hz = tmp;  
  121.             retval = spi_setup(spi);  
  122.             if (retval < 0)  
  123.                 spi->max_speed_hz = save;  
  124.             else  
  125.                 dev_dbg(&spi->dev, "%d Hz (max)\n", tmp);  
  126.         }  
  127.         break;  
  128.   
  129.     default:  
  130.         /* segmented and/or full-duplex I/O request */  
  131.         if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))  
  132.                 || _IOC_DIR(cmd) != _IOC_WRITE) {  
  133.             retval = -ENOTTY;  
  134.             break;  
  135.         }  
  136.   
  137.         tmp = _IOC_SIZE(cmd);  
  138.         if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {  
  139.             retval = -EINVAL;  
  140.             break;  
  141.         }  
  142.         n_ioc = tmp / sizeof(struct spi_ioc_transfer);  
  143.         if (n_ioc == 0)  
  144.             break;  
  145.   
  146.         /* copy into scratch area */  
  147.         ioc = kmalloc(tmp, GFP_KERNEL);  
  148.         if (!ioc) {  
  149.             retval = -ENOMEM;  
  150.             break;  
  151.         }  
  152.         if (__copy_from_user(ioc, (void __user *)arg, tmp)) {  
  153.             kfree(ioc);  
  154.             retval = -EFAULT;  
  155.             break;  
  156.         }  
  157.   
  158.         /* translate to spi_message, execute */  
  159.         retval = spidev_message(spidev, ioc, n_ioc);  
  160.         kfree(ioc);  
  161.         break;  
  162.     }  
  163.   
  164.     mutex_unlock(&spidev->buf_lock);  
  165.     spi_dev_put(spi);  
  166.     return retval;  
  167. }  
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/712560
推荐阅读
相关标签
  

闽ICP备14008679号