1 /*======================================================================
3 A driver for PCMCIA parallel port adapters
5 (specifically, for the Quatech SPP-100 EPP card: other cards will
6 probably require driver tweaks)
8 parport_cs.c 1.29 2002/10/11 06:57:41
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/
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.
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.
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.
35 ======================================================================*/
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>
48 #include <linux/parport.h>
49 #include <linux/parport_pc.h>
51 #include <pcmcia/cs_types.h>
52 #include <pcmcia/cs.h>
53 #include <pcmcia/cistpl.h>
54 #include <pcmcia/ds.h>
55 #include <pcmcia/cisreg.h>
56 #include <pcmcia/ciscode.h>
58 /*====================================================================*/
60 /* Module parameters */
62 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
63 MODULE_DESCRIPTION("PCMCIA parallel port card driver");
64 MODULE_LICENSE("Dual MPL/GPL");
66 #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
68 INT_MODULE_PARM(epp_mode, 1);
71 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
72 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
73 static char *version =
74 "parport_cs.c 1.29 2002/10/11 06:57:41 (David Hinds)";
76 #define DEBUG(n, args...)
79 /*====================================================================*/
81 #define FORCE_EPP_MODE 0x08
83 typedef struct parport_info_t {
90 static dev_link_t *parport_attach(void);
91 static void parport_detach(struct pcmcia_device *p_dev);
92 static void parport_config(dev_link_t *link);
93 static void parport_cs_release(dev_link_t *);
94 static int parport_event(event_t event, int priority,
95 event_callback_args_t *args);
97 static dev_info_t dev_info = "parport_cs";
99 /*======================================================================
101 parport_attach() creates an "instance" of the driver, allocating
102 local data structures for one device. The device is registered
105 ======================================================================*/
107 static dev_link_t *parport_attach(void)
109 parport_info_t *info;
111 client_reg_t client_reg;
114 DEBUG(0, "parport_attach()\n");
116 /* Create new parport device */
117 info = kmalloc(sizeof(*info), GFP_KERNEL);
118 if (!info) return NULL;
119 memset(info, 0, sizeof(*info));
120 link = &info->link; link->priv = info;
122 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
123 link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
124 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
125 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
126 link->conf.Attributes = CONF_ENABLE_IRQ;
128 link->conf.IntType = INT_MEMORY_AND_IO;
130 /* Register with Card Services */
132 client_reg.dev_info = &dev_info;
133 client_reg.Version = 0x0210;
134 client_reg.event_callback_args.client_data = link;
135 ret = pcmcia_register_client(&link->handle, &client_reg);
136 if (ret != CS_SUCCESS) {
137 cs_error(link->handle, RegisterClient, ret);
138 parport_detach(link->handle);
143 } /* parport_attach */
145 /*======================================================================
147 This deletes a driver "instance". The device is de-registered
148 with Card Services. If it has been released, all local data
149 structures are freed. Otherwise, the structures will be freed
150 when the device is released.
152 ======================================================================*/
154 static void parport_detach(struct pcmcia_device *p_dev)
156 dev_link_t *link = dev_to_instance(p_dev);
158 DEBUG(0, "parport_detach(0x%p)\n", link);
160 if (link->state & DEV_CONFIG)
161 parport_cs_release(link);
164 } /* parport_detach */
166 /*======================================================================
168 parport_config() is scheduled to run after a CARD_INSERTION event
169 is received, to configure the PCMCIA socket, and to make the
170 parport device available to the system.
172 ======================================================================*/
174 #define CS_CHECK(fn, ret) \
175 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
177 void parport_config(dev_link_t *link)
179 client_handle_t handle = link->handle;
180 parport_info_t *info = link->priv;
185 cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
186 cistpl_cftable_entry_t dflt = { 0 };
188 int last_ret, last_fn;
190 DEBUG(0, "parport_config(0x%p)\n", link);
192 tuple.TupleData = (cisdata_t *)buf;
193 tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
194 tuple.Attributes = 0;
195 tuple.DesiredTuple = CISTPL_CONFIG;
196 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
197 CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
198 CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
199 link->conf.ConfigBase = parse.config.base;
200 link->conf.Present = parse.config.rmask[0];
203 link->state |= DEV_CONFIG;
205 /* Not sure if this is right... look up the current Vcc */
206 CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
208 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
209 tuple.Attributes = 0;
210 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
212 if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
213 pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
216 if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
217 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
218 link->conf.ConfigIndex = cfg->index;
220 link->conf.ConfigIndex |= FORCE_EPP_MODE;
221 link->io.BasePort1 = io->win[0].base;
222 link->io.NumPorts1 = io->win[0].len;
223 link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
225 link->io.BasePort2 = io->win[1].base;
226 link->io.NumPorts2 = io->win[1].len;
228 if (pcmcia_request_io(link->handle, &link->io) != 0)
230 /* If we've got this far, we're done */
235 if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
236 CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
239 CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
240 CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
242 release_region(link->io.BasePort1, link->io.NumPorts1);
243 if (link->io.NumPorts2)
244 release_region(link->io.BasePort2, link->io.NumPorts2);
245 p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2,
246 link->irq.AssignedIRQ, PARPORT_DMA_NONE,
249 printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at "
250 "0x%3x, irq %u failed\n", link->io.BasePort1,
251 link->irq.AssignedIRQ);
255 p->modes |= PARPORT_MODE_PCSPP;
257 p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP;
259 info->node.major = LP_MAJOR;
260 info->node.minor = p->number;
262 strcpy(info->node.dev_name, p->name);
263 link->dev = &info->node;
265 link->state &= ~DEV_CONFIG_PENDING;
269 cs_error(link->handle, last_fn, last_ret);
271 parport_cs_release(link);
272 link->state &= ~DEV_CONFIG_PENDING;
274 } /* parport_config */
276 /*======================================================================
278 After a card is removed, parport_cs_release() will unregister the
279 device, and release the PCMCIA configuration. If the device is
280 still open, this will be postponed until it is closed.
282 ======================================================================*/
284 void parport_cs_release(dev_link_t *link)
286 parport_info_t *info = link->priv;
288 DEBUG(0, "parport_release(0x%p)\n", link);
291 struct parport *p = info->port;
292 parport_pc_unregister_port(p);
293 request_region(link->io.BasePort1, link->io.NumPorts1,
294 info->node.dev_name);
295 if (link->io.NumPorts2)
296 request_region(link->io.BasePort2, link->io.NumPorts2,
297 info->node.dev_name);
302 pcmcia_release_configuration(link->handle);
303 pcmcia_release_io(link->handle, &link->io);
304 pcmcia_release_irq(link->handle, &link->irq);
306 link->state &= ~DEV_CONFIG;
308 } /* parport_cs_release */
310 static int parport_suspend(struct pcmcia_device *dev)
312 dev_link_t *link = dev_to_instance(dev);
314 link->state |= DEV_SUSPEND;
315 if (link->state & DEV_CONFIG)
316 pcmcia_release_configuration(link->handle);
321 static int parport_resume(struct pcmcia_device *dev)
323 dev_link_t *link = dev_to_instance(dev);
325 link->state &= ~DEV_SUSPEND;
327 pcmcia_request_configuration(link->handle, &link->conf);
332 /*======================================================================
334 The card status event handler. Mostly, this schedules other
335 stuff to run after an event is received.
337 ======================================================================*/
339 int parport_event(event_t event, int priority,
340 event_callback_args_t *args)
342 dev_link_t *link = args->client_data;
344 DEBUG(1, "parport_event(0x%06x)\n", event);
347 case CS_EVENT_CARD_INSERTION:
348 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
349 parport_config(link);
353 } /* parport_event */
355 static struct pcmcia_device_id parport_ids[] = {
356 PCMCIA_DEVICE_FUNC_ID(3),
357 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003),
360 MODULE_DEVICE_TABLE(pcmcia, parport_ids);
362 static struct pcmcia_driver parport_cs_driver = {
363 .owner = THIS_MODULE,
365 .name = "parport_cs",
367 .attach = parport_attach,
368 .event = parport_event,
369 .remove = parport_detach,
370 .id_table = parport_ids,
371 .suspend = parport_suspend,
372 .resume = parport_resume,
375 static int __init init_parport_cs(void)
377 return pcmcia_register_driver(&parport_cs_driver);
380 static void __exit exit_parport_cs(void)
382 pcmcia_unregister_driver(&parport_cs_driver);
385 module_init(init_parport_cs);
386 module_exit(exit_parport_cs);