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. };  
static const struct file_operations spidev_fops = {
	.owner =	THIS_MODULE,
	/* REVISIT switch to aio primitives, so that userspace
	 * gets more complete API coverage.  It'll simplify things
	 * too, except for the locking.
	 */
	.write =	spidev_write,
	.read =		spidev_read,
	.unlocked_ioctl = spidev_ioctl,
	.compat_ioctl = spidev_compat_ioctl,
	.open =		spidev_open,
	.release =	spidev_release,
	.llseek =	no_llseek,
};

  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");  
static struct spi_driver spidev_spi_driver = {
	.driver = {
		.name =		"spidev",
		.owner =	THIS_MODULE,
	},
	.probe =	spidev_probe,
	.remove =	__devexit_p(spidev_remove),

	/* NOTE:  suspend/resume methods are not necessary here.
	 * We don't do anything except pass the requests to/from
	 * the underlying controller.  The refrigerator handles
	 * most issues; the controller driver handles the rest.
	 */
};

/*-------------------------------------------------------------------------*/

static int __init spidev_init(void)
{
	int status;

	/* Claim our 256 reserved device numbers.  Then register a class
	 * that will key udev/mdev to add/remove /dev nodes.  Last, register
	 * the driver which manages those device numbers.
	 */
	BUILD_BUG_ON(N_SPI_MINORS > 256);
	//注册字符设备,参数spidev_fops是struct file_operations的实例,这里就可以知道,用户程序的open、write等操作最终会调用这里面的函数
	status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
	if (status < 0)
		return status;

	spidev_class = class_create(THIS_MODULE, "spidev"); //创建spidev这一类设备,为后面自动生成设备节点做准备
	if (IS_ERR(spidev_class)) {
		unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
		return PTR_ERR(spidev_class);
	}

	status = spi_register_driver(&spidev_spi_driver); //注册spi设备驱动
	if (status < 0) {
		class_destroy(spidev_class);
		unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
	}
	return status;
}
module_init(spidev_init);

static void __exit spidev_exit(void)
{
	spi_unregister_driver(&spidev_spi_driver);
	class_destroy(spidev_class);
	unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
}
module_exit(spidev_exit);

MODULE_AUTHOR("Andrea Paterniani, <a.paterniani@swapp-eng.it>");
MODULE_DESCRIPTION("User mode SPI device interface");
MODULE_LICENSE("GPL");
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. }  
int spi_register_driver(struct spi_driver *sdrv)
{
	sdrv->driver.bus = &spi_bus_type; //该驱动所属的总线
	if (sdrv->probe)
		sdrv->driver.probe = spi_drv_probe;
	if (sdrv->remove)
		sdrv->driver.remove = spi_drv_remove;
	if (sdrv->shutdown)
		sdrv->driver.shutdown = spi_drv_shutdown;
	//将驱动注册进设备模型,注册成功的话就会在总线上寻找设备,调用总线上的match函数,看能否与之匹配起来,匹配成功的话,驱动中的probe函数就会被调用
	return driver_register(&sdrv->driver);
}

在调用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. }  
static int __devinit spidev_probe(struct spi_device *spi)
{
	struct spidev_data	*spidev;
	int			status;
	unsigned long		minor;

	/* Allocate driver data */
	spidev = kzalloc(sizeof(*spidev), GFP_KERNEL); //分配内存,注意对象的类型是struct spidev_data
	if (!spidev)
		return -ENOMEM;

	/* Initialize the driver data */
	spidev->spi = spi;
	spin_lock_init(&spidev->spi_lock); //一些锁和链表的初始化
	mutex_init(&spidev->buf_lock);

	INIT_LIST_HEAD(&spidev->device_entry);

	/* If we can allocate a minor number, hook up this device.
	 * Reusing minors is fine so long as udev or mdev is working.
	 */
	mutex_lock(&device_list_lock);
	minor = find_first_zero_bit(minors, N_SPI_MINORS); //从名字上就可以知道,就是找到第一个为0的位,分析见下面
	if (minor < N_SPI_MINORS) {
		struct device *dev;

		spidev->devt = MKDEV(SPIDEV_MAJOR, minor); //如果找到了非0位,就将它作为次设备号与之前注册的主设备号生成设备号
		dev = device_create(spidev_class, &spi->dev, spidev->devt,//创建设备,并生成设备节点,设备节点在/dev目录下,名字的形式为“spidevx.x”
				    spidev, "spidev%d.%d",
				    spi->master->bus_num, spi->chip_select);
		status = IS_ERR(dev) ? PTR_ERR(dev) : 0;
	} else {
		dev_dbg(&spi->dev, "no minor number available!\n");
		status = -ENODEV;
	}
	if (status == 0) { //创建设备成功后,将相应的位置1,表示该次设备号已经被使用,同时将该设备加入到设备链表
		set_bit(minor, minors);
		list_add(&spidev->device_entry, &device_list);
	}
	mutex_unlock(&device_list_lock);

	if (status == 0)
		spi_set_drvdata(spi, spidev); //将设备的私有数据指针指向该设备
	else
		kfree(spidev);

	return status;
}

static int __devexit spidev_remove(struct spi_device *spi)
{
	struct spidev_data	*spidev = spi_get_drvdata(spi);

	/* make sure ops on existing fds can abort cleanly */
	spin_lock_irq(&spidev->spi_lock);
	spidev->spi = NULL;
	spi_set_drvdata(spi, NULL);
	spin_unlock_irq(&spidev->spi_lock);

	/* prevent new opens */
	mutex_lock(&device_list_lock);
	list_del(&spidev->device_entry);
	device_destroy(spidev_class, spidev->devt);
	clear_bit(MINOR(spidev->devt), minors);
	if (spidev->users == 0)
		kfree(spidev);
	mutex_unlock(&device_list_lock);

	return 0;
}

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. };  
struct spidev_data {
	dev_t			devt; //设备号
	spinlock_t		spi_lock;
	struct spi_device	*spi;
	struct list_head	device_entry; //设备链表,所有采用此驱动的设备将连成一个链表

	/* buffer is NULL unless this device is open (users > 0) */
	struct mutex		buf_lock;
	unsigned		users; //计数,也即是此设备被open的次数
	u8			*buffer;
};
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);  
#define N_SPI_MINORS			32	/* ... up to 256 */

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)]  
#define DECLARE_BITMAP(name,bits) \
	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. }  
static int spidev_open(struct inode *inode, struct file *filp)
{
	struct spidev_data	*spidev;
	int			status = -ENXIO;

	mutex_lock(&device_list_lock);

	list_for_each_entry(spidev, &device_list, device_entry) {
		if (spidev->devt == inode->i_rdev) { //遍历设备链表,每找到一个设备就将它的设备号与打开文件的设备号进行比较,相等的话表示查找成功
			status = 0;
			break;
		}
	}
	//查找成功后就分配读写数据内存,使用计数加1,设置文件私有数据指针指向查找到的设备,以后在驱动的write、read函数里就可以把它取出来
	if (status == 0) {
		if (!spidev->buffer) {
			spidev->buffer = kmalloc(bufsiz, GFP_KERNEL);
			if (!spidev->buffer) {
				dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");
				status = -ENOMEM;
			}
		}
		if (status == 0) {
			spidev->users++;
			filp->private_data = spidev;
			nonseekable_open(inode, filp);
		}
	} else
		pr_debug("spidev: nothing for minor %d\n", iminor(inode));

	mutex_unlock(&device_list_lock);
	return status;
}

static int spidev_release(struct inode *inode, struct file *filp)
{
	struct spidev_data	*spidev;
	int			status = 0;

	mutex_lock(&device_list_lock);
	spidev = filp->private_data;
	filp->private_data = NULL;

	/* last close? */
	spidev->users--;
	if (!spidev->users) {
		int		dofree;

		kfree(spidev->buffer);
		spidev->buffer = NULL;

		/* ... after we unbound from the underlying device? */
		spin_lock_irq(&spidev->spi_lock);
		dofree = (spidev->spi == NULL);
		spin_unlock_irq(&spidev->spi_lock);

		if (dofree)
			kfree(spidev);
	}
	mutex_unlock(&device_list_lock);

	return status;
}

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. }  
/* Read-only message with current device setup */
static ssize_t
spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
	struct spidev_data	*spidev;
	ssize_t			status = 0;

	/* chipselect only toggles at start or end of operation */
	if (count > bufsiz)
		return -EMSGSIZE;

	spidev = filp->private_data;

	mutex_lock(&spidev->buf_lock);
	status = spidev_sync_read(spidev, count);
	if (status > 0) {
		unsigned long	missing;

		missing = copy_to_user(buf, spidev->buffer, status);
		if (missing == status)
			status = -EFAULT;
		else
			status = status - missing;
	}
	mutex_unlock(&spidev->buf_lock);

	return status;
}

/* Write-only message with current device setup */
static ssize_t
spidev_write(struct file *filp, const char __user *buf,
		size_t count, loff_t *f_pos)
{
	struct spidev_data	*spidev;
	ssize_t			status = 0;
	unsigned long		missing;

	/* chipselect only toggles at start or end of operation */
	if (count > bufsiz) //应用程序写入的数据不能大于驱动中缓冲区的大小,默认为4096个字节
		return -EMSGSIZE;

	spidev = filp->private_data; //指向文件的私有数据

	mutex_lock(&spidev->buf_lock);
	missing = copy_from_user(spidev->buffer, buf, count); //拷贝用户空间的数据到内核空间
	if (missing == 0) {
		status = spidev_sync_write(spidev, count);
	} else
		status = -EFAULT;
	mutex_unlock(&spidev->buf_lock);

	return status;
}

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. }  
  • 12
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值