diff options
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r-- | drivers/pcmcia/Kconfig | 43 | ||||
-rw-r--r-- | drivers/pcmcia/Makefile | 3 | ||||
-rw-r--r-- | drivers/pcmcia/cistpl.c | 28 | ||||
-rw-r--r-- | drivers/pcmcia/cs.c | 1164 | ||||
-rw-r--r-- | drivers/pcmcia/cs_internal.h | 13 | ||||
-rw-r--r-- | drivers/pcmcia/ds.c | 1255 | ||||
-rw-r--r-- | drivers/pcmcia/ds_internal.h | 21 | ||||
-rw-r--r-- | drivers/pcmcia/i82365.c | 23 | ||||
-rw-r--r-- | drivers/pcmcia/pcmcia_compat.c | 34 | ||||
-rw-r--r-- | drivers/pcmcia/pcmcia_ioctl.c | 786 | ||||
-rw-r--r-- | drivers/pcmcia/pcmcia_resource.c | 998 | ||||
-rw-r--r-- | drivers/pcmcia/rsrc_mgr.c | 11 | ||||
-rw-r--r-- | drivers/pcmcia/rsrc_nonstatic.c | 170 | ||||
-rw-r--r-- | drivers/pcmcia/socket_sysfs.c | 166 | ||||
-rw-r--r-- | drivers/pcmcia/yenta_socket.c | 6 |
15 files changed, 2677 insertions, 2044 deletions
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 14e4124e1523..52ea34594363 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig | |||
@@ -14,8 +14,8 @@ config PCCARD | |||
14 | Say Y here if you want to attach PCMCIA- or PC-cards to your Linux | 14 | Say Y here if you want to attach PCMCIA- or PC-cards to your Linux |
15 | computer. These are credit-card size devices such as network cards, | 15 | computer. These are credit-card size devices such as network cards, |
16 | modems or hard drives often used with laptops computers. There are | 16 | modems or hard drives often used with laptops computers. There are |
17 | actually two varieties of these cards: the older 16 bit PCMCIA cards | 17 | actually two varieties of these cards: 16 bit PCMCIA and 32 bit |
18 | and the newer 32 bit CardBus cards. | 18 | CardBus cards. |
19 | 19 | ||
20 | To compile this driver as modules, choose M here: the | 20 | To compile this driver as modules, choose M here: the |
21 | module will be called pcmcia_core. | 21 | module will be called pcmcia_core. |
@@ -42,22 +42,51 @@ config PCMCIA_DEBUG | |||
42 | 42 | ||
43 | config PCMCIA | 43 | config PCMCIA |
44 | tristate "16-bit PCMCIA support" | 44 | tristate "16-bit PCMCIA support" |
45 | select CRC32 | ||
45 | default y | 46 | default y |
46 | ---help--- | 47 | ---help--- |
47 | This option enables support for 16-bit PCMCIA cards. Most older | 48 | This option enables support for 16-bit PCMCIA cards. Most older |
48 | PC-cards are such 16-bit PCMCIA cards, so unless you know you're | 49 | PC-cards are such 16-bit PCMCIA cards, so unless you know you're |
49 | only using 32-bit CardBus cards, say Y or M here. | 50 | only using 32-bit CardBus cards, say Y or M here. |
50 | 51 | ||
51 | To use 16-bit PCMCIA cards, you will need supporting software from | 52 | To use 16-bit PCMCIA cards, you will need supporting software in |
52 | David Hinds' pcmcia-cs package (see the file <file:Documentation/Changes> | 53 | most cases. (see the file <file:Documentation/Changes> for |
53 | for location). Please also read the PCMCIA-HOWTO, available from | 54 | location and details). |
54 | <http://www.tldp.org/docs.html#howto>. | ||
55 | 55 | ||
56 | To compile this driver as modules, choose M here: the | 56 | To compile this driver as modules, choose M here: the |
57 | module will be called pcmcia. | 57 | module will be called pcmcia. |
58 | 58 | ||
59 | If unsure, say Y. | 59 | If unsure, say Y. |
60 | 60 | ||
61 | config PCMCIA_LOAD_CIS | ||
62 | bool "Load CIS updates from userspace (EXPERIMENTAL)" | ||
63 | depends on PCMCIA && EXPERIMENTAL | ||
64 | select FW_LOADER | ||
65 | default y | ||
66 | help | ||
67 | Some PCMCIA cards require an updated Card Information Structure (CIS) | ||
68 | to be loaded from userspace to work correctly. If you say Y here, | ||
69 | and your userspace is arranged correctly, this will be loaded | ||
70 | automatically using the in-kernel firmware loader and the hotplug | ||
71 | subsystem, instead of relying on cardmgr from pcmcia-cs to do so. | ||
72 | |||
73 | If unsure, say Y. | ||
74 | |||
75 | config PCMCIA_IOCTL | ||
76 | bool | ||
77 | depends on PCMCIA | ||
78 | default y | ||
79 | help | ||
80 | If you say Y here, the deprecated ioctl interface to the PCMCIA | ||
81 | subsystem will be built. It is needed by cardmgr and cardctl | ||
82 | (pcmcia-cs) to function properly. | ||
83 | |||
84 | If you do not use the new pcmciautils package, and have a | ||
85 | yenta, Cirrus PD6729, i82092, i82365 or tcic compatible bridge, | ||
86 | you need to say Y here to be able to use 16-bit PCMCIA cards. | ||
87 | |||
88 | If unsure, say Y. | ||
89 | |||
61 | config CARDBUS | 90 | config CARDBUS |
62 | bool "32-bit CardBus support" | 91 | bool "32-bit CardBus support" |
63 | depends on PCI | 92 | depends on PCI |
@@ -77,8 +106,6 @@ comment "PC-card bridges" | |||
77 | 106 | ||
78 | config YENTA | 107 | config YENTA |
79 | tristate "CardBus yenta-compatible bridge support" | 108 | tristate "CardBus yenta-compatible bridge support" |
80 | depends on PCI | ||
81 | #fixme: remove dependendcy on CARDBUS | ||
82 | depends on CARDBUS | 109 | depends on CARDBUS |
83 | select PCCARD_NONSTATIC | 110 | select PCCARD_NONSTATIC |
84 | ---help--- | 111 | ---help--- |
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index 50c29361bc5f..ef694c74dfb7 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile | |||
@@ -10,7 +10,8 @@ pcmcia_core-y += cs.o cistpl.o rsrc_mgr.o socket_sysfs.o | |||
10 | pcmcia_core-$(CONFIG_CARDBUS) += cardbus.o | 10 | pcmcia_core-$(CONFIG_CARDBUS) += cardbus.o |
11 | obj-$(CONFIG_PCCARD) += pcmcia_core.o | 11 | obj-$(CONFIG_PCCARD) += pcmcia_core.o |
12 | 12 | ||
13 | pcmcia-y += ds.o pcmcia_compat.o | 13 | pcmcia-y += ds.o pcmcia_compat.o pcmcia_resource.o |
14 | pcmcia-$(CONFIG_PCMCIA_IOCTL) += pcmcia_ioctl.o | ||
14 | obj-$(CONFIG_PCMCIA) += pcmcia.o | 15 | obj-$(CONFIG_PCMCIA) += pcmcia.o |
15 | 16 | ||
16 | obj-$(CONFIG_PCCARD_NONSTATIC) += rsrc_nonstatic.o | 17 | obj-$(CONFIG_PCCARD_NONSTATIC) += rsrc_nonstatic.o |
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index e29a6ddf2fd7..dd7651ff5b43 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c | |||
@@ -89,8 +89,10 @@ static void __iomem * | |||
89 | set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags) | 89 | set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags) |
90 | { | 90 | { |
91 | pccard_mem_map *mem = &s->cis_mem; | 91 | pccard_mem_map *mem = &s->cis_mem; |
92 | int ret; | ||
93 | |||
92 | if (!(s->features & SS_CAP_STATIC_MAP) && mem->res == NULL) { | 94 | if (!(s->features & SS_CAP_STATIC_MAP) && mem->res == NULL) { |
93 | mem->res = find_mem_region(0, s->map_size, s->map_size, 0, s); | 95 | mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 0, s); |
94 | if (mem->res == NULL) { | 96 | if (mem->res == NULL) { |
95 | printk(KERN_NOTICE "cs: unable to map card memory!\n"); | 97 | printk(KERN_NOTICE "cs: unable to map card memory!\n"); |
96 | return NULL; | 98 | return NULL; |
@@ -99,7 +101,12 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag | |||
99 | } | 101 | } |
100 | mem->card_start = card_offset; | 102 | mem->card_start = card_offset; |
101 | mem->flags = flags; | 103 | mem->flags = flags; |
102 | s->ops->set_mem_map(s, mem); | 104 | ret = s->ops->set_mem_map(s, mem); |
105 | if (ret) { | ||
106 | iounmap(s->cis_virt); | ||
107 | return NULL; | ||
108 | } | ||
109 | |||
103 | if (s->features & SS_CAP_STATIC_MAP) { | 110 | if (s->features & SS_CAP_STATIC_MAP) { |
104 | if (s->cis_virt) | 111 | if (s->cis_virt) |
105 | iounmap(s->cis_virt); | 112 | iounmap(s->cis_virt); |
@@ -119,13 +126,13 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag | |||
119 | #define IS_ATTR 1 | 126 | #define IS_ATTR 1 |
120 | #define IS_INDIRECT 8 | 127 | #define IS_INDIRECT 8 |
121 | 128 | ||
122 | int read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, | 129 | int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, |
123 | u_int len, void *ptr) | 130 | u_int len, void *ptr) |
124 | { | 131 | { |
125 | void __iomem *sys, *end; | 132 | void __iomem *sys, *end; |
126 | unsigned char *buf = ptr; | 133 | unsigned char *buf = ptr; |
127 | 134 | ||
128 | cs_dbg(s, 3, "read_cis_mem(%d, %#x, %u)\n", attr, addr, len); | 135 | cs_dbg(s, 3, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len); |
129 | 136 | ||
130 | if (attr & IS_INDIRECT) { | 137 | if (attr & IS_INDIRECT) { |
131 | /* Indirect accesses use a bunch of special registers at fixed | 138 | /* Indirect accesses use a bunch of special registers at fixed |
@@ -182,14 +189,16 @@ int read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, | |||
182 | *(u_char *)(ptr+2), *(u_char *)(ptr+3)); | 189 | *(u_char *)(ptr+2), *(u_char *)(ptr+3)); |
183 | return 0; | 190 | return 0; |
184 | } | 191 | } |
192 | EXPORT_SYMBOL(pcmcia_read_cis_mem); | ||
193 | |||
185 | 194 | ||
186 | void write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, | 195 | void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, |
187 | u_int len, void *ptr) | 196 | u_int len, void *ptr) |
188 | { | 197 | { |
189 | void __iomem *sys, *end; | 198 | void __iomem *sys, *end; |
190 | unsigned char *buf = ptr; | 199 | unsigned char *buf = ptr; |
191 | 200 | ||
192 | cs_dbg(s, 3, "write_cis_mem(%d, %#x, %u)\n", attr, addr, len); | 201 | cs_dbg(s, 3, "pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len); |
193 | 202 | ||
194 | if (attr & IS_INDIRECT) { | 203 | if (attr & IS_INDIRECT) { |
195 | /* Indirect accesses use a bunch of special registers at fixed | 204 | /* Indirect accesses use a bunch of special registers at fixed |
@@ -239,6 +248,8 @@ void write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, | |||
239 | } | 248 | } |
240 | } | 249 | } |
241 | } | 250 | } |
251 | EXPORT_SYMBOL(pcmcia_write_cis_mem); | ||
252 | |||
242 | 253 | ||
243 | /*====================================================================== | 254 | /*====================================================================== |
244 | 255 | ||
@@ -274,7 +285,7 @@ static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, | |||
274 | ret = read_cb_mem(s, attr, addr, len, ptr); | 285 | ret = read_cb_mem(s, attr, addr, len, ptr); |
275 | else | 286 | else |
276 | #endif | 287 | #endif |
277 | ret = read_cis_mem(s, attr, addr, len, ptr); | 288 | ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr); |
278 | 289 | ||
279 | if (ret == 0) { | 290 | if (ret == 0) { |
280 | /* Copy data into the cache */ | 291 | /* Copy data into the cache */ |
@@ -348,7 +359,7 @@ int verify_cis_cache(struct pcmcia_socket *s) | |||
348 | read_cb_mem(s, cis->attr, cis->addr, len, buf); | 359 | read_cb_mem(s, cis->attr, cis->addr, len, buf); |
349 | else | 360 | else |
350 | #endif | 361 | #endif |
351 | read_cis_mem(s, cis->attr, cis->addr, len, buf); | 362 | pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf); |
352 | 363 | ||
353 | if (memcmp(buf, cis->cache, len) != 0) { | 364 | if (memcmp(buf, cis->cache, len) != 0) { |
354 | kfree(buf); | 365 | kfree(buf); |
@@ -381,6 +392,7 @@ int pcmcia_replace_cis(struct pcmcia_socket *s, cisdump_t *cis) | |||
381 | memcpy(s->fake_cis, cis->Data, cis->Length); | 392 | memcpy(s->fake_cis, cis->Data, cis->Length); |
382 | return CS_SUCCESS; | 393 | return CS_SUCCESS; |
383 | } | 394 | } |
395 | EXPORT_SYMBOL(pcmcia_replace_cis); | ||
384 | 396 | ||
385 | /*====================================================================== | 397 | /*====================================================================== |
386 | 398 | ||
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 48e4f04530d8..e82859d3227a 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c | |||
@@ -43,36 +43,11 @@ | |||
43 | #include <pcmcia/ds.h> | 43 | #include <pcmcia/ds.h> |
44 | #include "cs_internal.h" | 44 | #include "cs_internal.h" |
45 | 45 | ||
46 | #ifdef CONFIG_PCI | ||
47 | #define PCI_OPT " [pci]" | ||
48 | #else | ||
49 | #define PCI_OPT "" | ||
50 | #endif | ||
51 | #ifdef CONFIG_CARDBUS | ||
52 | #define CB_OPT " [cardbus]" | ||
53 | #else | ||
54 | #define CB_OPT "" | ||
55 | #endif | ||
56 | #ifdef CONFIG_PM | ||
57 | #define PM_OPT " [pm]" | ||
58 | #else | ||
59 | #define PM_OPT "" | ||
60 | #endif | ||
61 | #if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI) && !defined(CONFIG_PM) | ||
62 | #define OPTIONS " none" | ||
63 | #else | ||
64 | #define OPTIONS PCI_OPT CB_OPT PM_OPT | ||
65 | #endif | ||
66 | |||
67 | static const char *release = "Linux Kernel Card Services"; | ||
68 | static const char *options = "options: " OPTIONS; | ||
69 | |||
70 | /*====================================================================*/ | ||
71 | 46 | ||
72 | /* Module parameters */ | 47 | /* Module parameters */ |
73 | 48 | ||
74 | MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); | 49 | MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); |
75 | MODULE_DESCRIPTION("Linux Kernel Card Services\noptions:" OPTIONS); | 50 | MODULE_DESCRIPTION("Linux Kernel Card Services"); |
76 | MODULE_LICENSE("GPL"); | 51 | MODULE_LICENSE("GPL"); |
77 | 52 | ||
78 | #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444) | 53 | #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444) |
@@ -89,9 +64,6 @@ INT_MODULE_PARM(unreset_limit, 30); /* unreset_check's */ | |||
89 | /* Access speed for attribute memory windows */ | 64 | /* Access speed for attribute memory windows */ |
90 | INT_MODULE_PARM(cis_speed, 300); /* ns */ | 65 | INT_MODULE_PARM(cis_speed, 300); /* ns */ |
91 | 66 | ||
92 | /* Access speed for IO windows */ | ||
93 | INT_MODULE_PARM(io_speed, 0); /* ns */ | ||
94 | |||
95 | #ifdef DEBUG | 67 | #ifdef DEBUG |
96 | static int pc_debug; | 68 | static int pc_debug; |
97 | 69 | ||
@@ -103,34 +75,26 @@ int cs_debug_level(int level) | |||
103 | } | 75 | } |
104 | #endif | 76 | #endif |
105 | 77 | ||
106 | /*====================================================================*/ | ||
107 | 78 | ||
108 | socket_state_t dead_socket = { | 79 | socket_state_t dead_socket = { |
109 | .csc_mask = SS_DETECT, | 80 | .csc_mask = SS_DETECT, |
110 | }; | 81 | }; |
82 | EXPORT_SYMBOL(dead_socket); | ||
111 | 83 | ||
112 | 84 | ||
113 | /* List of all sockets, protected by a rwsem */ | 85 | /* List of all sockets, protected by a rwsem */ |
114 | LIST_HEAD(pcmcia_socket_list); | 86 | LIST_HEAD(pcmcia_socket_list); |
115 | DECLARE_RWSEM(pcmcia_socket_list_rwsem); | ||
116 | EXPORT_SYMBOL(pcmcia_socket_list); | 87 | EXPORT_SYMBOL(pcmcia_socket_list); |
117 | EXPORT_SYMBOL(pcmcia_socket_list_rwsem); | ||
118 | |||
119 | 88 | ||
120 | #ifdef CONFIG_PCMCIA_PROBE | 89 | DECLARE_RWSEM(pcmcia_socket_list_rwsem); |
121 | /* mask ofIRQs already reserved by other cards, we should avoid using them */ | 90 | EXPORT_SYMBOL(pcmcia_socket_list_rwsem); |
122 | static u8 pcmcia_used_irq[NR_IRQS]; | ||
123 | #endif | ||
124 | 91 | ||
125 | /*==================================================================== | ||
126 | |||
127 | Low-level PC Card interface drivers need to register with Card | ||
128 | Services using these calls. | ||
129 | |||
130 | ======================================================================*/ | ||
131 | 92 | ||
132 | /** | 93 | /** |
133 | * socket drivers are expected to use the following callbacks in their | 94 | * Low-level PCMCIA socket drivers need to register with the PCCard |
95 | * core using pcmcia_register_socket. | ||
96 | * | ||
97 | * socket drivers are expected to use the following callbacks in their | ||
134 | * .drv struct: | 98 | * .drv struct: |
135 | * - pcmcia_socket_dev_suspend | 99 | * - pcmcia_socket_dev_suspend |
136 | * - pcmcia_socket_dev_resume | 100 | * - pcmcia_socket_dev_resume |
@@ -230,8 +194,8 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) | |||
230 | } | 194 | } |
231 | 195 | ||
232 | /* try to obtain a socket number [yes, it gets ugly if we | 196 | /* try to obtain a socket number [yes, it gets ugly if we |
233 | * register more than 2^sizeof(unsigned int) pcmcia | 197 | * register more than 2^sizeof(unsigned int) pcmcia |
234 | * sockets... but the socket number is deprecated | 198 | * sockets... but the socket number is deprecated |
235 | * anyways, so I don't care] */ | 199 | * anyways, so I don't care] */ |
236 | down_write(&pcmcia_socket_list_rwsem); | 200 | down_write(&pcmcia_socket_list_rwsem); |
237 | if (list_empty(&pcmcia_socket_list)) | 201 | if (list_empty(&pcmcia_socket_list)) |
@@ -340,54 +304,49 @@ struct pcmcia_socket * pcmcia_get_socket_by_nr(unsigned int nr) | |||
340 | EXPORT_SYMBOL(pcmcia_get_socket_by_nr); | 304 | EXPORT_SYMBOL(pcmcia_get_socket_by_nr); |
341 | 305 | ||
342 | 306 | ||
343 | /*====================================================================== | 307 | /** |
344 | 308 | * socket_setup() and shutdown_socket() are called by the main event | |
345 | socket_setup() and shutdown_socket() are called by the main event | 309 | * handler when card insertion and removal events are received. |
346 | handler when card insertion and removal events are received. | 310 | * socket_setup() turns on socket power and resets the socket, in two stages. |
347 | socket_setup() turns on socket power and resets the socket, in two stages. | 311 | * shutdown_socket() unconfigures a socket and turns off socket power. |
348 | shutdown_socket() unconfigures a socket and turns off socket power. | 312 | */ |
349 | |||
350 | ======================================================================*/ | ||
351 | |||
352 | static void shutdown_socket(struct pcmcia_socket *s) | 313 | static void shutdown_socket(struct pcmcia_socket *s) |
353 | { | 314 | { |
354 | cs_dbg(s, 1, "shutdown_socket\n"); | 315 | cs_dbg(s, 1, "shutdown_socket\n"); |
355 | 316 | ||
356 | /* Blank out the socket state */ | 317 | /* Blank out the socket state */ |
357 | s->socket = dead_socket; | 318 | s->socket = dead_socket; |
358 | s->ops->init(s); | 319 | s->ops->init(s); |
359 | s->ops->set_socket(s, &s->socket); | 320 | s->ops->set_socket(s, &s->socket); |
360 | s->irq.AssignedIRQ = s->irq.Config = 0; | 321 | s->irq.AssignedIRQ = s->irq.Config = 0; |
361 | s->lock_count = 0; | 322 | s->lock_count = 0; |
362 | destroy_cis_cache(s); | 323 | destroy_cis_cache(s); |
363 | #ifdef CONFIG_CARDBUS | 324 | #ifdef CONFIG_CARDBUS |
364 | cb_free(s); | 325 | cb_free(s); |
365 | #endif | 326 | #endif |
366 | s->functions = 0; | 327 | s->functions = 0; |
367 | if (s->config) { | 328 | if (s->config) { |
368 | kfree(s->config); | 329 | kfree(s->config); |
369 | s->config = NULL; | 330 | s->config = NULL; |
370 | } | ||
371 | |||
372 | { | ||
373 | int status; | ||
374 | s->ops->get_status(s, &status); | ||
375 | if (status & SS_POWERON) { | ||
376 | printk(KERN_ERR "PCMCIA: socket %p: *** DANGER *** unable to remove socket power\n", s); | ||
377 | } | 331 | } |
378 | } | ||
379 | } /* shutdown_socket */ | ||
380 | 332 | ||
381 | /*====================================================================== | 333 | { |
334 | int status; | ||
335 | s->ops->get_status(s, &status); | ||
336 | if (status & SS_POWERON) { | ||
337 | printk(KERN_ERR "PCMCIA: socket %p: *** DANGER *** unable to remove socket power\n", s); | ||
338 | } | ||
339 | } | ||
340 | } /* shutdown_socket */ | ||
382 | 341 | ||
383 | The central event handler. Send_event() sends an event to the | ||
384 | 16-bit subsystem, which then calls the relevant device drivers. | ||
385 | Parse_events() interprets the event bits from | ||
386 | a card status change report. Do_shutdown() handles the high | ||
387 | priority stuff associated with a card removal. | ||
388 | |||
389 | ======================================================================*/ | ||
390 | 342 | ||
343 | /** | ||
344 | * The central event handler. Send_event() sends an event to the | ||
345 | * 16-bit subsystem, which then calls the relevant device drivers. | ||
346 | * Parse_events() interprets the event bits from | ||
347 | * a card status change report. Do_shutdown() handles the high | ||
348 | * priority stuff associated with a card removal. | ||
349 | */ | ||
391 | 350 | ||
392 | /* NOTE: send_event needs to be called with skt->sem held. */ | 351 | /* NOTE: send_event needs to be called with skt->sem held. */ |
393 | 352 | ||
@@ -746,420 +705,9 @@ void pcmcia_parse_events(struct pcmcia_socket *s, u_int events) | |||
746 | wake_up(&s->thread_wait); | 705 | wake_up(&s->thread_wait); |
747 | } | 706 | } |
748 | } /* pcmcia_parse_events */ | 707 | } /* pcmcia_parse_events */ |
708 | EXPORT_SYMBOL(pcmcia_parse_events); | ||
749 | 709 | ||
750 | 710 | ||
751 | /*====================================================================== | ||
752 | |||
753 | Special stuff for managing IO windows, because they are scarce. | ||
754 | |||
755 | ======================================================================*/ | ||
756 | |||
757 | static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base, | ||
758 | ioaddr_t num, u_int lines) | ||
759 | { | ||
760 | int i; | ||
761 | kio_addr_t try, align; | ||
762 | |||
763 | align = (*base) ? (lines ? 1<<lines : 0) : 1; | ||
764 | if (align && (align < num)) { | ||
765 | if (*base) { | ||
766 | cs_dbg(s, 0, "odd IO request: num %#x align %#lx\n", | ||
767 | num, align); | ||
768 | align = 0; | ||
769 | } else | ||
770 | while (align && (align < num)) align <<= 1; | ||
771 | } | ||
772 | if (*base & ~(align-1)) { | ||
773 | cs_dbg(s, 0, "odd IO request: base %#x align %#lx\n", | ||
774 | *base, align); | ||
775 | align = 0; | ||
776 | } | ||
777 | if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) { | ||
778 | *base = s->io_offset | (*base & 0x0fff); | ||
779 | return 0; | ||
780 | } | ||
781 | /* Check for an already-allocated window that must conflict with | ||
782 | what was asked for. It is a hack because it does not catch all | ||
783 | potential conflicts, just the most obvious ones. */ | ||
784 | for (i = 0; i < MAX_IO_WIN; i++) | ||
785 | if ((s->io[i].NumPorts != 0) && | ||
786 | ((s->io[i].BasePort & (align-1)) == *base)) | ||
787 | return 1; | ||
788 | for (i = 0; i < MAX_IO_WIN; i++) { | ||
789 | if (s->io[i].NumPorts == 0) { | ||
790 | s->io[i].res = find_io_region(*base, num, align, s); | ||
791 | if (s->io[i].res) { | ||
792 | s->io[i].Attributes = attr; | ||
793 | s->io[i].BasePort = *base = s->io[i].res->start; | ||
794 | s->io[i].NumPorts = s->io[i].InUse = num; | ||
795 | break; | ||
796 | } else | ||
797 | return 1; | ||
798 | } else if (s->io[i].Attributes != attr) | ||
799 | continue; | ||
800 | /* Try to extend top of window */ | ||
801 | try = s->io[i].BasePort + s->io[i].NumPorts; | ||
802 | if ((*base == 0) || (*base == try)) | ||
803 | if (adjust_io_region(s->io[i].res, s->io[i].res->start, | ||
804 | s->io[i].res->end + num, s) == 0) { | ||
805 | *base = try; | ||
806 | s->io[i].NumPorts += num; | ||
807 | s->io[i].InUse += num; | ||
808 | break; | ||
809 | } | ||
810 | /* Try to extend bottom of window */ | ||
811 | try = s->io[i].BasePort - num; | ||
812 | if ((*base == 0) || (*base == try)) | ||
813 | if (adjust_io_region(s->io[i].res, s->io[i].res->start - num, | ||
814 | s->io[i].res->end, s) == 0) { | ||
815 | s->io[i].BasePort = *base = try; | ||
816 | s->io[i].NumPorts += num; | ||
817 | s->io[i].InUse += num; | ||
818 | break; | ||
819 | } | ||
820 | } | ||
821 | return (i == MAX_IO_WIN); | ||
822 | } /* alloc_io_space */ | ||
823 | |||
824 | static void release_io_space(struct pcmcia_socket *s, ioaddr_t base, | ||
825 | ioaddr_t num) | ||
826 | { | ||
827 | int i; | ||
828 | |||
829 | for (i = 0; i < MAX_IO_WIN; i++) { | ||
830 | if ((s->io[i].BasePort <= base) && | ||
831 | (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) { | ||
832 | s->io[i].InUse -= num; | ||
833 | /* Free the window if no one else is using it */ | ||
834 | if (s->io[i].InUse == 0) { | ||
835 | s->io[i].NumPorts = 0; | ||
836 | release_resource(s->io[i].res); | ||
837 | kfree(s->io[i].res); | ||
838 | s->io[i].res = NULL; | ||
839 | } | ||
840 | } | ||
841 | } | ||
842 | } | ||
843 | |||
844 | /*====================================================================== | ||
845 | |||
846 | Access_configuration_register() reads and writes configuration | ||
847 | registers in attribute memory. Memory window 0 is reserved for | ||
848 | this and the tuple reading services. | ||
849 | |||
850 | ======================================================================*/ | ||
851 | |||
852 | int pccard_access_configuration_register(struct pcmcia_socket *s, | ||
853 | unsigned int function, | ||
854 | conf_reg_t *reg) | ||
855 | { | ||
856 | config_t *c; | ||
857 | int addr; | ||
858 | u_char val; | ||
859 | |||
860 | if (!s || !s->config) | ||
861 | return CS_NO_CARD; | ||
862 | |||
863 | c = &s->config[function]; | ||
864 | |||
865 | if (c == NULL) | ||
866 | return CS_NO_CARD; | ||
867 | |||
868 | if (!(c->state & CONFIG_LOCKED)) | ||
869 | return CS_CONFIGURATION_LOCKED; | ||
870 | |||
871 | addr = (c->ConfigBase + reg->Offset) >> 1; | ||
872 | |||
873 | switch (reg->Action) { | ||
874 | case CS_READ: | ||
875 | read_cis_mem(s, 1, addr, 1, &val); | ||
876 | reg->Value = val; | ||
877 | break; | ||
878 | case CS_WRITE: | ||
879 | val = reg->Value; | ||
880 | write_cis_mem(s, 1, addr, 1, &val); | ||
881 | break; | ||
882 | default: | ||
883 | return CS_BAD_ARGS; | ||
884 | break; | ||
885 | } | ||
886 | return CS_SUCCESS; | ||
887 | } /* access_configuration_register */ | ||
888 | EXPORT_SYMBOL(pccard_access_configuration_register); | ||
889 | |||
890 | |||
891 | /*====================================================================*/ | ||
892 | |||
893 | int pccard_get_configuration_info(struct pcmcia_socket *s, | ||
894 | unsigned int function, | ||
895 | config_info_t *config) | ||
896 | { | ||
897 | config_t *c; | ||
898 | |||
899 | if (!(s->state & SOCKET_PRESENT)) | ||
900 | return CS_NO_CARD; | ||
901 | |||
902 | config->Function = function; | ||
903 | |||
904 | #ifdef CONFIG_CARDBUS | ||
905 | if (s->state & SOCKET_CARDBUS) { | ||
906 | memset(config, 0, sizeof(config_info_t)); | ||
907 | config->Vcc = s->socket.Vcc; | ||
908 | config->Vpp1 = config->Vpp2 = s->socket.Vpp; | ||
909 | config->Option = s->cb_dev->subordinate->number; | ||
910 | if (s->state & SOCKET_CARDBUS_CONFIG) { | ||
911 | config->Attributes = CONF_VALID_CLIENT; | ||
912 | config->IntType = INT_CARDBUS; | ||
913 | config->AssignedIRQ = s->irq.AssignedIRQ; | ||
914 | if (config->AssignedIRQ) | ||
915 | config->Attributes |= CONF_ENABLE_IRQ; | ||
916 | config->BasePort1 = s->io[0].BasePort; | ||
917 | config->NumPorts1 = s->io[0].NumPorts; | ||
918 | } | ||
919 | return CS_SUCCESS; | ||
920 | } | ||
921 | #endif | ||
922 | |||
923 | c = (s->config != NULL) ? &s->config[function] : NULL; | ||
924 | |||
925 | if ((c == NULL) || !(c->state & CONFIG_LOCKED)) { | ||
926 | config->Attributes = 0; | ||
927 | config->Vcc = s->socket.Vcc; | ||
928 | config->Vpp1 = config->Vpp2 = s->socket.Vpp; | ||
929 | return CS_SUCCESS; | ||
930 | } | ||
931 | |||
932 | /* !!! This is a hack !!! */ | ||
933 | memcpy(&config->Attributes, &c->Attributes, sizeof(config_t)); | ||
934 | config->Attributes |= CONF_VALID_CLIENT; | ||
935 | config->CardValues = c->CardValues; | ||
936 | config->IRQAttributes = c->irq.Attributes; | ||
937 | config->AssignedIRQ = s->irq.AssignedIRQ; | ||
938 | config->BasePort1 = c->io.BasePort1; | ||
939 | config->NumPorts1 = c->io.NumPorts1; | ||
940 | config->Attributes1 = c->io.Attributes1; | ||
941 | config->BasePort2 = c->io.BasePort2; | ||
942 | config->NumPorts2 = c->io.NumPorts2; | ||
943 | config->Attributes2 = c->io.Attributes2; | ||
944 | config->IOAddrLines = c->io.IOAddrLines; | ||
945 | |||
946 | return CS_SUCCESS; | ||
947 | } /* get_configuration_info */ | ||
948 | EXPORT_SYMBOL(pccard_get_configuration_info); | ||
949 | |||
950 | /*====================================================================== | ||
951 | |||
952 | Return information about this version of Card Services. | ||
953 | |||
954 | ======================================================================*/ | ||
955 | |||
956 | int pcmcia_get_card_services_info(servinfo_t *info) | ||
957 | { | ||
958 | unsigned int socket_count = 0; | ||
959 | struct list_head *tmp; | ||
960 | info->Signature[0] = 'C'; | ||
961 | info->Signature[1] = 'S'; | ||
962 | down_read(&pcmcia_socket_list_rwsem); | ||
963 | list_for_each(tmp, &pcmcia_socket_list) | ||
964 | socket_count++; | ||
965 | up_read(&pcmcia_socket_list_rwsem); | ||
966 | info->Count = socket_count; | ||
967 | info->Revision = CS_RELEASE_CODE; | ||
968 | info->CSLevel = 0x0210; | ||
969 | info->VendorString = (char *)release; | ||
970 | return CS_SUCCESS; | ||
971 | } /* get_card_services_info */ | ||
972 | |||
973 | |||
974 | /*====================================================================*/ | ||
975 | |||
976 | int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle, int idx, win_req_t *req) | ||
977 | { | ||
978 | window_t *win; | ||
979 | int w; | ||
980 | |||
981 | if (!s || !(s->state & SOCKET_PRESENT)) | ||
982 | return CS_NO_CARD; | ||
983 | for (w = idx; w < MAX_WIN; w++) | ||
984 | if (s->state & SOCKET_WIN_REQ(w)) break; | ||
985 | if (w == MAX_WIN) | ||
986 | return CS_NO_MORE_ITEMS; | ||
987 | win = &s->win[w]; | ||
988 | req->Base = win->ctl.res->start; | ||
989 | req->Size = win->ctl.res->end - win->ctl.res->start + 1; | ||
990 | req->AccessSpeed = win->ctl.speed; | ||
991 | req->Attributes = 0; | ||
992 | if (win->ctl.flags & MAP_ATTRIB) | ||
993 | req->Attributes |= WIN_MEMORY_TYPE_AM; | ||
994 | if (win->ctl.flags & MAP_ACTIVE) | ||
995 | req->Attributes |= WIN_ENABLE; | ||
996 | if (win->ctl.flags & MAP_16BIT) | ||
997 | req->Attributes |= WIN_DATA_WIDTH_16; | ||
998 | if (win->ctl.flags & MAP_USE_WAIT) | ||
999 | req->Attributes |= WIN_USE_WAIT; | ||
1000 | *handle = win; | ||
1001 | return CS_SUCCESS; | ||
1002 | } /* get_window */ | ||
1003 | EXPORT_SYMBOL(pcmcia_get_window); | ||
1004 | |||
1005 | /*===================================================================== | ||
1006 | |||
1007 | Return the PCI device associated with a card.. | ||
1008 | |||
1009 | ======================================================================*/ | ||
1010 | |||
1011 | #ifdef CONFIG_CARDBUS | ||
1012 | |||
1013 | struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s) | ||
1014 | { | ||
1015 | if (!s || !(s->state & SOCKET_CARDBUS)) | ||
1016 | return NULL; | ||
1017 | |||
1018 | return s->cb_dev->subordinate; | ||
1019 | } | ||
1020 | |||
1021 | EXPORT_SYMBOL(pcmcia_lookup_bus); | ||
1022 | |||
1023 | #endif | ||
1024 | |||
1025 | /*====================================================================== | ||
1026 | |||
1027 | Get the current socket state bits. We don't support the latched | ||
1028 | SocketState yet: I haven't seen any point for it. | ||
1029 | |||
1030 | ======================================================================*/ | ||
1031 | |||
1032 | int pccard_get_status(struct pcmcia_socket *s, unsigned int function, cs_status_t *status) | ||
1033 | { | ||
1034 | config_t *c; | ||
1035 | int val; | ||
1036 | |||
1037 | s->ops->get_status(s, &val); | ||
1038 | status->CardState = status->SocketState = 0; | ||
1039 | status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0; | ||
1040 | status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0; | ||
1041 | status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0; | ||
1042 | status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0; | ||
1043 | if (s->state & SOCKET_SUSPEND) | ||
1044 | status->CardState |= CS_EVENT_PM_SUSPEND; | ||
1045 | if (!(s->state & SOCKET_PRESENT)) | ||
1046 | return CS_NO_CARD; | ||
1047 | |||
1048 | c = (s->config != NULL) ? &s->config[function] : NULL; | ||
1049 | if ((c != NULL) && (c->state & CONFIG_LOCKED) && | ||
1050 | (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) { | ||
1051 | u_char reg; | ||
1052 | if (c->Present & PRESENT_PIN_REPLACE) { | ||
1053 | read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, ®); | ||
1054 | status->CardState |= | ||
1055 | (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0; | ||
1056 | status->CardState |= | ||
1057 | (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0; | ||
1058 | status->CardState |= | ||
1059 | (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0; | ||
1060 | status->CardState |= | ||
1061 | (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0; | ||
1062 | } else { | ||
1063 | /* No PRR? Then assume we're always ready */ | ||
1064 | status->CardState |= CS_EVENT_READY_CHANGE; | ||
1065 | } | ||
1066 | if (c->Present & PRESENT_EXT_STATUS) { | ||
1067 | read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, ®); | ||
1068 | status->CardState |= | ||
1069 | (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0; | ||
1070 | } | ||
1071 | return CS_SUCCESS; | ||
1072 | } | ||
1073 | status->CardState |= | ||
1074 | (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0; | ||
1075 | status->CardState |= | ||
1076 | (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0; | ||
1077 | status->CardState |= | ||
1078 | (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0; | ||
1079 | status->CardState |= | ||
1080 | (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0; | ||
1081 | return CS_SUCCESS; | ||
1082 | } /* get_status */ | ||
1083 | EXPORT_SYMBOL(pccard_get_status); | ||
1084 | |||
1085 | /*====================================================================== | ||
1086 | |||
1087 | Change the card address of an already open memory window. | ||
1088 | |||
1089 | ======================================================================*/ | ||
1090 | |||
1091 | int pcmcia_get_mem_page(window_handle_t win, memreq_t *req) | ||
1092 | { | ||
1093 | if ((win == NULL) || (win->magic != WINDOW_MAGIC)) | ||
1094 | return CS_BAD_HANDLE; | ||
1095 | req->Page = 0; | ||
1096 | req->CardOffset = win->ctl.card_start; | ||
1097 | return CS_SUCCESS; | ||
1098 | } /* get_mem_page */ | ||
1099 | |||
1100 | int pcmcia_map_mem_page(window_handle_t win, memreq_t *req) | ||
1101 | { | ||
1102 | struct pcmcia_socket *s; | ||
1103 | if ((win == NULL) || (win->magic != WINDOW_MAGIC)) | ||
1104 | return CS_BAD_HANDLE; | ||
1105 | if (req->Page != 0) | ||
1106 | return CS_BAD_PAGE; | ||
1107 | s = win->sock; | ||
1108 | win->ctl.card_start = req->CardOffset; | ||
1109 | if (s->ops->set_mem_map(s, &win->ctl) != 0) | ||
1110 | return CS_BAD_OFFSET; | ||
1111 | return CS_SUCCESS; | ||
1112 | } /* map_mem_page */ | ||
1113 | |||
1114 | /*====================================================================== | ||
1115 | |||
1116 | Modify a locked socket configuration | ||
1117 | |||
1118 | ======================================================================*/ | ||
1119 | |||
1120 | int pcmcia_modify_configuration(client_handle_t handle, | ||
1121 | modconf_t *mod) | ||
1122 | { | ||
1123 | struct pcmcia_socket *s; | ||
1124 | config_t *c; | ||
1125 | |||
1126 | if (CHECK_HANDLE(handle)) | ||
1127 | return CS_BAD_HANDLE; | ||
1128 | s = SOCKET(handle); c = CONFIG(handle); | ||
1129 | if (!(s->state & SOCKET_PRESENT)) | ||
1130 | return CS_NO_CARD; | ||
1131 | if (!(c->state & CONFIG_LOCKED)) | ||
1132 | return CS_CONFIGURATION_LOCKED; | ||
1133 | |||
1134 | if (mod->Attributes & CONF_IRQ_CHANGE_VALID) { | ||
1135 | if (mod->Attributes & CONF_ENABLE_IRQ) { | ||
1136 | c->Attributes |= CONF_ENABLE_IRQ; | ||
1137 | s->socket.io_irq = s->irq.AssignedIRQ; | ||
1138 | } else { | ||
1139 | c->Attributes &= ~CONF_ENABLE_IRQ; | ||
1140 | s->socket.io_irq = 0; | ||
1141 | } | ||
1142 | s->ops->set_socket(s, &s->socket); | ||
1143 | } | ||
1144 | |||
1145 | if (mod->Attributes & CONF_VCC_CHANGE_VALID) | ||
1146 | return CS_BAD_VCC; | ||
1147 | |||
1148 | /* We only allow changing Vpp1 and Vpp2 to the same value */ | ||
1149 | if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) && | ||
1150 | (mod->Attributes & CONF_VPP2_CHANGE_VALID)) { | ||
1151 | if (mod->Vpp1 != mod->Vpp2) | ||
1152 | return CS_BAD_VPP; | ||
1153 | c->Vpp1 = c->Vpp2 = s->socket.Vpp = mod->Vpp1; | ||
1154 | if (s->ops->set_socket(s, &s->socket)) | ||
1155 | return CS_BAD_VPP; | ||
1156 | } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) || | ||
1157 | (mod->Attributes & CONF_VPP2_CHANGE_VALID)) | ||
1158 | return CS_BAD_VPP; | ||
1159 | |||
1160 | return CS_SUCCESS; | ||
1161 | } /* modify_configuration */ | ||
1162 | |||
1163 | /* register pcmcia_callback */ | 711 | /* register pcmcia_callback */ |
1164 | int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c) | 712 | int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c) |
1165 | { | 713 | { |
@@ -1188,543 +736,16 @@ int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c) | |||
1188 | } | 736 | } |
1189 | EXPORT_SYMBOL(pccard_register_pcmcia); | 737 | EXPORT_SYMBOL(pccard_register_pcmcia); |
1190 | 738 | ||
1191 | /*====================================================================*/ | ||
1192 | 739 | ||
1193 | int pcmcia_release_configuration(client_handle_t handle) | 740 | /* I'm not sure which "reset" function this is supposed to use, |
1194 | { | 741 | * but for now, it uses the low-level interface's reset, not the |
1195 | pccard_io_map io = { 0, 0, 0, 0, 1 }; | 742 | * CIS register. |
1196 | struct pcmcia_socket *s; | 743 | */ |
1197 | int i; | ||
1198 | |||
1199 | if (CHECK_HANDLE(handle) || | ||
1200 | !(handle->state & CLIENT_CONFIG_LOCKED)) | ||
1201 | return CS_BAD_HANDLE; | ||
1202 | handle->state &= ~CLIENT_CONFIG_LOCKED; | ||
1203 | s = SOCKET(handle); | ||
1204 | |||
1205 | #ifdef CONFIG_CARDBUS | ||
1206 | if (handle->state & CLIENT_CARDBUS) | ||
1207 | return CS_SUCCESS; | ||
1208 | #endif | ||
1209 | |||
1210 | if (!(handle->state & CLIENT_STALE)) { | ||
1211 | config_t *c = CONFIG(handle); | ||
1212 | if (--(s->lock_count) == 0) { | ||
1213 | s->socket.flags = SS_OUTPUT_ENA; /* Is this correct? */ | ||
1214 | s->socket.Vpp = 0; | ||
1215 | s->socket.io_irq = 0; | ||
1216 | s->ops->set_socket(s, &s->socket); | ||
1217 | } | ||
1218 | if (c->state & CONFIG_IO_REQ) | ||
1219 | for (i = 0; i < MAX_IO_WIN; i++) { | ||
1220 | if (s->io[i].NumPorts == 0) | ||
1221 | continue; | ||
1222 | s->io[i].Config--; | ||
1223 | if (s->io[i].Config != 0) | ||
1224 | continue; | ||
1225 | io.map = i; | ||
1226 | s->ops->set_io_map(s, &io); | ||
1227 | } | ||
1228 | c->state &= ~CONFIG_LOCKED; | ||
1229 | } | ||
1230 | |||
1231 | return CS_SUCCESS; | ||
1232 | } /* release_configuration */ | ||
1233 | |||
1234 | /*====================================================================== | ||
1235 | |||
1236 | Release_io() releases the I/O ranges allocated by a client. This | ||
1237 | may be invoked some time after a card ejection has already dumped | ||
1238 | the actual socket configuration, so if the client is "stale", we | ||
1239 | don't bother checking the port ranges against the current socket | ||
1240 | values. | ||
1241 | |||
1242 | ======================================================================*/ | ||
1243 | |||
1244 | int pcmcia_release_io(client_handle_t handle, io_req_t *req) | ||
1245 | { | ||
1246 | struct pcmcia_socket *s; | ||
1247 | |||
1248 | if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IO_REQ)) | ||
1249 | return CS_BAD_HANDLE; | ||
1250 | handle->state &= ~CLIENT_IO_REQ; | ||
1251 | s = SOCKET(handle); | ||
1252 | |||
1253 | #ifdef CONFIG_CARDBUS | ||
1254 | if (handle->state & CLIENT_CARDBUS) | ||
1255 | return CS_SUCCESS; | ||
1256 | #endif | ||
1257 | |||
1258 | if (!(handle->state & CLIENT_STALE)) { | ||
1259 | config_t *c = CONFIG(handle); | ||
1260 | if (c->state & CONFIG_LOCKED) | ||
1261 | return CS_CONFIGURATION_LOCKED; | ||
1262 | if ((c->io.BasePort1 != req->BasePort1) || | ||
1263 | (c->io.NumPorts1 != req->NumPorts1) || | ||
1264 | (c->io.BasePort2 != req->BasePort2) || | ||
1265 | (c->io.NumPorts2 != req->NumPorts2)) | ||
1266 | return CS_BAD_ARGS; | ||
1267 | c->state &= ~CONFIG_IO_REQ; | ||
1268 | } | ||
1269 | |||
1270 | release_io_space(s, req->BasePort1, req->NumPorts1); | ||
1271 | if (req->NumPorts2) | ||
1272 | release_io_space(s, req->BasePort2, req->NumPorts2); | ||
1273 | |||
1274 | return CS_SUCCESS; | ||
1275 | } /* release_io */ | ||
1276 | |||
1277 | /*====================================================================*/ | ||
1278 | |||
1279 | int pcmcia_release_irq(client_handle_t handle, irq_req_t *req) | ||
1280 | { | ||
1281 | struct pcmcia_socket *s; | ||
1282 | if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IRQ_REQ)) | ||
1283 | return CS_BAD_HANDLE; | ||
1284 | handle->state &= ~CLIENT_IRQ_REQ; | ||
1285 | s = SOCKET(handle); | ||
1286 | |||
1287 | if (!(handle->state & CLIENT_STALE)) { | ||
1288 | config_t *c = CONFIG(handle); | ||
1289 | if (c->state & CONFIG_LOCKED) | ||
1290 | return CS_CONFIGURATION_LOCKED; | ||
1291 | if (c->irq.Attributes != req->Attributes) | ||
1292 | return CS_BAD_ATTRIBUTE; | ||
1293 | if (s->irq.AssignedIRQ != req->AssignedIRQ) | ||
1294 | return CS_BAD_IRQ; | ||
1295 | if (--s->irq.Config == 0) { | ||
1296 | c->state &= ~CONFIG_IRQ_REQ; | ||
1297 | s->irq.AssignedIRQ = 0; | ||
1298 | } | ||
1299 | } | ||
1300 | |||
1301 | if (req->Attributes & IRQ_HANDLE_PRESENT) { | ||
1302 | free_irq(req->AssignedIRQ, req->Instance); | ||
1303 | } | ||
1304 | |||
1305 | #ifdef CONFIG_PCMCIA_PROBE | ||
1306 | pcmcia_used_irq[req->AssignedIRQ]--; | ||
1307 | #endif | ||
1308 | |||
1309 | return CS_SUCCESS; | ||
1310 | } /* cs_release_irq */ | ||
1311 | |||
1312 | /*====================================================================*/ | ||
1313 | |||
1314 | int pcmcia_release_window(window_handle_t win) | ||
1315 | { | ||
1316 | struct pcmcia_socket *s; | ||
1317 | |||
1318 | if ((win == NULL) || (win->magic != WINDOW_MAGIC)) | ||
1319 | return CS_BAD_HANDLE; | ||
1320 | s = win->sock; | ||
1321 | if (!(win->handle->state & CLIENT_WIN_REQ(win->index))) | ||
1322 | return CS_BAD_HANDLE; | ||
1323 | |||
1324 | /* Shut down memory window */ | ||
1325 | win->ctl.flags &= ~MAP_ACTIVE; | ||
1326 | s->ops->set_mem_map(s, &win->ctl); | ||
1327 | s->state &= ~SOCKET_WIN_REQ(win->index); | ||
1328 | |||
1329 | /* Release system memory */ | ||
1330 | if (win->ctl.res) { | ||
1331 | release_resource(win->ctl.res); | ||
1332 | kfree(win->ctl.res); | ||
1333 | win->ctl.res = NULL; | ||
1334 | } | ||
1335 | win->handle->state &= ~CLIENT_WIN_REQ(win->index); | ||
1336 | |||
1337 | win->magic = 0; | ||
1338 | |||
1339 | return CS_SUCCESS; | ||
1340 | } /* release_window */ | ||
1341 | |||
1342 | /*====================================================================*/ | ||
1343 | |||
1344 | int pcmcia_request_configuration(client_handle_t handle, | ||
1345 | config_req_t *req) | ||
1346 | { | ||
1347 | int i; | ||
1348 | u_int base; | ||
1349 | struct pcmcia_socket *s; | ||
1350 | config_t *c; | ||
1351 | pccard_io_map iomap; | ||
1352 | |||
1353 | if (CHECK_HANDLE(handle)) | ||
1354 | return CS_BAD_HANDLE; | ||
1355 | s = SOCKET(handle); | ||
1356 | if (!(s->state & SOCKET_PRESENT)) | ||
1357 | return CS_NO_CARD; | ||
1358 | |||
1359 | #ifdef CONFIG_CARDBUS | ||
1360 | if (handle->state & CLIENT_CARDBUS) | ||
1361 | return CS_UNSUPPORTED_MODE; | ||
1362 | #endif | ||
1363 | |||
1364 | if (req->IntType & INT_CARDBUS) | ||
1365 | return CS_UNSUPPORTED_MODE; | ||
1366 | c = CONFIG(handle); | ||
1367 | if (c->state & CONFIG_LOCKED) | ||
1368 | return CS_CONFIGURATION_LOCKED; | ||
1369 | |||
1370 | /* Do power control. We don't allow changes in Vcc. */ | ||
1371 | if (s->socket.Vcc != req->Vcc) | ||
1372 | return CS_BAD_VCC; | ||
1373 | if (req->Vpp1 != req->Vpp2) | ||
1374 | return CS_BAD_VPP; | ||
1375 | s->socket.Vpp = req->Vpp1; | ||
1376 | if (s->ops->set_socket(s, &s->socket)) | ||
1377 | return CS_BAD_VPP; | ||
1378 | |||
1379 | c->Vcc = req->Vcc; c->Vpp1 = c->Vpp2 = req->Vpp1; | ||
1380 | |||
1381 | /* Pick memory or I/O card, DMA mode, interrupt */ | ||
1382 | c->IntType = req->IntType; | ||
1383 | c->Attributes = req->Attributes; | ||
1384 | if (req->IntType & INT_MEMORY_AND_IO) | ||
1385 | s->socket.flags |= SS_IOCARD; | ||
1386 | if (req->IntType & INT_ZOOMED_VIDEO) | ||
1387 | s->socket.flags |= SS_ZVCARD | SS_IOCARD; | ||
1388 | if (req->Attributes & CONF_ENABLE_DMA) | ||
1389 | s->socket.flags |= SS_DMA_MODE; | ||
1390 | if (req->Attributes & CONF_ENABLE_SPKR) | ||
1391 | s->socket.flags |= SS_SPKR_ENA; | ||
1392 | if (req->Attributes & CONF_ENABLE_IRQ) | ||
1393 | s->socket.io_irq = s->irq.AssignedIRQ; | ||
1394 | else | ||
1395 | s->socket.io_irq = 0; | ||
1396 | s->ops->set_socket(s, &s->socket); | ||
1397 | s->lock_count++; | ||
1398 | |||
1399 | /* Set up CIS configuration registers */ | ||
1400 | base = c->ConfigBase = req->ConfigBase; | ||
1401 | c->Present = c->CardValues = req->Present; | ||
1402 | if (req->Present & PRESENT_COPY) { | ||
1403 | c->Copy = req->Copy; | ||
1404 | write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy); | ||
1405 | } | ||
1406 | if (req->Present & PRESENT_OPTION) { | ||
1407 | if (s->functions == 1) { | ||
1408 | c->Option = req->ConfigIndex & COR_CONFIG_MASK; | ||
1409 | } else { | ||
1410 | c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK; | ||
1411 | c->Option |= COR_FUNC_ENA|COR_IREQ_ENA; | ||
1412 | if (req->Present & PRESENT_IOBASE_0) | ||
1413 | c->Option |= COR_ADDR_DECODE; | ||
1414 | } | ||
1415 | if (c->state & CONFIG_IRQ_REQ) | ||
1416 | if (!(c->irq.Attributes & IRQ_FORCED_PULSE)) | ||
1417 | c->Option |= COR_LEVEL_REQ; | ||
1418 | write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option); | ||
1419 | mdelay(40); | ||
1420 | } | ||
1421 | if (req->Present & PRESENT_STATUS) { | ||
1422 | c->Status = req->Status; | ||
1423 | write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &c->Status); | ||
1424 | } | ||
1425 | if (req->Present & PRESENT_PIN_REPLACE) { | ||
1426 | c->Pin = req->Pin; | ||
1427 | write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &c->Pin); | ||
1428 | } | ||
1429 | if (req->Present & PRESENT_EXT_STATUS) { | ||
1430 | c->ExtStatus = req->ExtStatus; | ||
1431 | write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus); | ||
1432 | } | ||
1433 | if (req->Present & PRESENT_IOBASE_0) { | ||
1434 | u_char b = c->io.BasePort1 & 0xff; | ||
1435 | write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b); | ||
1436 | b = (c->io.BasePort1 >> 8) & 0xff; | ||
1437 | write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b); | ||
1438 | } | ||
1439 | if (req->Present & PRESENT_IOSIZE) { | ||
1440 | u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1; | ||
1441 | write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b); | ||
1442 | } | ||
1443 | |||
1444 | /* Configure I/O windows */ | ||
1445 | if (c->state & CONFIG_IO_REQ) { | ||
1446 | iomap.speed = io_speed; | ||
1447 | for (i = 0; i < MAX_IO_WIN; i++) | ||
1448 | if (s->io[i].NumPorts != 0) { | ||
1449 | iomap.map = i; | ||
1450 | iomap.flags = MAP_ACTIVE; | ||
1451 | switch (s->io[i].Attributes & IO_DATA_PATH_WIDTH) { | ||
1452 | case IO_DATA_PATH_WIDTH_16: | ||
1453 | iomap.flags |= MAP_16BIT; break; | ||
1454 | case IO_DATA_PATH_WIDTH_AUTO: | ||
1455 | iomap.flags |= MAP_AUTOSZ; break; | ||
1456 | default: | ||
1457 | break; | ||
1458 | } | ||
1459 | iomap.start = s->io[i].BasePort; | ||
1460 | iomap.stop = iomap.start + s->io[i].NumPorts - 1; | ||
1461 | s->ops->set_io_map(s, &iomap); | ||
1462 | s->io[i].Config++; | ||
1463 | } | ||
1464 | } | ||
1465 | |||
1466 | c->state |= CONFIG_LOCKED; | ||
1467 | handle->state |= CLIENT_CONFIG_LOCKED; | ||
1468 | return CS_SUCCESS; | ||
1469 | } /* request_configuration */ | ||
1470 | |||
1471 | /*====================================================================== | ||
1472 | |||
1473 | Request_io() reserves ranges of port addresses for a socket. | ||
1474 | I have not implemented range sharing or alias addressing. | ||
1475 | |||
1476 | ======================================================================*/ | ||
1477 | |||
1478 | int pcmcia_request_io(client_handle_t handle, io_req_t *req) | ||
1479 | { | ||
1480 | struct pcmcia_socket *s; | ||
1481 | config_t *c; | ||
1482 | |||
1483 | if (CHECK_HANDLE(handle)) | ||
1484 | return CS_BAD_HANDLE; | ||
1485 | s = SOCKET(handle); | ||
1486 | if (!(s->state & SOCKET_PRESENT)) | ||
1487 | return CS_NO_CARD; | ||
1488 | |||
1489 | if (handle->state & CLIENT_CARDBUS) { | ||
1490 | #ifdef CONFIG_CARDBUS | ||
1491 | handle->state |= CLIENT_IO_REQ; | ||
1492 | return CS_SUCCESS; | ||
1493 | #else | ||
1494 | return CS_UNSUPPORTED_FUNCTION; | ||
1495 | #endif | ||
1496 | } | ||
1497 | |||
1498 | if (!req) | ||
1499 | return CS_UNSUPPORTED_MODE; | ||
1500 | c = CONFIG(handle); | ||
1501 | if (c->state & CONFIG_LOCKED) | ||
1502 | return CS_CONFIGURATION_LOCKED; | ||
1503 | if (c->state & CONFIG_IO_REQ) | ||
1504 | return CS_IN_USE; | ||
1505 | if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)) | ||
1506 | return CS_BAD_ATTRIBUTE; | ||
1507 | if ((req->NumPorts2 > 0) && | ||
1508 | (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))) | ||
1509 | return CS_BAD_ATTRIBUTE; | ||
1510 | |||
1511 | if (alloc_io_space(s, req->Attributes1, &req->BasePort1, | ||
1512 | req->NumPorts1, req->IOAddrLines)) | ||
1513 | return CS_IN_USE; | ||
1514 | |||
1515 | if (req->NumPorts2) { | ||
1516 | if (alloc_io_space(s, req->Attributes2, &req->BasePort2, | ||
1517 | req->NumPorts2, req->IOAddrLines)) { | ||
1518 | release_io_space(s, req->BasePort1, req->NumPorts1); | ||
1519 | return CS_IN_USE; | ||
1520 | } | ||
1521 | } | ||
1522 | |||
1523 | c->io = *req; | ||
1524 | c->state |= CONFIG_IO_REQ; | ||
1525 | handle->state |= CLIENT_IO_REQ; | ||
1526 | return CS_SUCCESS; | ||
1527 | } /* request_io */ | ||
1528 | |||
1529 | /*====================================================================== | ||
1530 | |||
1531 | Request_irq() reserves an irq for this client. | ||
1532 | |||
1533 | Also, since Linux only reserves irq's when they are actually | ||
1534 | hooked, we don't guarantee that an irq will still be available | ||
1535 | when the configuration is locked. Now that I think about it, | ||
1536 | there might be a way to fix this using a dummy handler. | ||
1537 | |||
1538 | ======================================================================*/ | ||
1539 | |||
1540 | #ifdef CONFIG_PCMCIA_PROBE | ||
1541 | static irqreturn_t test_action(int cpl, void *dev_id, struct pt_regs *regs) | ||
1542 | { | ||
1543 | return IRQ_NONE; | ||
1544 | } | ||
1545 | #endif | ||
1546 | |||
1547 | int pcmcia_request_irq(client_handle_t handle, irq_req_t *req) | ||
1548 | { | ||
1549 | struct pcmcia_socket *s; | ||
1550 | config_t *c; | ||
1551 | int ret = CS_IN_USE, irq = 0; | ||
1552 | struct pcmcia_device *p_dev = handle_to_pdev(handle); | ||
1553 | |||
1554 | if (CHECK_HANDLE(handle)) | ||
1555 | return CS_BAD_HANDLE; | ||
1556 | s = SOCKET(handle); | ||
1557 | if (!(s->state & SOCKET_PRESENT)) | ||
1558 | return CS_NO_CARD; | ||
1559 | c = CONFIG(handle); | ||
1560 | if (c->state & CONFIG_LOCKED) | ||
1561 | return CS_CONFIGURATION_LOCKED; | ||
1562 | if (c->state & CONFIG_IRQ_REQ) | ||
1563 | return CS_IN_USE; | ||
1564 | |||
1565 | #ifdef CONFIG_PCMCIA_PROBE | ||
1566 | if (s->irq.AssignedIRQ != 0) { | ||
1567 | /* If the interrupt is already assigned, it must be the same */ | ||
1568 | irq = s->irq.AssignedIRQ; | ||
1569 | } else { | ||
1570 | int try; | ||
1571 | u32 mask = s->irq_mask; | ||
1572 | void *data = NULL; | ||
1573 | |||
1574 | for (try = 0; try < 64; try++) { | ||
1575 | irq = try % 32; | ||
1576 | |||
1577 | /* marked as available by driver, and not blocked by userspace? */ | ||
1578 | if (!((mask >> irq) & 1)) | ||
1579 | continue; | ||
1580 | |||
1581 | /* avoid an IRQ which is already used by a PCMCIA card */ | ||
1582 | if ((try < 32) && pcmcia_used_irq[irq]) | ||
1583 | continue; | ||
1584 | |||
1585 | /* register the correct driver, if possible, of check whether | ||
1586 | * registering a dummy handle works, i.e. if the IRQ isn't | ||
1587 | * marked as used by the kernel resource management core */ | ||
1588 | ret = request_irq(irq, | ||
1589 | (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Handler : test_action, | ||
1590 | ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || | ||
1591 | (s->functions > 1) || | ||
1592 | (irq == s->pci_irq)) ? SA_SHIRQ : 0, | ||
1593 | p_dev->dev.bus_id, | ||
1594 | (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Instance : data); | ||
1595 | if (!ret) { | ||
1596 | if (!(req->Attributes & IRQ_HANDLE_PRESENT)) | ||
1597 | free_irq(irq, data); | ||
1598 | break; | ||
1599 | } | ||
1600 | } | ||
1601 | } | ||
1602 | #endif | ||
1603 | if (ret) { | ||
1604 | if (!s->pci_irq) | ||
1605 | return ret; | ||
1606 | irq = s->pci_irq; | ||
1607 | } | ||
1608 | |||
1609 | if (ret && req->Attributes & IRQ_HANDLE_PRESENT) { | ||
1610 | if (request_irq(irq, req->Handler, | ||
1611 | ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || | ||
1612 | (s->functions > 1) || | ||
1613 | (irq == s->pci_irq)) ? SA_SHIRQ : 0, | ||
1614 | p_dev->dev.bus_id, req->Instance)) | ||
1615 | return CS_IN_USE; | ||
1616 | } | ||
1617 | |||
1618 | c->irq.Attributes = req->Attributes; | ||
1619 | s->irq.AssignedIRQ = req->AssignedIRQ = irq; | ||
1620 | s->irq.Config++; | ||
1621 | |||
1622 | c->state |= CONFIG_IRQ_REQ; | ||
1623 | handle->state |= CLIENT_IRQ_REQ; | ||
1624 | |||
1625 | #ifdef CONFIG_PCMCIA_PROBE | ||
1626 | pcmcia_used_irq[irq]++; | ||
1627 | #endif | ||
1628 | |||
1629 | return CS_SUCCESS; | ||
1630 | } /* pcmcia_request_irq */ | ||
1631 | |||
1632 | /*====================================================================== | ||
1633 | |||
1634 | Request_window() establishes a mapping between card memory space | ||
1635 | and system memory space. | ||
1636 | |||
1637 | ======================================================================*/ | ||
1638 | |||
1639 | int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle_t *wh) | ||
1640 | { | ||
1641 | struct pcmcia_socket *s; | ||
1642 | window_t *win; | ||
1643 | u_long align; | ||
1644 | int w; | ||
1645 | |||
1646 | if (CHECK_HANDLE(*handle)) | ||
1647 | return CS_BAD_HANDLE; | ||
1648 | s = (*handle)->Socket; | ||
1649 | if (!(s->state & SOCKET_PRESENT)) | ||
1650 | return CS_NO_CARD; | ||
1651 | if (req->Attributes & (WIN_PAGED | WIN_SHARED)) | ||
1652 | return CS_BAD_ATTRIBUTE; | ||
1653 | |||
1654 | /* Window size defaults to smallest available */ | ||
1655 | if (req->Size == 0) | ||
1656 | req->Size = s->map_size; | ||
1657 | align = (((s->features & SS_CAP_MEM_ALIGN) || | ||
1658 | (req->Attributes & WIN_STRICT_ALIGN)) ? | ||
1659 | req->Size : s->map_size); | ||
1660 | if (req->Size & (s->map_size-1)) | ||
1661 | return CS_BAD_SIZE; | ||
1662 | if ((req->Base && (s->features & SS_CAP_STATIC_MAP)) || | ||
1663 | (req->Base & (align-1))) | ||
1664 | return CS_BAD_BASE; | ||
1665 | if (req->Base) | ||
1666 | align = 0; | ||
1667 | |||
1668 | /* Allocate system memory window */ | ||
1669 | for (w = 0; w < MAX_WIN; w++) | ||
1670 | if (!(s->state & SOCKET_WIN_REQ(w))) break; | ||
1671 | if (w == MAX_WIN) | ||
1672 | return CS_OUT_OF_RESOURCE; | ||
1673 | |||
1674 | win = &s->win[w]; | ||
1675 | win->magic = WINDOW_MAGIC; | ||
1676 | win->index = w; | ||
1677 | win->handle = *handle; | ||
1678 | win->sock = s; | ||
1679 | |||
1680 | if (!(s->features & SS_CAP_STATIC_MAP)) { | ||
1681 | win->ctl.res = find_mem_region(req->Base, req->Size, align, | ||
1682 | (req->Attributes & WIN_MAP_BELOW_1MB), s); | ||
1683 | if (!win->ctl.res) | ||
1684 | return CS_IN_USE; | ||
1685 | } | ||
1686 | (*handle)->state |= CLIENT_WIN_REQ(w); | ||
1687 | |||
1688 | /* Configure the socket controller */ | ||
1689 | win->ctl.map = w+1; | ||
1690 | win->ctl.flags = 0; | ||
1691 | win->ctl.speed = req->AccessSpeed; | ||
1692 | if (req->Attributes & WIN_MEMORY_TYPE) | ||
1693 | win->ctl.flags |= MAP_ATTRIB; | ||
1694 | if (req->Attributes & WIN_ENABLE) | ||
1695 | win->ctl.flags |= MAP_ACTIVE; | ||
1696 | if (req->Attributes & WIN_DATA_WIDTH_16) | ||
1697 | win->ctl.flags |= MAP_16BIT; | ||
1698 | if (req->Attributes & WIN_USE_WAIT) | ||
1699 | win->ctl.flags |= MAP_USE_WAIT; | ||
1700 | win->ctl.card_start = 0; | ||
1701 | if (s->ops->set_mem_map(s, &win->ctl) != 0) | ||
1702 | return CS_BAD_ARGS; | ||
1703 | s->state |= SOCKET_WIN_REQ(w); | ||
1704 | |||
1705 | /* Return window handle */ | ||
1706 | if (s->features & SS_CAP_STATIC_MAP) { | ||
1707 | req->Base = win->ctl.static_start; | ||
1708 | } else { | ||
1709 | req->Base = win->ctl.res->start; | ||
1710 | } | ||
1711 | *wh = win; | ||
1712 | |||
1713 | return CS_SUCCESS; | ||
1714 | } /* request_window */ | ||
1715 | |||
1716 | /*====================================================================== | ||
1717 | |||
1718 | I'm not sure which "reset" function this is supposed to use, | ||
1719 | but for now, it uses the low-level interface's reset, not the | ||
1720 | CIS register. | ||
1721 | |||
1722 | ======================================================================*/ | ||
1723 | 744 | ||
1724 | int pccard_reset_card(struct pcmcia_socket *skt) | 745 | int pccard_reset_card(struct pcmcia_socket *skt) |
1725 | { | 746 | { |
1726 | int ret; | 747 | int ret; |
1727 | 748 | ||
1728 | cs_dbg(skt, 1, "resetting socket\n"); | 749 | cs_dbg(skt, 1, "resetting socket\n"); |
1729 | 750 | ||
1730 | down(&skt->skt_sem); | 751 | down(&skt->skt_sem); |
@@ -1757,17 +778,14 @@ int pccard_reset_card(struct pcmcia_socket *skt) | |||
1757 | } /* reset_card */ | 778 | } /* reset_card */ |
1758 | EXPORT_SYMBOL(pccard_reset_card); | 779 | EXPORT_SYMBOL(pccard_reset_card); |
1759 | 780 | ||
1760 | /*====================================================================== | ||
1761 | |||
1762 | These shut down or wake up a socket. They are sort of user | ||
1763 | initiated versions of the APM suspend and resume actions. | ||
1764 | |||
1765 | ======================================================================*/ | ||
1766 | 781 | ||
782 | /* These shut down or wake up a socket. They are sort of user | ||
783 | * initiated versions of the APM suspend and resume actions. | ||
784 | */ | ||
1767 | int pcmcia_suspend_card(struct pcmcia_socket *skt) | 785 | int pcmcia_suspend_card(struct pcmcia_socket *skt) |
1768 | { | 786 | { |
1769 | int ret; | 787 | int ret; |
1770 | 788 | ||
1771 | cs_dbg(skt, 1, "suspending socket\n"); | 789 | cs_dbg(skt, 1, "suspending socket\n"); |
1772 | 790 | ||
1773 | down(&skt->skt_sem); | 791 | down(&skt->skt_sem); |
@@ -1786,6 +804,8 @@ int pcmcia_suspend_card(struct pcmcia_socket *skt) | |||
1786 | 804 | ||
1787 | return ret; | 805 | return ret; |
1788 | } /* suspend_card */ | 806 | } /* suspend_card */ |
807 | EXPORT_SYMBOL(pcmcia_suspend_card); | ||
808 | |||
1789 | 809 | ||
1790 | int pcmcia_resume_card(struct pcmcia_socket *skt) | 810 | int pcmcia_resume_card(struct pcmcia_socket *skt) |
1791 | { | 811 | { |
@@ -1809,13 +829,10 @@ int pcmcia_resume_card(struct pcmcia_socket *skt) | |||
1809 | 829 | ||
1810 | return ret; | 830 | return ret; |
1811 | } /* resume_card */ | 831 | } /* resume_card */ |
832 | EXPORT_SYMBOL(pcmcia_resume_card); | ||
1812 | 833 | ||
1813 | /*====================================================================== | ||
1814 | |||
1815 | These handle user requests to eject or insert a card. | ||
1816 | |||
1817 | ======================================================================*/ | ||
1818 | 834 | ||
835 | /* These handle user requests to eject or insert a card. */ | ||
1819 | int pcmcia_eject_card(struct pcmcia_socket *skt) | 836 | int pcmcia_eject_card(struct pcmcia_socket *skt) |
1820 | { | 837 | { |
1821 | int ret; | 838 | int ret; |
@@ -1842,6 +859,8 @@ int pcmcia_eject_card(struct pcmcia_socket *skt) | |||
1842 | 859 | ||
1843 | return ret; | 860 | return ret; |
1844 | } /* eject_card */ | 861 | } /* eject_card */ |
862 | EXPORT_SYMBOL(pcmcia_eject_card); | ||
863 | |||
1845 | 864 | ||
1846 | int pcmcia_insert_card(struct pcmcia_socket *skt) | 865 | int pcmcia_insert_card(struct pcmcia_socket *skt) |
1847 | { | 866 | { |
@@ -1865,37 +884,38 @@ int pcmcia_insert_card(struct pcmcia_socket *skt) | |||
1865 | 884 | ||
1866 | return ret; | 885 | return ret; |
1867 | } /* insert_card */ | 886 | } /* insert_card */ |
887 | EXPORT_SYMBOL(pcmcia_insert_card); | ||
1868 | 888 | ||
1869 | /*====================================================================== | ||
1870 | 889 | ||
1871 | OS-specific module glue goes here | 890 | static int pcmcia_socket_hotplug(struct class_device *dev, char **envp, |
1872 | 891 | int num_envp, char *buffer, int buffer_size) | |
1873 | ======================================================================*/ | 892 | { |
1874 | /* in alpha order */ | 893 | struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev); |
1875 | EXPORT_SYMBOL(pcmcia_eject_card); | 894 | int i = 0, length = 0; |
1876 | EXPORT_SYMBOL(pcmcia_get_card_services_info); | 895 | |
1877 | EXPORT_SYMBOL(pcmcia_get_mem_page); | 896 | if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, |
1878 | EXPORT_SYMBOL(pcmcia_insert_card); | 897 | &length, "SOCKET_NO=%u", s->sock)) |
1879 | EXPORT_SYMBOL(pcmcia_map_mem_page); | 898 | return -ENOMEM; |
1880 | EXPORT_SYMBOL(pcmcia_modify_configuration); | 899 | |
1881 | EXPORT_SYMBOL(pcmcia_release_configuration); | 900 | envp[i] = NULL; |
1882 | EXPORT_SYMBOL(pcmcia_release_io); | 901 | |
1883 | EXPORT_SYMBOL(pcmcia_release_irq); | 902 | return 0; |
1884 | EXPORT_SYMBOL(pcmcia_release_window); | 903 | } |
1885 | EXPORT_SYMBOL(pcmcia_replace_cis); | 904 | |
1886 | EXPORT_SYMBOL(pcmcia_request_configuration); | 905 | |
1887 | EXPORT_SYMBOL(pcmcia_request_io); | 906 | static struct completion pcmcia_unload; |
1888 | EXPORT_SYMBOL(pcmcia_request_irq); | 907 | |
1889 | EXPORT_SYMBOL(pcmcia_request_window); | 908 | static void pcmcia_release_socket_class(struct class *data) |
1890 | EXPORT_SYMBOL(pcmcia_resume_card); | 909 | { |
1891 | EXPORT_SYMBOL(pcmcia_suspend_card); | 910 | complete(&pcmcia_unload); |
911 | } | ||
1892 | 912 | ||
1893 | EXPORT_SYMBOL(dead_socket); | ||
1894 | EXPORT_SYMBOL(pcmcia_parse_events); | ||
1895 | 913 | ||
1896 | struct class pcmcia_socket_class = { | 914 | struct class pcmcia_socket_class = { |
1897 | .name = "pcmcia_socket", | 915 | .name = "pcmcia_socket", |
916 | .hotplug = pcmcia_socket_hotplug, | ||
1898 | .release = pcmcia_release_socket, | 917 | .release = pcmcia_release_socket, |
918 | .class_release = pcmcia_release_socket_class, | ||
1899 | }; | 919 | }; |
1900 | EXPORT_SYMBOL(pcmcia_socket_class); | 920 | EXPORT_SYMBOL(pcmcia_socket_class); |
1901 | 921 | ||
@@ -1903,9 +923,8 @@ EXPORT_SYMBOL(pcmcia_socket_class); | |||
1903 | static int __init init_pcmcia_cs(void) | 923 | static int __init init_pcmcia_cs(void) |
1904 | { | 924 | { |
1905 | int ret; | 925 | int ret; |
1906 | printk(KERN_INFO "%s\n", release); | ||
1907 | printk(KERN_INFO " %s\n", options); | ||
1908 | 926 | ||
927 | init_completion(&pcmcia_unload); | ||
1909 | ret = class_register(&pcmcia_socket_class); | 928 | ret = class_register(&pcmcia_socket_class); |
1910 | if (ret) | 929 | if (ret) |
1911 | return (ret); | 930 | return (ret); |
@@ -1914,13 +933,12 @@ static int __init init_pcmcia_cs(void) | |||
1914 | 933 | ||
1915 | static void __exit exit_pcmcia_cs(void) | 934 | static void __exit exit_pcmcia_cs(void) |
1916 | { | 935 | { |
1917 | printk(KERN_INFO "unloading Kernel Card Services\n"); | 936 | class_interface_unregister(&pccard_sysfs_interface); |
1918 | class_interface_unregister(&pccard_sysfs_interface); | 937 | class_unregister(&pcmcia_socket_class); |
1919 | class_unregister(&pcmcia_socket_class); | 938 | |
939 | wait_for_completion(&pcmcia_unload); | ||
1920 | } | 940 | } |
1921 | 941 | ||
1922 | subsys_initcall(init_pcmcia_cs); | 942 | subsys_initcall(init_pcmcia_cs); |
1923 | module_exit(exit_pcmcia_cs); | 943 | module_exit(exit_pcmcia_cs); |
1924 | 944 | ||
1925 | /*====================================================================*/ | ||
1926 | |||
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 7933a7db49d3..0b4c18edfa49 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h | |||
@@ -123,9 +123,9 @@ void cb_free(struct pcmcia_socket *s); | |||
123 | int read_cb_mem(struct pcmcia_socket *s, int space, u_int addr, u_int len, void *ptr); | 123 | int read_cb_mem(struct pcmcia_socket *s, int space, u_int addr, u_int len, void *ptr); |
124 | 124 | ||
125 | /* In cistpl.c */ | 125 | /* In cistpl.c */ |
126 | int read_cis_mem(struct pcmcia_socket *s, int attr, | 126 | int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, |
127 | u_int addr, u_int len, void *ptr); | 127 | u_int addr, u_int len, void *ptr); |
128 | void write_cis_mem(struct pcmcia_socket *s, int attr, | 128 | void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, |
129 | u_int addr, u_int len, void *ptr); | 129 | u_int addr, u_int len, void *ptr); |
130 | void release_cis_mem(struct pcmcia_socket *s); | 130 | void release_cis_mem(struct pcmcia_socket *s); |
131 | void destroy_cis_cache(struct pcmcia_socket *s); | 131 | void destroy_cis_cache(struct pcmcia_socket *s); |
@@ -134,13 +134,12 @@ int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t | |||
134 | 134 | ||
135 | /* In rsrc_mgr */ | 135 | /* In rsrc_mgr */ |
136 | void pcmcia_validate_mem(struct pcmcia_socket *s); | 136 | void pcmcia_validate_mem(struct pcmcia_socket *s); |
137 | struct resource *find_io_region(unsigned long base, int num, unsigned long align, | 137 | struct resource *pcmcia_find_io_region(unsigned long base, int num, unsigned long align, |
138 | struct pcmcia_socket *s); | 138 | struct pcmcia_socket *s); |
139 | int adjust_io_region(struct resource *res, unsigned long r_start, | 139 | int pcmcia_adjust_io_region(struct resource *res, unsigned long r_start, |
140 | unsigned long r_end, struct pcmcia_socket *s); | 140 | unsigned long r_end, struct pcmcia_socket *s); |
141 | struct resource *find_mem_region(u_long base, u_long num, u_long align, | 141 | struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align, |
142 | int low, struct pcmcia_socket *s); | 142 | int low, struct pcmcia_socket *s); |
143 | int adjust_resource_info(client_handle_t handle, adjust_t *adj); | ||
144 | void release_resource_db(struct pcmcia_socket *s); | 143 | void release_resource_db(struct pcmcia_socket *s); |
145 | 144 | ||
146 | /* In socket_sysfs.c */ | 145 | /* In socket_sysfs.c */ |
@@ -159,7 +158,7 @@ int pccard_access_configuration_register(struct pcmcia_socket *s, unsigned int f | |||
159 | struct pcmcia_callback{ | 158 | struct pcmcia_callback{ |
160 | struct module *owner; | 159 | struct module *owner; |
161 | int (*event) (struct pcmcia_socket *s, event_t event, int priority); | 160 | int (*event) (struct pcmcia_socket *s, event_t event, int priority); |
162 | int (*resources_done) (struct pcmcia_socket *s); | 161 | void (*requery) (struct pcmcia_socket *s); |
163 | }; | 162 | }; |
164 | 163 | ||
165 | int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c); | 164 | int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c); |
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 569e55feecfd..cabddd49f6ff 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c | |||
@@ -10,44 +10,29 @@ | |||
10 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | 10 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. |
11 | * | 11 | * |
12 | * (C) 1999 David A. Hinds | 12 | * (C) 1999 David A. Hinds |
13 | * (C) 2003 - 2004 Dominik Brodowski | 13 | * (C) 2003 - 2005 Dominik Brodowski |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/config.h> | 16 | #include <linux/config.h> |
17 | #include <linux/kernel.h> | ||
17 | #include <linux/module.h> | 18 | #include <linux/module.h> |
18 | #include <linux/moduleparam.h> | ||
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/kernel.h> | ||
21 | #include <linux/major.h> | ||
22 | #include <linux/string.h> | ||
23 | #include <linux/errno.h> | 20 | #include <linux/errno.h> |
24 | #include <linux/slab.h> | ||
25 | #include <linux/mm.h> | ||
26 | #include <linux/fcntl.h> | ||
27 | #include <linux/sched.h> | ||
28 | #include <linux/smp_lock.h> | ||
29 | #include <linux/timer.h> | ||
30 | #include <linux/ioctl.h> | ||
31 | #include <linux/proc_fs.h> | ||
32 | #include <linux/poll.h> | ||
33 | #include <linux/pci.h> | ||
34 | #include <linux/list.h> | 21 | #include <linux/list.h> |
35 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
36 | #include <linux/kref.h> | ||
37 | #include <linux/workqueue.h> | 23 | #include <linux/workqueue.h> |
38 | 24 | #include <linux/crc32.h> | |
39 | #include <asm/atomic.h> | 25 | #include <linux/firmware.h> |
40 | 26 | ||
41 | #define IN_CARD_SERVICES | 27 | #define IN_CARD_SERVICES |
42 | #include <pcmcia/version.h> | ||
43 | #include <pcmcia/cs_types.h> | 28 | #include <pcmcia/cs_types.h> |
44 | #include <pcmcia/cs.h> | 29 | #include <pcmcia/cs.h> |
45 | #include <pcmcia/bulkmem.h> | ||
46 | #include <pcmcia/cistpl.h> | 30 | #include <pcmcia/cistpl.h> |
47 | #include <pcmcia/ds.h> | 31 | #include <pcmcia/ds.h> |
48 | #include <pcmcia/ss.h> | 32 | #include <pcmcia/ss.h> |
49 | 33 | ||
50 | #include "cs_internal.h" | 34 | #include "cs_internal.h" |
35 | #include "ds_internal.h" | ||
51 | 36 | ||
52 | /*====================================================================*/ | 37 | /*====================================================================*/ |
53 | 38 | ||
@@ -70,49 +55,9 @@ module_param_named(pc_debug, ds_pc_debug, int, 0644); | |||
70 | #define ds_dbg(lvl, fmt, arg...) do { } while (0) | 55 | #define ds_dbg(lvl, fmt, arg...) do { } while (0) |
71 | #endif | 56 | #endif |
72 | 57 | ||
73 | /*====================================================================*/ | 58 | spinlock_t pcmcia_dev_list_lock; |
74 | 59 | ||
75 | /* Device user information */ | 60 | static int unbind_request(struct pcmcia_socket *s); |
76 | #define MAX_EVENTS 32 | ||
77 | #define USER_MAGIC 0x7ea4 | ||
78 | #define CHECK_USER(u) \ | ||
79 | (((u) == NULL) || ((u)->user_magic != USER_MAGIC)) | ||
80 | typedef struct user_info_t { | ||
81 | u_int user_magic; | ||
82 | int event_head, event_tail; | ||
83 | event_t event[MAX_EVENTS]; | ||
84 | struct user_info_t *next; | ||
85 | struct pcmcia_bus_socket *socket; | ||
86 | } user_info_t; | ||
87 | |||
88 | /* Socket state information */ | ||
89 | struct pcmcia_bus_socket { | ||
90 | struct kref refcount; | ||
91 | struct pcmcia_callback callback; | ||
92 | int state; | ||
93 | user_info_t *user; | ||
94 | wait_queue_head_t queue; | ||
95 | struct pcmcia_socket *parent; | ||
96 | |||
97 | /* the PCMCIA devices connected to this socket (normally one, more | ||
98 | * for multifunction devices: */ | ||
99 | struct list_head devices_list; | ||
100 | u8 device_count; /* the number of devices, used | ||
101 | * only internally and subject | ||
102 | * to incorrectness and change */ | ||
103 | }; | ||
104 | static spinlock_t pcmcia_dev_list_lock; | ||
105 | |||
106 | #define DS_SOCKET_PRESENT 0x01 | ||
107 | #define DS_SOCKET_BUSY 0x02 | ||
108 | #define DS_SOCKET_REMOVAL_PENDING 0x10 | ||
109 | #define DS_SOCKET_DEAD 0x80 | ||
110 | |||
111 | /*====================================================================*/ | ||
112 | |||
113 | static int major_dev = -1; | ||
114 | |||
115 | static int unbind_request(struct pcmcia_bus_socket *s); | ||
116 | 61 | ||
117 | /*====================================================================*/ | 62 | /*====================================================================*/ |
118 | 63 | ||
@@ -213,7 +158,7 @@ static const lookup_t service_table[] = { | |||
213 | }; | 158 | }; |
214 | 159 | ||
215 | 160 | ||
216 | int pcmcia_report_error(client_handle_t handle, error_info_t *err) | 161 | static int pcmcia_report_error(client_handle_t handle, error_info_t *err) |
217 | { | 162 | { |
218 | int i; | 163 | int i; |
219 | char *serv; | 164 | char *serv; |
@@ -243,7 +188,6 @@ int pcmcia_report_error(client_handle_t handle, error_info_t *err) | |||
243 | 188 | ||
244 | return CS_SUCCESS; | 189 | return CS_SUCCESS; |
245 | } /* report_error */ | 190 | } /* report_error */ |
246 | EXPORT_SYMBOL(pcmcia_report_error); | ||
247 | 191 | ||
248 | /* end of code which was in cs.c before */ | 192 | /* end of code which was in cs.c before */ |
249 | 193 | ||
@@ -256,29 +200,101 @@ void cs_error(client_handle_t handle, int func, int ret) | |||
256 | } | 200 | } |
257 | EXPORT_SYMBOL(cs_error); | 201 | EXPORT_SYMBOL(cs_error); |
258 | 202 | ||
259 | /*======================================================================*/ | ||
260 | |||
261 | static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info); | ||
262 | static struct pcmcia_bus_socket * get_socket_info_by_nr(unsigned int nr); | ||
263 | 203 | ||
264 | static void pcmcia_release_bus_socket(struct kref *refcount) | 204 | static void pcmcia_check_driver(struct pcmcia_driver *p_drv) |
265 | { | 205 | { |
266 | struct pcmcia_bus_socket *s = container_of(refcount, struct pcmcia_bus_socket, refcount); | 206 | struct pcmcia_device_id *did = p_drv->id_table; |
267 | pcmcia_put_socket(s->parent); | 207 | unsigned int i; |
268 | kfree(s); | 208 | u32 hash; |
209 | |||
210 | while (did && did->match_flags) { | ||
211 | for (i=0; i<4; i++) { | ||
212 | if (!did->prod_id[i]) | ||
213 | continue; | ||
214 | |||
215 | hash = crc32(0, did->prod_id[i], strlen(did->prod_id[i])); | ||
216 | if (hash == did->prod_id_hash[i]) | ||
217 | continue; | ||
218 | |||
219 | printk(KERN_DEBUG "pcmcia: %s: invalid hash for " | ||
220 | "product string \"%s\": is 0x%x, should " | ||
221 | "be 0x%x\n", p_drv->drv.name, did->prod_id[i], | ||
222 | did->prod_id_hash[i], hash); | ||
223 | printk(KERN_DEBUG "pcmcia: see " | ||
224 | "Documentation/pcmcia/devicetable.txt for " | ||
225 | "details\n"); | ||
226 | } | ||
227 | did++; | ||
228 | } | ||
229 | |||
230 | return; | ||
269 | } | 231 | } |
270 | 232 | ||
271 | static void pcmcia_put_bus_socket(struct pcmcia_bus_socket *s) | 233 | |
234 | #ifdef CONFIG_PCMCIA_LOAD_CIS | ||
235 | |||
236 | /** | ||
237 | * pcmcia_load_firmware - load CIS from userspace if device-provided is broken | ||
238 | * @dev - the pcmcia device which needs a CIS override | ||
239 | * @filename - requested filename in /lib/firmware/cis/ | ||
240 | * | ||
241 | * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if | ||
242 | * the one provided by the card is broken. The firmware files reside in | ||
243 | * /lib/firmware/cis/ in userspace. | ||
244 | */ | ||
245 | static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) | ||
272 | { | 246 | { |
273 | kref_put(&s->refcount, pcmcia_release_bus_socket); | 247 | struct pcmcia_socket *s = dev->socket; |
248 | const struct firmware *fw; | ||
249 | char path[20]; | ||
250 | int ret=-ENOMEM; | ||
251 | cisdump_t *cis; | ||
252 | |||
253 | if (!filename) | ||
254 | return -EINVAL; | ||
255 | |||
256 | ds_dbg(1, "trying to load firmware %s\n", filename); | ||
257 | |||
258 | if (strlen(filename) > 14) | ||
259 | return -EINVAL; | ||
260 | |||
261 | snprintf(path, 20, "%s", filename); | ||
262 | |||
263 | if (request_firmware(&fw, path, &dev->dev) == 0) { | ||
264 | if (fw->size >= CISTPL_MAX_CIS_SIZE) | ||
265 | goto release; | ||
266 | |||
267 | cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL); | ||
268 | if (!cis) | ||
269 | goto release; | ||
270 | |||
271 | memset(cis, 0, sizeof(cisdump_t)); | ||
272 | |||
273 | cis->Length = fw->size + 1; | ||
274 | memcpy(cis->Data, fw->data, fw->size); | ||
275 | |||
276 | if (!pcmcia_replace_cis(s, cis)) | ||
277 | ret = 0; | ||
278 | } | ||
279 | release: | ||
280 | release_firmware(fw); | ||
281 | |||
282 | return (ret); | ||
274 | } | 283 | } |
275 | 284 | ||
276 | static struct pcmcia_bus_socket *pcmcia_get_bus_socket(struct pcmcia_bus_socket *s) | 285 | #else /* !CONFIG_PCMCIA_LOAD_CIS */ |
286 | |||
287 | static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) | ||
277 | { | 288 | { |
278 | kref_get(&s->refcount); | 289 | return -ENODEV; |
279 | return (s); | ||
280 | } | 290 | } |
281 | 291 | ||
292 | #endif | ||
293 | |||
294 | |||
295 | /*======================================================================*/ | ||
296 | |||
297 | |||
282 | /** | 298 | /** |
283 | * pcmcia_register_driver - register a PCMCIA driver with the bus core | 299 | * pcmcia_register_driver - register a PCMCIA driver with the bus core |
284 | * | 300 | * |
@@ -292,6 +308,8 @@ int pcmcia_register_driver(struct pcmcia_driver *driver) | |||
292 | if (!driver) | 308 | if (!driver) |
293 | return -EINVAL; | 309 | return -EINVAL; |
294 | 310 | ||
311 | pcmcia_check_driver(driver); | ||
312 | |||
295 | /* initialize common fields */ | 313 | /* initialize common fields */ |
296 | driver->drv.bus = &pcmcia_bus_type; | 314 | driver->drv.bus = &pcmcia_bus_type; |
297 | driver->drv.owner = driver->owner; | 315 | driver->drv.owner = driver->owner; |
@@ -311,42 +329,10 @@ void pcmcia_unregister_driver(struct pcmcia_driver *driver) | |||
311 | } | 329 | } |
312 | EXPORT_SYMBOL(pcmcia_unregister_driver); | 330 | EXPORT_SYMBOL(pcmcia_unregister_driver); |
313 | 331 | ||
314 | #ifdef CONFIG_PROC_FS | ||
315 | static struct proc_dir_entry *proc_pccard = NULL; | ||
316 | |||
317 | static int proc_read_drivers_callback(struct device_driver *driver, void *d) | ||
318 | { | ||
319 | char **p = d; | ||
320 | struct pcmcia_driver *p_drv = container_of(driver, | ||
321 | struct pcmcia_driver, drv); | ||
322 | |||
323 | *p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name, | ||
324 | #ifdef CONFIG_MODULE_UNLOAD | ||
325 | (p_drv->owner) ? module_refcount(p_drv->owner) : 1 | ||
326 | #else | ||
327 | 1 | ||
328 | #endif | ||
329 | ); | ||
330 | d = (void *) p; | ||
331 | |||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | static int proc_read_drivers(char *buf, char **start, off_t pos, | ||
336 | int count, int *eof, void *data) | ||
337 | { | ||
338 | char *p = buf; | ||
339 | |||
340 | bus_for_each_drv(&pcmcia_bus_type, NULL, | ||
341 | (void *) &p, proc_read_drivers_callback); | ||
342 | |||
343 | return (p - buf); | ||
344 | } | ||
345 | #endif | ||
346 | 332 | ||
347 | /* pcmcia_device handling */ | 333 | /* pcmcia_device handling */ |
348 | 334 | ||
349 | static struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev) | 335 | struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev) |
350 | { | 336 | { |
351 | struct device *tmp_dev; | 337 | struct device *tmp_dev; |
352 | tmp_dev = get_device(&p_dev->dev); | 338 | tmp_dev = get_device(&p_dev->dev); |
@@ -355,7 +341,7 @@ static struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev) | |||
355 | return to_pcmcia_dev(tmp_dev); | 341 | return to_pcmcia_dev(tmp_dev); |
356 | } | 342 | } |
357 | 343 | ||
358 | static void pcmcia_put_dev(struct pcmcia_device *p_dev) | 344 | void pcmcia_put_dev(struct pcmcia_device *p_dev) |
359 | { | 345 | { |
360 | if (p_dev) | 346 | if (p_dev) |
361 | put_device(&p_dev->dev); | 347 | put_device(&p_dev->dev); |
@@ -365,7 +351,7 @@ static void pcmcia_release_dev(struct device *dev) | |||
365 | { | 351 | { |
366 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 352 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
367 | ds_dbg(1, "releasing dev %p\n", p_dev); | 353 | ds_dbg(1, "releasing dev %p\n", p_dev); |
368 | pcmcia_put_bus_socket(p_dev->socket->pcmcia); | 354 | pcmcia_put_socket(p_dev->socket); |
369 | kfree(p_dev); | 355 | kfree(p_dev); |
370 | } | 356 | } |
371 | 357 | ||
@@ -500,34 +486,38 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev) | |||
500 | */ | 486 | */ |
501 | static DECLARE_MUTEX(device_add_lock); | 487 | static DECLARE_MUTEX(device_add_lock); |
502 | 488 | ||
503 | static struct pcmcia_device * pcmcia_device_add(struct pcmcia_bus_socket *s, unsigned int function) | 489 | struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function) |
504 | { | 490 | { |
505 | struct pcmcia_device *p_dev; | 491 | struct pcmcia_device *p_dev; |
506 | unsigned long flags; | 492 | unsigned long flags; |
507 | 493 | ||
508 | s = pcmcia_get_bus_socket(s); | 494 | s = pcmcia_get_socket(s); |
509 | if (!s) | 495 | if (!s) |
510 | return NULL; | 496 | return NULL; |
511 | 497 | ||
512 | down(&device_add_lock); | 498 | down(&device_add_lock); |
513 | 499 | ||
500 | /* max of 2 devices per card */ | ||
501 | if (s->device_count == 2) | ||
502 | goto err_put; | ||
503 | |||
514 | p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL); | 504 | p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL); |
515 | if (!p_dev) | 505 | if (!p_dev) |
516 | goto err_put; | 506 | goto err_put; |
517 | memset(p_dev, 0, sizeof(struct pcmcia_device)); | 507 | memset(p_dev, 0, sizeof(struct pcmcia_device)); |
518 | 508 | ||
519 | p_dev->socket = s->parent; | 509 | p_dev->socket = s; |
520 | p_dev->device_no = (s->device_count++); | 510 | p_dev->device_no = (s->device_count++); |
521 | p_dev->func = function; | 511 | p_dev->func = function; |
522 | 512 | ||
523 | p_dev->dev.bus = &pcmcia_bus_type; | 513 | p_dev->dev.bus = &pcmcia_bus_type; |
524 | p_dev->dev.parent = s->parent->dev.dev; | 514 | p_dev->dev.parent = s->dev.dev; |
525 | p_dev->dev.release = pcmcia_release_dev; | 515 | p_dev->dev.release = pcmcia_release_dev; |
526 | sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no); | 516 | sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no); |
527 | 517 | ||
528 | /* compat */ | 518 | /* compat */ |
529 | p_dev->client.client_magic = CLIENT_MAGIC; | 519 | p_dev->client.client_magic = CLIENT_MAGIC; |
530 | p_dev->client.Socket = s->parent; | 520 | p_dev->client.Socket = s; |
531 | p_dev->client.Function = function; | 521 | p_dev->client.Function = function; |
532 | p_dev->client.state = CLIENT_UNBOUND; | 522 | p_dev->client.state = CLIENT_UNBOUND; |
533 | 523 | ||
@@ -536,6 +526,8 @@ static struct pcmcia_device * pcmcia_device_add(struct pcmcia_bus_socket *s, uns | |||
536 | list_add_tail(&p_dev->socket_device_list, &s->devices_list); | 526 | list_add_tail(&p_dev->socket_device_list, &s->devices_list); |
537 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | 527 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); |
538 | 528 | ||
529 | pcmcia_device_query(p_dev); | ||
530 | |||
539 | if (device_register(&p_dev->dev)) { | 531 | if (device_register(&p_dev->dev)) { |
540 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | 532 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); |
541 | list_del(&p_dev->socket_device_list); | 533 | list_del(&p_dev->socket_device_list); |
@@ -553,7 +545,7 @@ static struct pcmcia_device * pcmcia_device_add(struct pcmcia_bus_socket *s, uns | |||
553 | s->device_count--; | 545 | s->device_count--; |
554 | err_put: | 546 | err_put: |
555 | up(&device_add_lock); | 547 | up(&device_add_lock); |
556 | pcmcia_put_bus_socket(s); | 548 | pcmcia_put_socket(s); |
557 | 549 | ||
558 | return NULL; | 550 | return NULL; |
559 | } | 551 | } |
@@ -584,23 +576,252 @@ static int pcmcia_card_add(struct pcmcia_socket *s) | |||
584 | /* this doesn't handle multifunction devices on one pcmcia function | 576 | /* this doesn't handle multifunction devices on one pcmcia function |
585 | * yet. */ | 577 | * yet. */ |
586 | for (i=0; i < no_funcs; i++) | 578 | for (i=0; i < no_funcs; i++) |
587 | pcmcia_device_add(s->pcmcia, i); | 579 | pcmcia_device_add(s, i); |
588 | 580 | ||
589 | return (ret); | 581 | return (ret); |
590 | } | 582 | } |
591 | 583 | ||
592 | 584 | ||
585 | static void pcmcia_delayed_add_pseudo_device(void *data) | ||
586 | { | ||
587 | struct pcmcia_socket *s = data; | ||
588 | pcmcia_device_add(s, 0); | ||
589 | s->pcmcia_state.device_add_pending = 0; | ||
590 | } | ||
591 | |||
592 | static inline void pcmcia_add_pseudo_device(struct pcmcia_socket *s) | ||
593 | { | ||
594 | if (!s->pcmcia_state.device_add_pending) { | ||
595 | schedule_work(&s->device_add); | ||
596 | s->pcmcia_state.device_add_pending = 1; | ||
597 | } | ||
598 | return; | ||
599 | } | ||
600 | |||
601 | static int pcmcia_requery(struct device *dev, void * _data) | ||
602 | { | ||
603 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | ||
604 | if (!p_dev->dev.driver) | ||
605 | pcmcia_device_query(p_dev); | ||
606 | |||
607 | return 0; | ||
608 | } | ||
609 | |||
610 | static void pcmcia_bus_rescan(struct pcmcia_socket *skt) | ||
611 | { | ||
612 | int no_devices=0; | ||
613 | unsigned long flags; | ||
614 | |||
615 | /* must be called with skt_sem held */ | ||
616 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
617 | if (list_empty(&skt->devices_list)) | ||
618 | no_devices=1; | ||
619 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
620 | |||
621 | /* if no devices were added for this socket yet because of | ||
622 | * missing resource information or other trouble, we need to | ||
623 | * do this now. */ | ||
624 | if (no_devices) { | ||
625 | int ret = pcmcia_card_add(skt); | ||
626 | if (ret) | ||
627 | return; | ||
628 | } | ||
629 | |||
630 | /* some device information might have changed because of a CIS | ||
631 | * update or because we can finally read it correctly... so | ||
632 | * determine it again, overwriting old values if necessary. */ | ||
633 | bus_for_each_dev(&pcmcia_bus_type, NULL, NULL, pcmcia_requery); | ||
634 | |||
635 | /* we re-scan all devices, not just the ones connected to this | ||
636 | * socket. This does not matter, though. */ | ||
637 | bus_rescan_devices(&pcmcia_bus_type); | ||
638 | } | ||
639 | |||
640 | static inline int pcmcia_devmatch(struct pcmcia_device *dev, | ||
641 | struct pcmcia_device_id *did) | ||
642 | { | ||
643 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID) { | ||
644 | if ((!dev->has_manf_id) || (dev->manf_id != did->manf_id)) | ||
645 | return 0; | ||
646 | } | ||
647 | |||
648 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID) { | ||
649 | if ((!dev->has_card_id) || (dev->card_id != did->card_id)) | ||
650 | return 0; | ||
651 | } | ||
652 | |||
653 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION) { | ||
654 | if (dev->func != did->function) | ||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1) { | ||
659 | if (!dev->prod_id[0]) | ||
660 | return 0; | ||
661 | if (strcmp(did->prod_id[0], dev->prod_id[0])) | ||
662 | return 0; | ||
663 | } | ||
664 | |||
665 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2) { | ||
666 | if (!dev->prod_id[1]) | ||
667 | return 0; | ||
668 | if (strcmp(did->prod_id[1], dev->prod_id[1])) | ||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3) { | ||
673 | if (!dev->prod_id[2]) | ||
674 | return 0; | ||
675 | if (strcmp(did->prod_id[2], dev->prod_id[2])) | ||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4) { | ||
680 | if (!dev->prod_id[3]) | ||
681 | return 0; | ||
682 | if (strcmp(did->prod_id[3], dev->prod_id[3])) | ||
683 | return 0; | ||
684 | } | ||
685 | |||
686 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) { | ||
687 | /* handle pseudo multifunction devices: | ||
688 | * there are at most two pseudo multifunction devices. | ||
689 | * if we're matching against the first, schedule a | ||
690 | * call which will then check whether there are two | ||
691 | * pseudo devices, and if not, add the second one. | ||
692 | */ | ||
693 | if (dev->device_no == 0) | ||
694 | pcmcia_add_pseudo_device(dev->socket); | ||
695 | |||
696 | if (dev->device_no != did->device_no) | ||
697 | return 0; | ||
698 | } | ||
699 | |||
700 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) { | ||
701 | if ((!dev->has_func_id) || (dev->func_id != did->func_id)) | ||
702 | return 0; | ||
703 | |||
704 | /* if this is a pseudo-multi-function device, | ||
705 | * we need explicit matches */ | ||
706 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) | ||
707 | return 0; | ||
708 | if (dev->device_no) | ||
709 | return 0; | ||
710 | |||
711 | /* also, FUNC_ID matching needs to be activated by userspace | ||
712 | * after it has re-checked that there is no possible module | ||
713 | * with a prod_id/manf_id/card_id match. | ||
714 | */ | ||
715 | if (!dev->allow_func_id_match) | ||
716 | return 0; | ||
717 | } | ||
718 | |||
719 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) { | ||
720 | if (!dev->socket->fake_cis) | ||
721 | pcmcia_load_firmware(dev, did->cisfile); | ||
722 | |||
723 | if (!dev->socket->fake_cis) | ||
724 | return 0; | ||
725 | } | ||
726 | |||
727 | if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) { | ||
728 | int i; | ||
729 | for (i=0; i<4; i++) | ||
730 | if (dev->prod_id[i]) | ||
731 | return 0; | ||
732 | if (dev->has_manf_id || dev->has_card_id || dev->has_func_id) | ||
733 | return 0; | ||
734 | } | ||
735 | |||
736 | dev->dev.driver_data = (void *) did; | ||
737 | |||
738 | return 1; | ||
739 | } | ||
740 | |||
741 | |||
593 | static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) { | 742 | static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) { |
594 | struct pcmcia_device * p_dev = to_pcmcia_dev(dev); | 743 | struct pcmcia_device * p_dev = to_pcmcia_dev(dev); |
595 | struct pcmcia_driver * p_drv = to_pcmcia_drv(drv); | 744 | struct pcmcia_driver * p_drv = to_pcmcia_drv(drv); |
745 | struct pcmcia_device_id *did = p_drv->id_table; | ||
596 | 746 | ||
597 | /* matching by cardmgr */ | 747 | /* matching by cardmgr */ |
598 | if (p_dev->cardmgr == p_drv) | 748 | if (p_dev->cardmgr == p_drv) |
599 | return 1; | 749 | return 1; |
600 | 750 | ||
751 | while (did && did->match_flags) { | ||
752 | if (pcmcia_devmatch(p_dev, did)) | ||
753 | return 1; | ||
754 | did++; | ||
755 | } | ||
756 | |||
601 | return 0; | 757 | return 0; |
602 | } | 758 | } |
603 | 759 | ||
760 | #ifdef CONFIG_HOTPLUG | ||
761 | |||
762 | static int pcmcia_bus_hotplug(struct device *dev, char **envp, int num_envp, | ||
763 | char *buffer, int buffer_size) | ||
764 | { | ||
765 | struct pcmcia_device *p_dev; | ||
766 | int i, length = 0; | ||
767 | u32 hash[4] = { 0, 0, 0, 0}; | ||
768 | |||
769 | if (!dev) | ||
770 | return -ENODEV; | ||
771 | |||
772 | p_dev = to_pcmcia_dev(dev); | ||
773 | |||
774 | /* calculate hashes */ | ||
775 | for (i=0; i<4; i++) { | ||
776 | if (!p_dev->prod_id[i]) | ||
777 | continue; | ||
778 | hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i])); | ||
779 | } | ||
780 | |||
781 | i = 0; | ||
782 | |||
783 | if (add_hotplug_env_var(envp, num_envp, &i, | ||
784 | buffer, buffer_size, &length, | ||
785 | "SOCKET_NO=%u", | ||
786 | p_dev->socket->sock)) | ||
787 | return -ENOMEM; | ||
788 | |||
789 | if (add_hotplug_env_var(envp, num_envp, &i, | ||
790 | buffer, buffer_size, &length, | ||
791 | "DEVICE_NO=%02X", | ||
792 | p_dev->device_no)) | ||
793 | return -ENOMEM; | ||
794 | |||
795 | if (add_hotplug_env_var(envp, num_envp, &i, | ||
796 | buffer, buffer_size, &length, | ||
797 | "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X" | ||
798 | "pa%08Xpb%08Xpc%08Xpd%08X", | ||
799 | p_dev->has_manf_id ? p_dev->manf_id : 0, | ||
800 | p_dev->has_card_id ? p_dev->card_id : 0, | ||
801 | p_dev->has_func_id ? p_dev->func_id : 0, | ||
802 | p_dev->func, | ||
803 | p_dev->device_no, | ||
804 | hash[0], | ||
805 | hash[1], | ||
806 | hash[2], | ||
807 | hash[3])) | ||
808 | return -ENOMEM; | ||
809 | |||
810 | envp[i] = NULL; | ||
811 | |||
812 | return 0; | ||
813 | } | ||
814 | |||
815 | #else | ||
816 | |||
817 | static int pcmcia_bus_hotplug(struct device *dev, char **envp, int num_envp, | ||
818 | char *buffer, int buffer_size) | ||
819 | { | ||
820 | return -ENODEV; | ||
821 | } | ||
822 | |||
823 | #endif | ||
824 | |||
604 | /************************ per-device sysfs output ***************************/ | 825 | /************************ per-device sysfs output ***************************/ |
605 | 826 | ||
606 | #define pcmcia_device_attr(field, test, format) \ | 827 | #define pcmcia_device_attr(field, test, format) \ |
@@ -626,6 +847,43 @@ pcmcia_device_stringattr(prod_id2, prod_id[1]); | |||
626 | pcmcia_device_stringattr(prod_id3, prod_id[2]); | 847 | pcmcia_device_stringattr(prod_id3, prod_id[2]); |
627 | pcmcia_device_stringattr(prod_id4, prod_id[3]); | 848 | pcmcia_device_stringattr(prod_id4, prod_id[3]); |
628 | 849 | ||
850 | static ssize_t modalias_show(struct device *dev, char *buf) | ||
851 | { | ||
852 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | ||
853 | int i; | ||
854 | u32 hash[4] = { 0, 0, 0, 0}; | ||
855 | |||
856 | /* calculate hashes */ | ||
857 | for (i=0; i<4; i++) { | ||
858 | if (!p_dev->prod_id[i]) | ||
859 | continue; | ||
860 | hash[i] = crc32(0,p_dev->prod_id[i],strlen(p_dev->prod_id[i])); | ||
861 | } | ||
862 | return sprintf(buf, "pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X" | ||
863 | "pa%08Xpb%08Xpc%08Xpd%08X\n", | ||
864 | p_dev->has_manf_id ? p_dev->manf_id : 0, | ||
865 | p_dev->has_card_id ? p_dev->card_id : 0, | ||
866 | p_dev->has_func_id ? p_dev->func_id : 0, | ||
867 | p_dev->func, p_dev->device_no, | ||
868 | hash[0], hash[1], hash[2], hash[3]); | ||
869 | } | ||
870 | |||
871 | static ssize_t pcmcia_store_allow_func_id_match(struct device *dev, | ||
872 | struct device_attribute *attr, const char *buf, size_t count) | ||
873 | { | ||
874 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | ||
875 | if (!count) | ||
876 | return -EINVAL; | ||
877 | |||
878 | down(&p_dev->socket->skt_sem); | ||
879 | p_dev->allow_func_id_match = 1; | ||
880 | up(&p_dev->socket->skt_sem); | ||
881 | |||
882 | bus_rescan_devices(&pcmcia_bus_type); | ||
883 | |||
884 | return count; | ||
885 | } | ||
886 | |||
629 | static struct device_attribute pcmcia_dev_attrs[] = { | 887 | static struct device_attribute pcmcia_dev_attrs[] = { |
630 | __ATTR(function, 0444, func_show, NULL), | 888 | __ATTR(function, 0444, func_show, NULL), |
631 | __ATTR_RO(func_id), | 889 | __ATTR_RO(func_id), |
@@ -635,46 +893,14 @@ static struct device_attribute pcmcia_dev_attrs[] = { | |||
635 | __ATTR_RO(prod_id2), | 893 | __ATTR_RO(prod_id2), |
636 | __ATTR_RO(prod_id3), | 894 | __ATTR_RO(prod_id3), |
637 | __ATTR_RO(prod_id4), | 895 | __ATTR_RO(prod_id4), |
896 | __ATTR_RO(modalias), | ||
897 | __ATTR(allow_func_id_match, 0200, NULL, pcmcia_store_allow_func_id_match), | ||
638 | __ATTR_NULL, | 898 | __ATTR_NULL, |
639 | }; | 899 | }; |
640 | 900 | ||
641 | 901 | ||
642 | /*====================================================================== | 902 | /*====================================================================== |
643 | 903 | ||
644 | These manage a ring buffer of events pending for one user process | ||
645 | |||
646 | ======================================================================*/ | ||
647 | |||
648 | static int queue_empty(user_info_t *user) | ||
649 | { | ||
650 | return (user->event_head == user->event_tail); | ||
651 | } | ||
652 | |||
653 | static event_t get_queued_event(user_info_t *user) | ||
654 | { | ||
655 | user->event_tail = (user->event_tail+1) % MAX_EVENTS; | ||
656 | return user->event[user->event_tail]; | ||
657 | } | ||
658 | |||
659 | static void queue_event(user_info_t *user, event_t event) | ||
660 | { | ||
661 | user->event_head = (user->event_head+1) % MAX_EVENTS; | ||
662 | if (user->event_head == user->event_tail) | ||
663 | user->event_tail = (user->event_tail+1) % MAX_EVENTS; | ||
664 | user->event[user->event_head] = event; | ||
665 | } | ||
666 | |||
667 | static void handle_event(struct pcmcia_bus_socket *s, event_t event) | ||
668 | { | ||
669 | user_info_t *user; | ||
670 | for (user = s->user; user; user = user->next) | ||
671 | queue_event(user, event); | ||
672 | wake_up_interruptible(&s->queue); | ||
673 | } | ||
674 | |||
675 | |||
676 | /*====================================================================== | ||
677 | |||
678 | The card status event handler. | 904 | The card status event handler. |
679 | 905 | ||
680 | ======================================================================*/ | 906 | ======================================================================*/ |
@@ -706,21 +932,13 @@ static int send_event_callback(struct device *dev, void * _data) | |||
706 | 932 | ||
707 | static int send_event(struct pcmcia_socket *s, event_t event, int priority) | 933 | static int send_event(struct pcmcia_socket *s, event_t event, int priority) |
708 | { | 934 | { |
709 | int ret = 0; | ||
710 | struct send_event_data private; | 935 | struct send_event_data private; |
711 | struct pcmcia_bus_socket *skt = pcmcia_get_bus_socket(s->pcmcia); | ||
712 | |||
713 | if (!skt) | ||
714 | return 0; | ||
715 | 936 | ||
716 | private.skt = s; | 937 | private.skt = s; |
717 | private.event = event; | 938 | private.event = event; |
718 | private.priority = priority; | 939 | private.priority = priority; |
719 | 940 | ||
720 | ret = bus_for_each_dev(&pcmcia_bus_type, NULL, &private, send_event_callback); | 941 | return bus_for_each_dev(&pcmcia_bus_type, NULL, &private, send_event_callback); |
721 | |||
722 | pcmcia_put_bus_socket(skt); | ||
723 | return ret; | ||
724 | } /* send_event */ | 942 | } /* send_event */ |
725 | 943 | ||
726 | 944 | ||
@@ -731,25 +949,25 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority) | |||
731 | 949 | ||
732 | static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | 950 | static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) |
733 | { | 951 | { |
734 | struct pcmcia_bus_socket *s = skt->pcmcia; | 952 | struct pcmcia_socket *s = pcmcia_get_socket(skt); |
735 | int ret = 0; | 953 | int ret = 0; |
736 | 954 | ||
737 | ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n", | 955 | ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n", |
738 | event, priority, s); | 956 | event, priority, skt); |
739 | 957 | ||
740 | switch (event) { | 958 | switch (event) { |
741 | 959 | ||
742 | case CS_EVENT_CARD_REMOVAL: | 960 | case CS_EVENT_CARD_REMOVAL: |
743 | s->state &= ~DS_SOCKET_PRESENT; | 961 | s->pcmcia_state.present = 0; |
744 | send_event(skt, event, priority); | 962 | send_event(skt, event, priority); |
745 | unbind_request(s); | 963 | unbind_request(skt); |
746 | handle_event(s, event); | 964 | handle_event(skt, event); |
747 | break; | 965 | break; |
748 | 966 | ||
749 | case CS_EVENT_CARD_INSERTION: | 967 | case CS_EVENT_CARD_INSERTION: |
750 | s->state |= DS_SOCKET_PRESENT; | 968 | s->pcmcia_state.present = 1; |
751 | pcmcia_card_add(skt); | 969 | pcmcia_card_add(skt); |
752 | handle_event(s, event); | 970 | handle_event(skt, event); |
753 | break; | 971 | break; |
754 | 972 | ||
755 | case CS_EVENT_EJECTION_REQUEST: | 973 | case CS_EVENT_EJECTION_REQUEST: |
@@ -757,137 +975,22 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | |||
757 | break; | 975 | break; |
758 | 976 | ||
759 | default: | 977 | default: |
760 | handle_event(s, event); | 978 | handle_event(skt, event); |
761 | send_event(skt, event, priority); | 979 | send_event(skt, event, priority); |
762 | break; | 980 | break; |
763 | } | 981 | } |
764 | 982 | ||
983 | pcmcia_put_socket(s); | ||
984 | |||
765 | return 0; | 985 | return 0; |
766 | } /* ds_event */ | 986 | } /* ds_event */ |
767 | 987 | ||
768 | 988 | ||
769 | /*====================================================================== | ||
770 | |||
771 | bind_request() and bind_device() are merged by now. Register_client() | ||
772 | is called right at the end of bind_request(), during the driver's | ||
773 | ->attach() call. Individual descriptions: | ||
774 | |||
775 | bind_request() connects a socket to a particular client driver. | ||
776 | It looks up the specified device ID in the list of registered | ||
777 | drivers, binds it to the socket, and tries to create an instance | ||
778 | of the device. unbind_request() deletes a driver instance. | ||
779 | |||
780 | Bind_device() associates a device driver with a particular socket. | ||
781 | It is normally called by Driver Services after it has identified | ||
782 | a newly inserted card. An instance of that driver will then be | ||
783 | eligible to register as a client of this socket. | ||
784 | |||
785 | Register_client() uses the dev_info_t handle to match the | ||
786 | caller with a socket. The driver must have already been bound | ||
787 | to a socket with bind_device() -- in fact, bind_device() | ||
788 | allocates the client structure that will be used. | ||
789 | |||
790 | ======================================================================*/ | ||
791 | |||
792 | static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) | ||
793 | { | ||
794 | struct pcmcia_driver *p_drv; | ||
795 | struct pcmcia_device *p_dev; | ||
796 | int ret = 0; | ||
797 | unsigned long flags; | ||
798 | |||
799 | s = pcmcia_get_bus_socket(s); | ||
800 | if (!s) | ||
801 | return -EINVAL; | ||
802 | |||
803 | ds_dbg(2, "bind_request(%d, '%s')\n", s->parent->sock, | ||
804 | (char *)bind_info->dev_info); | ||
805 | |||
806 | p_drv = get_pcmcia_driver(&bind_info->dev_info); | ||
807 | if (!p_drv) { | ||
808 | ret = -EINVAL; | ||
809 | goto err_put; | ||
810 | } | ||
811 | |||
812 | if (!try_module_get(p_drv->owner)) { | ||
813 | ret = -EINVAL; | ||
814 | goto err_put_driver; | ||
815 | } | ||
816 | |||
817 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
818 | list_for_each_entry(p_dev, &s->devices_list, socket_device_list) { | ||
819 | if (p_dev->func == bind_info->function) { | ||
820 | if ((p_dev->dev.driver == &p_drv->drv)) { | ||
821 | if (p_dev->cardmgr) { | ||
822 | /* if there's already a device | ||
823 | * registered, and it was registered | ||
824 | * by userspace before, we need to | ||
825 | * return the "instance". */ | ||
826 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
827 | bind_info->instance = p_dev->instance; | ||
828 | ret = -EBUSY; | ||
829 | goto err_put_module; | ||
830 | } else { | ||
831 | /* the correct driver managed to bind | ||
832 | * itself magically to the correct | ||
833 | * device. */ | ||
834 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
835 | p_dev->cardmgr = p_drv; | ||
836 | ret = 0; | ||
837 | goto err_put_module; | ||
838 | } | ||
839 | } else if (!p_dev->dev.driver) { | ||
840 | /* there's already a device available where | ||
841 | * no device has been bound to yet. So we don't | ||
842 | * need to register a device! */ | ||
843 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
844 | goto rescan; | ||
845 | } | ||
846 | } | ||
847 | } | ||
848 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
849 | |||
850 | p_dev = pcmcia_device_add(s, bind_info->function); | ||
851 | if (!p_dev) { | ||
852 | ret = -EIO; | ||
853 | goto err_put_module; | ||
854 | } | ||
855 | |||
856 | rescan: | ||
857 | p_dev->cardmgr = p_drv; | ||
858 | |||
859 | pcmcia_device_query(p_dev); | ||
860 | |||
861 | /* | ||
862 | * Prevent this racing with a card insertion. | ||
863 | */ | ||
864 | down(&s->parent->skt_sem); | ||
865 | bus_rescan_devices(&pcmcia_bus_type); | ||
866 | up(&s->parent->skt_sem); | ||
867 | |||
868 | /* check whether the driver indeed matched. I don't care if this | ||
869 | * is racy or not, because it can only happen on cardmgr access | ||
870 | * paths... | ||
871 | */ | ||
872 | if (!(p_dev->dev.driver == &p_drv->drv)) | ||
873 | p_dev->cardmgr = NULL; | ||
874 | |||
875 | err_put_module: | ||
876 | module_put(p_drv->owner); | ||
877 | err_put_driver: | ||
878 | put_driver(&p_drv->drv); | ||
879 | err_put: | ||
880 | pcmcia_put_bus_socket(s); | ||
881 | |||
882 | return (ret); | ||
883 | } /* bind_request */ | ||
884 | |||
885 | 989 | ||
886 | int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) | 990 | int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) |
887 | { | 991 | { |
888 | client_t *client = NULL; | 992 | client_t *client = NULL; |
889 | struct pcmcia_socket *s; | 993 | struct pcmcia_socket *s = NULL; |
890 | struct pcmcia_bus_socket *skt = NULL; | ||
891 | struct pcmcia_device *p_dev = NULL; | 994 | struct pcmcia_device *p_dev = NULL; |
892 | 995 | ||
893 | /* Look for unbound client with matching dev_info */ | 996 | /* Look for unbound client with matching dev_info */ |
@@ -898,14 +1001,11 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) | |||
898 | if (s->state & SOCKET_CARDBUS) | 1001 | if (s->state & SOCKET_CARDBUS) |
899 | continue; | 1002 | continue; |
900 | 1003 | ||
901 | skt = s->pcmcia; | 1004 | s = pcmcia_get_socket(s); |
902 | if (!skt) | 1005 | if (!s) |
903 | continue; | ||
904 | skt = pcmcia_get_bus_socket(skt); | ||
905 | if (!skt) | ||
906 | continue; | 1006 | continue; |
907 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | 1007 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); |
908 | list_for_each_entry(p_dev, &skt->devices_list, socket_device_list) { | 1008 | list_for_each_entry(p_dev, &s->devices_list, socket_device_list) { |
909 | struct pcmcia_driver *p_drv; | 1009 | struct pcmcia_driver *p_drv; |
910 | p_dev = pcmcia_get_dev(p_dev); | 1010 | p_dev = pcmcia_get_dev(p_dev); |
911 | if (!p_dev) | 1011 | if (!p_dev) |
@@ -924,14 +1024,14 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) | |||
924 | pcmcia_put_dev(p_dev); | 1024 | pcmcia_put_dev(p_dev); |
925 | } | 1025 | } |
926 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | 1026 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); |
927 | pcmcia_put_bus_socket(skt); | 1027 | pcmcia_put_socket(s); |
928 | } | 1028 | } |
929 | found: | 1029 | found: |
930 | up_read(&pcmcia_socket_list_rwsem); | 1030 | up_read(&pcmcia_socket_list_rwsem); |
931 | if (!p_dev || !client) | 1031 | if (!p_dev || !client) |
932 | return -ENODEV; | 1032 | return -ENODEV; |
933 | 1033 | ||
934 | pcmcia_put_bus_socket(skt); /* safe, as we already hold a reference from bind_device */ | 1034 | pcmcia_put_socket(s); /* safe, as we already hold a reference from bind_device */ |
935 | 1035 | ||
936 | *handle = client; | 1036 | *handle = client; |
937 | client->state &= ~CLIENT_UNBOUND; | 1037 | client->state &= ~CLIENT_UNBOUND; |
@@ -978,106 +1078,15 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) | |||
978 | EXPORT_SYMBOL(pcmcia_register_client); | 1078 | EXPORT_SYMBOL(pcmcia_register_client); |
979 | 1079 | ||
980 | 1080 | ||
981 | /*====================================================================*/ | ||
982 | |||
983 | extern struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s); | ||
984 | |||
985 | static int get_device_info(struct pcmcia_bus_socket *s, bind_info_t *bind_info, int first) | ||
986 | { | ||
987 | dev_node_t *node; | ||
988 | struct pcmcia_device *p_dev; | ||
989 | unsigned long flags; | ||
990 | int ret = 0; | ||
991 | |||
992 | #ifdef CONFIG_CARDBUS | ||
993 | /* | ||
994 | * Some unbelievably ugly code to associate the PCI cardbus | ||
995 | * device and its driver with the PCMCIA "bind" information. | ||
996 | */ | ||
997 | { | ||
998 | struct pci_bus *bus; | ||
999 | |||
1000 | bus = pcmcia_lookup_bus(s->parent); | ||
1001 | if (bus) { | ||
1002 | struct list_head *list; | ||
1003 | struct pci_dev *dev = NULL; | ||
1004 | |||
1005 | list = bus->devices.next; | ||
1006 | while (list != &bus->devices) { | ||
1007 | struct pci_dev *pdev = pci_dev_b(list); | ||
1008 | list = list->next; | ||
1009 | |||
1010 | if (first) { | ||
1011 | dev = pdev; | ||
1012 | break; | ||
1013 | } | ||
1014 | |||
1015 | /* Try to handle "next" here some way? */ | ||
1016 | } | ||
1017 | if (dev && dev->driver) { | ||
1018 | strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN); | ||
1019 | bind_info->major = 0; | ||
1020 | bind_info->minor = 0; | ||
1021 | bind_info->next = NULL; | ||
1022 | return 0; | ||
1023 | } | ||
1024 | } | ||
1025 | } | ||
1026 | #endif | ||
1027 | |||
1028 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
1029 | list_for_each_entry(p_dev, &s->devices_list, socket_device_list) { | ||
1030 | if (p_dev->func == bind_info->function) { | ||
1031 | p_dev = pcmcia_get_dev(p_dev); | ||
1032 | if (!p_dev) | ||
1033 | continue; | ||
1034 | goto found; | ||
1035 | } | ||
1036 | } | ||
1037 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
1038 | return -ENODEV; | ||
1039 | |||
1040 | found: | ||
1041 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
1042 | |||
1043 | if ((!p_dev->instance) || | ||
1044 | (p_dev->instance->state & DEV_CONFIG_PENDING)) { | ||
1045 | ret = -EAGAIN; | ||
1046 | goto err_put; | ||
1047 | } | ||
1048 | |||
1049 | if (first) | ||
1050 | node = p_dev->instance->dev; | ||
1051 | else | ||
1052 | for (node = p_dev->instance->dev; node; node = node->next) | ||
1053 | if (node == bind_info->next) | ||
1054 | break; | ||
1055 | if (!node) { | ||
1056 | ret = -ENODEV; | ||
1057 | goto err_put; | ||
1058 | } | ||
1059 | |||
1060 | strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN); | ||
1061 | bind_info->major = node->major; | ||
1062 | bind_info->minor = node->minor; | ||
1063 | bind_info->next = node->next; | ||
1064 | |||
1065 | err_put: | ||
1066 | pcmcia_put_dev(p_dev); | ||
1067 | return (ret); | ||
1068 | } /* get_device_info */ | ||
1069 | |||
1070 | /*====================================================================*/ | ||
1071 | |||
1072 | /* unbind _all_ devices attached to a given pcmcia_bus_socket. The | 1081 | /* unbind _all_ devices attached to a given pcmcia_bus_socket. The |
1073 | * drivers have been called with EVENT_CARD_REMOVAL before. | 1082 | * drivers have been called with EVENT_CARD_REMOVAL before. |
1074 | */ | 1083 | */ |
1075 | static int unbind_request(struct pcmcia_bus_socket *s) | 1084 | static int unbind_request(struct pcmcia_socket *s) |
1076 | { | 1085 | { |
1077 | struct pcmcia_device *p_dev; | 1086 | struct pcmcia_device *p_dev; |
1078 | unsigned long flags; | 1087 | unsigned long flags; |
1079 | 1088 | ||
1080 | ds_dbg(2, "unbind_request(%d)\n", s->parent->sock); | 1089 | ds_dbg(2, "unbind_request(%d)\n", s->sock); |
1081 | 1090 | ||
1082 | s->device_count = 0; | 1091 | s->device_count = 0; |
1083 | 1092 | ||
@@ -1133,433 +1142,58 @@ int pcmcia_deregister_client(client_handle_t handle) | |||
1133 | } /* deregister_client */ | 1142 | } /* deregister_client */ |
1134 | EXPORT_SYMBOL(pcmcia_deregister_client); | 1143 | EXPORT_SYMBOL(pcmcia_deregister_client); |
1135 | 1144 | ||
1136 | 1145 | static struct pcmcia_callback pcmcia_bus_callback = { | |
1137 | /*====================================================================== | 1146 | .owner = THIS_MODULE, |
1138 | 1147 | .event = ds_event, | |
1139 | The user-mode PC Card device interface | 1148 | .requery = pcmcia_bus_rescan, |
1140 | |||
1141 | ======================================================================*/ | ||
1142 | |||
1143 | static int ds_open(struct inode *inode, struct file *file) | ||
1144 | { | ||
1145 | socket_t i = iminor(inode); | ||
1146 | struct pcmcia_bus_socket *s; | ||
1147 | user_info_t *user; | ||
1148 | |||
1149 | ds_dbg(0, "ds_open(socket %d)\n", i); | ||
1150 | |||
1151 | s = get_socket_info_by_nr(i); | ||
1152 | if (!s) | ||
1153 | return -ENODEV; | ||
1154 | s = pcmcia_get_bus_socket(s); | ||
1155 | if (!s) | ||
1156 | return -ENODEV; | ||
1157 | |||
1158 | if ((file->f_flags & O_ACCMODE) != O_RDONLY) { | ||
1159 | if (s->state & DS_SOCKET_BUSY) { | ||
1160 | pcmcia_put_bus_socket(s); | ||
1161 | return -EBUSY; | ||
1162 | } | ||
1163 | else | ||
1164 | s->state |= DS_SOCKET_BUSY; | ||
1165 | } | ||
1166 | |||
1167 | user = kmalloc(sizeof(user_info_t), GFP_KERNEL); | ||
1168 | if (!user) { | ||
1169 | pcmcia_put_bus_socket(s); | ||
1170 | return -ENOMEM; | ||
1171 | } | ||
1172 | user->event_tail = user->event_head = 0; | ||
1173 | user->next = s->user; | ||
1174 | user->user_magic = USER_MAGIC; | ||
1175 | user->socket = s; | ||
1176 | s->user = user; | ||
1177 | file->private_data = user; | ||
1178 | |||
1179 | if (s->state & DS_SOCKET_PRESENT) | ||
1180 | queue_event(user, CS_EVENT_CARD_INSERTION); | ||
1181 | return 0; | ||
1182 | } /* ds_open */ | ||
1183 | |||
1184 | /*====================================================================*/ | ||
1185 | |||
1186 | static int ds_release(struct inode *inode, struct file *file) | ||
1187 | { | ||
1188 | struct pcmcia_bus_socket *s; | ||
1189 | user_info_t *user, **link; | ||
1190 | |||
1191 | ds_dbg(0, "ds_release(socket %d)\n", iminor(inode)); | ||
1192 | |||
1193 | user = file->private_data; | ||
1194 | if (CHECK_USER(user)) | ||
1195 | goto out; | ||
1196 | |||
1197 | s = user->socket; | ||
1198 | |||
1199 | /* Unlink user data structure */ | ||
1200 | if ((file->f_flags & O_ACCMODE) != O_RDONLY) { | ||
1201 | s->state &= ~DS_SOCKET_BUSY; | ||
1202 | } | ||
1203 | file->private_data = NULL; | ||
1204 | for (link = &s->user; *link; link = &(*link)->next) | ||
1205 | if (*link == user) break; | ||
1206 | if (link == NULL) | ||
1207 | goto out; | ||
1208 | *link = user->next; | ||
1209 | user->user_magic = 0; | ||
1210 | kfree(user); | ||
1211 | pcmcia_put_bus_socket(s); | ||
1212 | out: | ||
1213 | return 0; | ||
1214 | } /* ds_release */ | ||
1215 | |||
1216 | /*====================================================================*/ | ||
1217 | |||
1218 | static ssize_t ds_read(struct file *file, char __user *buf, | ||
1219 | size_t count, loff_t *ppos) | ||
1220 | { | ||
1221 | struct pcmcia_bus_socket *s; | ||
1222 | user_info_t *user; | ||
1223 | int ret; | ||
1224 | |||
1225 | ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode)); | ||
1226 | |||
1227 | if (count < 4) | ||
1228 | return -EINVAL; | ||
1229 | |||
1230 | user = file->private_data; | ||
1231 | if (CHECK_USER(user)) | ||
1232 | return -EIO; | ||
1233 | |||
1234 | s = user->socket; | ||
1235 | if (s->state & DS_SOCKET_DEAD) | ||
1236 | return -EIO; | ||
1237 | |||
1238 | ret = wait_event_interruptible(s->queue, !queue_empty(user)); | ||
1239 | if (ret == 0) | ||
1240 | ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4; | ||
1241 | |||
1242 | return ret; | ||
1243 | } /* ds_read */ | ||
1244 | |||
1245 | /*====================================================================*/ | ||
1246 | |||
1247 | static ssize_t ds_write(struct file *file, const char __user *buf, | ||
1248 | size_t count, loff_t *ppos) | ||
1249 | { | ||
1250 | ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode)); | ||
1251 | |||
1252 | if (count != 4) | ||
1253 | return -EINVAL; | ||
1254 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) | ||
1255 | return -EBADF; | ||
1256 | |||
1257 | return -EIO; | ||
1258 | } /* ds_write */ | ||
1259 | |||
1260 | /*====================================================================*/ | ||
1261 | |||
1262 | /* No kernel lock - fine */ | ||
1263 | static u_int ds_poll(struct file *file, poll_table *wait) | ||
1264 | { | ||
1265 | struct pcmcia_bus_socket *s; | ||
1266 | user_info_t *user; | ||
1267 | |||
1268 | ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode)); | ||
1269 | |||
1270 | user = file->private_data; | ||
1271 | if (CHECK_USER(user)) | ||
1272 | return POLLERR; | ||
1273 | s = user->socket; | ||
1274 | /* | ||
1275 | * We don't check for a dead socket here since that | ||
1276 | * will send cardmgr into an endless spin. | ||
1277 | */ | ||
1278 | poll_wait(file, &s->queue, wait); | ||
1279 | if (!queue_empty(user)) | ||
1280 | return POLLIN | POLLRDNORM; | ||
1281 | return 0; | ||
1282 | } /* ds_poll */ | ||
1283 | |||
1284 | /*====================================================================*/ | ||
1285 | |||
1286 | extern int pcmcia_adjust_resource_info(adjust_t *adj); | ||
1287 | |||
1288 | static int ds_ioctl(struct inode * inode, struct file * file, | ||
1289 | u_int cmd, u_long arg) | ||
1290 | { | ||
1291 | struct pcmcia_bus_socket *s; | ||
1292 | void __user *uarg = (char __user *)arg; | ||
1293 | u_int size; | ||
1294 | int ret, err; | ||
1295 | ds_ioctl_arg_t *buf; | ||
1296 | user_info_t *user; | ||
1297 | |||
1298 | ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg); | ||
1299 | |||
1300 | user = file->private_data; | ||
1301 | if (CHECK_USER(user)) | ||
1302 | return -EIO; | ||
1303 | |||
1304 | s = user->socket; | ||
1305 | if (s->state & DS_SOCKET_DEAD) | ||
1306 | return -EIO; | ||
1307 | |||
1308 | size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; | ||
1309 | if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL; | ||
1310 | |||
1311 | /* Permission check */ | ||
1312 | if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN)) | ||
1313 | return -EPERM; | ||
1314 | |||
1315 | if (cmd & IOC_IN) { | ||
1316 | if (!access_ok(VERIFY_READ, uarg, size)) { | ||
1317 | ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT); | ||
1318 | return -EFAULT; | ||
1319 | } | ||
1320 | } | ||
1321 | if (cmd & IOC_OUT) { | ||
1322 | if (!access_ok(VERIFY_WRITE, uarg, size)) { | ||
1323 | ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT); | ||
1324 | return -EFAULT; | ||
1325 | } | ||
1326 | } | ||
1327 | buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL); | ||
1328 | if (!buf) | ||
1329 | return -ENOMEM; | ||
1330 | |||
1331 | err = ret = 0; | ||
1332 | |||
1333 | if (cmd & IOC_IN) __copy_from_user((char *)buf, uarg, size); | ||
1334 | |||
1335 | switch (cmd) { | ||
1336 | case DS_ADJUST_RESOURCE_INFO: | ||
1337 | ret = pcmcia_adjust_resource_info(&buf->adjust); | ||
1338 | break; | ||
1339 | case DS_GET_CARD_SERVICES_INFO: | ||
1340 | ret = pcmcia_get_card_services_info(&buf->servinfo); | ||
1341 | break; | ||
1342 | case DS_GET_CONFIGURATION_INFO: | ||
1343 | if (buf->config.Function && | ||
1344 | (buf->config.Function >= s->parent->functions)) | ||
1345 | ret = CS_BAD_ARGS; | ||
1346 | else | ||
1347 | ret = pccard_get_configuration_info(s->parent, | ||
1348 | buf->config.Function, &buf->config); | ||
1349 | break; | ||
1350 | case DS_GET_FIRST_TUPLE: | ||
1351 | down(&s->parent->skt_sem); | ||
1352 | pcmcia_validate_mem(s->parent); | ||
1353 | up(&s->parent->skt_sem); | ||
1354 | ret = pccard_get_first_tuple(s->parent, BIND_FN_ALL, &buf->tuple); | ||
1355 | break; | ||
1356 | case DS_GET_NEXT_TUPLE: | ||
1357 | ret = pccard_get_next_tuple(s->parent, BIND_FN_ALL, &buf->tuple); | ||
1358 | break; | ||
1359 | case DS_GET_TUPLE_DATA: | ||
1360 | buf->tuple.TupleData = buf->tuple_parse.data; | ||
1361 | buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data); | ||
1362 | ret = pccard_get_tuple_data(s->parent, &buf->tuple); | ||
1363 | break; | ||
1364 | case DS_PARSE_TUPLE: | ||
1365 | buf->tuple.TupleData = buf->tuple_parse.data; | ||
1366 | ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse); | ||
1367 | break; | ||
1368 | case DS_RESET_CARD: | ||
1369 | ret = pccard_reset_card(s->parent); | ||
1370 | break; | ||
1371 | case DS_GET_STATUS: | ||
1372 | if (buf->status.Function && | ||
1373 | (buf->status.Function >= s->parent->functions)) | ||
1374 | ret = CS_BAD_ARGS; | ||
1375 | else | ||
1376 | ret = pccard_get_status(s->parent, buf->status.Function, &buf->status); | ||
1377 | break; | ||
1378 | case DS_VALIDATE_CIS: | ||
1379 | down(&s->parent->skt_sem); | ||
1380 | pcmcia_validate_mem(s->parent); | ||
1381 | up(&s->parent->skt_sem); | ||
1382 | ret = pccard_validate_cis(s->parent, BIND_FN_ALL, &buf->cisinfo); | ||
1383 | break; | ||
1384 | case DS_SUSPEND_CARD: | ||
1385 | ret = pcmcia_suspend_card(s->parent); | ||
1386 | break; | ||
1387 | case DS_RESUME_CARD: | ||
1388 | ret = pcmcia_resume_card(s->parent); | ||
1389 | break; | ||
1390 | case DS_EJECT_CARD: | ||
1391 | err = pcmcia_eject_card(s->parent); | ||
1392 | break; | ||
1393 | case DS_INSERT_CARD: | ||
1394 | err = pcmcia_insert_card(s->parent); | ||
1395 | break; | ||
1396 | case DS_ACCESS_CONFIGURATION_REGISTER: | ||
1397 | if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) { | ||
1398 | err = -EPERM; | ||
1399 | goto free_out; | ||
1400 | } | ||
1401 | if (buf->conf_reg.Function && | ||
1402 | (buf->conf_reg.Function >= s->parent->functions)) | ||
1403 | ret = CS_BAD_ARGS; | ||
1404 | else | ||
1405 | ret = pccard_access_configuration_register(s->parent, | ||
1406 | buf->conf_reg.Function, &buf->conf_reg); | ||
1407 | break; | ||
1408 | case DS_GET_FIRST_REGION: | ||
1409 | case DS_GET_NEXT_REGION: | ||
1410 | case DS_BIND_MTD: | ||
1411 | if (!capable(CAP_SYS_ADMIN)) { | ||
1412 | err = -EPERM; | ||
1413 | goto free_out; | ||
1414 | } else { | ||
1415 | static int printed = 0; | ||
1416 | if (!printed) { | ||
1417 | printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n"); | ||
1418 | printk(KERN_WARNING "MTD handling any more.\n"); | ||
1419 | printed++; | ||
1420 | } | ||
1421 | } | ||
1422 | err = -EINVAL; | ||
1423 | goto free_out; | ||
1424 | break; | ||
1425 | case DS_GET_FIRST_WINDOW: | ||
1426 | ret = pcmcia_get_window(s->parent, &buf->win_info.handle, 0, | ||
1427 | &buf->win_info.window); | ||
1428 | break; | ||
1429 | case DS_GET_NEXT_WINDOW: | ||
1430 | ret = pcmcia_get_window(s->parent, &buf->win_info.handle, | ||
1431 | buf->win_info.handle->index + 1, &buf->win_info.window); | ||
1432 | break; | ||
1433 | case DS_GET_MEM_PAGE: | ||
1434 | ret = pcmcia_get_mem_page(buf->win_info.handle, | ||
1435 | &buf->win_info.map); | ||
1436 | break; | ||
1437 | case DS_REPLACE_CIS: | ||
1438 | ret = pcmcia_replace_cis(s->parent, &buf->cisdump); | ||
1439 | break; | ||
1440 | case DS_BIND_REQUEST: | ||
1441 | if (!capable(CAP_SYS_ADMIN)) { | ||
1442 | err = -EPERM; | ||
1443 | goto free_out; | ||
1444 | } | ||
1445 | err = bind_request(s, &buf->bind_info); | ||
1446 | break; | ||
1447 | case DS_GET_DEVICE_INFO: | ||
1448 | err = get_device_info(s, &buf->bind_info, 1); | ||
1449 | break; | ||
1450 | case DS_GET_NEXT_DEVICE: | ||
1451 | err = get_device_info(s, &buf->bind_info, 0); | ||
1452 | break; | ||
1453 | case DS_UNBIND_REQUEST: | ||
1454 | err = 0; | ||
1455 | break; | ||
1456 | default: | ||
1457 | err = -EINVAL; | ||
1458 | } | ||
1459 | |||
1460 | if ((err == 0) && (ret != CS_SUCCESS)) { | ||
1461 | ds_dbg(2, "ds_ioctl: ret = %d\n", ret); | ||
1462 | switch (ret) { | ||
1463 | case CS_BAD_SOCKET: case CS_NO_CARD: | ||
1464 | err = -ENODEV; break; | ||
1465 | case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ: | ||
1466 | case CS_BAD_TUPLE: | ||
1467 | err = -EINVAL; break; | ||
1468 | case CS_IN_USE: | ||
1469 | err = -EBUSY; break; | ||
1470 | case CS_OUT_OF_RESOURCE: | ||
1471 | err = -ENOSPC; break; | ||
1472 | case CS_NO_MORE_ITEMS: | ||
1473 | err = -ENODATA; break; | ||
1474 | case CS_UNSUPPORTED_FUNCTION: | ||
1475 | err = -ENOSYS; break; | ||
1476 | default: | ||
1477 | err = -EIO; break; | ||
1478 | } | ||
1479 | } | ||
1480 | |||
1481 | if (cmd & IOC_OUT) { | ||
1482 | if (__copy_to_user(uarg, (char *)buf, size)) | ||
1483 | err = -EFAULT; | ||
1484 | } | ||
1485 | |||
1486 | free_out: | ||
1487 | kfree(buf); | ||
1488 | return err; | ||
1489 | } /* ds_ioctl */ | ||
1490 | |||
1491 | /*====================================================================*/ | ||
1492 | |||
1493 | static struct file_operations ds_fops = { | ||
1494 | .owner = THIS_MODULE, | ||
1495 | .open = ds_open, | ||
1496 | .release = ds_release, | ||
1497 | .ioctl = ds_ioctl, | ||
1498 | .read = ds_read, | ||
1499 | .write = ds_write, | ||
1500 | .poll = ds_poll, | ||
1501 | }; | 1149 | }; |
1502 | 1150 | ||
1503 | static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev) | 1151 | static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev) |
1504 | { | 1152 | { |
1505 | struct pcmcia_socket *socket = class_get_devdata(class_dev); | 1153 | struct pcmcia_socket *socket = class_get_devdata(class_dev); |
1506 | struct pcmcia_bus_socket *s; | ||
1507 | int ret; | 1154 | int ret; |
1508 | 1155 | ||
1509 | s = kmalloc(sizeof(struct pcmcia_bus_socket), GFP_KERNEL); | 1156 | socket = pcmcia_get_socket(socket); |
1510 | if(!s) | 1157 | if (!socket) { |
1511 | return -ENOMEM; | ||
1512 | memset(s, 0, sizeof(struct pcmcia_bus_socket)); | ||
1513 | |||
1514 | /* get reference to parent socket */ | ||
1515 | s->parent = pcmcia_get_socket(socket); | ||
1516 | if (!s->parent) { | ||
1517 | printk(KERN_ERR "PCMCIA obtaining reference to socket %p failed\n", socket); | 1158 | printk(KERN_ERR "PCMCIA obtaining reference to socket %p failed\n", socket); |
1518 | kfree (s); | ||
1519 | return -ENODEV; | 1159 | return -ENODEV; |
1520 | } | 1160 | } |
1521 | 1161 | ||
1522 | kref_init(&s->refcount); | ||
1523 | |||
1524 | /* | 1162 | /* |
1525 | * Ugly. But we want to wait for the socket threads to have started up. | 1163 | * Ugly. But we want to wait for the socket threads to have started up. |
1526 | * We really should let the drivers themselves drive some of this.. | 1164 | * We really should let the drivers themselves drive some of this.. |
1527 | */ | 1165 | */ |
1528 | msleep(250); | 1166 | msleep(250); |
1529 | 1167 | ||
1530 | init_waitqueue_head(&s->queue); | 1168 | #ifdef CONFIG_PCMCIA_IOCTL |
1531 | INIT_LIST_HEAD(&s->devices_list); | 1169 | init_waitqueue_head(&socket->queue); |
1532 | 1170 | #endif | |
1533 | /* Set up hotline to Card Services */ | 1171 | INIT_LIST_HEAD(&socket->devices_list); |
1534 | s->callback.owner = THIS_MODULE; | 1172 | INIT_WORK(&socket->device_add, pcmcia_delayed_add_pseudo_device, socket); |
1535 | s->callback.event = &ds_event; | 1173 | memset(&socket->pcmcia_state, 0, sizeof(u8)); |
1536 | s->callback.resources_done = &pcmcia_card_add; | 1174 | socket->device_count = 0; |
1537 | socket->pcmcia = s; | ||
1538 | 1175 | ||
1539 | ret = pccard_register_pcmcia(socket, &s->callback); | 1176 | ret = pccard_register_pcmcia(socket, &pcmcia_bus_callback); |
1540 | if (ret) { | 1177 | if (ret) { |
1541 | printk(KERN_ERR "PCMCIA registration PCCard core failed for socket %p\n", socket); | 1178 | printk(KERN_ERR "PCMCIA registration PCCard core failed for socket %p\n", socket); |
1542 | pcmcia_put_bus_socket(s); | 1179 | pcmcia_put_socket(socket); |
1543 | socket->pcmcia = NULL; | ||
1544 | return (ret); | 1180 | return (ret); |
1545 | } | 1181 | } |
1546 | 1182 | ||
1547 | return 0; | 1183 | return 0; |
1548 | } | 1184 | } |
1549 | 1185 | ||
1550 | |||
1551 | static void pcmcia_bus_remove_socket(struct class_device *class_dev) | 1186 | static void pcmcia_bus_remove_socket(struct class_device *class_dev) |
1552 | { | 1187 | { |
1553 | struct pcmcia_socket *socket = class_get_devdata(class_dev); | 1188 | struct pcmcia_socket *socket = class_get_devdata(class_dev); |
1554 | 1189 | ||
1555 | if (!socket || !socket->pcmcia) | 1190 | if (!socket) |
1556 | return; | 1191 | return; |
1557 | 1192 | ||
1193 | socket->pcmcia_state.dead = 1; | ||
1558 | pccard_register_pcmcia(socket, NULL); | 1194 | pccard_register_pcmcia(socket, NULL); |
1559 | 1195 | ||
1560 | socket->pcmcia->state |= DS_SOCKET_DEAD; | 1196 | pcmcia_put_socket(socket); |
1561 | pcmcia_put_bus_socket(socket->pcmcia); | ||
1562 | socket->pcmcia = NULL; | ||
1563 | 1197 | ||
1564 | return; | 1198 | return; |
1565 | } | 1199 | } |
@@ -1575,34 +1209,20 @@ static struct class_interface pcmcia_bus_interface = { | |||
1575 | 1209 | ||
1576 | struct bus_type pcmcia_bus_type = { | 1210 | struct bus_type pcmcia_bus_type = { |
1577 | .name = "pcmcia", | 1211 | .name = "pcmcia", |
1212 | .hotplug = pcmcia_bus_hotplug, | ||
1578 | .match = pcmcia_bus_match, | 1213 | .match = pcmcia_bus_match, |
1579 | .dev_attrs = pcmcia_dev_attrs, | 1214 | .dev_attrs = pcmcia_dev_attrs, |
1580 | }; | 1215 | }; |
1581 | EXPORT_SYMBOL(pcmcia_bus_type); | ||
1582 | 1216 | ||
1583 | 1217 | ||
1584 | static int __init init_pcmcia_bus(void) | 1218 | static int __init init_pcmcia_bus(void) |
1585 | { | 1219 | { |
1586 | int i; | ||
1587 | |||
1588 | spin_lock_init(&pcmcia_dev_list_lock); | 1220 | spin_lock_init(&pcmcia_dev_list_lock); |
1589 | 1221 | ||
1590 | bus_register(&pcmcia_bus_type); | 1222 | bus_register(&pcmcia_bus_type); |
1591 | class_interface_register(&pcmcia_bus_interface); | 1223 | class_interface_register(&pcmcia_bus_interface); |
1592 | 1224 | ||
1593 | /* Set up character device for user mode clients */ | 1225 | pcmcia_setup_ioctl(); |
1594 | i = register_chrdev(0, "pcmcia", &ds_fops); | ||
1595 | if (i < 0) | ||
1596 | printk(KERN_NOTICE "unable to find a free device # for " | ||
1597 | "Driver Services (error=%d)\n", i); | ||
1598 | else | ||
1599 | major_dev = i; | ||
1600 | |||
1601 | #ifdef CONFIG_PROC_FS | ||
1602 | proc_pccard = proc_mkdir("pccard", proc_bus); | ||
1603 | if (proc_pccard) | ||
1604 | create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL); | ||
1605 | #endif | ||
1606 | 1226 | ||
1607 | return 0; | 1227 | return 0; |
1608 | } | 1228 | } |
@@ -1612,48 +1232,13 @@ fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that | |||
1612 | 1232 | ||
1613 | static void __exit exit_pcmcia_bus(void) | 1233 | static void __exit exit_pcmcia_bus(void) |
1614 | { | 1234 | { |
1615 | class_interface_unregister(&pcmcia_bus_interface); | 1235 | pcmcia_cleanup_ioctl(); |
1616 | 1236 | ||
1617 | #ifdef CONFIG_PROC_FS | 1237 | class_interface_unregister(&pcmcia_bus_interface); |
1618 | if (proc_pccard) { | ||
1619 | remove_proc_entry("drivers", proc_pccard); | ||
1620 | remove_proc_entry("pccard", proc_bus); | ||
1621 | } | ||
1622 | #endif | ||
1623 | if (major_dev != -1) | ||
1624 | unregister_chrdev(major_dev, "pcmcia"); | ||
1625 | 1238 | ||
1626 | bus_unregister(&pcmcia_bus_type); | 1239 | bus_unregister(&pcmcia_bus_type); |
1627 | } | 1240 | } |
1628 | module_exit(exit_pcmcia_bus); | 1241 | module_exit(exit_pcmcia_bus); |
1629 | 1242 | ||
1630 | 1243 | ||
1631 | |||
1632 | /* helpers for backwards-compatible functions */ | ||
1633 | |||
1634 | static struct pcmcia_bus_socket * get_socket_info_by_nr(unsigned int nr) | ||
1635 | { | ||
1636 | struct pcmcia_socket * s = pcmcia_get_socket_by_nr(nr); | ||
1637 | if (s && s->pcmcia) | ||
1638 | return s->pcmcia; | ||
1639 | else | ||
1640 | return NULL; | ||
1641 | } | ||
1642 | |||
1643 | /* backwards-compatible accessing of driver --- by name! */ | ||
1644 | |||
1645 | static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info) | ||
1646 | { | ||
1647 | struct device_driver *drv; | ||
1648 | struct pcmcia_driver *p_drv; | ||
1649 | |||
1650 | drv = driver_find((char *) dev_info, &pcmcia_bus_type); | ||
1651 | if (!drv) | ||
1652 | return NULL; | ||
1653 | |||
1654 | p_drv = container_of(drv, struct pcmcia_driver, drv); | ||
1655 | |||
1656 | return (p_drv); | ||
1657 | } | ||
1658 | |||
1659 | MODULE_ALIAS("ds"); | 1244 | MODULE_ALIAS("ds"); |
diff --git a/drivers/pcmcia/ds_internal.h b/drivers/pcmcia/ds_internal.h new file mode 100644 index 000000000000..d359bd25a51c --- /dev/null +++ b/drivers/pcmcia/ds_internal.h | |||
@@ -0,0 +1,21 @@ | |||
1 | /* ds_internal.h - internal header for 16-bit PCMCIA devices management */ | ||
2 | |||
3 | extern spinlock_t pcmcia_dev_list_lock; | ||
4 | extern struct bus_type pcmcia_bus_type; | ||
5 | |||
6 | extern struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev); | ||
7 | extern void pcmcia_put_dev(struct pcmcia_device *p_dev); | ||
8 | |||
9 | struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function); | ||
10 | |||
11 | #ifdef CONFIG_PCMCIA_IOCTL | ||
12 | extern void __init pcmcia_setup_ioctl(void); | ||
13 | extern void __exit pcmcia_cleanup_ioctl(void); | ||
14 | extern void handle_event(struct pcmcia_socket *s, event_t event); | ||
15 | extern int handle_request(struct pcmcia_socket *s, event_t event); | ||
16 | #else | ||
17 | static inline void __init pcmcia_setup_ioctl(void) { return; } | ||
18 | static inline void __init pcmcia_cleanup_ioctl(void) { return; } | ||
19 | static inline void handle_event(struct pcmcia_socket *s, event_t event) { return; } | ||
20 | static inline int handle_request(struct pcmcia_socket *s, event_t event) { return CS_SUCCESS; } | ||
21 | #endif | ||
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 90a335a5d9fa..d72f9a35c8bd 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c | |||
@@ -669,11 +669,13 @@ static int __init is_alive(u_short sock) | |||
669 | if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) && | 669 | if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) && |
670 | (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) && | 670 | (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) && |
671 | (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(0)) && | 671 | (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(0)) && |
672 | (check_region(start, stop-start+1) != 0) && | 672 | ((start & 0xfeef) != 0x02e8)) { |
673 | ((start & 0xfeef) != 0x02e8)) | 673 | if (!request_region(start, stop-start+1, "i82365")) |
674 | return 1; | 674 | return 1; |
675 | else | 675 | release_region(start, stop-start+1); |
676 | return 0; | 676 | } |
677 | |||
678 | return 0; | ||
677 | } | 679 | } |
678 | 680 | ||
679 | /*====================================================================*/ | 681 | /*====================================================================*/ |
@@ -696,7 +698,13 @@ static void __init add_pcic(int ns, int type) | |||
696 | struct i82365_socket *t = &socket[sockets-ns]; | 698 | struct i82365_socket *t = &socket[sockets-ns]; |
697 | 699 | ||
698 | base = sockets-ns; | 700 | base = sockets-ns; |
699 | if (t->ioaddr > 0) request_region(t->ioaddr, 2, "i82365"); | 701 | if (t->ioaddr > 0) { |
702 | if (!request_region(t->ioaddr, 2, "i82365")) { | ||
703 | printk(KERN_ERR "i82365: IO region conflict at %#lx, not available\n", | ||
704 | t->ioaddr); | ||
705 | return; | ||
706 | } | ||
707 | } | ||
700 | 708 | ||
701 | if (base == 0) printk("\n"); | 709 | if (base == 0) printk("\n"); |
702 | printk(KERN_INFO " %s", pcic[type].name); | 710 | printk(KERN_INFO " %s", pcic[type].name); |
@@ -803,7 +811,7 @@ static void __init isa_probe(void) | |||
803 | } | 811 | } |
804 | #endif | 812 | #endif |
805 | 813 | ||
806 | if (check_region(i365_base, 2) != 0) { | 814 | if (!request_region(i365_base, 2, "i82365")) { |
807 | if (sockets == 0) | 815 | if (sockets == 0) |
808 | printk("port conflict at %#lx\n", i365_base); | 816 | printk("port conflict at %#lx\n", i365_base); |
809 | return; | 817 | return; |
@@ -1441,6 +1449,7 @@ static void __exit exit_i82365(void) | |||
1441 | i365_set(i, I365_CSCINT, 0); | 1449 | i365_set(i, I365_CSCINT, 0); |
1442 | release_region(socket[i].ioaddr, 2); | 1450 | release_region(socket[i].ioaddr, 2); |
1443 | } | 1451 | } |
1452 | release_region(i365_base, 2); | ||
1444 | #ifdef CONFIG_PNP | 1453 | #ifdef CONFIG_PNP |
1445 | if (i82365_pnpdev) | 1454 | if (i82365_pnpdev) |
1446 | pnp_disable_dev(i82365_pnpdev); | 1455 | pnp_disable_dev(i82365_pnpdev); |
diff --git a/drivers/pcmcia/pcmcia_compat.c b/drivers/pcmcia/pcmcia_compat.c index 68b80084f83f..1cc83317e7e3 100644 --- a/drivers/pcmcia/pcmcia_compat.c +++ b/drivers/pcmcia/pcmcia_compat.c | |||
@@ -74,19 +74,6 @@ int pcmcia_validate_cis(client_handle_t handle, cisinfo_t *info) | |||
74 | } | 74 | } |
75 | EXPORT_SYMBOL(pcmcia_validate_cis); | 75 | EXPORT_SYMBOL(pcmcia_validate_cis); |
76 | 76 | ||
77 | int pcmcia_get_configuration_info(client_handle_t handle, | ||
78 | config_info_t *config) | ||
79 | { | ||
80 | struct pcmcia_socket *s; | ||
81 | |||
82 | if ((CHECK_HANDLE(handle)) || !config) | ||
83 | return CS_BAD_HANDLE; | ||
84 | s = SOCKET(handle); | ||
85 | if (!s) | ||
86 | return CS_BAD_HANDLE; | ||
87 | return pccard_get_configuration_info(s, handle->Function, config); | ||
88 | } | ||
89 | EXPORT_SYMBOL(pcmcia_get_configuration_info); | ||
90 | 77 | ||
91 | int pcmcia_reset_card(client_handle_t handle, client_req_t *req) | 78 | int pcmcia_reset_card(client_handle_t handle, client_req_t *req) |
92 | { | 79 | { |
@@ -102,24 +89,3 @@ int pcmcia_reset_card(client_handle_t handle, client_req_t *req) | |||
102 | } | 89 | } |
103 | EXPORT_SYMBOL(pcmcia_reset_card); | 90 | EXPORT_SYMBOL(pcmcia_reset_card); |
104 | 91 | ||
105 | int pcmcia_get_status(client_handle_t handle, cs_status_t *status) | ||
106 | { | ||
107 | struct pcmcia_socket *s; | ||
108 | if (CHECK_HANDLE(handle)) | ||
109 | return CS_BAD_HANDLE; | ||
110 | s = SOCKET(handle); | ||
111 | return pccard_get_status(s, handle->Function, status); | ||
112 | } | ||
113 | EXPORT_SYMBOL(pcmcia_get_status); | ||
114 | |||
115 | int pcmcia_access_configuration_register(client_handle_t handle, | ||
116 | conf_reg_t *reg) | ||
117 | { | ||
118 | struct pcmcia_socket *s; | ||
119 | if (CHECK_HANDLE(handle)) | ||
120 | return CS_BAD_HANDLE; | ||
121 | s = SOCKET(handle); | ||
122 | return pccard_access_configuration_register(s, handle->Function, reg); | ||
123 | } | ||
124 | EXPORT_SYMBOL(pcmcia_access_configuration_register); | ||
125 | |||
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c new file mode 100644 index 000000000000..b883bc151ed0 --- /dev/null +++ b/drivers/pcmcia/pcmcia_ioctl.c | |||
@@ -0,0 +1,786 @@ | |||
1 | /* | ||
2 | * pcmcia_ioctl.c -- ioctl interface for cardmgr and cardctl | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * The initial developer of the original code is David A. Hinds | ||
9 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
10 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
11 | * | ||
12 | * (C) 1999 David A. Hinds | ||
13 | * (C) 2003 - 2004 Dominik Brodowski | ||
14 | */ | ||
15 | |||
16 | /* | ||
17 | * This file will go away soon. | ||
18 | */ | ||
19 | |||
20 | |||
21 | #include <linux/config.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/major.h> | ||
26 | #include <linux/errno.h> | ||
27 | #include <linux/ioctl.h> | ||
28 | #include <linux/proc_fs.h> | ||
29 | #include <linux/poll.h> | ||
30 | #include <linux/pci.h> | ||
31 | #include <linux/workqueue.h> | ||
32 | |||
33 | #define IN_CARD_SERVICES | ||
34 | #include <pcmcia/version.h> | ||
35 | #include <pcmcia/cs_types.h> | ||
36 | #include <pcmcia/cs.h> | ||
37 | #include <pcmcia/cistpl.h> | ||
38 | #include <pcmcia/ds.h> | ||
39 | #include <pcmcia/ss.h> | ||
40 | |||
41 | #include "cs_internal.h" | ||
42 | #include "ds_internal.h" | ||
43 | |||
44 | static int major_dev = -1; | ||
45 | |||
46 | |||
47 | /* Device user information */ | ||
48 | #define MAX_EVENTS 32 | ||
49 | #define USER_MAGIC 0x7ea4 | ||
50 | #define CHECK_USER(u) \ | ||
51 | (((u) == NULL) || ((u)->user_magic != USER_MAGIC)) | ||
52 | |||
53 | typedef struct user_info_t { | ||
54 | u_int user_magic; | ||
55 | int event_head, event_tail; | ||
56 | event_t event[MAX_EVENTS]; | ||
57 | struct user_info_t *next; | ||
58 | struct pcmcia_socket *socket; | ||
59 | } user_info_t; | ||
60 | |||
61 | |||
62 | #ifdef DEBUG | ||
63 | extern int ds_pc_debug; | ||
64 | #define cs_socket_name(skt) ((skt)->dev.class_id) | ||
65 | |||
66 | #define ds_dbg(lvl, fmt, arg...) do { \ | ||
67 | if (ds_pc_debug >= lvl) \ | ||
68 | printk(KERN_DEBUG "ds: " fmt , ## arg); \ | ||
69 | } while (0) | ||
70 | #else | ||
71 | #define ds_dbg(lvl, fmt, arg...) do { } while (0) | ||
72 | #endif | ||
73 | |||
74 | static const char *release = "Linux Kernel Card Services"; | ||
75 | |||
76 | /** pcmcia_get_card_services_info | ||
77 | * | ||
78 | * Return information about this version of Card Services | ||
79 | */ | ||
80 | static int pcmcia_get_card_services_info(servinfo_t *info) | ||
81 | { | ||
82 | unsigned int socket_count = 0; | ||
83 | struct list_head *tmp; | ||
84 | info->Signature[0] = 'C'; | ||
85 | info->Signature[1] = 'S'; | ||
86 | down_read(&pcmcia_socket_list_rwsem); | ||
87 | list_for_each(tmp, &pcmcia_socket_list) | ||
88 | socket_count++; | ||
89 | up_read(&pcmcia_socket_list_rwsem); | ||
90 | info->Count = socket_count; | ||
91 | info->Revision = CS_RELEASE_CODE; | ||
92 | info->CSLevel = 0x0210; | ||
93 | info->VendorString = (char *)release; | ||
94 | return CS_SUCCESS; | ||
95 | } /* get_card_services_info */ | ||
96 | |||
97 | |||
98 | /* backwards-compatible accessing of driver --- by name! */ | ||
99 | |||
100 | static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info) | ||
101 | { | ||
102 | struct device_driver *drv; | ||
103 | struct pcmcia_driver *p_drv; | ||
104 | |||
105 | drv = driver_find((char *) dev_info, &pcmcia_bus_type); | ||
106 | if (!drv) | ||
107 | return NULL; | ||
108 | |||
109 | p_drv = container_of(drv, struct pcmcia_driver, drv); | ||
110 | |||
111 | return (p_drv); | ||
112 | } | ||
113 | |||
114 | |||
115 | #ifdef CONFIG_PROC_FS | ||
116 | static struct proc_dir_entry *proc_pccard = NULL; | ||
117 | |||
118 | static int proc_read_drivers_callback(struct device_driver *driver, void *d) | ||
119 | { | ||
120 | char **p = d; | ||
121 | struct pcmcia_driver *p_drv = container_of(driver, | ||
122 | struct pcmcia_driver, drv); | ||
123 | |||
124 | *p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name, | ||
125 | #ifdef CONFIG_MODULE_UNLOAD | ||
126 | (p_drv->owner) ? module_refcount(p_drv->owner) : 1 | ||
127 | #else | ||
128 | 1 | ||
129 | #endif | ||
130 | ); | ||
131 | d = (void *) p; | ||
132 | |||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static int proc_read_drivers(char *buf, char **start, off_t pos, | ||
137 | int count, int *eof, void *data) | ||
138 | { | ||
139 | char *p = buf; | ||
140 | |||
141 | bus_for_each_drv(&pcmcia_bus_type, NULL, | ||
142 | (void *) &p, proc_read_drivers_callback); | ||
143 | |||
144 | return (p - buf); | ||
145 | } | ||
146 | #endif | ||
147 | |||
148 | /*====================================================================== | ||
149 | |||
150 | These manage a ring buffer of events pending for one user process | ||
151 | |||
152 | ======================================================================*/ | ||
153 | |||
154 | |||
155 | static int queue_empty(user_info_t *user) | ||
156 | { | ||
157 | return (user->event_head == user->event_tail); | ||
158 | } | ||
159 | |||
160 | static event_t get_queued_event(user_info_t *user) | ||
161 | { | ||
162 | user->event_tail = (user->event_tail+1) % MAX_EVENTS; | ||
163 | return user->event[user->event_tail]; | ||
164 | } | ||
165 | |||
166 | static void queue_event(user_info_t *user, event_t event) | ||
167 | { | ||
168 | user->event_head = (user->event_head+1) % MAX_EVENTS; | ||
169 | if (user->event_head == user->event_tail) | ||
170 | user->event_tail = (user->event_tail+1) % MAX_EVENTS; | ||
171 | user->event[user->event_head] = event; | ||
172 | } | ||
173 | |||
174 | void handle_event(struct pcmcia_socket *s, event_t event) | ||
175 | { | ||
176 | user_info_t *user; | ||
177 | for (user = s->user; user; user = user->next) | ||
178 | queue_event(user, event); | ||
179 | wake_up_interruptible(&s->queue); | ||
180 | } | ||
181 | |||
182 | |||
183 | /*====================================================================== | ||
184 | |||
185 | bind_request() and bind_device() are merged by now. Register_client() | ||
186 | is called right at the end of bind_request(), during the driver's | ||
187 | ->attach() call. Individual descriptions: | ||
188 | |||
189 | bind_request() connects a socket to a particular client driver. | ||
190 | It looks up the specified device ID in the list of registered | ||
191 | drivers, binds it to the socket, and tries to create an instance | ||
192 | of the device. unbind_request() deletes a driver instance. | ||
193 | |||
194 | Bind_device() associates a device driver with a particular socket. | ||
195 | It is normally called by Driver Services after it has identified | ||
196 | a newly inserted card. An instance of that driver will then be | ||
197 | eligible to register as a client of this socket. | ||
198 | |||
199 | Register_client() uses the dev_info_t handle to match the | ||
200 | caller with a socket. The driver must have already been bound | ||
201 | to a socket with bind_device() -- in fact, bind_device() | ||
202 | allocates the client structure that will be used. | ||
203 | |||
204 | ======================================================================*/ | ||
205 | |||
206 | static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info) | ||
207 | { | ||
208 | struct pcmcia_driver *p_drv; | ||
209 | struct pcmcia_device *p_dev; | ||
210 | int ret = 0; | ||
211 | unsigned long flags; | ||
212 | |||
213 | s = pcmcia_get_socket(s); | ||
214 | if (!s) | ||
215 | return -EINVAL; | ||
216 | |||
217 | ds_dbg(2, "bind_request(%d, '%s')\n", s->sock, | ||
218 | (char *)bind_info->dev_info); | ||
219 | |||
220 | p_drv = get_pcmcia_driver(&bind_info->dev_info); | ||
221 | if (!p_drv) { | ||
222 | ret = -EINVAL; | ||
223 | goto err_put; | ||
224 | } | ||
225 | |||
226 | if (!try_module_get(p_drv->owner)) { | ||
227 | ret = -EINVAL; | ||
228 | goto err_put_driver; | ||
229 | } | ||
230 | |||
231 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
232 | list_for_each_entry(p_dev, &s->devices_list, socket_device_list) { | ||
233 | if (p_dev->func == bind_info->function) { | ||
234 | if ((p_dev->dev.driver == &p_drv->drv)) { | ||
235 | if (p_dev->cardmgr) { | ||
236 | /* if there's already a device | ||
237 | * registered, and it was registered | ||
238 | * by userspace before, we need to | ||
239 | * return the "instance". */ | ||
240 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
241 | bind_info->instance = p_dev->instance; | ||
242 | ret = -EBUSY; | ||
243 | goto err_put_module; | ||
244 | } else { | ||
245 | /* the correct driver managed to bind | ||
246 | * itself magically to the correct | ||
247 | * device. */ | ||
248 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
249 | p_dev->cardmgr = p_drv; | ||
250 | ret = 0; | ||
251 | goto err_put_module; | ||
252 | } | ||
253 | } else if (!p_dev->dev.driver) { | ||
254 | /* there's already a device available where | ||
255 | * no device has been bound to yet. So we don't | ||
256 | * need to register a device! */ | ||
257 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
258 | goto rescan; | ||
259 | } | ||
260 | } | ||
261 | } | ||
262 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
263 | |||
264 | p_dev = pcmcia_device_add(s, bind_info->function); | ||
265 | if (!p_dev) { | ||
266 | ret = -EIO; | ||
267 | goto err_put_module; | ||
268 | } | ||
269 | |||
270 | rescan: | ||
271 | p_dev->cardmgr = p_drv; | ||
272 | |||
273 | /* if a driver is already running, we can abort */ | ||
274 | if (p_dev->dev.driver) | ||
275 | goto err_put_module; | ||
276 | |||
277 | /* | ||
278 | * Prevent this racing with a card insertion. | ||
279 | */ | ||
280 | down(&s->skt_sem); | ||
281 | bus_rescan_devices(&pcmcia_bus_type); | ||
282 | up(&s->skt_sem); | ||
283 | |||
284 | /* check whether the driver indeed matched. I don't care if this | ||
285 | * is racy or not, because it can only happen on cardmgr access | ||
286 | * paths... | ||
287 | */ | ||
288 | if (!(p_dev->dev.driver == &p_drv->drv)) | ||
289 | p_dev->cardmgr = NULL; | ||
290 | |||
291 | err_put_module: | ||
292 | module_put(p_drv->owner); | ||
293 | err_put_driver: | ||
294 | put_driver(&p_drv->drv); | ||
295 | err_put: | ||
296 | pcmcia_put_socket(s); | ||
297 | |||
298 | return (ret); | ||
299 | } /* bind_request */ | ||
300 | |||
301 | #ifdef CONFIG_CARDBUS | ||
302 | |||
303 | static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s) | ||
304 | { | ||
305 | if (!s || !(s->state & SOCKET_CARDBUS)) | ||
306 | return NULL; | ||
307 | |||
308 | return s->cb_dev->subordinate; | ||
309 | } | ||
310 | #endif | ||
311 | |||
312 | static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first) | ||
313 | { | ||
314 | dev_node_t *node; | ||
315 | struct pcmcia_device *p_dev; | ||
316 | unsigned long flags; | ||
317 | int ret = 0; | ||
318 | |||
319 | #ifdef CONFIG_CARDBUS | ||
320 | /* | ||
321 | * Some unbelievably ugly code to associate the PCI cardbus | ||
322 | * device and its driver with the PCMCIA "bind" information. | ||
323 | */ | ||
324 | { | ||
325 | struct pci_bus *bus; | ||
326 | |||
327 | bus = pcmcia_lookup_bus(s); | ||
328 | if (bus) { | ||
329 | struct list_head *list; | ||
330 | struct pci_dev *dev = NULL; | ||
331 | |||
332 | list = bus->devices.next; | ||
333 | while (list != &bus->devices) { | ||
334 | struct pci_dev *pdev = pci_dev_b(list); | ||
335 | list = list->next; | ||
336 | |||
337 | if (first) { | ||
338 | dev = pdev; | ||
339 | break; | ||
340 | } | ||
341 | |||
342 | /* Try to handle "next" here some way? */ | ||
343 | } | ||
344 | if (dev && dev->driver) { | ||
345 | strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN); | ||
346 | bind_info->major = 0; | ||
347 | bind_info->minor = 0; | ||
348 | bind_info->next = NULL; | ||
349 | return 0; | ||
350 | } | ||
351 | } | ||
352 | } | ||
353 | #endif | ||
354 | |||
355 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
356 | list_for_each_entry(p_dev, &s->devices_list, socket_device_list) { | ||
357 | if (p_dev->func == bind_info->function) { | ||
358 | p_dev = pcmcia_get_dev(p_dev); | ||
359 | if (!p_dev) | ||
360 | continue; | ||
361 | goto found; | ||
362 | } | ||
363 | } | ||
364 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
365 | return -ENODEV; | ||
366 | |||
367 | found: | ||
368 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
369 | |||
370 | if ((!p_dev->instance) || | ||
371 | (p_dev->instance->state & DEV_CONFIG_PENDING)) { | ||
372 | ret = -EAGAIN; | ||
373 | goto err_put; | ||
374 | } | ||
375 | |||
376 | if (first) | ||
377 | node = p_dev->instance->dev; | ||
378 | else | ||
379 | for (node = p_dev->instance->dev; node; node = node->next) | ||
380 | if (node == bind_info->next) | ||
381 | break; | ||
382 | if (!node) { | ||
383 | ret = -ENODEV; | ||
384 | goto err_put; | ||
385 | } | ||
386 | |||
387 | strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN); | ||
388 | bind_info->major = node->major; | ||
389 | bind_info->minor = node->minor; | ||
390 | bind_info->next = node->next; | ||
391 | |||
392 | err_put: | ||
393 | pcmcia_put_dev(p_dev); | ||
394 | return (ret); | ||
395 | } /* get_device_info */ | ||
396 | |||
397 | |||
398 | static int ds_open(struct inode *inode, struct file *file) | ||
399 | { | ||
400 | socket_t i = iminor(inode); | ||
401 | struct pcmcia_socket *s; | ||
402 | user_info_t *user; | ||
403 | |||
404 | ds_dbg(0, "ds_open(socket %d)\n", i); | ||
405 | |||
406 | s = pcmcia_get_socket_by_nr(i); | ||
407 | if (!s) | ||
408 | return -ENODEV; | ||
409 | s = pcmcia_get_socket(s); | ||
410 | if (!s) | ||
411 | return -ENODEV; | ||
412 | |||
413 | if ((file->f_flags & O_ACCMODE) != O_RDONLY) { | ||
414 | if (s->pcmcia_state.busy) { | ||
415 | pcmcia_put_socket(s); | ||
416 | return -EBUSY; | ||
417 | } | ||
418 | else | ||
419 | s->pcmcia_state.busy = 1; | ||
420 | } | ||
421 | |||
422 | user = kmalloc(sizeof(user_info_t), GFP_KERNEL); | ||
423 | if (!user) { | ||
424 | pcmcia_put_socket(s); | ||
425 | return -ENOMEM; | ||
426 | } | ||
427 | user->event_tail = user->event_head = 0; | ||
428 | user->next = s->user; | ||
429 | user->user_magic = USER_MAGIC; | ||
430 | user->socket = s; | ||
431 | s->user = user; | ||
432 | file->private_data = user; | ||
433 | |||
434 | if (s->pcmcia_state.present) | ||
435 | queue_event(user, CS_EVENT_CARD_INSERTION); | ||
436 | return 0; | ||
437 | } /* ds_open */ | ||
438 | |||
439 | /*====================================================================*/ | ||
440 | |||
441 | static int ds_release(struct inode *inode, struct file *file) | ||
442 | { | ||
443 | struct pcmcia_socket *s; | ||
444 | user_info_t *user, **link; | ||
445 | |||
446 | ds_dbg(0, "ds_release(socket %d)\n", iminor(inode)); | ||
447 | |||
448 | user = file->private_data; | ||
449 | if (CHECK_USER(user)) | ||
450 | goto out; | ||
451 | |||
452 | s = user->socket; | ||
453 | |||
454 | /* Unlink user data structure */ | ||
455 | if ((file->f_flags & O_ACCMODE) != O_RDONLY) { | ||
456 | s->pcmcia_state.busy = 0; | ||
457 | } | ||
458 | file->private_data = NULL; | ||
459 | for (link = &s->user; *link; link = &(*link)->next) | ||
460 | if (*link == user) break; | ||
461 | if (link == NULL) | ||
462 | goto out; | ||
463 | *link = user->next; | ||
464 | user->user_magic = 0; | ||
465 | kfree(user); | ||
466 | pcmcia_put_socket(s); | ||
467 | out: | ||
468 | return 0; | ||
469 | } /* ds_release */ | ||
470 | |||
471 | /*====================================================================*/ | ||
472 | |||
473 | static ssize_t ds_read(struct file *file, char __user *buf, | ||
474 | size_t count, loff_t *ppos) | ||
475 | { | ||
476 | struct pcmcia_socket *s; | ||
477 | user_info_t *user; | ||
478 | int ret; | ||
479 | |||
480 | ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode)); | ||
481 | |||
482 | if (count < 4) | ||
483 | return -EINVAL; | ||
484 | |||
485 | user = file->private_data; | ||
486 | if (CHECK_USER(user)) | ||
487 | return -EIO; | ||
488 | |||
489 | s = user->socket; | ||
490 | if (s->pcmcia_state.dead) | ||
491 | return -EIO; | ||
492 | |||
493 | ret = wait_event_interruptible(s->queue, !queue_empty(user)); | ||
494 | if (ret == 0) | ||
495 | ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4; | ||
496 | |||
497 | return ret; | ||
498 | } /* ds_read */ | ||
499 | |||
500 | /*====================================================================*/ | ||
501 | |||
502 | static ssize_t ds_write(struct file *file, const char __user *buf, | ||
503 | size_t count, loff_t *ppos) | ||
504 | { | ||
505 | ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode)); | ||
506 | |||
507 | if (count != 4) | ||
508 | return -EINVAL; | ||
509 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) | ||
510 | return -EBADF; | ||
511 | |||
512 | return -EIO; | ||
513 | } /* ds_write */ | ||
514 | |||
515 | /*====================================================================*/ | ||
516 | |||
517 | /* No kernel lock - fine */ | ||
518 | static u_int ds_poll(struct file *file, poll_table *wait) | ||
519 | { | ||
520 | struct pcmcia_socket *s; | ||
521 | user_info_t *user; | ||
522 | |||
523 | ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode)); | ||
524 | |||
525 | user = file->private_data; | ||
526 | if (CHECK_USER(user)) | ||
527 | return POLLERR; | ||
528 | s = user->socket; | ||
529 | /* | ||
530 | * We don't check for a dead socket here since that | ||
531 | * will send cardmgr into an endless spin. | ||
532 | */ | ||
533 | poll_wait(file, &s->queue, wait); | ||
534 | if (!queue_empty(user)) | ||
535 | return POLLIN | POLLRDNORM; | ||
536 | return 0; | ||
537 | } /* ds_poll */ | ||
538 | |||
539 | /*====================================================================*/ | ||
540 | |||
541 | extern int pcmcia_adjust_resource_info(adjust_t *adj); | ||
542 | |||
543 | static int ds_ioctl(struct inode * inode, struct file * file, | ||
544 | u_int cmd, u_long arg) | ||
545 | { | ||
546 | struct pcmcia_socket *s; | ||
547 | void __user *uarg = (char __user *)arg; | ||
548 | u_int size; | ||
549 | int ret, err; | ||
550 | ds_ioctl_arg_t *buf; | ||
551 | user_info_t *user; | ||
552 | |||
553 | ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg); | ||
554 | |||
555 | user = file->private_data; | ||
556 | if (CHECK_USER(user)) | ||
557 | return -EIO; | ||
558 | |||
559 | s = user->socket; | ||
560 | if (s->pcmcia_state.dead) | ||
561 | return -EIO; | ||
562 | |||
563 | size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; | ||
564 | if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL; | ||
565 | |||
566 | /* Permission check */ | ||
567 | if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN)) | ||
568 | return -EPERM; | ||
569 | |||
570 | if (cmd & IOC_IN) { | ||
571 | if (!access_ok(VERIFY_READ, uarg, size)) { | ||
572 | ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT); | ||
573 | return -EFAULT; | ||
574 | } | ||
575 | } | ||
576 | if (cmd & IOC_OUT) { | ||
577 | if (!access_ok(VERIFY_WRITE, uarg, size)) { | ||
578 | ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT); | ||
579 | return -EFAULT; | ||
580 | } | ||
581 | } | ||
582 | buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL); | ||
583 | if (!buf) | ||
584 | return -ENOMEM; | ||
585 | |||
586 | err = ret = 0; | ||
587 | |||
588 | if (cmd & IOC_IN) __copy_from_user((char *)buf, uarg, size); | ||
589 | |||
590 | switch (cmd) { | ||
591 | case DS_ADJUST_RESOURCE_INFO: | ||
592 | ret = pcmcia_adjust_resource_info(&buf->adjust); | ||
593 | break; | ||
594 | case DS_GET_CARD_SERVICES_INFO: | ||
595 | ret = pcmcia_get_card_services_info(&buf->servinfo); | ||
596 | break; | ||
597 | case DS_GET_CONFIGURATION_INFO: | ||
598 | if (buf->config.Function && | ||
599 | (buf->config.Function >= s->functions)) | ||
600 | ret = CS_BAD_ARGS; | ||
601 | else | ||
602 | ret = pccard_get_configuration_info(s, | ||
603 | buf->config.Function, &buf->config); | ||
604 | break; | ||
605 | case DS_GET_FIRST_TUPLE: | ||
606 | down(&s->skt_sem); | ||
607 | pcmcia_validate_mem(s); | ||
608 | up(&s->skt_sem); | ||
609 | ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple); | ||
610 | break; | ||
611 | case DS_GET_NEXT_TUPLE: | ||
612 | ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple); | ||
613 | break; | ||
614 | case DS_GET_TUPLE_DATA: | ||
615 | buf->tuple.TupleData = buf->tuple_parse.data; | ||
616 | buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data); | ||
617 | ret = pccard_get_tuple_data(s, &buf->tuple); | ||
618 | break; | ||
619 | case DS_PARSE_TUPLE: | ||
620 | buf->tuple.TupleData = buf->tuple_parse.data; | ||
621 | ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse); | ||
622 | break; | ||
623 | case DS_RESET_CARD: | ||
624 | ret = pccard_reset_card(s); | ||
625 | break; | ||
626 | case DS_GET_STATUS: | ||
627 | if (buf->status.Function && | ||
628 | (buf->status.Function >= s->functions)) | ||
629 | ret = CS_BAD_ARGS; | ||
630 | else | ||
631 | ret = pccard_get_status(s, buf->status.Function, &buf->status); | ||
632 | break; | ||
633 | case DS_VALIDATE_CIS: | ||
634 | down(&s->skt_sem); | ||
635 | pcmcia_validate_mem(s); | ||
636 | up(&s->skt_sem); | ||
637 | ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo); | ||
638 | break; | ||
639 | case DS_SUSPEND_CARD: | ||
640 | ret = pcmcia_suspend_card(s); | ||
641 | break; | ||
642 | case DS_RESUME_CARD: | ||
643 | ret = pcmcia_resume_card(s); | ||
644 | break; | ||
645 | case DS_EJECT_CARD: | ||
646 | err = pcmcia_eject_card(s); | ||
647 | break; | ||
648 | case DS_INSERT_CARD: | ||
649 | err = pcmcia_insert_card(s); | ||
650 | break; | ||
651 | case DS_ACCESS_CONFIGURATION_REGISTER: | ||
652 | if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) { | ||
653 | err = -EPERM; | ||
654 | goto free_out; | ||
655 | } | ||
656 | if (buf->conf_reg.Function && | ||
657 | (buf->conf_reg.Function >= s->functions)) | ||
658 | ret = CS_BAD_ARGS; | ||
659 | else | ||
660 | ret = pccard_access_configuration_register(s, | ||
661 | buf->conf_reg.Function, &buf->conf_reg); | ||
662 | break; | ||
663 | case DS_GET_FIRST_REGION: | ||
664 | case DS_GET_NEXT_REGION: | ||
665 | case DS_BIND_MTD: | ||
666 | if (!capable(CAP_SYS_ADMIN)) { | ||
667 | err = -EPERM; | ||
668 | goto free_out; | ||
669 | } else { | ||
670 | static int printed = 0; | ||
671 | if (!printed) { | ||
672 | printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n"); | ||
673 | printk(KERN_WARNING "MTD handling any more.\n"); | ||
674 | printed++; | ||
675 | } | ||
676 | } | ||
677 | err = -EINVAL; | ||
678 | goto free_out; | ||
679 | break; | ||
680 | case DS_GET_FIRST_WINDOW: | ||
681 | ret = pcmcia_get_window(s, &buf->win_info.handle, 0, | ||
682 | &buf->win_info.window); | ||
683 | break; | ||
684 | case DS_GET_NEXT_WINDOW: | ||
685 | ret = pcmcia_get_window(s, &buf->win_info.handle, | ||
686 | buf->win_info.handle->index + 1, &buf->win_info.window); | ||
687 | break; | ||
688 | case DS_GET_MEM_PAGE: | ||
689 | ret = pcmcia_get_mem_page(buf->win_info.handle, | ||
690 | &buf->win_info.map); | ||
691 | break; | ||
692 | case DS_REPLACE_CIS: | ||
693 | ret = pcmcia_replace_cis(s, &buf->cisdump); | ||
694 | break; | ||
695 | case DS_BIND_REQUEST: | ||
696 | if (!capable(CAP_SYS_ADMIN)) { | ||
697 | err = -EPERM; | ||
698 | goto free_out; | ||
699 | } | ||
700 | err = bind_request(s, &buf->bind_info); | ||
701 | break; | ||
702 | case DS_GET_DEVICE_INFO: | ||
703 | err = get_device_info(s, &buf->bind_info, 1); | ||
704 | break; | ||
705 | case DS_GET_NEXT_DEVICE: | ||
706 | err = get_device_info(s, &buf->bind_info, 0); | ||
707 | break; | ||
708 | case DS_UNBIND_REQUEST: | ||
709 | err = 0; | ||
710 | break; | ||
711 | default: | ||
712 | err = -EINVAL; | ||
713 | } | ||
714 | |||
715 | if ((err == 0) && (ret != CS_SUCCESS)) { | ||
716 | ds_dbg(2, "ds_ioctl: ret = %d\n", ret); | ||
717 | switch (ret) { | ||
718 | case CS_BAD_SOCKET: case CS_NO_CARD: | ||
719 | err = -ENODEV; break; | ||
720 | case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ: | ||
721 | case CS_BAD_TUPLE: | ||
722 | err = -EINVAL; break; | ||
723 | case CS_IN_USE: | ||
724 | err = -EBUSY; break; | ||
725 | case CS_OUT_OF_RESOURCE: | ||
726 | err = -ENOSPC; break; | ||
727 | case CS_NO_MORE_ITEMS: | ||
728 | err = -ENODATA; break; | ||
729 | case CS_UNSUPPORTED_FUNCTION: | ||
730 | err = -ENOSYS; break; | ||
731 | default: | ||
732 | err = -EIO; break; | ||
733 | } | ||
734 | } | ||
735 | |||
736 | if (cmd & IOC_OUT) { | ||
737 | if (__copy_to_user(uarg, (char *)buf, size)) | ||
738 | err = -EFAULT; | ||
739 | } | ||
740 | |||
741 | free_out: | ||
742 | kfree(buf); | ||
743 | return err; | ||
744 | } /* ds_ioctl */ | ||
745 | |||
746 | /*====================================================================*/ | ||
747 | |||
748 | static struct file_operations ds_fops = { | ||
749 | .owner = THIS_MODULE, | ||
750 | .open = ds_open, | ||
751 | .release = ds_release, | ||
752 | .ioctl = ds_ioctl, | ||
753 | .read = ds_read, | ||
754 | .write = ds_write, | ||
755 | .poll = ds_poll, | ||
756 | }; | ||
757 | |||
758 | void __init pcmcia_setup_ioctl(void) { | ||
759 | int i; | ||
760 | |||
761 | /* Set up character device for user mode clients */ | ||
762 | i = register_chrdev(0, "pcmcia", &ds_fops); | ||
763 | if (i < 0) | ||
764 | printk(KERN_NOTICE "unable to find a free device # for " | ||
765 | "Driver Services (error=%d)\n", i); | ||
766 | else | ||
767 | major_dev = i; | ||
768 | |||
769 | #ifdef CONFIG_PROC_FS | ||
770 | proc_pccard = proc_mkdir("pccard", proc_bus); | ||
771 | if (proc_pccard) | ||
772 | create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL); | ||
773 | #endif | ||
774 | } | ||
775 | |||
776 | |||
777 | void __exit pcmcia_cleanup_ioctl(void) { | ||
778 | #ifdef CONFIG_PROC_FS | ||
779 | if (proc_pccard) { | ||
780 | remove_proc_entry("drivers", proc_pccard); | ||
781 | remove_proc_entry("pccard", proc_bus); | ||
782 | } | ||
783 | #endif | ||
784 | if (major_dev != -1) | ||
785 | unregister_chrdev(major_dev, "pcmcia"); | ||
786 | } | ||
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c new file mode 100644 index 000000000000..c01dc6bf1526 --- /dev/null +++ b/drivers/pcmcia/pcmcia_resource.c | |||
@@ -0,0 +1,998 @@ | |||
1 | /* | ||
2 | * PCMCIA 16-bit resource management functions | ||
3 | * | ||
4 | * The initial developer of the original code is David A. Hinds | ||
5 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
6 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
7 | * | ||
8 | * Copyright (C) 1999 David A. Hinds | ||
9 | * Copyright (C) 2004-2005 Dominik Brodowski | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/config.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/device.h> | ||
24 | |||
25 | #define IN_CARD_SERVICES | ||
26 | #include <pcmcia/version.h> | ||
27 | #include <pcmcia/cs_types.h> | ||
28 | #include <pcmcia/ss.h> | ||
29 | #include <pcmcia/cs.h> | ||
30 | #include <pcmcia/bulkmem.h> | ||
31 | #include <pcmcia/cistpl.h> | ||
32 | #include <pcmcia/cisreg.h> | ||
33 | #include <pcmcia/ds.h> | ||
34 | |||
35 | #include "cs_internal.h" | ||
36 | #include "ds_internal.h" | ||
37 | |||
38 | |||
39 | /* Access speed for IO windows */ | ||
40 | static int io_speed = 0; | ||
41 | module_param(io_speed, int, 0444); | ||
42 | |||
43 | |||
44 | #ifdef CONFIG_PCMCIA_PROBE | ||
45 | /* mask of IRQs already reserved by other cards, we should avoid using them */ | ||
46 | static u8 pcmcia_used_irq[NR_IRQS]; | ||
47 | #endif | ||
48 | |||
49 | |||
50 | #ifdef DEBUG | ||
51 | extern int ds_pc_debug; | ||
52 | #define cs_socket_name(skt) ((skt)->dev.class_id) | ||
53 | |||
54 | #define ds_dbg(skt, lvl, fmt, arg...) do { \ | ||
55 | if (ds_pc_debug >= lvl) \ | ||
56 | printk(KERN_DEBUG "pcmcia_resource: %s: " fmt, \ | ||
57 | cs_socket_name(skt) , ## arg); \ | ||
58 | } while (0) | ||
59 | #else | ||
60 | #define ds_dbg(lvl, fmt, arg...) do { } while (0) | ||
61 | #endif | ||
62 | |||
63 | |||
64 | |||
65 | /** alloc_io_space | ||
66 | * | ||
67 | * Special stuff for managing IO windows, because they are scarce | ||
68 | */ | ||
69 | |||
70 | static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base, | ||
71 | ioaddr_t num, u_int lines) | ||
72 | { | ||
73 | int i; | ||
74 | kio_addr_t try, align; | ||
75 | |||
76 | align = (*base) ? (lines ? 1<<lines : 0) : 1; | ||
77 | if (align && (align < num)) { | ||
78 | if (*base) { | ||
79 | ds_dbg(s, 0, "odd IO request: num %#x align %#lx\n", | ||
80 | num, align); | ||
81 | align = 0; | ||
82 | } else | ||
83 | while (align && (align < num)) align <<= 1; | ||
84 | } | ||
85 | if (*base & ~(align-1)) { | ||
86 | ds_dbg(s, 0, "odd IO request: base %#x align %#lx\n", | ||
87 | *base, align); | ||
88 | align = 0; | ||
89 | } | ||
90 | if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) { | ||
91 | *base = s->io_offset | (*base & 0x0fff); | ||
92 | s->io[0].Attributes = attr; | ||
93 | return 0; | ||
94 | } | ||
95 | /* Check for an already-allocated window that must conflict with | ||
96 | * what was asked for. It is a hack because it does not catch all | ||
97 | * potential conflicts, just the most obvious ones. | ||
98 | */ | ||
99 | for (i = 0; i < MAX_IO_WIN; i++) | ||
100 | if ((s->io[i].NumPorts != 0) && | ||
101 | ((s->io[i].BasePort & (align-1)) == *base)) | ||
102 | return 1; | ||
103 | for (i = 0; i < MAX_IO_WIN; i++) { | ||
104 | if (s->io[i].NumPorts == 0) { | ||
105 | s->io[i].res = pcmcia_find_io_region(*base, num, align, s); | ||
106 | if (s->io[i].res) { | ||
107 | s->io[i].Attributes = attr; | ||
108 | s->io[i].BasePort = *base = s->io[i].res->start; | ||
109 | s->io[i].NumPorts = s->io[i].InUse = num; | ||
110 | break; | ||
111 | } else | ||
112 | return 1; | ||
113 | } else if (s->io[i].Attributes != attr) | ||
114 | continue; | ||
115 | /* Try to extend top of window */ | ||
116 | try = s->io[i].BasePort + s->io[i].NumPorts; | ||
117 | if ((*base == 0) || (*base == try)) | ||
118 | if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start, | ||
119 | s->io[i].res->end + num, s) == 0) { | ||
120 | *base = try; | ||
121 | s->io[i].NumPorts += num; | ||
122 | s->io[i].InUse += num; | ||
123 | break; | ||
124 | } | ||
125 | /* Try to extend bottom of window */ | ||
126 | try = s->io[i].BasePort - num; | ||
127 | if ((*base == 0) || (*base == try)) | ||
128 | if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start - num, | ||
129 | s->io[i].res->end, s) == 0) { | ||
130 | s->io[i].BasePort = *base = try; | ||
131 | s->io[i].NumPorts += num; | ||
132 | s->io[i].InUse += num; | ||
133 | break; | ||
134 | } | ||
135 | } | ||
136 | return (i == MAX_IO_WIN); | ||
137 | } /* alloc_io_space */ | ||
138 | |||
139 | |||
140 | static void release_io_space(struct pcmcia_socket *s, ioaddr_t base, | ||
141 | ioaddr_t num) | ||
142 | { | ||
143 | int i; | ||
144 | |||
145 | for (i = 0; i < MAX_IO_WIN; i++) { | ||
146 | if ((s->io[i].BasePort <= base) && | ||
147 | (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) { | ||
148 | s->io[i].InUse -= num; | ||
149 | /* Free the window if no one else is using it */ | ||
150 | if (s->io[i].InUse == 0) { | ||
151 | s->io[i].NumPorts = 0; | ||
152 | release_resource(s->io[i].res); | ||
153 | kfree(s->io[i].res); | ||
154 | s->io[i].res = NULL; | ||
155 | } | ||
156 | } | ||
157 | } | ||
158 | } /* release_io_space */ | ||
159 | |||
160 | |||
161 | /** pccard_access_configuration_register | ||
162 | * | ||
163 | * Access_configuration_register() reads and writes configuration | ||
164 | * registers in attribute memory. Memory window 0 is reserved for | ||
165 | * this and the tuple reading services. | ||
166 | */ | ||
167 | |||
168 | int pccard_access_configuration_register(struct pcmcia_socket *s, | ||
169 | unsigned int function, | ||
170 | conf_reg_t *reg) | ||
171 | { | ||
172 | config_t *c; | ||
173 | int addr; | ||
174 | u_char val; | ||
175 | |||
176 | if (!s || !s->config) | ||
177 | return CS_NO_CARD; | ||
178 | |||
179 | c = &s->config[function]; | ||
180 | |||
181 | if (c == NULL) | ||
182 | return CS_NO_CARD; | ||
183 | |||
184 | if (!(c->state & CONFIG_LOCKED)) | ||
185 | return CS_CONFIGURATION_LOCKED; | ||
186 | |||
187 | addr = (c->ConfigBase + reg->Offset) >> 1; | ||
188 | |||
189 | switch (reg->Action) { | ||
190 | case CS_READ: | ||
191 | pcmcia_read_cis_mem(s, 1, addr, 1, &val); | ||
192 | reg->Value = val; | ||
193 | break; | ||
194 | case CS_WRITE: | ||
195 | val = reg->Value; | ||
196 | pcmcia_write_cis_mem(s, 1, addr, 1, &val); | ||
197 | break; | ||
198 | default: | ||
199 | return CS_BAD_ARGS; | ||
200 | break; | ||
201 | } | ||
202 | return CS_SUCCESS; | ||
203 | } /* pccard_access_configuration_register */ | ||
204 | |||
205 | int pcmcia_access_configuration_register(client_handle_t handle, | ||
206 | conf_reg_t *reg) | ||
207 | { | ||
208 | struct pcmcia_socket *s; | ||
209 | if (CHECK_HANDLE(handle)) | ||
210 | return CS_BAD_HANDLE; | ||
211 | s = SOCKET(handle); | ||
212 | return pccard_access_configuration_register(s, handle->Function, reg); | ||
213 | } | ||
214 | EXPORT_SYMBOL(pcmcia_access_configuration_register); | ||
215 | |||
216 | |||
217 | |||
218 | int pccard_get_configuration_info(struct pcmcia_socket *s, | ||
219 | unsigned int function, | ||
220 | config_info_t *config) | ||
221 | { | ||
222 | config_t *c; | ||
223 | |||
224 | if (!(s->state & SOCKET_PRESENT)) | ||
225 | return CS_NO_CARD; | ||
226 | |||
227 | config->Function = function; | ||
228 | |||
229 | #ifdef CONFIG_CARDBUS | ||
230 | if (s->state & SOCKET_CARDBUS) { | ||
231 | memset(config, 0, sizeof(config_info_t)); | ||
232 | config->Vcc = s->socket.Vcc; | ||
233 | config->Vpp1 = config->Vpp2 = s->socket.Vpp; | ||
234 | config->Option = s->cb_dev->subordinate->number; | ||
235 | if (s->state & SOCKET_CARDBUS_CONFIG) { | ||
236 | config->Attributes = CONF_VALID_CLIENT; | ||
237 | config->IntType = INT_CARDBUS; | ||
238 | config->AssignedIRQ = s->irq.AssignedIRQ; | ||
239 | if (config->AssignedIRQ) | ||
240 | config->Attributes |= CONF_ENABLE_IRQ; | ||
241 | config->BasePort1 = s->io[0].BasePort; | ||
242 | config->NumPorts1 = s->io[0].NumPorts; | ||
243 | } | ||
244 | return CS_SUCCESS; | ||
245 | } | ||
246 | #endif | ||
247 | |||
248 | c = (s->config != NULL) ? &s->config[function] : NULL; | ||
249 | |||
250 | if ((c == NULL) || !(c->state & CONFIG_LOCKED)) { | ||
251 | config->Attributes = 0; | ||
252 | config->Vcc = s->socket.Vcc; | ||
253 | config->Vpp1 = config->Vpp2 = s->socket.Vpp; | ||
254 | return CS_SUCCESS; | ||
255 | } | ||
256 | |||
257 | /* !!! This is a hack !!! */ | ||
258 | memcpy(&config->Attributes, &c->Attributes, sizeof(config_t)); | ||
259 | config->Attributes |= CONF_VALID_CLIENT; | ||
260 | config->CardValues = c->CardValues; | ||
261 | config->IRQAttributes = c->irq.Attributes; | ||
262 | config->AssignedIRQ = s->irq.AssignedIRQ; | ||
263 | config->BasePort1 = c->io.BasePort1; | ||
264 | config->NumPorts1 = c->io.NumPorts1; | ||
265 | config->Attributes1 = c->io.Attributes1; | ||
266 | config->BasePort2 = c->io.BasePort2; | ||
267 | config->NumPorts2 = c->io.NumPorts2; | ||
268 | config->Attributes2 = c->io.Attributes2; | ||
269 | config->IOAddrLines = c->io.IOAddrLines; | ||
270 | |||
271 | return CS_SUCCESS; | ||
272 | } /* pccard_get_configuration_info */ | ||
273 | |||
274 | int pcmcia_get_configuration_info(client_handle_t handle, | ||
275 | config_info_t *config) | ||
276 | { | ||
277 | struct pcmcia_socket *s; | ||
278 | |||
279 | if ((CHECK_HANDLE(handle)) || !config) | ||
280 | return CS_BAD_HANDLE; | ||
281 | s = SOCKET(handle); | ||
282 | if (!s) | ||
283 | return CS_BAD_HANDLE; | ||
284 | return pccard_get_configuration_info(s, handle->Function, config); | ||
285 | } | ||
286 | EXPORT_SYMBOL(pcmcia_get_configuration_info); | ||
287 | |||
288 | |||
289 | /** pcmcia_get_window | ||
290 | */ | ||
291 | int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle, | ||
292 | int idx, win_req_t *req) | ||
293 | { | ||
294 | window_t *win; | ||
295 | int w; | ||
296 | |||
297 | if (!s || !(s->state & SOCKET_PRESENT)) | ||
298 | return CS_NO_CARD; | ||
299 | for (w = idx; w < MAX_WIN; w++) | ||
300 | if (s->state & SOCKET_WIN_REQ(w)) | ||
301 | break; | ||
302 | if (w == MAX_WIN) | ||
303 | return CS_NO_MORE_ITEMS; | ||
304 | win = &s->win[w]; | ||
305 | req->Base = win->ctl.res->start; | ||
306 | req->Size = win->ctl.res->end - win->ctl.res->start + 1; | ||
307 | req->AccessSpeed = win->ctl.speed; | ||
308 | req->Attributes = 0; | ||
309 | if (win->ctl.flags & MAP_ATTRIB) | ||
310 | req->Attributes |= WIN_MEMORY_TYPE_AM; | ||
311 | if (win->ctl.flags & MAP_ACTIVE) | ||
312 | req->Attributes |= WIN_ENABLE; | ||
313 | if (win->ctl.flags & MAP_16BIT) | ||
314 | req->Attributes |= WIN_DATA_WIDTH_16; | ||
315 | if (win->ctl.flags & MAP_USE_WAIT) | ||
316 | req->Attributes |= WIN_USE_WAIT; | ||
317 | *handle = win; | ||
318 | return CS_SUCCESS; | ||
319 | } /* pcmcia_get_window */ | ||
320 | EXPORT_SYMBOL(pcmcia_get_window); | ||
321 | |||
322 | |||
323 | /** pccard_get_status | ||
324 | * | ||
325 | * Get the current socket state bits. We don't support the latched | ||
326 | * SocketState yet: I haven't seen any point for it. | ||
327 | */ | ||
328 | |||
329 | int pccard_get_status(struct pcmcia_socket *s, unsigned int function, | ||
330 | cs_status_t *status) | ||
331 | { | ||
332 | config_t *c; | ||
333 | int val; | ||
334 | |||
335 | s->ops->get_status(s, &val); | ||
336 | status->CardState = status->SocketState = 0; | ||
337 | status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0; | ||
338 | status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0; | ||
339 | status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0; | ||
340 | status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0; | ||
341 | if (s->state & SOCKET_SUSPEND) | ||
342 | status->CardState |= CS_EVENT_PM_SUSPEND; | ||
343 | if (!(s->state & SOCKET_PRESENT)) | ||
344 | return CS_NO_CARD; | ||
345 | |||
346 | c = (s->config != NULL) ? &s->config[function] : NULL; | ||
347 | if ((c != NULL) && (c->state & CONFIG_LOCKED) && | ||
348 | (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) { | ||
349 | u_char reg; | ||
350 | if (c->Present & PRESENT_PIN_REPLACE) { | ||
351 | pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, ®); | ||
352 | status->CardState |= | ||
353 | (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0; | ||
354 | status->CardState |= | ||
355 | (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0; | ||
356 | status->CardState |= | ||
357 | (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0; | ||
358 | status->CardState |= | ||
359 | (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0; | ||
360 | } else { | ||
361 | /* No PRR? Then assume we're always ready */ | ||
362 | status->CardState |= CS_EVENT_READY_CHANGE; | ||
363 | } | ||
364 | if (c->Present & PRESENT_EXT_STATUS) { | ||
365 | pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, ®); | ||
366 | status->CardState |= | ||
367 | (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0; | ||
368 | } | ||
369 | return CS_SUCCESS; | ||
370 | } | ||
371 | status->CardState |= | ||
372 | (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0; | ||
373 | status->CardState |= | ||
374 | (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0; | ||
375 | status->CardState |= | ||
376 | (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0; | ||
377 | status->CardState |= | ||
378 | (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0; | ||
379 | return CS_SUCCESS; | ||
380 | } /* pccard_get_status */ | ||
381 | |||
382 | int pcmcia_get_status(client_handle_t handle, cs_status_t *status) | ||
383 | { | ||
384 | struct pcmcia_socket *s; | ||
385 | if (CHECK_HANDLE(handle)) | ||
386 | return CS_BAD_HANDLE; | ||
387 | s = SOCKET(handle); | ||
388 | return pccard_get_status(s, handle->Function, status); | ||
389 | } | ||
390 | EXPORT_SYMBOL(pcmcia_get_status); | ||
391 | |||
392 | |||
393 | |||
394 | /** pcmcia_get_mem_page | ||
395 | * | ||
396 | * Change the card address of an already open memory window. | ||
397 | */ | ||
398 | int pcmcia_get_mem_page(window_handle_t win, memreq_t *req) | ||
399 | { | ||
400 | if ((win == NULL) || (win->magic != WINDOW_MAGIC)) | ||
401 | return CS_BAD_HANDLE; | ||
402 | req->Page = 0; | ||
403 | req->CardOffset = win->ctl.card_start; | ||
404 | return CS_SUCCESS; | ||
405 | } /* pcmcia_get_mem_page */ | ||
406 | EXPORT_SYMBOL(pcmcia_get_mem_page); | ||
407 | |||
408 | |||
409 | int pcmcia_map_mem_page(window_handle_t win, memreq_t *req) | ||
410 | { | ||
411 | struct pcmcia_socket *s; | ||
412 | if ((win == NULL) || (win->magic != WINDOW_MAGIC)) | ||
413 | return CS_BAD_HANDLE; | ||
414 | if (req->Page != 0) | ||
415 | return CS_BAD_PAGE; | ||
416 | s = win->sock; | ||
417 | win->ctl.card_start = req->CardOffset; | ||
418 | if (s->ops->set_mem_map(s, &win->ctl) != 0) | ||
419 | return CS_BAD_OFFSET; | ||
420 | return CS_SUCCESS; | ||
421 | } /* pcmcia_map_mem_page */ | ||
422 | EXPORT_SYMBOL(pcmcia_map_mem_page); | ||
423 | |||
424 | |||
425 | /** pcmcia_modify_configuration | ||
426 | * | ||
427 | * Modify a locked socket configuration | ||
428 | */ | ||
429 | int pcmcia_modify_configuration(client_handle_t handle, | ||
430 | modconf_t *mod) | ||
431 | { | ||
432 | struct pcmcia_socket *s; | ||
433 | config_t *c; | ||
434 | |||
435 | if (CHECK_HANDLE(handle)) | ||
436 | return CS_BAD_HANDLE; | ||
437 | s = SOCKET(handle); | ||
438 | c = CONFIG(handle); | ||
439 | if (!(s->state & SOCKET_PRESENT)) | ||
440 | return CS_NO_CARD; | ||
441 | if (!(c->state & CONFIG_LOCKED)) | ||
442 | return CS_CONFIGURATION_LOCKED; | ||
443 | |||
444 | if (mod->Attributes & CONF_IRQ_CHANGE_VALID) { | ||
445 | if (mod->Attributes & CONF_ENABLE_IRQ) { | ||
446 | c->Attributes |= CONF_ENABLE_IRQ; | ||
447 | s->socket.io_irq = s->irq.AssignedIRQ; | ||
448 | } else { | ||
449 | c->Attributes &= ~CONF_ENABLE_IRQ; | ||
450 | s->socket.io_irq = 0; | ||
451 | } | ||
452 | s->ops->set_socket(s, &s->socket); | ||
453 | } | ||
454 | |||
455 | if (mod->Attributes & CONF_VCC_CHANGE_VALID) | ||
456 | return CS_BAD_VCC; | ||
457 | |||
458 | /* We only allow changing Vpp1 and Vpp2 to the same value */ | ||
459 | if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) && | ||
460 | (mod->Attributes & CONF_VPP2_CHANGE_VALID)) { | ||
461 | if (mod->Vpp1 != mod->Vpp2) | ||
462 | return CS_BAD_VPP; | ||
463 | c->Vpp1 = c->Vpp2 = s->socket.Vpp = mod->Vpp1; | ||
464 | if (s->ops->set_socket(s, &s->socket)) | ||
465 | return CS_BAD_VPP; | ||
466 | } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) || | ||
467 | (mod->Attributes & CONF_VPP2_CHANGE_VALID)) | ||
468 | return CS_BAD_VPP; | ||
469 | |||
470 | return CS_SUCCESS; | ||
471 | } /* modify_configuration */ | ||
472 | EXPORT_SYMBOL(pcmcia_modify_configuration); | ||
473 | |||
474 | |||
475 | int pcmcia_release_configuration(client_handle_t handle) | ||
476 | { | ||
477 | pccard_io_map io = { 0, 0, 0, 0, 1 }; | ||
478 | struct pcmcia_socket *s; | ||
479 | int i; | ||
480 | |||
481 | if (CHECK_HANDLE(handle) || | ||
482 | !(handle->state & CLIENT_CONFIG_LOCKED)) | ||
483 | return CS_BAD_HANDLE; | ||
484 | handle->state &= ~CLIENT_CONFIG_LOCKED; | ||
485 | s = SOCKET(handle); | ||
486 | |||
487 | #ifdef CONFIG_CARDBUS | ||
488 | if (handle->state & CLIENT_CARDBUS) | ||
489 | return CS_SUCCESS; | ||
490 | #endif | ||
491 | |||
492 | if (!(handle->state & CLIENT_STALE)) { | ||
493 | config_t *c = CONFIG(handle); | ||
494 | if (--(s->lock_count) == 0) { | ||
495 | s->socket.flags = SS_OUTPUT_ENA; /* Is this correct? */ | ||
496 | s->socket.Vpp = 0; | ||
497 | s->socket.io_irq = 0; | ||
498 | s->ops->set_socket(s, &s->socket); | ||
499 | } | ||
500 | if (c->state & CONFIG_IO_REQ) | ||
501 | for (i = 0; i < MAX_IO_WIN; i++) { | ||
502 | if (s->io[i].NumPorts == 0) | ||
503 | continue; | ||
504 | s->io[i].Config--; | ||
505 | if (s->io[i].Config != 0) | ||
506 | continue; | ||
507 | io.map = i; | ||
508 | s->ops->set_io_map(s, &io); | ||
509 | } | ||
510 | c->state &= ~CONFIG_LOCKED; | ||
511 | } | ||
512 | |||
513 | return CS_SUCCESS; | ||
514 | } /* pcmcia_release_configuration */ | ||
515 | EXPORT_SYMBOL(pcmcia_release_configuration); | ||
516 | |||
517 | |||
518 | /** pcmcia_release_io | ||
519 | * | ||
520 | * Release_io() releases the I/O ranges allocated by a client. This | ||
521 | * may be invoked some time after a card ejection has already dumped | ||
522 | * the actual socket configuration, so if the client is "stale", we | ||
523 | * don't bother checking the port ranges against the current socket | ||
524 | * values. | ||
525 | */ | ||
526 | int pcmcia_release_io(client_handle_t handle, io_req_t *req) | ||
527 | { | ||
528 | struct pcmcia_socket *s; | ||
529 | |||
530 | if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IO_REQ)) | ||
531 | return CS_BAD_HANDLE; | ||
532 | handle->state &= ~CLIENT_IO_REQ; | ||
533 | s = SOCKET(handle); | ||
534 | |||
535 | #ifdef CONFIG_CARDBUS | ||
536 | if (handle->state & CLIENT_CARDBUS) | ||
537 | return CS_SUCCESS; | ||
538 | #endif | ||
539 | |||
540 | if (!(handle->state & CLIENT_STALE)) { | ||
541 | config_t *c = CONFIG(handle); | ||
542 | if (c->state & CONFIG_LOCKED) | ||
543 | return CS_CONFIGURATION_LOCKED; | ||
544 | if ((c->io.BasePort1 != req->BasePort1) || | ||
545 | (c->io.NumPorts1 != req->NumPorts1) || | ||
546 | (c->io.BasePort2 != req->BasePort2) || | ||
547 | (c->io.NumPorts2 != req->NumPorts2)) | ||
548 | return CS_BAD_ARGS; | ||
549 | c->state &= ~CONFIG_IO_REQ; | ||
550 | } | ||
551 | |||
552 | release_io_space(s, req->BasePort1, req->NumPorts1); | ||
553 | if (req->NumPorts2) | ||
554 | release_io_space(s, req->BasePort2, req->NumPorts2); | ||
555 | |||
556 | return CS_SUCCESS; | ||
557 | } /* pcmcia_release_io */ | ||
558 | EXPORT_SYMBOL(pcmcia_release_io); | ||
559 | |||
560 | |||
561 | int pcmcia_release_irq(client_handle_t handle, irq_req_t *req) | ||
562 | { | ||
563 | struct pcmcia_socket *s; | ||
564 | if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IRQ_REQ)) | ||
565 | return CS_BAD_HANDLE; | ||
566 | handle->state &= ~CLIENT_IRQ_REQ; | ||
567 | s = SOCKET(handle); | ||
568 | |||
569 | if (!(handle->state & CLIENT_STALE)) { | ||
570 | config_t *c = CONFIG(handle); | ||
571 | if (c->state & CONFIG_LOCKED) | ||
572 | return CS_CONFIGURATION_LOCKED; | ||
573 | if (c->irq.Attributes != req->Attributes) | ||
574 | return CS_BAD_ATTRIBUTE; | ||
575 | if (s->irq.AssignedIRQ != req->AssignedIRQ) | ||
576 | return CS_BAD_IRQ; | ||
577 | if (--s->irq.Config == 0) { | ||
578 | c->state &= ~CONFIG_IRQ_REQ; | ||
579 | s->irq.AssignedIRQ = 0; | ||
580 | } | ||
581 | } | ||
582 | |||
583 | if (req->Attributes & IRQ_HANDLE_PRESENT) { | ||
584 | free_irq(req->AssignedIRQ, req->Instance); | ||
585 | } | ||
586 | |||
587 | #ifdef CONFIG_PCMCIA_PROBE | ||
588 | pcmcia_used_irq[req->AssignedIRQ]--; | ||
589 | #endif | ||
590 | |||
591 | return CS_SUCCESS; | ||
592 | } /* pcmcia_release_irq */ | ||
593 | EXPORT_SYMBOL(pcmcia_release_irq); | ||
594 | |||
595 | |||
596 | int pcmcia_release_window(window_handle_t win) | ||
597 | { | ||
598 | struct pcmcia_socket *s; | ||
599 | |||
600 | if ((win == NULL) || (win->magic != WINDOW_MAGIC)) | ||
601 | return CS_BAD_HANDLE; | ||
602 | s = win->sock; | ||
603 | if (!(win->handle->state & CLIENT_WIN_REQ(win->index))) | ||
604 | return CS_BAD_HANDLE; | ||
605 | |||
606 | /* Shut down memory window */ | ||
607 | win->ctl.flags &= ~MAP_ACTIVE; | ||
608 | s->ops->set_mem_map(s, &win->ctl); | ||
609 | s->state &= ~SOCKET_WIN_REQ(win->index); | ||
610 | |||
611 | /* Release system memory */ | ||
612 | if (win->ctl.res) { | ||
613 | release_resource(win->ctl.res); | ||
614 | kfree(win->ctl.res); | ||
615 | win->ctl.res = NULL; | ||
616 | } | ||
617 | win->handle->state &= ~CLIENT_WIN_REQ(win->index); | ||
618 | |||
619 | win->magic = 0; | ||
620 | |||
621 | return CS_SUCCESS; | ||
622 | } /* pcmcia_release_window */ | ||
623 | EXPORT_SYMBOL(pcmcia_release_window); | ||
624 | |||
625 | |||
626 | int pcmcia_request_configuration(client_handle_t handle, | ||
627 | config_req_t *req) | ||
628 | { | ||
629 | int i; | ||
630 | u_int base; | ||
631 | struct pcmcia_socket *s; | ||
632 | config_t *c; | ||
633 | pccard_io_map iomap; | ||
634 | |||
635 | if (CHECK_HANDLE(handle)) | ||
636 | return CS_BAD_HANDLE; | ||
637 | s = SOCKET(handle); | ||
638 | if (!(s->state & SOCKET_PRESENT)) | ||
639 | return CS_NO_CARD; | ||
640 | |||
641 | #ifdef CONFIG_CARDBUS | ||
642 | if (handle->state & CLIENT_CARDBUS) | ||
643 | return CS_UNSUPPORTED_MODE; | ||
644 | #endif | ||
645 | |||
646 | if (req->IntType & INT_CARDBUS) | ||
647 | return CS_UNSUPPORTED_MODE; | ||
648 | c = CONFIG(handle); | ||
649 | if (c->state & CONFIG_LOCKED) | ||
650 | return CS_CONFIGURATION_LOCKED; | ||
651 | |||
652 | /* Do power control. We don't allow changes in Vcc. */ | ||
653 | if (s->socket.Vcc != req->Vcc) | ||
654 | return CS_BAD_VCC; | ||
655 | if (req->Vpp1 != req->Vpp2) | ||
656 | return CS_BAD_VPP; | ||
657 | s->socket.Vpp = req->Vpp1; | ||
658 | if (s->ops->set_socket(s, &s->socket)) | ||
659 | return CS_BAD_VPP; | ||
660 | |||
661 | c->Vcc = req->Vcc; c->Vpp1 = c->Vpp2 = req->Vpp1; | ||
662 | |||
663 | /* Pick memory or I/O card, DMA mode, interrupt */ | ||
664 | c->IntType = req->IntType; | ||
665 | c->Attributes = req->Attributes; | ||
666 | if (req->IntType & INT_MEMORY_AND_IO) | ||
667 | s->socket.flags |= SS_IOCARD; | ||
668 | if (req->IntType & INT_ZOOMED_VIDEO) | ||
669 | s->socket.flags |= SS_ZVCARD | SS_IOCARD; | ||
670 | if (req->Attributes & CONF_ENABLE_DMA) | ||
671 | s->socket.flags |= SS_DMA_MODE; | ||
672 | if (req->Attributes & CONF_ENABLE_SPKR) | ||
673 | s->socket.flags |= SS_SPKR_ENA; | ||
674 | if (req->Attributes & CONF_ENABLE_IRQ) | ||
675 | s->socket.io_irq = s->irq.AssignedIRQ; | ||
676 | else | ||
677 | s->socket.io_irq = 0; | ||
678 | s->ops->set_socket(s, &s->socket); | ||
679 | s->lock_count++; | ||
680 | |||
681 | /* Set up CIS configuration registers */ | ||
682 | base = c->ConfigBase = req->ConfigBase; | ||
683 | c->Present = c->CardValues = req->Present; | ||
684 | if (req->Present & PRESENT_COPY) { | ||
685 | c->Copy = req->Copy; | ||
686 | pcmcia_write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy); | ||
687 | } | ||
688 | if (req->Present & PRESENT_OPTION) { | ||
689 | if (s->functions == 1) { | ||
690 | c->Option = req->ConfigIndex & COR_CONFIG_MASK; | ||
691 | } else { | ||
692 | c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK; | ||
693 | c->Option |= COR_FUNC_ENA|COR_IREQ_ENA; | ||
694 | if (req->Present & PRESENT_IOBASE_0) | ||
695 | c->Option |= COR_ADDR_DECODE; | ||
696 | } | ||
697 | if (c->state & CONFIG_IRQ_REQ) | ||
698 | if (!(c->irq.Attributes & IRQ_FORCED_PULSE)) | ||
699 | c->Option |= COR_LEVEL_REQ; | ||
700 | pcmcia_write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option); | ||
701 | mdelay(40); | ||
702 | } | ||
703 | if (req->Present & PRESENT_STATUS) { | ||
704 | c->Status = req->Status; | ||
705 | pcmcia_write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &c->Status); | ||
706 | } | ||
707 | if (req->Present & PRESENT_PIN_REPLACE) { | ||
708 | c->Pin = req->Pin; | ||
709 | pcmcia_write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &c->Pin); | ||
710 | } | ||
711 | if (req->Present & PRESENT_EXT_STATUS) { | ||
712 | c->ExtStatus = req->ExtStatus; | ||
713 | pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus); | ||
714 | } | ||
715 | if (req->Present & PRESENT_IOBASE_0) { | ||
716 | u_char b = c->io.BasePort1 & 0xff; | ||
717 | pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b); | ||
718 | b = (c->io.BasePort1 >> 8) & 0xff; | ||
719 | pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b); | ||
720 | } | ||
721 | if (req->Present & PRESENT_IOSIZE) { | ||
722 | u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1; | ||
723 | pcmcia_write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b); | ||
724 | } | ||
725 | |||
726 | /* Configure I/O windows */ | ||
727 | if (c->state & CONFIG_IO_REQ) { | ||
728 | iomap.speed = io_speed; | ||
729 | for (i = 0; i < MAX_IO_WIN; i++) | ||
730 | if (s->io[i].NumPorts != 0) { | ||
731 | iomap.map = i; | ||
732 | iomap.flags = MAP_ACTIVE; | ||
733 | switch (s->io[i].Attributes & IO_DATA_PATH_WIDTH) { | ||
734 | case IO_DATA_PATH_WIDTH_16: | ||
735 | iomap.flags |= MAP_16BIT; break; | ||
736 | case IO_DATA_PATH_WIDTH_AUTO: | ||
737 | iomap.flags |= MAP_AUTOSZ; break; | ||
738 | default: | ||
739 | break; | ||
740 | } | ||
741 | iomap.start = s->io[i].BasePort; | ||
742 | iomap.stop = iomap.start + s->io[i].NumPorts - 1; | ||
743 | s->ops->set_io_map(s, &iomap); | ||
744 | s->io[i].Config++; | ||
745 | } | ||
746 | } | ||
747 | |||
748 | c->state |= CONFIG_LOCKED; | ||
749 | handle->state |= CLIENT_CONFIG_LOCKED; | ||
750 | return CS_SUCCESS; | ||
751 | } /* pcmcia_request_configuration */ | ||
752 | EXPORT_SYMBOL(pcmcia_request_configuration); | ||
753 | |||
754 | |||
755 | /** pcmcia_request_io | ||
756 | * | ||
757 | * Request_io() reserves ranges of port addresses for a socket. | ||
758 | * I have not implemented range sharing or alias addressing. | ||
759 | */ | ||
760 | int pcmcia_request_io(client_handle_t handle, io_req_t *req) | ||
761 | { | ||
762 | struct pcmcia_socket *s; | ||
763 | config_t *c; | ||
764 | |||
765 | if (CHECK_HANDLE(handle)) | ||
766 | return CS_BAD_HANDLE; | ||
767 | s = SOCKET(handle); | ||
768 | if (!(s->state & SOCKET_PRESENT)) | ||
769 | return CS_NO_CARD; | ||
770 | |||
771 | if (handle->state & CLIENT_CARDBUS) { | ||
772 | #ifdef CONFIG_CARDBUS | ||
773 | handle->state |= CLIENT_IO_REQ; | ||
774 | return CS_SUCCESS; | ||
775 | #else | ||
776 | return CS_UNSUPPORTED_FUNCTION; | ||
777 | #endif | ||
778 | } | ||
779 | |||
780 | if (!req) | ||
781 | return CS_UNSUPPORTED_MODE; | ||
782 | c = CONFIG(handle); | ||
783 | if (c->state & CONFIG_LOCKED) | ||
784 | return CS_CONFIGURATION_LOCKED; | ||
785 | if (c->state & CONFIG_IO_REQ) | ||
786 | return CS_IN_USE; | ||
787 | if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)) | ||
788 | return CS_BAD_ATTRIBUTE; | ||
789 | if ((req->NumPorts2 > 0) && | ||
790 | (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))) | ||
791 | return CS_BAD_ATTRIBUTE; | ||
792 | |||
793 | if (alloc_io_space(s, req->Attributes1, &req->BasePort1, | ||
794 | req->NumPorts1, req->IOAddrLines)) | ||
795 | return CS_IN_USE; | ||
796 | |||
797 | if (req->NumPorts2) { | ||
798 | if (alloc_io_space(s, req->Attributes2, &req->BasePort2, | ||
799 | req->NumPorts2, req->IOAddrLines)) { | ||
800 | release_io_space(s, req->BasePort1, req->NumPorts1); | ||
801 | return CS_IN_USE; | ||
802 | } | ||
803 | } | ||
804 | |||
805 | c->io = *req; | ||
806 | c->state |= CONFIG_IO_REQ; | ||
807 | handle->state |= CLIENT_IO_REQ; | ||
808 | return CS_SUCCESS; | ||
809 | } /* pcmcia_request_io */ | ||
810 | EXPORT_SYMBOL(pcmcia_request_io); | ||
811 | |||
812 | |||
813 | /** pcmcia_request_irq | ||
814 | * | ||
815 | * Request_irq() reserves an irq for this client. | ||
816 | * | ||
817 | * Also, since Linux only reserves irq's when they are actually | ||
818 | * hooked, we don't guarantee that an irq will still be available | ||
819 | * when the configuration is locked. Now that I think about it, | ||
820 | * there might be a way to fix this using a dummy handler. | ||
821 | */ | ||
822 | |||
823 | #ifdef CONFIG_PCMCIA_PROBE | ||
824 | static irqreturn_t test_action(int cpl, void *dev_id, struct pt_regs *regs) | ||
825 | { | ||
826 | return IRQ_NONE; | ||
827 | } | ||
828 | #endif | ||
829 | |||
830 | int pcmcia_request_irq(client_handle_t handle, irq_req_t *req) | ||
831 | { | ||
832 | struct pcmcia_socket *s; | ||
833 | config_t *c; | ||
834 | int ret = CS_IN_USE, irq = 0; | ||
835 | struct pcmcia_device *p_dev = handle_to_pdev(handle); | ||
836 | |||
837 | if (CHECK_HANDLE(handle)) | ||
838 | return CS_BAD_HANDLE; | ||
839 | s = SOCKET(handle); | ||
840 | if (!(s->state & SOCKET_PRESENT)) | ||
841 | return CS_NO_CARD; | ||
842 | c = CONFIG(handle); | ||
843 | if (c->state & CONFIG_LOCKED) | ||
844 | return CS_CONFIGURATION_LOCKED; | ||
845 | if (c->state & CONFIG_IRQ_REQ) | ||
846 | return CS_IN_USE; | ||
847 | |||
848 | #ifdef CONFIG_PCMCIA_PROBE | ||
849 | if (s->irq.AssignedIRQ != 0) { | ||
850 | /* If the interrupt is already assigned, it must be the same */ | ||
851 | irq = s->irq.AssignedIRQ; | ||
852 | } else { | ||
853 | int try; | ||
854 | u32 mask = s->irq_mask; | ||
855 | void *data = NULL; | ||
856 | |||
857 | for (try = 0; try < 64; try++) { | ||
858 | irq = try % 32; | ||
859 | |||
860 | /* marked as available by driver, and not blocked by userspace? */ | ||
861 | if (!((mask >> irq) & 1)) | ||
862 | continue; | ||
863 | |||
864 | /* avoid an IRQ which is already used by a PCMCIA card */ | ||
865 | if ((try < 32) && pcmcia_used_irq[irq]) | ||
866 | continue; | ||
867 | |||
868 | /* register the correct driver, if possible, of check whether | ||
869 | * registering a dummy handle works, i.e. if the IRQ isn't | ||
870 | * marked as used by the kernel resource management core */ | ||
871 | ret = request_irq(irq, | ||
872 | (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Handler : test_action, | ||
873 | ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || | ||
874 | (s->functions > 1) || | ||
875 | (irq == s->pci_irq)) ? SA_SHIRQ : 0, | ||
876 | p_dev->dev.bus_id, | ||
877 | (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Instance : data); | ||
878 | if (!ret) { | ||
879 | if (!(req->Attributes & IRQ_HANDLE_PRESENT)) | ||
880 | free_irq(irq, data); | ||
881 | break; | ||
882 | } | ||
883 | } | ||
884 | } | ||
885 | #endif | ||
886 | if (ret) { | ||
887 | if (!s->pci_irq) | ||
888 | return ret; | ||
889 | irq = s->pci_irq; | ||
890 | } | ||
891 | |||
892 | if (ret && req->Attributes & IRQ_HANDLE_PRESENT) { | ||
893 | if (request_irq(irq, req->Handler, | ||
894 | ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || | ||
895 | (s->functions > 1) || | ||
896 | (irq == s->pci_irq)) ? SA_SHIRQ : 0, | ||
897 | p_dev->dev.bus_id, req->Instance)) | ||
898 | return CS_IN_USE; | ||
899 | } | ||
900 | |||
901 | c->irq.Attributes = req->Attributes; | ||
902 | s->irq.AssignedIRQ = req->AssignedIRQ = irq; | ||
903 | s->irq.Config++; | ||
904 | |||
905 | c->state |= CONFIG_IRQ_REQ; | ||
906 | handle->state |= CLIENT_IRQ_REQ; | ||
907 | |||
908 | #ifdef CONFIG_PCMCIA_PROBE | ||
909 | pcmcia_used_irq[irq]++; | ||
910 | #endif | ||
911 | |||
912 | return CS_SUCCESS; | ||
913 | } /* pcmcia_request_irq */ | ||
914 | EXPORT_SYMBOL(pcmcia_request_irq); | ||
915 | |||
916 | |||
917 | /** pcmcia_request_window | ||
918 | * | ||
919 | * Request_window() establishes a mapping between card memory space | ||
920 | * and system memory space. | ||
921 | */ | ||
922 | int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle_t *wh) | ||
923 | { | ||
924 | struct pcmcia_socket *s; | ||
925 | window_t *win; | ||
926 | u_long align; | ||
927 | int w; | ||
928 | |||
929 | if (CHECK_HANDLE(*handle)) | ||
930 | return CS_BAD_HANDLE; | ||
931 | s = (*handle)->Socket; | ||
932 | if (!(s->state & SOCKET_PRESENT)) | ||
933 | return CS_NO_CARD; | ||
934 | if (req->Attributes & (WIN_PAGED | WIN_SHARED)) | ||
935 | return CS_BAD_ATTRIBUTE; | ||
936 | |||
937 | /* Window size defaults to smallest available */ | ||
938 | if (req->Size == 0) | ||
939 | req->Size = s->map_size; | ||
940 | align = (((s->features & SS_CAP_MEM_ALIGN) || | ||
941 | (req->Attributes & WIN_STRICT_ALIGN)) ? | ||
942 | req->Size : s->map_size); | ||
943 | if (req->Size & (s->map_size-1)) | ||
944 | return CS_BAD_SIZE; | ||
945 | if ((req->Base && (s->features & SS_CAP_STATIC_MAP)) || | ||
946 | (req->Base & (align-1))) | ||
947 | return CS_BAD_BASE; | ||
948 | if (req->Base) | ||
949 | align = 0; | ||
950 | |||
951 | /* Allocate system memory window */ | ||
952 | for (w = 0; w < MAX_WIN; w++) | ||
953 | if (!(s->state & SOCKET_WIN_REQ(w))) break; | ||
954 | if (w == MAX_WIN) | ||
955 | return CS_OUT_OF_RESOURCE; | ||
956 | |||
957 | win = &s->win[w]; | ||
958 | win->magic = WINDOW_MAGIC; | ||
959 | win->index = w; | ||
960 | win->handle = *handle; | ||
961 | win->sock = s; | ||
962 | |||
963 | if (!(s->features & SS_CAP_STATIC_MAP)) { | ||
964 | win->ctl.res = pcmcia_find_mem_region(req->Base, req->Size, align, | ||
965 | (req->Attributes & WIN_MAP_BELOW_1MB), s); | ||
966 | if (!win->ctl.res) | ||
967 | return CS_IN_USE; | ||
968 | } | ||
969 | (*handle)->state |= CLIENT_WIN_REQ(w); | ||
970 | |||
971 | /* Configure the socket controller */ | ||
972 | win->ctl.map = w+1; | ||
973 | win->ctl.flags = 0; | ||
974 | win->ctl.speed = req->AccessSpeed; | ||
975 | if (req->Attributes & WIN_MEMORY_TYPE) | ||
976 | win->ctl.flags |= MAP_ATTRIB; | ||
977 | if (req->Attributes & WIN_ENABLE) | ||
978 | win->ctl.flags |= MAP_ACTIVE; | ||
979 | if (req->Attributes & WIN_DATA_WIDTH_16) | ||
980 | win->ctl.flags |= MAP_16BIT; | ||
981 | if (req->Attributes & WIN_USE_WAIT) | ||
982 | win->ctl.flags |= MAP_USE_WAIT; | ||
983 | win->ctl.card_start = 0; | ||
984 | if (s->ops->set_mem_map(s, &win->ctl) != 0) | ||
985 | return CS_BAD_ARGS; | ||
986 | s->state |= SOCKET_WIN_REQ(w); | ||
987 | |||
988 | /* Return window handle */ | ||
989 | if (s->features & SS_CAP_STATIC_MAP) { | ||
990 | req->Base = win->ctl.static_start; | ||
991 | } else { | ||
992 | req->Base = win->ctl.res->start; | ||
993 | } | ||
994 | *wh = win; | ||
995 | |||
996 | return CS_SUCCESS; | ||
997 | } /* pcmcia_request_window */ | ||
998 | EXPORT_SYMBOL(pcmcia_request_window); | ||
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index b6843f8d300d..0668384ebc8b 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c | |||
@@ -72,7 +72,7 @@ int pcmcia_adjust_resource_info(adjust_t *adj) | |||
72 | /* you can't use the old interface if the new | 72 | /* you can't use the old interface if the new |
73 | * one was used before */ | 73 | * one was used before */ |
74 | spin_lock_irqsave(&s->lock, flags); | 74 | spin_lock_irqsave(&s->lock, flags); |
75 | if ((s->resource_setup_done) && | 75 | if ((s->resource_setup_new) && |
76 | !(s->resource_setup_old)) { | 76 | !(s->resource_setup_old)) { |
77 | spin_unlock_irqrestore(&s->lock, flags); | 77 | spin_unlock_irqrestore(&s->lock, flags); |
78 | continue; | 78 | continue; |
@@ -105,29 +105,32 @@ void pcmcia_validate_mem(struct pcmcia_socket *s) | |||
105 | } | 105 | } |
106 | EXPORT_SYMBOL(pcmcia_validate_mem); | 106 | EXPORT_SYMBOL(pcmcia_validate_mem); |
107 | 107 | ||
108 | int adjust_io_region(struct resource *res, unsigned long r_start, | 108 | int pcmcia_adjust_io_region(struct resource *res, unsigned long r_start, |
109 | unsigned long r_end, struct pcmcia_socket *s) | 109 | unsigned long r_end, struct pcmcia_socket *s) |
110 | { | 110 | { |
111 | if (s->resource_ops->adjust_io_region) | 111 | if (s->resource_ops->adjust_io_region) |
112 | return s->resource_ops->adjust_io_region(res, r_start, r_end, s); | 112 | return s->resource_ops->adjust_io_region(res, r_start, r_end, s); |
113 | return -ENOMEM; | 113 | return -ENOMEM; |
114 | } | 114 | } |
115 | EXPORT_SYMBOL(pcmcia_adjust_io_region); | ||
115 | 116 | ||
116 | struct resource *find_io_region(unsigned long base, int num, | 117 | struct resource *pcmcia_find_io_region(unsigned long base, int num, |
117 | unsigned long align, struct pcmcia_socket *s) | 118 | unsigned long align, struct pcmcia_socket *s) |
118 | { | 119 | { |
119 | if (s->resource_ops->find_io) | 120 | if (s->resource_ops->find_io) |
120 | return s->resource_ops->find_io(base, num, align, s); | 121 | return s->resource_ops->find_io(base, num, align, s); |
121 | return NULL; | 122 | return NULL; |
122 | } | 123 | } |
124 | EXPORT_SYMBOL(pcmcia_find_io_region); | ||
123 | 125 | ||
124 | struct resource *find_mem_region(u_long base, u_long num, u_long align, | 126 | struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align, |
125 | int low, struct pcmcia_socket *s) | 127 | int low, struct pcmcia_socket *s) |
126 | { | 128 | { |
127 | if (s->resource_ops->find_mem) | 129 | if (s->resource_ops->find_mem) |
128 | return s->resource_ops->find_mem(base, num, align, low, s); | 130 | return s->resource_ops->find_mem(base, num, align, low, s); |
129 | return NULL; | 131 | return NULL; |
130 | } | 132 | } |
133 | EXPORT_SYMBOL(pcmcia_find_mem_region); | ||
131 | 134 | ||
132 | void release_resource_db(struct pcmcia_socket *s) | 135 | void release_resource_db(struct pcmcia_socket *s) |
133 | { | 136 | { |
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 5876bab7c14c..c42455d20eb6 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c | |||
@@ -372,6 +372,9 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) | |||
372 | base, base+num-1); | 372 | base, base+num-1); |
373 | bad = fail = 0; | 373 | bad = fail = 0; |
374 | step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff); | 374 | step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff); |
375 | /* don't allow too large steps */ | ||
376 | if (step > 0x800000) | ||
377 | step = 0x800000; | ||
375 | /* cis_readable wants to map 2x map_size */ | 378 | /* cis_readable wants to map 2x map_size */ |
376 | if (step < 2 * s->map_size) | 379 | if (step < 2 * s->map_size) |
377 | step = 2 * s->map_size; | 380 | step = 2 * s->map_size; |
@@ -465,8 +468,7 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | |||
465 | 468 | ||
466 | for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) { | 469 | for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) { |
467 | mm = *m; | 470 | mm = *m; |
468 | if (do_mem_probe(mm.base, mm.num, s)) | 471 | do_mem_probe(mm.base, mm.num, s); |
469 | break; | ||
470 | } | 472 | } |
471 | } | 473 | } |
472 | 474 | ||
@@ -601,7 +603,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star | |||
601 | 603 | ||
602 | ======================================================================*/ | 604 | ======================================================================*/ |
603 | 605 | ||
604 | struct resource *nonstatic_find_io_region(unsigned long base, int num, | 606 | static struct resource *nonstatic_find_io_region(unsigned long base, int num, |
605 | unsigned long align, struct pcmcia_socket *s) | 607 | unsigned long align, struct pcmcia_socket *s) |
606 | { | 608 | { |
607 | struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.class_id); | 609 | struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.class_id); |
@@ -635,8 +637,8 @@ struct resource *nonstatic_find_io_region(unsigned long base, int num, | |||
635 | return res; | 637 | return res; |
636 | } | 638 | } |
637 | 639 | ||
638 | struct resource * nonstatic_find_mem_region(u_long base, u_long num, u_long align, | 640 | static struct resource * nonstatic_find_mem_region(u_long base, u_long num, |
639 | int low, struct pcmcia_socket *s) | 641 | u_long align, int low, struct pcmcia_socket *s) |
640 | { | 642 | { |
641 | struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id); | 643 | struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id); |
642 | struct socket_data *s_data = s->resource_data; | 644 | struct socket_data *s_data = s->resource_data; |
@@ -683,27 +685,23 @@ struct resource * nonstatic_find_mem_region(u_long base, u_long num, u_long alig | |||
683 | } | 685 | } |
684 | 686 | ||
685 | 687 | ||
686 | static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj) | 688 | static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end) |
687 | { | 689 | { |
688 | u_long base, num; | ||
689 | struct socket_data *data = s->resource_data; | 690 | struct socket_data *data = s->resource_data; |
690 | int ret; | 691 | unsigned long size = end - start + 1; |
691 | 692 | int ret = 0; | |
692 | base = adj->resource.memory.Base; | ||
693 | num = adj->resource.memory.Size; | ||
694 | if ((num == 0) || (base+num-1 < base)) | ||
695 | return CS_BAD_SIZE; | ||
696 | 693 | ||
697 | ret = CS_SUCCESS; | 694 | if (end <= start) |
695 | return -EINVAL; | ||
698 | 696 | ||
699 | down(&rsrc_sem); | 697 | down(&rsrc_sem); |
700 | switch (adj->Action) { | 698 | switch (action) { |
701 | case ADD_MANAGED_RESOURCE: | 699 | case ADD_MANAGED_RESOURCE: |
702 | ret = add_interval(&data->mem_db, base, num); | 700 | ret = add_interval(&data->mem_db, start, size); |
703 | break; | 701 | break; |
704 | case REMOVE_MANAGED_RESOURCE: | 702 | case REMOVE_MANAGED_RESOURCE: |
705 | ret = sub_interval(&data->mem_db, base, num); | 703 | ret = sub_interval(&data->mem_db, start, size); |
706 | if (ret == CS_SUCCESS) { | 704 | if (!ret) { |
707 | struct pcmcia_socket *socket; | 705 | struct pcmcia_socket *socket; |
708 | down_read(&pcmcia_socket_list_rwsem); | 706 | down_read(&pcmcia_socket_list_rwsem); |
709 | list_for_each_entry(socket, &pcmcia_socket_list, socket_list) | 707 | list_for_each_entry(socket, &pcmcia_socket_list, socket_list) |
@@ -712,7 +710,7 @@ static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj) | |||
712 | } | 710 | } |
713 | break; | 711 | break; |
714 | default: | 712 | default: |
715 | ret = CS_UNSUPPORTED_FUNCTION; | 713 | ret = -EINVAL; |
716 | } | 714 | } |
717 | up(&rsrc_sem); | 715 | up(&rsrc_sem); |
718 | 716 | ||
@@ -720,36 +718,35 @@ static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj) | |||
720 | } | 718 | } |
721 | 719 | ||
722 | 720 | ||
723 | static int adjust_io(struct pcmcia_socket *s, adjust_t *adj) | 721 | static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end) |
724 | { | 722 | { |
725 | struct socket_data *data = s->resource_data; | 723 | struct socket_data *data = s->resource_data; |
726 | kio_addr_t base, num; | 724 | unsigned long size = end - start + 1; |
727 | int ret = CS_SUCCESS; | 725 | int ret = 0; |
728 | 726 | ||
729 | base = adj->resource.io.BasePort; | 727 | if (end <= start) |
730 | num = adj->resource.io.NumPorts; | 728 | return -EINVAL; |
731 | if ((base < 0) || (base > 0xffff)) | 729 | |
732 | return CS_BAD_BASE; | 730 | if (end > IO_SPACE_LIMIT) |
733 | if ((num <= 0) || (base+num > 0x10000) || (base+num <= base)) | 731 | return -EINVAL; |
734 | return CS_BAD_SIZE; | ||
735 | 732 | ||
736 | down(&rsrc_sem); | 733 | down(&rsrc_sem); |
737 | switch (adj->Action) { | 734 | switch (action) { |
738 | case ADD_MANAGED_RESOURCE: | 735 | case ADD_MANAGED_RESOURCE: |
739 | if (add_interval(&data->io_db, base, num) != 0) { | 736 | if (add_interval(&data->io_db, start, size) != 0) { |
740 | ret = CS_IN_USE; | 737 | ret = -EBUSY; |
741 | break; | 738 | break; |
742 | } | 739 | } |
743 | #ifdef CONFIG_PCMCIA_PROBE | 740 | #ifdef CONFIG_PCMCIA_PROBE |
744 | if (probe_io) | 741 | if (probe_io) |
745 | do_io_probe(s, base, num); | 742 | do_io_probe(s, start, size); |
746 | #endif | 743 | #endif |
747 | break; | 744 | break; |
748 | case REMOVE_MANAGED_RESOURCE: | 745 | case REMOVE_MANAGED_RESOURCE: |
749 | sub_interval(&data->io_db, base, num); | 746 | sub_interval(&data->io_db, start, size); |
750 | break; | 747 | break; |
751 | default: | 748 | default: |
752 | ret = CS_UNSUPPORTED_FUNCTION; | 749 | ret = -EINVAL; |
753 | break; | 750 | break; |
754 | } | 751 | } |
755 | up(&rsrc_sem); | 752 | up(&rsrc_sem); |
@@ -760,15 +757,82 @@ static int adjust_io(struct pcmcia_socket *s, adjust_t *adj) | |||
760 | 757 | ||
761 | static int nonstatic_adjust_resource_info(struct pcmcia_socket *s, adjust_t *adj) | 758 | static int nonstatic_adjust_resource_info(struct pcmcia_socket *s, adjust_t *adj) |
762 | { | 759 | { |
760 | unsigned long end; | ||
761 | |||
763 | switch (adj->Resource) { | 762 | switch (adj->Resource) { |
764 | case RES_MEMORY_RANGE: | 763 | case RES_MEMORY_RANGE: |
765 | return adjust_memory(s, adj); | 764 | end = adj->resource.memory.Base + adj->resource.memory.Size - 1; |
765 | return adjust_memory(s, adj->Action, adj->resource.memory.Base, end); | ||
766 | case RES_IO_RANGE: | 766 | case RES_IO_RANGE: |
767 | return adjust_io(s, adj); | 767 | end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1; |
768 | return adjust_io(s, adj->Action, adj->resource.io.BasePort, end); | ||
768 | } | 769 | } |
769 | return CS_UNSUPPORTED_FUNCTION; | 770 | return CS_UNSUPPORTED_FUNCTION; |
770 | } | 771 | } |
771 | 772 | ||
773 | #ifdef CONFIG_PCI | ||
774 | static int nonstatic_autoadd_resources(struct pcmcia_socket *s) | ||
775 | { | ||
776 | struct resource *res; | ||
777 | int i, done = 0; | ||
778 | |||
779 | if (!s->cb_dev || !s->cb_dev->bus) | ||
780 | return -ENODEV; | ||
781 | |||
782 | #if defined(CONFIG_X86) || defined(CONFIG_X86_64) | ||
783 | /* If this is the root bus, the risk of hitting | ||
784 | * some strange system devices which aren't protected | ||
785 | * by either ACPI resource tables or properly requested | ||
786 | * resources is too big. Therefore, don't do auto-adding | ||
787 | * of resources at the moment. | ||
788 | */ | ||
789 | if (s->cb_dev->bus->number == 0) | ||
790 | return -EINVAL; | ||
791 | #endif | ||
792 | |||
793 | for (i=0; i < PCI_BUS_NUM_RESOURCES; i++) { | ||
794 | res = s->cb_dev->bus->resource[i]; | ||
795 | if (!res) | ||
796 | continue; | ||
797 | |||
798 | if (res->flags & IORESOURCE_IO) { | ||
799 | if (res == &ioport_resource) | ||
800 | continue; | ||
801 | printk(KERN_INFO "pcmcia: parent PCI bridge I/O window: 0x%lx - 0x%lx\n", | ||
802 | res->start, res->end); | ||
803 | if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end)) | ||
804 | done |= IORESOURCE_IO; | ||
805 | |||
806 | } | ||
807 | |||
808 | if (res->flags & IORESOURCE_MEM) { | ||
809 | if (res == &iomem_resource) | ||
810 | continue; | ||
811 | printk(KERN_INFO "pcmcia: parent PCI bridge Memory window: 0x%lx - 0x%lx\n", | ||
812 | res->start, res->end); | ||
813 | if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end)) | ||
814 | done |= IORESOURCE_MEM; | ||
815 | } | ||
816 | } | ||
817 | |||
818 | /* if we got at least one of IO, and one of MEM, we can be glad and | ||
819 | * activate the PCMCIA subsystem */ | ||
820 | if (done & (IORESOURCE_MEM | IORESOURCE_IO)) | ||
821 | s->resource_setup_done = 1; | ||
822 | |||
823 | return 0; | ||
824 | } | ||
825 | |||
826 | #else | ||
827 | |||
828 | static inline int nonstatic_autoadd_resources(struct pcmcia_socket *s) | ||
829 | { | ||
830 | return -ENODEV; | ||
831 | } | ||
832 | |||
833 | #endif | ||
834 | |||
835 | |||
772 | static int nonstatic_init(struct pcmcia_socket *s) | 836 | static int nonstatic_init(struct pcmcia_socket *s) |
773 | { | 837 | { |
774 | struct socket_data *data; | 838 | struct socket_data *data; |
@@ -783,6 +847,8 @@ static int nonstatic_init(struct pcmcia_socket *s) | |||
783 | 847 | ||
784 | s->resource_data = (void *) data; | 848 | s->resource_data = (void *) data; |
785 | 849 | ||
850 | nonstatic_autoadd_resources(s); | ||
851 | |||
786 | return 0; | 852 | return 0; |
787 | } | 853 | } |
788 | 854 | ||
@@ -845,17 +911,16 @@ static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size | |||
845 | { | 911 | { |
846 | struct pcmcia_socket *s = class_get_devdata(class_dev); | 912 | struct pcmcia_socket *s = class_get_devdata(class_dev); |
847 | unsigned long start_addr, end_addr; | 913 | unsigned long start_addr, end_addr; |
848 | unsigned int add = 1; | 914 | unsigned int add = ADD_MANAGED_RESOURCE; |
849 | adjust_t adj; | ||
850 | ssize_t ret = 0; | 915 | ssize_t ret = 0; |
851 | 916 | ||
852 | ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr); | 917 | ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr); |
853 | if (ret != 2) { | 918 | if (ret != 2) { |
854 | ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr); | 919 | ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr); |
855 | add = 0; | 920 | add = REMOVE_MANAGED_RESOURCE; |
856 | if (ret != 2) { | 921 | if (ret != 2) { |
857 | ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr); | 922 | ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr); |
858 | add = 1; | 923 | add = ADD_MANAGED_RESOURCE; |
859 | if (ret != 2) | 924 | if (ret != 2) |
860 | return -EINVAL; | 925 | return -EINVAL; |
861 | } | 926 | } |
@@ -863,12 +928,9 @@ static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size | |||
863 | if (end_addr <= start_addr) | 928 | if (end_addr <= start_addr) |
864 | return -EINVAL; | 929 | return -EINVAL; |
865 | 930 | ||
866 | adj.Action = add ? ADD_MANAGED_RESOURCE : REMOVE_MANAGED_RESOURCE; | 931 | ret = adjust_io(s, add, start_addr, end_addr); |
867 | adj.Resource = RES_IO_RANGE; | 932 | if (!ret) |
868 | adj.resource.io.BasePort = start_addr; | 933 | s->resource_setup_new = 1; |
869 | adj.resource.io.NumPorts = end_addr - start_addr + 1; | ||
870 | |||
871 | ret = adjust_io(s, &adj); | ||
872 | 934 | ||
873 | return ret ? ret : count; | 935 | return ret ? ret : count; |
874 | } | 936 | } |
@@ -901,17 +963,16 @@ static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, siz | |||
901 | { | 963 | { |
902 | struct pcmcia_socket *s = class_get_devdata(class_dev); | 964 | struct pcmcia_socket *s = class_get_devdata(class_dev); |
903 | unsigned long start_addr, end_addr; | 965 | unsigned long start_addr, end_addr; |
904 | unsigned int add = 1; | 966 | unsigned int add = ADD_MANAGED_RESOURCE; |
905 | adjust_t adj; | ||
906 | ssize_t ret = 0; | 967 | ssize_t ret = 0; |
907 | 968 | ||
908 | ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr); | 969 | ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr); |
909 | if (ret != 2) { | 970 | if (ret != 2) { |
910 | ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr); | 971 | ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr); |
911 | add = 0; | 972 | add = REMOVE_MANAGED_RESOURCE; |
912 | if (ret != 2) { | 973 | if (ret != 2) { |
913 | ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr); | 974 | ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr); |
914 | add = 1; | 975 | add = ADD_MANAGED_RESOURCE; |
915 | if (ret != 2) | 976 | if (ret != 2) |
916 | return -EINVAL; | 977 | return -EINVAL; |
917 | } | 978 | } |
@@ -919,12 +980,9 @@ static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, siz | |||
919 | if (end_addr <= start_addr) | 980 | if (end_addr <= start_addr) |
920 | return -EINVAL; | 981 | return -EINVAL; |
921 | 982 | ||
922 | adj.Action = add ? ADD_MANAGED_RESOURCE : REMOVE_MANAGED_RESOURCE; | 983 | ret = adjust_memory(s, add, start_addr, end_addr); |
923 | adj.Resource = RES_MEMORY_RANGE; | 984 | if (!ret) |
924 | adj.resource.memory.Base = start_addr; | 985 | s->resource_setup_new = 1; |
925 | adj.resource.memory.Size = end_addr - start_addr + 1; | ||
926 | |||
927 | ret = adjust_memory(s, &adj); | ||
928 | 986 | ||
929 | return ret ? ret : count; | 987 | return ret ? ret : count; |
930 | } | 988 | } |
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index 8eed03938214..fcef54c1c2da 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c | |||
@@ -163,28 +163,164 @@ static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, | |||
163 | return -EINVAL; | 163 | return -EINVAL; |
164 | 164 | ||
165 | spin_lock_irqsave(&s->lock, flags); | 165 | spin_lock_irqsave(&s->lock, flags); |
166 | if (!s->resource_setup_done) { | 166 | if (!s->resource_setup_done) |
167 | s->resource_setup_done = 1; | 167 | s->resource_setup_done = 1; |
168 | spin_unlock_irqrestore(&s->lock, flags); | 168 | spin_unlock_irqrestore(&s->lock, flags); |
169 | |||
170 | down(&s->skt_sem); | ||
171 | if ((s->callback) && | ||
172 | (s->state & SOCKET_PRESENT) && | ||
173 | !(s->state & SOCKET_CARDBUS)) { | ||
174 | if (try_module_get(s->callback->owner)) { | ||
175 | s->callback->requery(s); | ||
176 | module_put(s->callback->owner); | ||
177 | } | ||
178 | } | ||
179 | up(&s->skt_sem); | ||
180 | |||
181 | return count; | ||
182 | } | ||
183 | static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource); | ||
184 | |||
185 | |||
186 | static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off, size_t count) | ||
187 | { | ||
188 | tuple_t tuple; | ||
189 | int status, i; | ||
190 | loff_t pointer = 0; | ||
191 | ssize_t ret = 0; | ||
192 | u_char *tuplebuffer; | ||
193 | u_char *tempbuffer; | ||
194 | |||
195 | tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL); | ||
196 | if (!tuplebuffer) | ||
197 | return -ENOMEM; | ||
198 | |||
199 | tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL); | ||
200 | if (!tempbuffer) { | ||
201 | ret = -ENOMEM; | ||
202 | goto free_tuple; | ||
203 | } | ||
204 | |||
205 | memset(&tuple, 0, sizeof(tuple_t)); | ||
206 | |||
207 | tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON; | ||
208 | tuple.DesiredTuple = RETURN_FIRST_TUPLE; | ||
209 | tuple.TupleOffset = 0; | ||
210 | |||
211 | status = pccard_get_first_tuple(s, BIND_FN_ALL, &tuple); | ||
212 | while (!status) { | ||
213 | tuple.TupleData = tuplebuffer; | ||
214 | tuple.TupleDataMax = 255; | ||
215 | memset(tuplebuffer, 0, sizeof(u_char) * 255); | ||
169 | 216 | ||
217 | status = pccard_get_tuple_data(s, &tuple); | ||
218 | if (status) | ||
219 | break; | ||
220 | |||
221 | if (off < (pointer + 2 + tuple.TupleDataLen)) { | ||
222 | tempbuffer[0] = tuple.TupleCode & 0xff; | ||
223 | tempbuffer[1] = tuple.TupleLink & 0xff; | ||
224 | for (i = 0; i < tuple.TupleDataLen; i++) | ||
225 | tempbuffer[i + 2] = tuplebuffer[i] & 0xff; | ||
226 | |||
227 | for (i = 0; i < (2 + tuple.TupleDataLen); i++) { | ||
228 | if (((i + pointer) >= off) && | ||
229 | (i + pointer) < (off + count)) { | ||
230 | buf[ret] = tempbuffer[i]; | ||
231 | ret++; | ||
232 | } | ||
233 | } | ||
234 | } | ||
235 | |||
236 | pointer += 2 + tuple.TupleDataLen; | ||
237 | |||
238 | if (pointer >= (off + count)) | ||
239 | break; | ||
240 | |||
241 | if (tuple.TupleCode == CISTPL_END) | ||
242 | break; | ||
243 | status = pccard_get_next_tuple(s, BIND_FN_ALL, &tuple); | ||
244 | } | ||
245 | |||
246 | kfree(tempbuffer); | ||
247 | free_tuple: | ||
248 | kfree(tuplebuffer); | ||
249 | |||
250 | return (ret); | ||
251 | } | ||
252 | |||
253 | static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||
254 | { | ||
255 | unsigned int size = 0x200; | ||
256 | |||
257 | if (off >= size) | ||
258 | count = 0; | ||
259 | else { | ||
260 | struct pcmcia_socket *s; | ||
261 | cisinfo_t cisinfo; | ||
262 | |||
263 | if (off + count > size) | ||
264 | count = size - off; | ||
265 | |||
266 | s = to_socket(container_of(kobj, struct class_device, kobj)); | ||
267 | |||
268 | if (!(s->state & SOCKET_PRESENT)) | ||
269 | return -ENODEV; | ||
270 | if (pccard_validate_cis(s, BIND_FN_ALL, &cisinfo)) | ||
271 | return -EIO; | ||
272 | if (!cisinfo.Chains) | ||
273 | return -ENODATA; | ||
274 | |||
275 | count = pccard_extract_cis(s, buf, off, count); | ||
276 | } | ||
277 | |||
278 | return (count); | ||
279 | } | ||
280 | |||
281 | static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||
282 | { | ||
283 | struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj)); | ||
284 | cisdump_t *cis; | ||
285 | ssize_t ret = count; | ||
286 | |||
287 | if (off) | ||
288 | return -EINVAL; | ||
289 | |||
290 | if (count >= 0x200) | ||
291 | return -EINVAL; | ||
292 | |||
293 | if (!(s->state & SOCKET_PRESENT)) | ||
294 | return -ENODEV; | ||
295 | |||
296 | cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL); | ||
297 | if (!cis) | ||
298 | return -ENOMEM; | ||
299 | memset(cis, 0, sizeof(cisdump_t)); | ||
300 | |||
301 | cis->Length = count + 1; | ||
302 | memcpy(cis->Data, buf, count); | ||
303 | |||
304 | if (pcmcia_replace_cis(s, cis)) | ||
305 | ret = -EIO; | ||
306 | |||
307 | kfree(cis); | ||
308 | |||
309 | if (!ret) { | ||
170 | down(&s->skt_sem); | 310 | down(&s->skt_sem); |
171 | if ((s->callback) && | 311 | if ((s->callback) && (s->state & SOCKET_PRESENT) && |
172 | (s->state & SOCKET_PRESENT) && | ||
173 | !(s->state & SOCKET_CARDBUS)) { | 312 | !(s->state & SOCKET_CARDBUS)) { |
174 | if (try_module_get(s->callback->owner)) { | 313 | if (try_module_get(s->callback->owner)) { |
175 | s->callback->resources_done(s); | 314 | s->callback->requery(s); |
176 | module_put(s->callback->owner); | 315 | module_put(s->callback->owner); |
177 | } | 316 | } |
178 | } | 317 | } |
179 | up(&s->skt_sem); | 318 | up(&s->skt_sem); |
180 | |||
181 | return count; | ||
182 | } | 319 | } |
183 | spin_unlock_irqrestore(&s->lock, flags); | ||
184 | 320 | ||
185 | return count; | 321 | |
322 | return (ret); | ||
186 | } | 323 | } |
187 | static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource); | ||
188 | 324 | ||
189 | 325 | ||
190 | static struct class_device_attribute *pccard_socket_attributes[] = { | 326 | static struct class_device_attribute *pccard_socket_attributes[] = { |
@@ -199,6 +335,13 @@ static struct class_device_attribute *pccard_socket_attributes[] = { | |||
199 | NULL, | 335 | NULL, |
200 | }; | 336 | }; |
201 | 337 | ||
338 | static struct bin_attribute pccard_cis_attr = { | ||
339 | .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR, .owner = THIS_MODULE}, | ||
340 | .size = 0x200, | ||
341 | .read = pccard_show_cis, | ||
342 | .write = pccard_store_cis, | ||
343 | }; | ||
344 | |||
202 | static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) | 345 | static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) |
203 | { | 346 | { |
204 | struct class_device_attribute **attr; | 347 | struct class_device_attribute **attr; |
@@ -209,6 +352,8 @@ static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev) | |||
209 | if (ret) | 352 | if (ret) |
210 | break; | 353 | break; |
211 | } | 354 | } |
355 | if (!ret) | ||
356 | ret = sysfs_create_bin_file(&class_dev->kobj, &pccard_cis_attr); | ||
212 | 357 | ||
213 | return ret; | 358 | return ret; |
214 | } | 359 | } |
@@ -217,6 +362,7 @@ static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev) | |||
217 | { | 362 | { |
218 | struct class_device_attribute **attr; | 363 | struct class_device_attribute **attr; |
219 | 364 | ||
365 | sysfs_remove_bin_file(&class_dev->kobj, &pccard_cis_attr); | ||
220 | for (attr = pccard_socket_attributes; *attr; attr++) | 366 | for (attr = pccard_socket_attributes; *attr; attr++) |
221 | class_device_remove_file(class_dev, *attr); | 367 | class_device_remove_file(class_dev, *attr); |
222 | } | 368 | } |
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index bee05362fd24..02b23abc2df1 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c | |||
@@ -549,6 +549,11 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ | |||
549 | unsigned offset; | 549 | unsigned offset; |
550 | unsigned mask; | 550 | unsigned mask; |
551 | 551 | ||
552 | res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; | ||
553 | /* Already allocated? */ | ||
554 | if (res->parent) | ||
555 | return 0; | ||
556 | |||
552 | /* The granularity of the memory limit is 4kB, on IO it's 4 bytes */ | 557 | /* The granularity of the memory limit is 4kB, on IO it's 4 bytes */ |
553 | mask = ~0xfff; | 558 | mask = ~0xfff; |
554 | if (type & IORESOURCE_IO) | 559 | if (type & IORESOURCE_IO) |
@@ -556,7 +561,6 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ | |||
556 | 561 | ||
557 | offset = 0x1c + 8*nr; | 562 | offset = 0x1c + 8*nr; |
558 | bus = socket->dev->subordinate; | 563 | bus = socket->dev->subordinate; |
559 | res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; | ||
560 | res->name = bus->name; | 564 | res->name = bus->name; |
561 | res->flags = type; | 565 | res->flags = type; |
562 | res->start = 0; | 566 | res->start = 0; |