[PATCH] pcmcia: move event handler
[linux-2.6.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);