(转载)SPI驱动之SPI设备驱动程序

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

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

[cpp] view plain copy

  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. };

[cpp] view plain copy

  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, <[email protected]>");  
  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.  
  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, <[email protected]>");

  56. MODULE_DESCRIPTION("User mode SPI device interface");

  57. MODULE_LICENSE("GPL");

  58. 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

[cpp] view plain copy

  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

[cpp] view plain copy

  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.  
  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. }

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

[cpp] view plain copy

  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.  
  7. /* buffer is NULL unless this device is open (users > 0) */

  8. struct mutex buf_lock;

  9. unsigned users; //计数,也即是此设备被open的次数

  10. u8 *buffer;

  11. };

find_first_zero_bit(minors, N_SPI_MINORS)
第一个参数minors的定义:

kernel3.0.15/driver/spi/spidev.c

[cpp] view plain copy

  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.  
  3. static DECLARE_BITMAP(minors, N_SPI_MINORS);

DECLARE_BITMAP是一个宏,定义如下:

kernel3.0.15/include/linux/types.h

[cpp] view plain copy

  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

[cpp] view plain copy

  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.  
  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. }

4. 读和写函数:spidev_read & spidev_write

[cpp] view plain copy

  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.  
  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. }

5.ioctl函数:spidev_ioctl

[cpp] view plain copy

  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. }  

猜你喜欢

转载自blog.csdn.net/weixin_42015463/article/details/81430552