ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[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_PARM(n, "i")
68
69 /* Bit map of interrupts to choose from */
70 INT_MODULE_PARM(irq_mask, 0xdeb8);
71 static int irq_list[4] = { -1 };
72 MODULE_PARM(irq_list, "1-4i");
73
74 INT_MODULE_PARM(epp_mode, 1);
75
76 #ifdef PCMCIA_DEBUG
77 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
78 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
79 static char *version =
80 "parport_cs.c 1.29 2002/10/11 06:57:41 (David Hinds)";
81 #else
82 #define DEBUG(n, args...)
83 #endif
84
85 /*====================================================================*/
86
87 #define FORCE_EPP_MODE  0x08
88
89 typedef struct parport_info_t {
90     dev_link_t          link;
91     int                 ndev;
92     dev_node_t          node;
93     struct parport      *port;
94 } parport_info_t;
95
96 static dev_link_t *parport_attach(void);
97 static void parport_detach(dev_link_t *);
98 static void parport_config(dev_link_t *link);
99 static void parport_cs_release(dev_link_t *);
100 static int parport_event(event_t event, int priority,
101                          event_callback_args_t *args);
102
103 static dev_info_t dev_info = "parport_cs";
104 static dev_link_t *dev_list = NULL;
105
106 /*======================================================================
107
108     parport_attach() creates an "instance" of the driver, allocating
109     local data structures for one device.  The device is registered
110     with Card Services.
111
112 ======================================================================*/
113
114 static dev_link_t *parport_attach(void)
115 {
116     parport_info_t *info;
117     dev_link_t *link;
118     client_reg_t client_reg;
119     int i, ret;
120     
121     DEBUG(0, "parport_attach()\n");
122
123     /* Create new parport device */
124     info = kmalloc(sizeof(*info), GFP_KERNEL);
125     if (!info) return NULL;
126     memset(info, 0, sizeof(*info));
127     link = &info->link; link->priv = info;
128
129     link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
130     link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
131     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
132     link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
133     if (irq_list[0] == -1)
134         link->irq.IRQInfo2 = irq_mask;
135     else
136         for (i = 0; i < 4; i++)
137             link->irq.IRQInfo2 |= 1 << irq_list[i];
138     link->conf.Attributes = CONF_ENABLE_IRQ;
139     link->conf.Vcc = 50;
140     link->conf.IntType = INT_MEMORY_AND_IO;
141     
142     /* Register with Card Services */
143     link->next = dev_list;
144     dev_list = link;
145     client_reg.dev_info = &dev_info;
146     client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
147     client_reg.EventMask =
148         CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
149         CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
150         CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
151     client_reg.event_handler = &parport_event;
152     client_reg.Version = 0x0210;
153     client_reg.event_callback_args.client_data = link;
154     ret = pcmcia_register_client(&link->handle, &client_reg);
155     if (ret != CS_SUCCESS) {
156         cs_error(link->handle, RegisterClient, ret);
157         parport_detach(link);
158         return NULL;
159     }
160     
161     return link;
162 } /* parport_attach */
163
164 /*======================================================================
165
166     This deletes a driver "instance".  The device is de-registered
167     with Card Services.  If it has been released, all local data
168     structures are freed.  Otherwise, the structures will be freed
169     when the device is released.
170
171 ======================================================================*/
172
173 static void parport_detach(dev_link_t *link)
174 {
175     dev_link_t **linkp;
176     int ret;
177
178     DEBUG(0, "parport_detach(0x%p)\n", link);
179     
180     /* Locate device structure */
181     for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
182         if (*linkp == link) break;
183     if (*linkp == NULL)
184         return;
185
186     if (link->state & DEV_CONFIG)
187         parport_cs_release(link);
188     
189     if (link->handle) {
190         ret = pcmcia_deregister_client(link->handle);
191         if (ret != CS_SUCCESS)
192             cs_error(link->handle, DeregisterClient, ret);
193     }
194     
195     /* Unlink, free device structure */
196     *linkp = link->next;
197     kfree(link->priv);
198     
199 } /* parport_detach */
200
201 /*======================================================================
202
203     parport_config() is scheduled to run after a CARD_INSERTION event
204     is received, to configure the PCMCIA socket, and to make the
205     parport device available to the system.
206
207 ======================================================================*/
208
209 #define CS_CHECK(fn, ret) \
210 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
211
212 void parport_config(dev_link_t *link)
213 {
214     client_handle_t handle = link->handle;
215     parport_info_t *info = link->priv;
216     tuple_t tuple;
217     u_short buf[128];
218     cisparse_t parse;
219     config_info_t conf;
220     cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
221     cistpl_cftable_entry_t dflt = { 0 };
222     struct parport *p;
223     int last_ret, last_fn;
224     
225     DEBUG(0, "parport_config(0x%p)\n", link);
226     
227     tuple.TupleData = (cisdata_t *)buf;
228     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
229     tuple.Attributes = 0;
230     tuple.DesiredTuple = CISTPL_CONFIG;
231     CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
232     CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
233     CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
234     link->conf.ConfigBase = parse.config.base;
235     link->conf.Present = parse.config.rmask[0];
236     
237     /* Configure card */
238     link->state |= DEV_CONFIG;
239
240     /* Not sure if this is right... look up the current Vcc */
241     CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
242     
243     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
244     tuple.Attributes = 0;
245     CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
246     while (1) {
247         if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
248                 pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
249             goto next_entry;
250
251         if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
252             cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
253             link->conf.ConfigIndex = cfg->index;
254             if (epp_mode)
255                 link->conf.ConfigIndex |= FORCE_EPP_MODE;
256             link->io.BasePort1 = io->win[0].base;
257             link->io.NumPorts1 = io->win[0].len;
258             link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
259             if (io->nwin == 2) {
260                 link->io.BasePort2 = io->win[1].base;
261                 link->io.NumPorts2 = io->win[1].len;
262             }
263             if (pcmcia_request_io(link->handle, &link->io) != 0)
264                 goto next_entry;
265             /* If we've got this far, we're done */
266             break;
267         }
268         
269     next_entry:
270         if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
271         CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
272     }
273     
274     CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
275     CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
276
277     release_region(link->io.BasePort1, link->io.NumPorts1);
278     if (link->io.NumPorts2)
279         release_region(link->io.BasePort2, link->io.NumPorts2);
280     p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2,
281                               link->irq.AssignedIRQ, PARPORT_DMA_NONE,
282                               NULL);
283     if (p == NULL) {
284         printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at "
285                "0x%3x, irq %u failed\n", link->io.BasePort1,
286                link->irq.AssignedIRQ);
287         goto failed;
288     }
289
290     p->modes |= PARPORT_MODE_PCSPP;
291     if (epp_mode)
292         p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP;
293     info->ndev = 1;
294     info->node.major = LP_MAJOR;
295     info->node.minor = p->number;
296     info->port = p;
297     strcpy(info->node.dev_name, p->name);
298     link->dev = &info->node;
299
300     link->state &= ~DEV_CONFIG_PENDING;
301     return;
302     
303 cs_failed:
304     cs_error(link->handle, last_fn, last_ret);
305 failed:
306     parport_cs_release(link);
307     link->state &= ~DEV_CONFIG_PENDING;
308
309 } /* parport_config */
310
311 /*======================================================================
312
313     After a card is removed, parport_cs_release() will unregister the
314     device, and release the PCMCIA configuration.  If the device is
315     still open, this will be postponed until it is closed.
316     
317 ======================================================================*/
318
319 void parport_cs_release(dev_link_t *link)
320 {
321     parport_info_t *info = link->priv;
322     
323     DEBUG(0, "parport_release(0x%p)\n", link);
324
325     if (info->ndev) {
326         struct parport *p = info->port;
327         parport_pc_unregister_port(p);
328         request_region(link->io.BasePort1, link->io.NumPorts1,
329                        info->node.dev_name);
330         if (link->io.NumPorts2)
331             request_region(link->io.BasePort2, link->io.NumPorts2,
332                            info->node.dev_name);
333     }
334     info->ndev = 0;
335     link->dev = NULL;
336     
337     pcmcia_release_configuration(link->handle);
338     pcmcia_release_io(link->handle, &link->io);
339     pcmcia_release_irq(link->handle, &link->irq);
340     
341     link->state &= ~DEV_CONFIG;
342
343 } /* parport_cs_release */
344
345 /*======================================================================
346
347     The card status event handler.  Mostly, this schedules other
348     stuff to run after an event is received.
349     
350 ======================================================================*/
351
352 int parport_event(event_t event, int priority,
353                   event_callback_args_t *args)
354 {
355     dev_link_t *link = args->client_data;
356
357     DEBUG(1, "parport_event(0x%06x)\n", event);
358     
359     switch (event) {
360     case CS_EVENT_CARD_REMOVAL:
361         link->state &= ~DEV_PRESENT;
362         if (link->state & DEV_CONFIG)
363                 parport_cs_release(link);
364         break;
365     case CS_EVENT_CARD_INSERTION:
366         link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
367         parport_config(link);
368         break;
369     case CS_EVENT_PM_SUSPEND:
370         link->state |= DEV_SUSPEND;
371         /* Fall through... */
372     case CS_EVENT_RESET_PHYSICAL:
373         if (link->state & DEV_CONFIG)
374             pcmcia_release_configuration(link->handle);
375         break;
376     case CS_EVENT_PM_RESUME:
377         link->state &= ~DEV_SUSPEND;
378         /* Fall through... */
379     case CS_EVENT_CARD_RESET:
380         if (DEV_OK(link))
381             pcmcia_request_configuration(link->handle, &link->conf);
382         break;
383     }
384     return 0;
385 } /* parport_event */
386
387 static struct pcmcia_driver parport_cs_driver = {
388         .owner          = THIS_MODULE,
389         .drv            = {
390                 .name   = "parport_cs",
391         },
392         .attach         = parport_attach,
393         .detach         = parport_detach,
394 };
395
396 static int __init init_parport_cs(void)
397 {
398         return pcmcia_register_driver(&parport_cs_driver);
399 }
400
401 static void __exit exit_parport_cs(void)
402 {
403         pcmcia_unregister_driver(&parport_cs_driver);
404
405         /* XXX: this really needs to move into generic code.. */
406         while (dev_list != NULL)
407                 parport_detach(dev_list);
408 }
409
410 module_init(init_parport_cs);
411 module_exit(exit_parport_cs);