aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pcmcia/cs.c177
-rw-r--r--drivers/pcmcia/cs_internal.h10
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c8
-rw-r--r--drivers/pcmcia/socket_sysfs.c26
-rw-r--r--include/pcmcia/ss.h3
5 files changed, 83 insertions, 141 deletions
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 7ba45b0cca6b..823ecda32216 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -505,7 +505,10 @@ static int socket_insert(struct pcmcia_socket *skt)
505 dev_dbg(&skt->dev, "insert\n"); 505 dev_dbg(&skt->dev, "insert\n");
506 506
507 mutex_lock(&skt->ops_mutex); 507 mutex_lock(&skt->ops_mutex);
508 WARN_ON(skt->state & SOCKET_INUSE); 508 if (skt->state & SOCKET_INUSE) {
509 mutex_unlock(&skt->ops_mutex);
510 return -EINVAL;
511 }
509 skt->state |= SOCKET_INUSE; 512 skt->state |= SOCKET_INUSE;
510 513
511 ret = socket_setup(skt, setup_delay); 514 ret = socket_setup(skt, setup_delay);
@@ -682,16 +685,19 @@ static int pccardd(void *__skt)
682 for (;;) { 685 for (;;) {
683 unsigned long flags; 686 unsigned long flags;
684 unsigned int events; 687 unsigned int events;
688 unsigned int sysfs_events;
685 689
686 set_current_state(TASK_INTERRUPTIBLE); 690 set_current_state(TASK_INTERRUPTIBLE);
687 691
688 spin_lock_irqsave(&skt->thread_lock, flags); 692 spin_lock_irqsave(&skt->thread_lock, flags);
689 events = skt->thread_events; 693 events = skt->thread_events;
690 skt->thread_events = 0; 694 skt->thread_events = 0;
695 sysfs_events = skt->sysfs_events;
696 skt->sysfs_events = 0;
691 spin_unlock_irqrestore(&skt->thread_lock, flags); 697 spin_unlock_irqrestore(&skt->thread_lock, flags);
692 698
699 mutex_lock(&skt->skt_mutex);
693 if (events) { 700 if (events) {
694 mutex_lock(&skt->skt_mutex);
695 if (events & SS_DETECT) 701 if (events & SS_DETECT)
696 socket_detect_change(skt); 702 socket_detect_change(skt);
697 if (events & SS_BATDEAD) 703 if (events & SS_BATDEAD)
@@ -700,10 +706,34 @@ static int pccardd(void *__skt)
700 send_event(skt, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW); 706 send_event(skt, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW);
701 if (events & SS_READY) 707 if (events & SS_READY)
702 send_event(skt, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW); 708 send_event(skt, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW);
703 mutex_unlock(&skt->skt_mutex);
704 continue;
705 } 709 }
706 710
711 if (sysfs_events) {
712 if (sysfs_events & PCMCIA_UEVENT_EJECT)
713 socket_remove(skt);
714 if (sysfs_events & PCMCIA_UEVENT_INSERT)
715 socket_insert(skt);
716 if ((sysfs_events & PCMCIA_UEVENT_RESUME) &&
717 !(skt->state & SOCKET_CARDBUS)) {
718 ret = socket_resume(skt);
719 if (!ret && skt->callback)
720 skt->callback->resume(skt);
721 }
722 if ((sysfs_events & PCMCIA_UEVENT_SUSPEND) &&
723 !(skt->state & SOCKET_CARDBUS)) {
724 if (skt->callback)
725 ret = skt->callback->suspend(skt);
726 else
727 ret = 0;
728 if (!ret)
729 socket_suspend(skt);
730 }
731 }
732 mutex_unlock(&skt->skt_mutex);
733
734 if (events || sysfs_events)
735 continue;
736
707 if (kthread_should_stop()) 737 if (kthread_should_stop())
708 break; 738 break;
709 739
@@ -745,6 +775,30 @@ void pcmcia_parse_events(struct pcmcia_socket *s, u_int events)
745} /* pcmcia_parse_events */ 775} /* pcmcia_parse_events */
746EXPORT_SYMBOL(pcmcia_parse_events); 776EXPORT_SYMBOL(pcmcia_parse_events);
747 777
778/**
779 * pcmcia_parse_uevents() - tell pccardd to issue manual commands
780 * @s: the PCMCIA socket we wan't to command
781 * @events: events to pass to pccardd
782 *
783 * userspace-issued insert, eject, suspend and resume commands must be
784 * handled by pccardd to avoid any sysfs-related deadlocks. Valid events
785 * are PCMCIA_UEVENT_EJECT (for eject), PCMCIA_UEVENT__INSERT (for insert),
786 * PCMCIA_UEVENT_RESUME (for resume) and PCMCIA_UEVENT_SUSPEND (for suspend).
787 */
788void pcmcia_parse_uevents(struct pcmcia_socket *s, u_int events)
789{
790 unsigned long flags;
791 dev_dbg(&s->dev, "parse_uevents: events %08x\n", events);
792 if (s->thread) {
793 spin_lock_irqsave(&s->thread_lock, flags);
794 s->sysfs_events |= events;
795 spin_unlock_irqrestore(&s->thread_lock, flags);
796
797 wake_up_process(s->thread);
798 }
799}
800EXPORT_SYMBOL(pcmcia_parse_uevents);
801
748 802
749/* register pcmcia_callback */ 803/* register pcmcia_callback */
750int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c) 804int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c)
@@ -828,121 +882,6 @@ int pcmcia_reset_card(struct pcmcia_socket *skt)
828EXPORT_SYMBOL(pcmcia_reset_card); 882EXPORT_SYMBOL(pcmcia_reset_card);
829 883
830 884
831/* These shut down or wake up a socket. They are sort of user
832 * initiated versions of the APM suspend and resume actions.
833 */
834int pcmcia_suspend_card(struct pcmcia_socket *skt)
835{
836 int ret;
837
838 dev_dbg(&skt->dev, "suspending socket\n");
839
840 mutex_lock(&skt->skt_mutex);
841 do {
842 if (!(skt->state & SOCKET_PRESENT)) {
843 ret = -ENODEV;
844 break;
845 }
846 if (skt->state & SOCKET_CARDBUS) {
847 ret = -EPERM;
848 break;
849 }
850 if (skt->callback) {
851 ret = skt->callback->suspend(skt);
852 if (ret)
853 break;
854 }
855 ret = socket_suspend(skt);
856 } while (0);
857 mutex_unlock(&skt->skt_mutex);
858
859 return ret;
860} /* suspend_card */
861EXPORT_SYMBOL(pcmcia_suspend_card);
862
863
864int pcmcia_resume_card(struct pcmcia_socket *skt)
865{
866 int ret;
867
868 dev_dbg(&skt->dev, "waking up socket\n");
869
870 mutex_lock(&skt->skt_mutex);
871 do {
872 if (!(skt->state & SOCKET_PRESENT)) {
873 ret = -ENODEV;
874 break;
875 }
876 if (skt->state & SOCKET_CARDBUS) {
877 ret = -EPERM;
878 break;
879 }
880 ret = socket_resume(skt);
881 if (!ret && skt->callback)
882 skt->callback->resume(skt);
883 } while (0);
884 mutex_unlock(&skt->skt_mutex);
885
886 return ret;
887} /* resume_card */
888EXPORT_SYMBOL(pcmcia_resume_card);
889
890
891/* These handle user requests to eject or insert a card. */
892int pcmcia_eject_card(struct pcmcia_socket *skt)
893{
894 int ret;
895
896 dev_dbg(&skt->dev, "user eject request\n");
897
898 mutex_lock(&skt->skt_mutex);
899 do {
900 if (!(skt->state & SOCKET_PRESENT)) {
901 ret = -ENODEV;
902 break;
903 }
904
905 ret = send_event(skt, CS_EVENT_EJECTION_REQUEST, CS_EVENT_PRI_LOW);
906 if (ret != 0) {
907 ret = -EINVAL;
908 break;
909 }
910
911 socket_remove(skt);
912 ret = 0;
913 } while (0);
914 mutex_unlock(&skt->skt_mutex);
915
916 return ret;
917} /* eject_card */
918EXPORT_SYMBOL(pcmcia_eject_card);
919
920
921int pcmcia_insert_card(struct pcmcia_socket *skt)
922{
923 int ret;
924
925 dev_dbg(&skt->dev, "user insert request\n");
926
927 mutex_lock(&skt->skt_mutex);
928 do {
929 if (skt->state & SOCKET_PRESENT) {
930 ret = -EBUSY;
931 break;
932 }
933 if (socket_insert(skt) == -ENODEV) {
934 ret = -ENODEV;
935 break;
936 }
937 ret = 0;
938 } while (0);
939 mutex_unlock(&skt->skt_mutex);
940
941 return ret;
942} /* insert_card */
943EXPORT_SYMBOL(pcmcia_insert_card);
944
945
946static int pcmcia_socket_uevent(struct device *dev, 885static int pcmcia_socket_uevent(struct device *dev,
947 struct kobj_uevent_env *env) 886 struct kobj_uevent_env *env)
948{ 887{
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index bd386d77845e..127c97acf849 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -124,11 +124,11 @@ extern struct class pcmcia_socket_class;
124int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c); 124int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c);
125struct pcmcia_socket *pcmcia_get_socket_by_nr(unsigned int nr); 125struct pcmcia_socket *pcmcia_get_socket_by_nr(unsigned int nr);
126 126
127int pcmcia_suspend_card(struct pcmcia_socket *skt); 127void pcmcia_parse_uevents(struct pcmcia_socket *socket, unsigned int events);
128int pcmcia_resume_card(struct pcmcia_socket *skt); 128#define PCMCIA_UEVENT_EJECT 0x0001
129 129#define PCMCIA_UEVENT_INSERT 0x0002
130int pcmcia_eject_card(struct pcmcia_socket *skt); 130#define PCMCIA_UEVENT_SUSPEND 0x0004
131int pcmcia_insert_card(struct pcmcia_socket *skt); 131#define PCMCIA_UEVENT_RESUME 0x0008
132 132
133struct pcmcia_socket *pcmcia_get_socket(struct pcmcia_socket *skt); 133struct pcmcia_socket *pcmcia_get_socket(struct pcmcia_socket *skt);
134void pcmcia_put_socket(struct pcmcia_socket *skt); 134void pcmcia_put_socket(struct pcmcia_socket *skt);
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index 96fd236f52a9..13a7132cf688 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -925,16 +925,16 @@ static int ds_ioctl(struct inode *inode, struct file *file,
925 ret = pccard_validate_cis(s, &buf->cisinfo.Chains); 925 ret = pccard_validate_cis(s, &buf->cisinfo.Chains);
926 break; 926 break;
927 case DS_SUSPEND_CARD: 927 case DS_SUSPEND_CARD:
928 ret = pcmcia_suspend_card(s); 928 pcmcia_parse_uevents(s, PCMCIA_UEVENT_SUSPEND);
929 break; 929 break;
930 case DS_RESUME_CARD: 930 case DS_RESUME_CARD:
931 ret = pcmcia_resume_card(s); 931 pcmcia_parse_uevents(s, PCMCIA_UEVENT_RESUME);
932 break; 932 break;
933 case DS_EJECT_CARD: 933 case DS_EJECT_CARD:
934 err = pcmcia_eject_card(s); 934 pcmcia_parse_uevents(s, PCMCIA_UEVENT_EJECT);
935 break; 935 break;
936 case DS_INSERT_CARD: 936 case DS_INSERT_CARD:
937 err = pcmcia_insert_card(s); 937 pcmcia_parse_uevents(s, PCMCIA_UEVENT_INSERT);
938 break; 938 break;
939 case DS_ACCESS_CONFIGURATION_REGISTER: 939 case DS_ACCESS_CONFIGURATION_REGISTER:
940 if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) { 940 if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index e8826df00a36..fba0e30183f4 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -88,15 +88,14 @@ static DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL);
88static ssize_t pccard_store_insert(struct device *dev, struct device_attribute *attr, 88static ssize_t pccard_store_insert(struct device *dev, struct device_attribute *attr,
89 const char *buf, size_t count) 89 const char *buf, size_t count)
90{ 90{
91 ssize_t ret;
92 struct pcmcia_socket *s = to_socket(dev); 91 struct pcmcia_socket *s = to_socket(dev);
93 92
94 if (!count) 93 if (!count)
95 return -EINVAL; 94 return -EINVAL;
96 95
97 ret = pcmcia_insert_card(s); 96 pcmcia_parse_uevents(s, PCMCIA_UEVENT_INSERT);
98 97
99 return ret ? ret : count; 98 return count;
100} 99}
101static DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert); 100static DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert);
102 101
@@ -113,18 +112,22 @@ static ssize_t pccard_store_card_pm_state(struct device *dev,
113 struct device_attribute *attr, 112 struct device_attribute *attr,
114 const char *buf, size_t count) 113 const char *buf, size_t count)
115{ 114{
116 ssize_t ret = -EINVAL;
117 struct pcmcia_socket *s = to_socket(dev); 115 struct pcmcia_socket *s = to_socket(dev);
116 ssize_t ret = count;
118 117
119 if (!count) 118 if (!count)
120 return -EINVAL; 119 return -EINVAL;
121 120
122 if (!(s->state & SOCKET_SUSPEND) && !strncmp(buf, "off", 3)) 121 if (!strncmp(buf, "off", 3))
123 ret = pcmcia_suspend_card(s); 122 pcmcia_parse_uevents(s, PCMCIA_UEVENT_SUSPEND);
124 else if ((s->state & SOCKET_SUSPEND) && !strncmp(buf, "on", 2)) 123 else {
125 ret = pcmcia_resume_card(s); 124 if (!strncmp(buf, "on", 2))
125 pcmcia_parse_uevents(s, PCMCIA_UEVENT_RESUME);
126 else
127 ret = -EINVAL;
128 }
126 129
127 return ret ? -ENODEV : count; 130 return ret;
128} 131}
129static DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state); 132static DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state);
130 133
@@ -132,15 +135,14 @@ static ssize_t pccard_store_eject(struct device *dev,
132 struct device_attribute *attr, 135 struct device_attribute *attr,
133 const char *buf, size_t count) 136 const char *buf, size_t count)
134{ 137{
135 ssize_t ret;
136 struct pcmcia_socket *s = to_socket(dev); 138 struct pcmcia_socket *s = to_socket(dev);
137 139
138 if (!count) 140 if (!count)
139 return -EINVAL; 141 return -EINVAL;
140 142
141 ret = pcmcia_eject_card(s); 143 pcmcia_parse_uevents(s, PCMCIA_UEVENT_EJECT);
142 144
143 return ret ? ret : count; 145 return count;
144} 146}
145static DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject); 147static DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject);
146 148
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h
index cfaccc224b50..ea5dec8c0d76 100644
--- a/include/pcmcia/ss.h
+++ b/include/pcmcia/ss.h
@@ -200,13 +200,14 @@ struct pcmcia_socket {
200 struct task_struct *thread; 200 struct task_struct *thread;
201 struct completion thread_done; 201 struct completion thread_done;
202 unsigned int thread_events; 202 unsigned int thread_events;
203 unsigned int sysfs_events;
203 204
204 /* For the non-trivial interaction between these locks, 205 /* For the non-trivial interaction between these locks,
205 * see Documentation/pcmcia/locking.txt */ 206 * see Documentation/pcmcia/locking.txt */
206 struct mutex skt_mutex; 207 struct mutex skt_mutex;
207 struct mutex ops_mutex; 208 struct mutex ops_mutex;
208 209
209 /* protects thread_events */ 210 /* protects thread_events and sysfs_events */
210 spinlock_t thread_lock; 211 spinlock_t thread_lock;
211 212
212 /* pcmcia (16-bit) */ 213 /* pcmcia (16-bit) */