* added 0.99 linux version
[mascara-docs.git] / i386 / linux / linux-2.3.21 / drivers / pcmcia / cb_enabler.c
blobb0e75ceecade5ff980212647e5a808cb0ed87646
1 /*======================================================================
3 Cardbus device enabler
5 cb_enabler.c 1.23 1999/09/15 15:32:19
7 The contents of this file are subject to the Mozilla Public
8 License Version 1.1 (the "License"); you may not use this file
9 except in compliance with the License. You may obtain a copy of
10 the License at http://www.mozilla.org/MPL/
12 Software distributed under the License is distributed on an "AS
13 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 implied. See the License for the specific language governing
15 rights and limitations under the License.
17 The initial developer of the original code is David A. Hinds
18 <dhinds@hyper.stanford.edu>. Portions created by David A. Hinds
19 are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
21 Alternatively, the contents of this file may be used under the
22 terms of the GNU Public License version 2 (the "GPL"), in which
23 case the provisions of the GPL are applicable instead of the
24 above. If you wish to allow the use of your version of this file
25 only under the terms of the GPL and not to allow others to use
26 your version of this file under the MPL, indicate your decision
27 by deleting the provisions above and replace them with the notice
28 and other provisions required by the GPL. If you do not delete
29 the provisions above, a recipient may use your version of this
30 file under either the MPL or the GPL.
32 The general idea:
34 A client driver registers using register_driver(). This module
35 then creates a Card Services pseudo-client and registers it, and
36 configures the socket if this is the first client. It then
37 invokes the appropriate PCI client routines in response to Card
38 Services events.
40 ======================================================================*/
42 #include <linux/module.h>
43 #include <linux/init.h>
44 #include <linux/kernel.h>
45 #include <linux/sched.h>
46 #include <linux/malloc.h>
47 #include <linux/string.h>
48 #include <linux/timer.h>
50 #include <pcmcia/version.h>
51 #include <pcmcia/cs_types.h>
52 #include <pcmcia/cs.h>
53 #include <pcmcia/cistpl.h>
54 #include <pcmcia/ds.h>
56 #ifdef PCMCIA_DEBUG
57 static int pc_debug = PCMCIA_DEBUG;
58 MODULE_PARM(pc_debug, "i");
59 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
60 static char *version =
61 "cb_enabler.c 1.23 1999/09/15 15:32:19 (David Hinds)";
62 #else
63 #define DEBUG(n, args...) do { } while (0)
64 #endif
66 /*====================================================================*/
68 /* Parameters that can be set with 'insmod' */
70 /*====================================================================*/
72 typedef struct driver_info_t {
73 dev_link_t *(*attach)(void);
74 dev_info_t dev_info;
75 driver_operations *ops;
76 dev_link_t *dev_list;
77 } driver_info_t;
79 static dev_link_t *cb_attach(int n);
80 #define MK_ENTRY(fn, n) \
81 static dev_link_t *fn(void) { return cb_attach(n); }
83 #define MAX_DRIVER 4
85 MK_ENTRY(attach_0, 0);
86 MK_ENTRY(attach_1, 1);
87 MK_ENTRY(attach_2, 2);
88 MK_ENTRY(attach_3, 3);
90 static driver_info_t driver[4] = {
91 { attach_0 }, { attach_1 }, { attach_2 }, { attach_3 }
94 typedef struct bus_info_t {
95 u_char bus;
96 int flags, ncfg, nuse;
97 dev_link_t *owner;
98 } bus_info_t;
100 #define DID_REQUEST 1
101 #define DID_CONFIG 2
103 static void cb_release(u_long arg);
104 static int cb_event(event_t event, int priority,
105 event_callback_args_t *args);
107 static void cb_detach(dev_link_t *);
109 static bus_info_t bus_table[MAX_DRIVER];
111 /*====================================================================*/
113 static void cs_error(client_handle_t handle, int func, int ret)
115 error_info_t err = { func, ret };
116 CardServices(ReportError, handle, &err);
119 /*====================================================================*/
121 struct dev_link_t *cb_attach(int n)
123 client_reg_t client_reg;
124 dev_link_t *link;
125 int ret;
127 DEBUG(0, "cb_attach(%d)\n", n);
129 MOD_INC_USE_COUNT;
130 link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
131 memset(link, 0, sizeof(struct dev_link_t));
133 link->conf.IntType = INT_CARDBUS;
134 link->conf.Vcc = 33;
136 /* Insert into instance chain for this driver */
137 link->priv = &driver[n];
138 link->next = driver[n].dev_list;
139 driver[n].dev_list = link;
141 /* Register with Card Services */
142 client_reg.dev_info = &driver[n].dev_info;
143 client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
144 client_reg.event_handler = &cb_event;
145 client_reg.EventMask =
146 CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
147 CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
148 CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
149 client_reg.Version = 0x0210;
150 client_reg.event_callback_args.client_data = link;
151 ret = CardServices(RegisterClient, &link->handle, &client_reg);
152 if (ret != 0) {
153 cs_error(link->handle, RegisterClient, ret);
154 cb_detach(link);
155 return NULL;
157 return link;
160 /*====================================================================*/
162 static void cb_detach(dev_link_t *link)
164 driver_info_t *dev = link->priv;
165 dev_link_t **linkp;
166 bus_info_t *b = (void *)link->win;
168 DEBUG(0, "cb_detach(0x%p)\n", link);
170 /* Locate device structure */
171 for (linkp = &dev->dev_list; *linkp; linkp = &(*linkp)->next)
172 if (*linkp == link) break;
173 if (*linkp == NULL)
174 return;
176 if (link->state & DEV_CONFIG)
177 cb_release((u_long)link);
179 /* Don't drop Card Services connection if we are the bus owner */
180 if ((b->flags != 0) && (link == b->owner)) {
181 link->state |= DEV_STALE_LINK;
182 return;
185 if (link->handle)
186 CardServices(DeregisterClient, link->handle);
188 *linkp = link->next;
189 kfree_s(link, sizeof(struct dev_link_t));
190 MOD_DEC_USE_COUNT;
193 /*====================================================================*/
195 static void cb_config(dev_link_t *link)
197 client_handle_t handle = link->handle;
198 driver_info_t *drv = link->priv;
199 dev_locator_t loc;
200 bus_info_t *b;
201 config_info_t config;
202 u_char bus, devfn;
203 int i;
205 DEBUG(0, "cb_config(0x%p)\n", link);
206 link->state |= DEV_CONFIG;
208 /* Get PCI bus info */
209 CardServices(GetConfigurationInfo, handle, &config);
210 bus = config.Option; devfn = config.Function;
212 /* Is this a new bus? */
213 for (i = 0; i < MAX_DRIVER; i++)
214 if (bus == bus_table[i].bus) break;
215 if (i == MAX_DRIVER) {
216 for (i = 0; i < MAX_DRIVER; i++)
217 if (bus_table[i].bus == 0) break;
218 b = &bus_table[i]; link->win = (void *)b;
219 b->bus = bus;
220 b->flags = 0;
221 b->ncfg = b->nuse = 1;
223 /* Special hook: CS know what to do... */
224 i = CardServices(RequestIO, handle, NULL);
225 if (i != CS_SUCCESS) {
226 cs_error(handle, RequestIO, i);
227 return;
229 b->flags |= DID_REQUEST;
230 b->owner = link;
231 i = CardServices(RequestConfiguration, handle, &link->conf);
232 if (i != CS_SUCCESS) {
233 cs_error(handle, RequestConfiguration, i);
234 return;
236 b->flags |= DID_CONFIG;
237 } else {
238 b = &bus_table[i]; link->win = (void *)b;
239 if (b->flags & DID_CONFIG) {
240 b->ncfg++; b->nuse++;
243 loc.bus = LOC_PCI;
244 loc.b.pci.bus = bus;
245 loc.b.pci.devfn = devfn;
246 link->dev = drv->ops->attach(&loc);
248 link->state &= ~DEV_CONFIG_PENDING;
251 /*====================================================================*/
253 static void cb_release(u_long arg)
255 dev_link_t *link = (dev_link_t *)arg;
256 driver_info_t *drv = link->priv;
257 bus_info_t *b = (void *)link->win;
259 DEBUG(0, "cb_release(0x%p)\n", link);
261 if (link->dev != NULL) {
262 drv->ops->detach(link->dev);
263 link->dev = NULL;
265 if (link->state & DEV_CONFIG) {
266 /* If we're suspended, config was already released */
267 if (link->state & DEV_SUSPEND)
268 b->flags &= ~DID_CONFIG;
269 else if ((b->flags & DID_CONFIG) && (--b->ncfg == 0)) {
270 CardServices(ReleaseConfiguration, b->owner->handle,
271 &b->owner->conf);
272 b->flags &= ~DID_CONFIG;
274 if ((b->flags & DID_REQUEST) && (--b->nuse == 0)) {
275 CardServices(ReleaseIO, b->owner->handle, NULL);
276 b->flags &= ~DID_REQUEST;
278 if (b->flags == 0) {
279 if (b->owner && (b->owner->state & DEV_STALE_LINK))
280 cb_detach(b->owner);
281 b->bus = 0; b->owner = NULL;
284 link->state &= ~DEV_CONFIG;
287 /*====================================================================*/
289 static int cb_event(event_t event, int priority,
290 event_callback_args_t *args)
292 dev_link_t *link = args->client_data;
293 driver_info_t *drv = link->priv;
294 bus_info_t *b = (void *)link->win;
296 DEBUG(0, "cb_event(0x%06x)\n", event);
298 switch (event) {
299 case CS_EVENT_CARD_REMOVAL:
300 link->state &= ~DEV_PRESENT;
301 if (link->state & DEV_CONFIG)
302 cb_release((u_long)link);
303 break;
304 case CS_EVENT_CARD_INSERTION:
305 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
306 cb_config(link);
307 break;
308 case CS_EVENT_PM_SUSPEND:
309 link->state |= DEV_SUSPEND;
310 /* Fall through... */
311 case CS_EVENT_RESET_PHYSICAL:
312 if (link->state & DEV_CONFIG) {
313 if (drv->ops->suspend != NULL)
314 drv->ops->suspend(link->dev);
315 b->ncfg--;
316 if (b->ncfg == 0)
317 CardServices(ReleaseConfiguration, link->handle,
318 &link->conf);
320 break;
321 case CS_EVENT_PM_RESUME:
322 link->state &= ~DEV_SUSPEND;
323 /* Fall through... */
324 case CS_EVENT_CARD_RESET:
325 if (link->state & DEV_CONFIG) {
326 b->ncfg++;
327 if (b->ncfg == 1)
328 CardServices(RequestConfiguration, link->handle,
329 &link->conf);
330 if (drv->ops->resume != NULL)
331 drv->ops->resume(link->dev);
333 break;
335 return 0;
338 /*====================================================================*/
340 int register_driver(struct driver_operations *ops)
342 int i;
344 DEBUG(0, "register_driver('%s')\n", ops->name);
346 for (i = 0; i < MAX_DRIVER; i++)
347 if (driver[i].ops == NULL) break;
348 if (i == MAX_DRIVER)
349 return -1;
351 MOD_INC_USE_COUNT;
352 driver[i].ops = ops;
353 strcpy(driver[i].dev_info, ops->name);
354 register_pccard_driver(&driver[i].dev_info, driver[i].attach,
355 &cb_detach);
356 return 0;
359 void unregister_driver(struct driver_operations *ops)
361 int i;
363 DEBUG(0, "unregister_driver('%s')\n", ops->name);
364 for (i = 0; i < MAX_DRIVER; i++)
365 if (driver[i].ops == ops) break;
366 if (i < MAX_DRIVER) {
367 unregister_pccard_driver(&driver[i].dev_info);
368 driver[i].ops = NULL;
369 MOD_DEC_USE_COUNT;
373 /*====================================================================*/
375 static int __init init_cb_enabler(void)
377 servinfo_t serv;
378 DEBUG(0, "%s\n", version);
379 CardServices(GetCardServicesInfo, &serv);
380 if (serv.Revision != CS_RELEASE_CODE) {
381 printk(KERN_NOTICE "cb_enabler: Card Services release "
382 "does not match!\n");
383 return -1;
385 return 0;
388 static void __exit exit_cb_enabler(void)
390 DEBUG(0, "cb_enabler: unloading\n");
393 module_init(init_cb_enabler);
394 module_exit(exit_cb_enabler);
396 /*====================================================================*/