Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.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.EventMask =
137         CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
138         CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
139         CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
140     client_reg.event_handler = &parport_event;
141     client_reg.Version = 0x0210;
142     client_reg.event_callback_args.client_data = link;
143     ret = pcmcia_register_client(&link->handle, &client_reg);
144     if (ret != CS_SUCCESS) {
145         cs_error(link->handle, RegisterClient, ret);
146         parport_detach(link);
147         return NULL;
148     }
149     
150     return link;
151 } /* parport_attach */
152
153 /*======================================================================
154
155     This deletes a driver "instance".  The device is de-registered
156     with Card Services.  If it has been released, all local data
157     structures are freed.  Otherwise, the structures will be freed
158     when the device is released.
159
160 ======================================================================*/
161
162 static void parport_detach(dev_link_t *link)
163 {
164     dev_link_t **linkp;
165     int ret;
166
167     DEBUG(0, "parport_detach(0x%p)\n", link);
168     
169     /* Locate device structure */
170     for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
171         if (*linkp == link) break;
172     if (*linkp == NULL)
173         return;
174
175     if (link->state & DEV_CONFIG)
176         parport_cs_release(link);
177     
178     if (link->handle) {
179         ret = pcmcia_deregister_client(link->handle);
180         if (ret != CS_SUCCESS)
181             cs_error(link->handle, DeregisterClient, ret);
182     }
183     
184     /* Unlink, free device structure */
185     *linkp = link->next;
186     kfree(link->priv);
187     
188 } /* parport_detach */
189
190 /*======================================================================
191
192     parport_config() is scheduled to run after a CARD_INSERTION event
193     is received, to configure the PCMCIA socket, and to make the
194     parport device available to the system.
195
196 ======================================================================*/
197
198 #define CS_CHECK(fn, ret) \
199 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
200
201 void parport_config(dev_link_t *link)
202 {
203     client_handle_t handle = link->handle;
204     parport_info_t *info = link->priv;
205     tuple_t tuple;
206     u_short buf[128];
207     cisparse_t parse;
208     config_info_t conf;
209     cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
210     cistpl_cftable_entry_t dflt = { 0 };
211     struct parport *p;
212     int last_ret, last_fn;
213     
214     DEBUG(0, "parport_config(0x%p)\n", link);
215     
216     tuple.TupleData = (cisdata_t *)buf;
217     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
218     tuple.Attributes = 0;
219     tuple.DesiredTuple = CISTPL_CONFIG;
220     CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
221     CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
222     CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
223     link->conf.ConfigBase = parse.config.base;
224     link->conf.Present = parse.config.rmask[0];
225     
226     /* Configure card */
227     link->state |= DEV_CONFIG;
228
229     /* Not sure if this is right... look up the current Vcc */
230     CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
231     
232     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
233     tuple.Attributes = 0;
234     CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
235     while (1) {
236         if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
237                 pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
238             goto next_entry;
239
240         if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
241             cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
242             link->conf.ConfigIndex = cfg->index;
243             if (epp_mode)
244                 link->conf.ConfigIndex |= FORCE_EPP_MODE;
245             link->io.BasePort1 = io->win[0].base;
246             link->io.NumPorts1 = io->win[0].len;
247             link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
248             if (io->nwin == 2) {
249                 link->io.BasePort2 = io->win[1].base;
250                 link->io.NumPorts2 = io->win[1].len;
251             }
252             if (pcmcia_request_io(link->handle, &link->io) != 0)
253                 goto next_entry;
254             /* If we've got this far, we're done */
255             break;
256         }
257         
258     next_entry:
259         if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
260         CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
261     }
262     
263     CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
264     CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
265
266     release_region(link->io.BasePort1, link->io.NumPorts1);
267     if (link->io.NumPorts2)
268         release_region(link->io.BasePort2, link->io.NumPorts2);
269     p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2,
270                               link->irq.AssignedIRQ, PARPORT_DMA_NONE,
271                               NULL);
272     if (p == NULL) {
273         printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at "
274                "0x%3x, irq %u failed\n", link->io.BasePort1,
275                link->irq.AssignedIRQ);
276         goto failed;
277     }
278
279     p->modes |= PARPORT_MODE_PCSPP;
280     if (epp_mode)
281         p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP;
282     info->ndev = 1;
283     info->node.major = LP_MAJOR;
284     info->node.minor = p->number;
285     info->port = p;
286     strcpy(info->node.dev_name, p->name);
287     link->dev = &info->node;
288
289     link->state &= ~DEV_CONFIG_PENDING;
290     return;
291     
292 cs_failed:
293     cs_error(link->handle, last_fn, last_ret);
294 failed:
295     parport_cs_release(link);
296     link->state &= ~DEV_CONFIG_PENDING;
297
298 } /* parport_config */
299
300 /*======================================================================
301
302     After a card is removed, parport_cs_release() will unregister the
303     device, and release the PCMCIA configuration.  If the device is
304     still open, this will be postponed until it is closed.
305     
306 ======================================================================*/
307
308 void parport_cs_release(dev_link_t *link)
309 {
310     parport_info_t *info = link->priv;
311     
312     DEBUG(0, "parport_release(0x%p)\n", link);
313
314     if (info->ndev) {
315         struct parport *p = info->port;
316         parport_pc_unregister_port(p);
317         request_region(link->io.BasePort1, link->io.NumPorts1,
318                        info->node.dev_name);
319         if (link->io.NumPorts2)
320             request_region(link->io.BasePort2, link->io.NumPorts2,
321                            info->node.dev_name);
322     }
323     info->ndev = 0;
324     link->dev = NULL;
325     
326     pcmcia_release_configuration(link->handle);
327     pcmcia_release_io(link->handle, &link->io);
328     pcmcia_release_irq(link->handle, &link->irq);
329     
330     link->state &= ~DEV_CONFIG;
331
332 } /* parport_cs_release */
333
334 /*======================================================================
335
336     The card status event handler.  Mostly, this schedules other
337     stuff to run after an event is received.
338     
339 ======================================================================*/
340
341 int parport_event(event_t event, int priority,
342                   event_callback_args_t *args)
343 {
344     dev_link_t *link = args->client_data;
345
346     DEBUG(1, "parport_event(0x%06x)\n", event);
347     
348     switch (event) {
349     case CS_EVENT_CARD_REMOVAL:
350         link->state &= ~DEV_PRESENT;
351         if (link->state & DEV_CONFIG)
352                 parport_cs_release(link);
353         break;
354     case CS_EVENT_CARD_INSERTION:
355         link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
356         parport_config(link);
357         break;
358     case CS_EVENT_PM_SUSPEND:
359         link->state |= DEV_SUSPEND;
360         /* Fall through... */
361     case CS_EVENT_RESET_PHYSICAL:
362         if (link->state & DEV_CONFIG)
363             pcmcia_release_configuration(link->handle);
364         break;
365     case CS_EVENT_PM_RESUME:
366         link->state &= ~DEV_SUSPEND;
367         /* Fall through... */
368     case CS_EVENT_CARD_RESET:
369         if (DEV_OK(link))
370             pcmcia_request_configuration(link->handle, &link->conf);
371         break;
372     }
373     return 0;
374 } /* parport_event */
375
376 static struct pcmcia_driver parport_cs_driver = {
377         .owner          = THIS_MODULE,
378         .drv            = {
379                 .name   = "parport_cs",
380         },
381         .attach         = parport_attach,
382         .detach         = parport_detach,
383 };
384
385 static int __init init_parport_cs(void)
386 {
387         return pcmcia_register_driver(&parport_cs_driver);
388 }
389
390 static void __exit exit_parport_cs(void)
391 {
392         pcmcia_unregister_driver(&parport_cs_driver);
393         BUG_ON(dev_list != NULL);
394 }
395
396 module_init(init_parport_cs);
397 module_exit(exit_parport_cs);