1 /*======================================================================
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.
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
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>
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)";
63 #define DEBUG(n, args...) do { } while (0)
66 /*====================================================================*/
68 /* Parameters that can be set with 'insmod' */
70 /*====================================================================*/
72 typedef struct driver_info_t
{
73 dev_link_t
*(*attach
)(void);
75 driver_operations
*ops
;
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); }
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
{
96 int flags
, ncfg
, nuse
;
100 #define DID_REQUEST 1
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
;
127 DEBUG(0, "cb_attach(%d)\n", n
);
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
;
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
);
153 cs_error(link
->handle
, RegisterClient
, ret
);
160 /*====================================================================*/
162 static void cb_detach(dev_link_t
*link
)
164 driver_info_t
*dev
= link
->priv
;
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;
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
;
186 CardServices(DeregisterClient
, link
->handle
);
189 kfree_s(link
, sizeof(struct dev_link_t
));
193 /*====================================================================*/
195 static void cb_config(dev_link_t
*link
)
197 client_handle_t handle
= link
->handle
;
198 driver_info_t
*drv
= link
->priv
;
201 config_info_t config
;
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
;
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
);
229 b
->flags
|= DID_REQUEST
;
231 i
= CardServices(RequestConfiguration
, handle
, &link
->conf
);
232 if (i
!= CS_SUCCESS
) {
233 cs_error(handle
, RequestConfiguration
, i
);
236 b
->flags
|= DID_CONFIG
;
238 b
= &bus_table
[i
]; link
->win
= (void *)b
;
239 if (b
->flags
& DID_CONFIG
) {
240 b
->ncfg
++; b
->nuse
++;
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
);
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
,
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
;
279 if (b
->owner
&& (b
->owner
->state
& DEV_STALE_LINK
))
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
);
299 case CS_EVENT_CARD_REMOVAL
:
300 link
->state
&= ~DEV_PRESENT
;
301 if (link
->state
& DEV_CONFIG
)
302 cb_release((u_long
)link
);
304 case CS_EVENT_CARD_INSERTION
:
305 link
->state
|= DEV_PRESENT
| DEV_CONFIG_PENDING
;
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
);
317 CardServices(ReleaseConfiguration
, link
->handle
,
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
) {
328 CardServices(RequestConfiguration
, link
->handle
,
330 if (drv
->ops
->resume
!= NULL
)
331 drv
->ops
->resume(link
->dev
);
338 /*====================================================================*/
340 int register_driver(struct driver_operations
*ops
)
344 DEBUG(0, "register_driver('%s')\n", ops
->name
);
346 for (i
= 0; i
< MAX_DRIVER
; i
++)
347 if (driver
[i
].ops
== NULL
) break;
353 strcpy(driver
[i
].dev_info
, ops
->name
);
354 register_pccard_driver(&driver
[i
].dev_info
, driver
[i
].attach
,
359 void unregister_driver(struct driver_operations
*ops
)
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
;
373 /*====================================================================*/
375 static int __init
init_cb_enabler(void)
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");
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 /*====================================================================*/