aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pcmcia/pcmcia_ioctl.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-07-15 01:44:51 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-07-15 01:44:51 -0400
commit43d2548bb2ef7e6d753f91468a746784041e522d (patch)
tree77d13fcd48fd998393abb825ec36e2b732684a73 /drivers/pcmcia/pcmcia_ioctl.c
parent585583d95c5660973bc0cf64add517b040acd8a4 (diff)
parent85082fd7cbe3173198aac0eb5e85ab1edcc6352c (diff)
Merge commit '85082fd7cbe3173198aac0eb5e85ab1edcc6352c' into test-build
Manual fixup of: arch/powerpc/Kconfig
Diffstat (limited to 'drivers/pcmcia/pcmcia_ioctl.c')
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c179
1 files changed, 168 insertions, 11 deletions
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index 5f186abca108..419f97fc9a62 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -27,12 +27,13 @@
27#include <linux/proc_fs.h> 27#include <linux/proc_fs.h>
28#include <linux/poll.h> 28#include <linux/poll.h>
29#include <linux/pci.h> 29#include <linux/pci.h>
30#include <linux/smp_lock.h>
30#include <linux/workqueue.h> 31#include <linux/workqueue.h>
31 32
32#define IN_CARD_SERVICES
33#include <pcmcia/cs_types.h> 33#include <pcmcia/cs_types.h>
34#include <pcmcia/cs.h> 34#include <pcmcia/cs.h>
35#include <pcmcia/cistpl.h> 35#include <pcmcia/cistpl.h>
36#include <pcmcia/cisreg.h>
36#include <pcmcia/ds.h> 37#include <pcmcia/ds.h>
37#include <pcmcia/ss.h> 38#include <pcmcia/ss.h>
38 39
@@ -138,6 +139,154 @@ static int proc_read_drivers(char *buf, char **start, off_t pos,
138} 139}
139#endif 140#endif
140 141
142
143#ifdef CONFIG_PCMCIA_PROBE
144
145static int adjust_irq(struct pcmcia_socket *s, adjust_t *adj)
146{
147 int irq;
148 u32 mask;
149
150 irq = adj->resource.irq.IRQ;
151 if ((irq < 0) || (irq > 15))
152 return CS_BAD_IRQ;
153
154 if (adj->Action != REMOVE_MANAGED_RESOURCE)
155 return 0;
156
157 mask = 1 << irq;
158
159 if (!(s->irq_mask & mask))
160 return 0;
161
162 s->irq_mask &= ~mask;
163
164 return 0;
165}
166
167#else
168
169static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) {
170 return CS_SUCCESS;
171}
172
173#endif
174
175static int pcmcia_adjust_resource_info(adjust_t *adj)
176{
177 struct pcmcia_socket *s;
178 int ret = CS_UNSUPPORTED_FUNCTION;
179 unsigned long flags;
180
181 down_read(&pcmcia_socket_list_rwsem);
182 list_for_each_entry(s, &pcmcia_socket_list, socket_list) {
183
184 if (adj->Resource == RES_IRQ)
185 ret = adjust_irq(s, adj);
186
187 else if (s->resource_ops->add_io) {
188 unsigned long begin, end;
189
190 /* you can't use the old interface if the new
191 * one was used before */
192 spin_lock_irqsave(&s->lock, flags);
193 if ((s->resource_setup_new) &&
194 !(s->resource_setup_old)) {
195 spin_unlock_irqrestore(&s->lock, flags);
196 continue;
197 } else if (!(s->resource_setup_old))
198 s->resource_setup_old = 1;
199 spin_unlock_irqrestore(&s->lock, flags);
200
201 switch (adj->Resource) {
202 case RES_MEMORY_RANGE:
203 begin = adj->resource.memory.Base;
204 end = adj->resource.memory.Base + adj->resource.memory.Size - 1;
205 if (s->resource_ops->add_mem)
206 ret =s->resource_ops->add_mem(s, adj->Action, begin, end);
207 case RES_IO_RANGE:
208 begin = adj->resource.io.BasePort;
209 end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1;
210 if (s->resource_ops->add_io)
211 ret = s->resource_ops->add_io(s, adj->Action, begin, end);
212 }
213 if (!ret) {
214 /* as there's no way we know this is the
215 * last call to adjust_resource_info, we
216 * always need to assume this is the latest
217 * one... */
218 spin_lock_irqsave(&s->lock, flags);
219 s->resource_setup_done = 1;
220 spin_unlock_irqrestore(&s->lock, flags);
221 }
222 }
223 }
224 up_read(&pcmcia_socket_list_rwsem);
225
226 return (ret);
227}
228
229/** pccard_get_status
230 *
231 * Get the current socket state bits. We don't support the latched
232 * SocketState yet: I haven't seen any point for it.
233 */
234
235static int pccard_get_status(struct pcmcia_socket *s,
236 struct pcmcia_device *p_dev,
237 cs_status_t *status)
238{
239 config_t *c;
240 int val;
241
242 s->ops->get_status(s, &val);
243 status->CardState = status->SocketState = 0;
244 status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0;
245 status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0;
246 status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0;
247 status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0;
248 if (s->state & SOCKET_SUSPEND)
249 status->CardState |= CS_EVENT_PM_SUSPEND;
250 if (!(s->state & SOCKET_PRESENT))
251 return CS_NO_CARD;
252
253 c = (p_dev) ? p_dev->function_config : NULL;
254
255 if ((c != NULL) && (c->state & CONFIG_LOCKED) &&
256 (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) {
257 u_char reg;
258 if (c->CardValues & PRESENT_PIN_REPLACE) {
259 pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
260 status->CardState |=
261 (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
262 status->CardState |=
263 (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0;
264 status->CardState |=
265 (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0;
266 status->CardState |=
267 (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0;
268 } else {
269 /* No PRR? Then assume we're always ready */
270 status->CardState |= CS_EVENT_READY_CHANGE;
271 }
272 if (c->CardValues & PRESENT_EXT_STATUS) {
273 pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
274 status->CardState |=
275 (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
276 }
277 return CS_SUCCESS;
278 }
279 status->CardState |=
280 (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
281 status->CardState |=
282 (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0;
283 status->CardState |=
284 (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
285 status->CardState |=
286 (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
287 return CS_SUCCESS;
288} /* pccard_get_status */
289
141/*====================================================================== 290/*======================================================================
142 291
143 These manage a ring buffer of events pending for one user process 292 These manage a ring buffer of events pending for one user process
@@ -397,20 +546,27 @@ static int ds_open(struct inode *inode, struct file *file)
397 struct pcmcia_socket *s; 546 struct pcmcia_socket *s;
398 user_info_t *user; 547 user_info_t *user;
399 static int warning_printed = 0; 548 static int warning_printed = 0;
549 int ret = 0;
400 550
401 ds_dbg(0, "ds_open(socket %d)\n", i); 551 ds_dbg(0, "ds_open(socket %d)\n", i);
402 552
553 lock_kernel();
403 s = pcmcia_get_socket_by_nr(i); 554 s = pcmcia_get_socket_by_nr(i);
404 if (!s) 555 if (!s) {
405 return -ENODEV; 556 ret = -ENODEV;
557 goto out;
558 }
406 s = pcmcia_get_socket(s); 559 s = pcmcia_get_socket(s);
407 if (!s) 560 if (!s) {
408 return -ENODEV; 561 ret = -ENODEV;
562 goto out;
563 }
409 564
410 if ((file->f_flags & O_ACCMODE) != O_RDONLY) { 565 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
411 if (s->pcmcia_state.busy) { 566 if (s->pcmcia_state.busy) {
412 pcmcia_put_socket(s); 567 pcmcia_put_socket(s);
413 return -EBUSY; 568 ret = -EBUSY;
569 goto out;
414 } 570 }
415 else 571 else
416 s->pcmcia_state.busy = 1; 572 s->pcmcia_state.busy = 1;
@@ -419,7 +575,8 @@ static int ds_open(struct inode *inode, struct file *file)
419 user = kmalloc(sizeof(user_info_t), GFP_KERNEL); 575 user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
420 if (!user) { 576 if (!user) {
421 pcmcia_put_socket(s); 577 pcmcia_put_socket(s);
422 return -ENOMEM; 578 ret = -ENOMEM;
579 goto out;
423 } 580 }
424 user->event_tail = user->event_head = 0; 581 user->event_tail = user->event_head = 0;
425 user->next = s->user; 582 user->next = s->user;
@@ -441,7 +598,9 @@ static int ds_open(struct inode *inode, struct file *file)
441 598
442 if (s->pcmcia_state.present) 599 if (s->pcmcia_state.present)
443 queue_event(user, CS_EVENT_CARD_INSERTION); 600 queue_event(user, CS_EVENT_CARD_INSERTION);
444 return 0; 601out:
602 unlock_kernel();
603 return ret;
445} /* ds_open */ 604} /* ds_open */
446 605
447/*====================================================================*/ 606/*====================================================================*/
@@ -546,8 +705,6 @@ static u_int ds_poll(struct file *file, poll_table *wait)
546 705
547/*====================================================================*/ 706/*====================================================================*/
548 707
549extern int pcmcia_adjust_resource_info(adjust_t *adj);
550
551static int ds_ioctl(struct inode * inode, struct file * file, 708static int ds_ioctl(struct inode * inode, struct file * file,
552 u_int cmd, u_long arg) 709 u_int cmd, u_long arg)
553{ 710{
@@ -649,7 +806,7 @@ static int ds_ioctl(struct inode * inode, struct file * file,
649 mutex_lock(&s->skt_mutex); 806 mutex_lock(&s->skt_mutex);
650 pcmcia_validate_mem(s); 807 pcmcia_validate_mem(s);
651 mutex_unlock(&s->skt_mutex); 808 mutex_unlock(&s->skt_mutex);
652 ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo); 809 ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo.Chains);
653 break; 810 break;
654 case DS_SUSPEND_CARD: 811 case DS_SUSPEND_CARD:
655 ret = pcmcia_suspend_card(s); 812 ret = pcmcia_suspend_card(s);