aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/spidev.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-07-08 01:47:47 -0400
committerIngo Molnar <mingo@elte.hu>2008-07-08 01:47:47 -0400
commit93022136fff9e6130aa128a5ed8a599e93ac813c (patch)
tree185390fb75a3d7423cc508610b76637c957205b9 /drivers/spi/spidev.c
parentc49c412a47b5102516d3313d4eba38cb1e968721 (diff)
parentb7279469d66b55119784b8b9529c99c1955fe747 (diff)
Merge commit 'v2.6.26-rc9' into x86/cpu
Diffstat (limited to 'drivers/spi/spidev.c')
-rw-r--r--drivers/spi/spidev.c74
1 files changed, 38 insertions, 36 deletions
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 41620c0fb046..f5b60c70389b 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -25,6 +25,7 @@
25#include <linux/ioctl.h> 25#include <linux/ioctl.h>
26#include <linux/fs.h> 26#include <linux/fs.h>
27#include <linux/device.h> 27#include <linux/device.h>
28#include <linux/err.h>
28#include <linux/list.h> 29#include <linux/list.h>
29#include <linux/errno.h> 30#include <linux/errno.h>
30#include <linux/mutex.h> 31#include <linux/mutex.h>
@@ -67,11 +68,12 @@ static unsigned long minors[N_SPI_MINORS / BITS_PER_LONG];
67 | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP) 68 | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP)
68 69
69struct spidev_data { 70struct spidev_data {
70 struct device dev; 71 dev_t devt;
71 spinlock_t spi_lock; 72 spinlock_t spi_lock;
72 struct spi_device *spi; 73 struct spi_device *spi;
73 struct list_head device_entry; 74 struct list_head device_entry;
74 75
76 /* buffer is NULL unless this device is open (users > 0) */
75 struct mutex buf_lock; 77 struct mutex buf_lock;
76 unsigned users; 78 unsigned users;
77 u8 *buffer; 79 u8 *buffer;
@@ -165,14 +167,14 @@ spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
165 167
166 mutex_lock(&spidev->buf_lock); 168 mutex_lock(&spidev->buf_lock);
167 status = spidev_sync_read(spidev, count); 169 status = spidev_sync_read(spidev, count);
168 if (status == 0) { 170 if (status > 0) {
169 unsigned long missing; 171 unsigned long missing;
170 172
171 missing = copy_to_user(buf, spidev->buffer, count); 173 missing = copy_to_user(buf, spidev->buffer, status);
172 if (count && missing == count) 174 if (missing == status)
173 status = -EFAULT; 175 status = -EFAULT;
174 else 176 else
175 status = count - missing; 177 status = status - missing;
176 } 178 }
177 mutex_unlock(&spidev->buf_lock); 179 mutex_unlock(&spidev->buf_lock);
178 180
@@ -198,8 +200,6 @@ spidev_write(struct file *filp, const char __user *buf,
198 missing = copy_from_user(spidev->buffer, buf, count); 200 missing = copy_from_user(spidev->buffer, buf, count);
199 if (missing == 0) { 201 if (missing == 0) {
200 status = spidev_sync_write(spidev, count); 202 status = spidev_sync_write(spidev, count);
201 if (status == 0)
202 status = count;
203 } else 203 } else
204 status = -EFAULT; 204 status = -EFAULT;
205 mutex_unlock(&spidev->buf_lock); 205 mutex_unlock(&spidev->buf_lock);
@@ -467,7 +467,7 @@ static int spidev_open(struct inode *inode, struct file *filp)
467 mutex_lock(&device_list_lock); 467 mutex_lock(&device_list_lock);
468 468
469 list_for_each_entry(spidev, &device_list, device_entry) { 469 list_for_each_entry(spidev, &device_list, device_entry) {
470 if (spidev->dev.devt == inode->i_rdev) { 470 if (spidev->devt == inode->i_rdev) {
471 status = 0; 471 status = 0;
472 break; 472 break;
473 } 473 }
@@ -500,10 +500,22 @@ static int spidev_release(struct inode *inode, struct file *filp)
500 mutex_lock(&device_list_lock); 500 mutex_lock(&device_list_lock);
501 spidev = filp->private_data; 501 spidev = filp->private_data;
502 filp->private_data = NULL; 502 filp->private_data = NULL;
503
504 /* last close? */
503 spidev->users--; 505 spidev->users--;
504 if (!spidev->users) { 506 if (!spidev->users) {
507 int dofree;
508
505 kfree(spidev->buffer); 509 kfree(spidev->buffer);
506 spidev->buffer = NULL; 510 spidev->buffer = NULL;
511
512 /* ... after we unbound from the underlying device? */
513 spin_lock_irq(&spidev->spi_lock);
514 dofree = (spidev->spi == NULL);
515 spin_unlock_irq(&spidev->spi_lock);
516
517 if (dofree)
518 kfree(spidev);
507 } 519 }
508 mutex_unlock(&device_list_lock); 520 mutex_unlock(&device_list_lock);
509 521
@@ -530,19 +542,7 @@ static struct file_operations spidev_fops = {
530 * It also simplifies memory management. 542 * It also simplifies memory management.
531 */ 543 */
532 544
533static void spidev_classdev_release(struct device *dev) 545static struct class *spidev_class;
534{
535 struct spidev_data *spidev;
536
537 spidev = container_of(dev, struct spidev_data, dev);
538 kfree(spidev);
539}
540
541static struct class spidev_class = {
542 .name = "spidev",
543 .owner = THIS_MODULE,
544 .dev_release = spidev_classdev_release,
545};
546 546
547/*-------------------------------------------------------------------------*/ 547/*-------------------------------------------------------------------------*/
548 548
@@ -570,20 +570,20 @@ static int spidev_probe(struct spi_device *spi)
570 mutex_lock(&device_list_lock); 570 mutex_lock(&device_list_lock);
571 minor = find_first_zero_bit(minors, N_SPI_MINORS); 571 minor = find_first_zero_bit(minors, N_SPI_MINORS);
572 if (minor < N_SPI_MINORS) { 572 if (minor < N_SPI_MINORS) {
573 spidev->dev.parent = &spi->dev; 573 struct device *dev;
574 spidev->dev.class = &spidev_class; 574
575 spidev->dev.devt = MKDEV(SPIDEV_MAJOR, minor); 575 spidev->devt = MKDEV(SPIDEV_MAJOR, minor);
576 snprintf(spidev->dev.bus_id, sizeof spidev->dev.bus_id, 576 dev = device_create(spidev_class, &spi->dev, spidev->devt,
577 "spidev%d.%d", 577 "spidev%d.%d",
578 spi->master->bus_num, spi->chip_select); 578 spi->master->bus_num, spi->chip_select);
579 status = device_register(&spidev->dev); 579 status = IS_ERR(dev) ? PTR_ERR(dev) : 0;
580 } else { 580 } else {
581 dev_dbg(&spi->dev, "no minor number available!\n"); 581 dev_dbg(&spi->dev, "no minor number available!\n");
582 status = -ENODEV; 582 status = -ENODEV;
583 } 583 }
584 if (status == 0) { 584 if (status == 0) {
585 set_bit(minor, minors); 585 set_bit(minor, minors);
586 dev_set_drvdata(&spi->dev, spidev); 586 spi_set_drvdata(spi, spidev);
587 list_add(&spidev->device_entry, &device_list); 587 list_add(&spidev->device_entry, &device_list);
588 } 588 }
589 mutex_unlock(&device_list_lock); 589 mutex_unlock(&device_list_lock);
@@ -596,19 +596,21 @@ static int spidev_probe(struct spi_device *spi)
596 596
597static int spidev_remove(struct spi_device *spi) 597static int spidev_remove(struct spi_device *spi)
598{ 598{
599 struct spidev_data *spidev = dev_get_drvdata(&spi->dev); 599 struct spidev_data *spidev = spi_get_drvdata(spi);
600 600
601 /* make sure ops on existing fds can abort cleanly */ 601 /* make sure ops on existing fds can abort cleanly */
602 spin_lock_irq(&spidev->spi_lock); 602 spin_lock_irq(&spidev->spi_lock);
603 spidev->spi = NULL; 603 spidev->spi = NULL;
604 spi_set_drvdata(spi, NULL);
604 spin_unlock_irq(&spidev->spi_lock); 605 spin_unlock_irq(&spidev->spi_lock);
605 606
606 /* prevent new opens */ 607 /* prevent new opens */
607 mutex_lock(&device_list_lock); 608 mutex_lock(&device_list_lock);
608 list_del(&spidev->device_entry); 609 list_del(&spidev->device_entry);
609 dev_set_drvdata(&spi->dev, NULL); 610 device_destroy(spidev_class, spidev->devt);
610 clear_bit(MINOR(spidev->dev.devt), minors); 611 clear_bit(MINOR(spidev->devt), minors);
611 device_unregister(&spidev->dev); 612 if (spidev->users == 0)
613 kfree(spidev);
612 mutex_unlock(&device_list_lock); 614 mutex_unlock(&device_list_lock);
613 615
614 return 0; 616 return 0;
@@ -644,15 +646,15 @@ static int __init spidev_init(void)
644 if (status < 0) 646 if (status < 0)
645 return status; 647 return status;
646 648
647 status = class_register(&spidev_class); 649 spidev_class = class_create(THIS_MODULE, "spidev");
648 if (status < 0) { 650 if (IS_ERR(spidev_class)) {
649 unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name); 651 unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
650 return status; 652 return PTR_ERR(spidev_class);
651 } 653 }
652 654
653 status = spi_register_driver(&spidev_spi); 655 status = spi_register_driver(&spidev_spi);
654 if (status < 0) { 656 if (status < 0) {
655 class_unregister(&spidev_class); 657 class_destroy(spidev_class);
656 unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name); 658 unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
657 } 659 }
658 return status; 660 return status;
@@ -662,7 +664,7 @@ module_init(spidev_init);
662static void __exit spidev_exit(void) 664static void __exit spidev_exit(void)
663{ 665{
664 spi_unregister_driver(&spidev_spi); 666 spi_unregister_driver(&spidev_spi);
665 class_unregister(&spidev_class); 667 class_destroy(spidev_class);
666 unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name); 668 unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
667} 669}
668module_exit(spidev_exit); 670module_exit(spidev_exit);