diff options
Diffstat (limited to 'drivers/pcmcia/pcmcia_ioctl.c')
-rw-r--r-- | drivers/pcmcia/pcmcia_ioctl.c | 154 |
1 files changed, 150 insertions, 4 deletions
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 5f186abca108..afd00e7bbbef 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c | |||
@@ -29,10 +29,10 @@ | |||
29 | #include <linux/pci.h> | 29 | #include <linux/pci.h> |
30 | #include <linux/workqueue.h> | 30 | #include <linux/workqueue.h> |
31 | 31 | ||
32 | #define IN_CARD_SERVICES | ||
33 | #include <pcmcia/cs_types.h> | 32 | #include <pcmcia/cs_types.h> |
34 | #include <pcmcia/cs.h> | 33 | #include <pcmcia/cs.h> |
35 | #include <pcmcia/cistpl.h> | 34 | #include <pcmcia/cistpl.h> |
35 | #include <pcmcia/cisreg.h> | ||
36 | #include <pcmcia/ds.h> | 36 | #include <pcmcia/ds.h> |
37 | #include <pcmcia/ss.h> | 37 | #include <pcmcia/ss.h> |
38 | 38 | ||
@@ -138,6 +138,154 @@ static int proc_read_drivers(char *buf, char **start, off_t pos, | |||
138 | } | 138 | } |
139 | #endif | 139 | #endif |
140 | 140 | ||
141 | |||
142 | #ifdef CONFIG_PCMCIA_PROBE | ||
143 | |||
144 | static int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) | ||
145 | { | ||
146 | int irq; | ||
147 | u32 mask; | ||
148 | |||
149 | irq = adj->resource.irq.IRQ; | ||
150 | if ((irq < 0) || (irq > 15)) | ||
151 | return CS_BAD_IRQ; | ||
152 | |||
153 | if (adj->Action != REMOVE_MANAGED_RESOURCE) | ||
154 | return 0; | ||
155 | |||
156 | mask = 1 << irq; | ||
157 | |||
158 | if (!(s->irq_mask & mask)) | ||
159 | return 0; | ||
160 | |||
161 | s->irq_mask &= ~mask; | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | #else | ||
167 | |||
168 | static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) { | ||
169 | return CS_SUCCESS; | ||
170 | } | ||
171 | |||
172 | #endif | ||
173 | |||
174 | static int pcmcia_adjust_resource_info(adjust_t *adj) | ||
175 | { | ||
176 | struct pcmcia_socket *s; | ||
177 | int ret = CS_UNSUPPORTED_FUNCTION; | ||
178 | unsigned long flags; | ||
179 | |||
180 | down_read(&pcmcia_socket_list_rwsem); | ||
181 | list_for_each_entry(s, &pcmcia_socket_list, socket_list) { | ||
182 | |||
183 | if (adj->Resource == RES_IRQ) | ||
184 | ret = adjust_irq(s, adj); | ||
185 | |||
186 | else if (s->resource_ops->add_io) { | ||
187 | unsigned long begin, end; | ||
188 | |||
189 | /* you can't use the old interface if the new | ||
190 | * one was used before */ | ||
191 | spin_lock_irqsave(&s->lock, flags); | ||
192 | if ((s->resource_setup_new) && | ||
193 | !(s->resource_setup_old)) { | ||
194 | spin_unlock_irqrestore(&s->lock, flags); | ||
195 | continue; | ||
196 | } else if (!(s->resource_setup_old)) | ||
197 | s->resource_setup_old = 1; | ||
198 | spin_unlock_irqrestore(&s->lock, flags); | ||
199 | |||
200 | switch (adj->Resource) { | ||
201 | case RES_MEMORY_RANGE: | ||
202 | begin = adj->resource.memory.Base; | ||
203 | end = adj->resource.memory.Base + adj->resource.memory.Size - 1; | ||
204 | if (s->resource_ops->add_mem) | ||
205 | ret =s->resource_ops->add_mem(s, adj->Action, begin, end); | ||
206 | case RES_IO_RANGE: | ||
207 | begin = adj->resource.io.BasePort; | ||
208 | end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1; | ||
209 | if (s->resource_ops->add_io) | ||
210 | ret = s->resource_ops->add_io(s, adj->Action, begin, end); | ||
211 | } | ||
212 | if (!ret) { | ||
213 | /* as there's no way we know this is the | ||
214 | * last call to adjust_resource_info, we | ||
215 | * always need to assume this is the latest | ||
216 | * one... */ | ||
217 | spin_lock_irqsave(&s->lock, flags); | ||
218 | s->resource_setup_done = 1; | ||
219 | spin_unlock_irqrestore(&s->lock, flags); | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | up_read(&pcmcia_socket_list_rwsem); | ||
224 | |||
225 | return (ret); | ||
226 | } | ||
227 | |||
228 | /** pccard_get_status | ||
229 | * | ||
230 | * Get the current socket state bits. We don't support the latched | ||
231 | * SocketState yet: I haven't seen any point for it. | ||
232 | */ | ||
233 | |||
234 | static int pccard_get_status(struct pcmcia_socket *s, | ||
235 | struct pcmcia_device *p_dev, | ||
236 | cs_status_t *status) | ||
237 | { | ||
238 | config_t *c; | ||
239 | int val; | ||
240 | |||
241 | s->ops->get_status(s, &val); | ||
242 | status->CardState = status->SocketState = 0; | ||
243 | status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0; | ||
244 | status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0; | ||
245 | status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0; | ||
246 | status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0; | ||
247 | if (s->state & SOCKET_SUSPEND) | ||
248 | status->CardState |= CS_EVENT_PM_SUSPEND; | ||
249 | if (!(s->state & SOCKET_PRESENT)) | ||
250 | return CS_NO_CARD; | ||
251 | |||
252 | c = (p_dev) ? p_dev->function_config : NULL; | ||
253 | |||
254 | if ((c != NULL) && (c->state & CONFIG_LOCKED) && | ||
255 | (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) { | ||
256 | u_char reg; | ||
257 | if (c->CardValues & PRESENT_PIN_REPLACE) { | ||
258 | pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, ®); | ||
259 | status->CardState |= | ||
260 | (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0; | ||
261 | status->CardState |= | ||
262 | (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0; | ||
263 | status->CardState |= | ||
264 | (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0; | ||
265 | status->CardState |= | ||
266 | (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0; | ||
267 | } else { | ||
268 | /* No PRR? Then assume we're always ready */ | ||
269 | status->CardState |= CS_EVENT_READY_CHANGE; | ||
270 | } | ||
271 | if (c->CardValues & PRESENT_EXT_STATUS) { | ||
272 | pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, ®); | ||
273 | status->CardState |= | ||
274 | (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0; | ||
275 | } | ||
276 | return CS_SUCCESS; | ||
277 | } | ||
278 | status->CardState |= | ||
279 | (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0; | ||
280 | status->CardState |= | ||
281 | (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0; | ||
282 | status->CardState |= | ||
283 | (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0; | ||
284 | status->CardState |= | ||
285 | (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0; | ||
286 | return CS_SUCCESS; | ||
287 | } /* pccard_get_status */ | ||
288 | |||
141 | /*====================================================================== | 289 | /*====================================================================== |
142 | 290 | ||
143 | These manage a ring buffer of events pending for one user process | 291 | These manage a ring buffer of events pending for one user process |
@@ -546,8 +694,6 @@ static u_int ds_poll(struct file *file, poll_table *wait) | |||
546 | 694 | ||
547 | /*====================================================================*/ | 695 | /*====================================================================*/ |
548 | 696 | ||
549 | extern int pcmcia_adjust_resource_info(adjust_t *adj); | ||
550 | |||
551 | static int ds_ioctl(struct inode * inode, struct file * file, | 697 | static int ds_ioctl(struct inode * inode, struct file * file, |
552 | u_int cmd, u_long arg) | 698 | u_int cmd, u_long arg) |
553 | { | 699 | { |
@@ -649,7 +795,7 @@ static int ds_ioctl(struct inode * inode, struct file * file, | |||
649 | mutex_lock(&s->skt_mutex); | 795 | mutex_lock(&s->skt_mutex); |
650 | pcmcia_validate_mem(s); | 796 | pcmcia_validate_mem(s); |
651 | mutex_unlock(&s->skt_mutex); | 797 | mutex_unlock(&s->skt_mutex); |
652 | ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo); | 798 | ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo.Chains); |
653 | break; | 799 | break; |
654 | case DS_SUSPEND_CARD: | 800 | case DS_SUSPEND_CARD: |
655 | ret = pcmcia_suspend_card(s); | 801 | ret = pcmcia_suspend_card(s); |