@@ -18,6 +18,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/property.h>
+#include <linux/rwsem.h>
#include <linux/slab.h>
#include <linux/compat.h>
@@ -68,7 +69,7 @@ static_assert(N_SPI_MINORS > 0 && N_SPI_MINORS <= 256);
struct spidev_data {
dev_t devt;
- spinlock_t spi_lock;
+ struct rw_semaphore sem;
struct spi_device *spi;
struct list_head device_entry;
@@ -95,9 +96,8 @@ spidev_sync(struct spidev_data *spidev, struct spi_message *message)
int status;
struct spi_device *spi;
- spin_lock_irq(&spidev->spi_lock);
+ down_read(&spidev->sem);
spi = spidev->spi;
- spin_unlock_irq(&spidev->spi_lock);
if (spi == NULL)
status = -ESHUTDOWN;
@@ -107,6 +107,7 @@ spidev_sync(struct spidev_data *spidev, struct spi_message *message)
if (status == 0)
status = message->actual_length;
+ up_read(&spidev->sem);
return status;
}
@@ -359,12 +360,12 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
* we issue this ioctl.
*/
spidev = filp->private_data;
- spin_lock_irq(&spidev->spi_lock);
+ down_read(&spidev->sem);
spi = spi_dev_get(spidev->spi);
- spin_unlock_irq(&spidev->spi_lock);
-
- if (spi == NULL)
+ if (spi == NULL) {
+ up_read(&spidev->sem);
return -ESHUTDOWN;
+ }
/* use the buffer lock here for triple duty:
* - prevent I/O (from us) so calling spi_setup() is safe;
@@ -508,6 +509,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
mutex_unlock(&spidev->buf_lock);
spi_dev_put(spi);
+ up_read(&spidev->sem);
return retval;
}
@@ -529,12 +531,12 @@ spidev_compat_ioc_message(struct file *filp, unsigned int cmd,
* we issue this ioctl.
*/
spidev = filp->private_data;
- spin_lock_irq(&spidev->spi_lock);
+ down_read(&spidev->sem);
spi = spi_dev_get(spidev->spi);
- spin_unlock_irq(&spidev->spi_lock);
-
- if (spi == NULL)
+ if (spi == NULL) {
+ up_read(&spidev->sem);
return -ESHUTDOWN;
+ }
/* SPI_IOC_MESSAGE needs the buffer locked "normally" */
mutex_lock(&spidev->buf_lock);
@@ -561,6 +563,7 @@ spidev_compat_ioc_message(struct file *filp, unsigned int cmd,
done:
mutex_unlock(&spidev->buf_lock);
spi_dev_put(spi);
+ up_read(&spidev->sem);
return retval;
}
@@ -640,10 +643,10 @@ static int spidev_release(struct inode *inode, struct file *filp)
spidev = filp->private_data;
filp->private_data = NULL;
- spin_lock_irq(&spidev->spi_lock);
+ down_read(&spidev->sem);
/* ... after we unbound from the underlying device? */
dofree = (spidev->spi == NULL);
- spin_unlock_irq(&spidev->spi_lock);
+ up_read(&spidev->sem);
/* last close? */
spidev->users--;
@@ -776,7 +779,7 @@ static int spidev_probe(struct spi_device *spi)
/* Initialize the driver data */
spidev->spi = spi;
- spin_lock_init(&spidev->spi_lock);
+ init_rwsem(&spidev->sem);
mutex_init(&spidev->buf_lock);
INIT_LIST_HEAD(&spidev->device_entry);
@@ -821,9 +824,9 @@ static void spidev_remove(struct spi_device *spi)
/* prevent new opens */
mutex_lock(&device_list_lock);
/* make sure ops on existing fds can abort cleanly */
- spin_lock_irq(&spidev->spi_lock);
+ down_write(&spidev->sem);
spidev->spi = NULL;
- spin_unlock_irq(&spidev->spi_lock);
+ up_write(&spidev->sem);
list_del(&spidev->device_entry);
device_destroy(spidev_class, spidev->devt);