[PATCH] pcmcia: move event handler
[deliverable/linux.git] / drivers / parport / parport_cs.c
1 /*======================================================================
2
3 A driver for PCMCIA parallel port adapters
4
5 (specifically, for the Quatech SPP-100 EPP card: other cards will
6 probably require driver tweaks)
7
8 parport_cs.c 1.29 2002/10/11 06:57:41
9
10 The contents of this file are subject to the Mozilla Public
11 License Version 1.1 (the "License"); you may not use this file
12 except in compliance with the License. You may obtain a copy of
13 the License at http://www.mozilla.org/MPL/
14
15 Software distributed under the License is distributed on an "AS
16 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
17 implied. See the License for the specific language governing
18 rights and limitations under the License.
19
20 The initial developer of the original code is David A. Hinds
21 <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
22 are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
23
24 Alternatively, the contents of this file may be used under the
25 terms of the GNU General Public License version 2 (the "GPL"), in
26 which case the provisions of the GPL are applicable instead of the
27 above. If you wish to allow the use of your version of this file
28 only under the terms of the GPL and not to allow others to use
29 your version of this file under the MPL, indicate your decision
30 by deleting the provisions above and replace them with the notice
31 and other provisions required by the GPL. If you do not delete
32 the provisions above, a recipient may use your version of this
33 file under either the MPL or the GPL.
34
35 ======================================================================*/
36
37 #include <linux/kernel.h>
38 #include <linux/module.h>
39 #include <linux/init.h>
40 #include <linux/sched.h>
41 #include <linux/ptrace.h>
42 #include <linux/slab.h>
43 #include <linux/string.h>
44 #include <linux/timer.h>
45 #include <linux/ioport.h>
46 #include <linux/major.h>
47
48 #include <linux/parport.h>
49 #include <linux/parport_pc.h>
50
51 #include <pcmcia/version.h>
52 #include <pcmcia/cs_types.h>
53 #include <pcmcia/cs.h>
54 #include <pcmcia/cistpl.h>
55 #include <pcmcia/ds.h>
56 #include <pcmcia/cisreg.h>
57 #include <pcmcia/ciscode.h>
58
59 /*====================================================================*/
60
61 /* Module parameters */
62
63 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
64 MODULE_DESCRIPTION("PCMCIA parallel port card driver");
65 MODULE_LICENSE("Dual MPL/GPL");
66
67 #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
68
69 INT_MODULE_PARM(epp_mode, 1);
70
71 #ifdef PCMCIA_DEBUG
72 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
73 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
74 static char *version =
75 "parport_cs.c 1.29 2002/10/11 06:57:41 (David Hinds)";
76 #else
77 #define DEBUG(n, args...)
78 #endif
79
80 /*====================================================================*/
81
82 #define FORCE_EPP_MODE 0x08
83
84 typedef struct parport_info_t {
85 dev_link_t link;
86 int ndev;
87 dev_node_t node;
88 struct parport *port;
89 } parport_info_t;
90
91 static dev_link_t *parport_attach(void);
92 static void parport_detach(dev_link_t *);
93 static void parport_config(dev_link_t *link);
94 static void parport_cs_release(dev_link_t *);
95 static int parport_event(event_t event, int priority,
96 event_callback_args_t *args);
97
98 static dev_info_t dev_info = "parport_cs";
99 static dev_link_t *dev_list = NULL;
100
101 /*======================================================================
102
103 parport_attach() creates an "instance" of the driver, allocating
104 local data structures for one device. The device is registered
105 with Card Services.
106
107 ======================================================================*/
108
109 static dev_link_t *parport_attach(void)
110 {
111 parport_info_t *info;
112 dev_link_t *link;
113 client_reg_t client_reg;
114 int ret;
115
116 DEBUG(0, "parport_attach()\n");
117
118 /* Create new parport device */
119 info = kmalloc(sizeof(*info), GFP_KERNEL);
120 if (!info) return NULL;
121 memset(info, 0, sizeof(*info));
122 link = &info->link; link->priv = info;
123
124 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
125 link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
126 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
127 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
128 link->conf.Attributes = CONF_ENABLE_IRQ;
129 link->conf.Vcc = 50;
130 link->conf.IntType = INT_MEMORY_AND_IO;
131
132 /* Register with Card Services */
133 link->next = dev_list;
134 dev_list = link;
135 client_reg.dev_info = &dev_info;
136 client_reg.Version = 0x0210;
137 client_reg.event_callback_args.client_data = link;
138 ret = pcmcia_register_client(&link->handle, &client_reg);
139 if (ret != CS_SUCCESS) {
140 cs_error(link->handle, RegisterClient, ret);
141 parport_detach(link);
142 return NULL;
143 }
144
145 return link;
146 } /* parport_attach */
147
148 /*======================================================================
149
150 This deletes a driver "instance". The device is de-registered
151 with Card Services. If it has been released, all local data
152 structures are freed. Otherwise, the structures will be freed
153 when the device is released.
154
155 ======================================================================*/
156
157 static void parport_detach(dev_link_t *link)
158 {
159 dev_link_t **linkp;
160 int ret;
161
162 DEBUG(0, "parport_detach(0x%p)\n", link);
163
164 /* Locate device structure */
165 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
166 if (*linkp == link) break;
167 if (*linkp == NULL)
168 return;
169
170 if (link->state & DEV_CONFIG)
171 parport_cs_release(link);
172
173 if (link->handle) {
174 ret = pcmcia_deregister_client(link->handle);
175 if (ret != CS_SUCCESS)
176 cs_error(link->handle, DeregisterClient, ret);
177 }
178
179 /* Unlink, free device structure */
180 *linkp = link->next;
181 kfree(link->priv);
182
183 } /* parport_detach */
184
185 /*======================================================================
186
187 parport_config() is scheduled to run after a CARD_INSERTION event
188 is received, to configure the PCMCIA socket, and to make the
189 parport device available to the system.
190
191 ======================================================================*/
192
193 #define CS_CHECK(fn, ret) \
194 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
195
196 void parport_config(dev_link_t *link)
197 {
198 client_handle_t handle = link->handle;
199 parport_info_t *info = link->priv;
200 tuple_t tuple;
201 u_short buf[128];
202 cisparse_t parse;
203 config_info_t conf;
204 cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
205 cistpl_cftable_entry_t dflt = { 0 };
206 struct parport *p;
207 int last_ret, last_fn;
208
209 DEBUG(0, "parport_config(0x%p)\n", link);
210
211 tuple.TupleData = (cisdata_t *)buf;
212 tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
213 tuple.Attributes = 0;
214 tuple.DesiredTuple = CISTPL_CONFIG;
215 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
216 CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
217 CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
218 link->conf.ConfigBase = parse.config.base;
219 link->conf.Present = parse.config.rmask[0];
220
221 /* Configure card */
222 link->state |= DEV_CONFIG;
223
224 /* Not sure if this is right... look up the current Vcc */
225 CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
226
227 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
228 tuple.Attributes = 0;
229 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
230 while (1) {
231 if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
232 pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
233 goto next_entry;
234
235 if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
236 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
237 link->conf.ConfigIndex = cfg->index;
238 if (epp_mode)
239 link->conf.ConfigIndex |= FORCE_EPP_MODE;
240 link->io.BasePort1 = io->win[0].base;
241 link->io.NumPorts1 = io->win[0].len;
242 link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
243 if (io->nwin == 2) {
244 link->io.BasePort2 = io->win[1].base;
245 link->io.NumPorts2 = io->win[1].len;
246 }
247 if (pcmcia_request_io(link->handle, &link->io) != 0)
248 goto next_entry;
249 /* If we've got this far, we're done */
250 break;
251 }
252
253 next_entry:
254 if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
255 CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
256 }
257
258 CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
259 CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
260
261 release_region(link->io.BasePort1, link->io.NumPorts1);
262 if (link->io.NumPorts2)
263 release_region(link->io.BasePort2, link->io.NumPorts2);
264 p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2,
265 link->irq.AssignedIRQ, PARPORT_DMA_NONE,
266 NULL);
267 if (p == NULL) {
268 printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at "
269 "0x%3x, irq %u failed\n", link->io.BasePort1,
270 link->irq.AssignedIRQ);
271 goto failed;
272 }
273
274 p->modes |= PARPORT_MODE_PCSPP;
275 if (epp_mode)
276 p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP;
277 info->ndev = 1;
278 info->node.major = LP_MAJOR;
279 info->node.minor = p->number;
280 info->port = p;
281 strcpy(info->node.dev_name, p->name);
282 link->dev = &info->node;
283
284 link->state &= ~DEV_CONFIG_PENDING;
285 return;
286
287 cs_failed:
288 cs_error(link->handle, last_fn, last_ret);
289 failed:
290 parport_cs_release(link);
291 link->state &= ~DEV_CONFIG_PENDING;
292
293 } /* parport_config */
294
295 /*======================================================================
296
297 After a card is removed, parport_cs_release() will unregister the
298 device, and release the PCMCIA configuration. If the device is
299 still open, this will be postponed until it is closed.
300
301 ======================================================================*/
302
303 void parport_cs_release(dev_link_t *link)
304 {
305 parport_info_t *info = link->priv;
306
307 DEBUG(0, "parport_release(0x%p)\n", link);
308
309 if (info->ndev) {
310 struct parport *p = info->port;
311 parport_pc_unregister_port(p);
312 request_region(link->io.BasePort1, link->io.NumPorts1,
313 info->node.dev_name);
314 if (link->io.NumPorts2)
315 request_region(link->io.BasePort2, link->io.NumPorts2,
316 info->node.dev_name);
317 }
318 info->ndev = 0;
319 link->dev = NULL;
320
321 pcmcia_release_configuration(link->handle);
322 pcmcia_release_io(link->handle, &link->io);
323 pcmcia_release_irq(link->handle, &link->irq);
324
325 link->state &= ~DEV_CONFIG;
326
327 } /* parport_cs_release */
328
329 /*======================================================================
330
331 The card status event handler. Mostly, this schedules other
332 stuff to run after an event is received.
333
334 ======================================================================*/
335
336 int parport_event(event_t event, int priority,
337 event_callback_args_t *args)
338 {
339 dev_link_t *link = args->client_data;
340
341 DEBUG(1, "parport_event(0x%06x)\n", event);
342
343 switch (event) {
344 case CS_EVENT_CARD_REMOVAL:
345 link->state &= ~DEV_PRESENT;
346 if (link->state & DEV_CONFIG)
347 parport_cs_release(link);
348 break;
349 case CS_EVENT_CARD_INSERTION:
350 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
351 parport_config(link);
352 break;
353 case CS_EVENT_PM_SUSPEND:
354 link->state |= DEV_SUSPEND;
355 /* Fall through... */
356 case CS_EVENT_RESET_PHYSICAL:
357 if (link->state & DEV_CONFIG)
358 pcmcia_release_configuration(link->handle);
359 break;
360 case CS_EVENT_PM_RESUME:
361 link->state &= ~DEV_SUSPEND;
362 /* Fall through... */
363 case CS_EVENT_CARD_RESET:
364 if (DEV_OK(link))
365 pcmcia_request_configuration(link->handle, &link->conf);
366 break;
367 }
368 return 0;
369 } /* parport_event */
370
371 static struct pcmcia_device_id parport_ids[] = {
372 PCMCIA_DEVICE_FUNC_ID(3),
373 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003),
374 PCMCIA_DEVICE_NULL
375 };
376 MODULE_DEVICE_TABLE(pcmcia, parport_ids);
377
378 static struct pcmcia_driver parport_cs_driver = {
379 .owner = THIS_MODULE,
380 .drv = {
381 .name = "parport_cs",
382 },
383 .attach = parport_attach,
384 .event = parport_event,
385 .detach = parport_detach,
386 .id_table = parport_ids,
387
388 };
389
390 static int __init init_parport_cs(void)
391 {
392 return pcmcia_register_driver(&parport_cs_driver);
393 }
394
395 static void __exit exit_parport_cs(void)
396 {
397 pcmcia_unregister_driver(&parport_cs_driver);
398 BUG_ON(dev_list != NULL);
399 }
400
401 module_init(init_parport_cs);
402 module_exit(exit_parport_cs);
This page took 0.074205 seconds and 5 git commands to generate.