diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2008-07-15 01:44:51 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2008-07-15 01:44:51 -0400 |
commit | 43d2548bb2ef7e6d753f91468a746784041e522d (patch) | |
tree | 77d13fcd48fd998393abb825ec36e2b732684a73 /drivers/pcmcia/pcmcia_ioctl.c | |
parent | 585583d95c5660973bc0cf64add517b040acd8a4 (diff) | |
parent | 85082fd7cbe3173198aac0eb5e85ab1edcc6352c (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.c | 179 |
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 | |||
145 | static 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 | |||
169 | static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) { | ||
170 | return CS_SUCCESS; | ||
171 | } | ||
172 | |||
173 | #endif | ||
174 | |||
175 | static 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 | |||
235 | static 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, ®); | ||
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, ®); | ||
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; | 601 | out: |
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 | ||
549 | extern int pcmcia_adjust_resource_info(adjust_t *adj); | ||
550 | |||
551 | static int ds_ioctl(struct inode * inode, struct file * file, | 708 | static 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); |