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/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>
59 /*====================================================================*/
61 /* Module parameters */
63 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
64 MODULE_DESCRIPTION("PCMCIA parallel port card driver");
65 MODULE_LICENSE("Dual MPL/GPL");
67 #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
69 INT_MODULE_PARM(epp_mode
, 1);
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)";
77 #define DEBUG(n, args...)
80 /*====================================================================*/
82 #define FORCE_EPP_MODE 0x08
84 typedef struct parport_info_t
{
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
);
98 static dev_info_t dev_info
= "parport_cs";
99 static dev_link_t
*dev_list
= NULL
;
101 /*======================================================================
103 parport_attach() creates an "instance" of the driver, allocating
104 local data structures for one device. The device is registered
107 ======================================================================*/
109 static dev_link_t
*parport_attach(void)
111 parport_info_t
*info
;
113 client_reg_t client_reg
;
116 DEBUG(0, "parport_attach()\n");
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
;
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
;
130 link
->conf
.IntType
= INT_MEMORY_AND_IO
;
132 /* Register with Card Services */
133 link
->next
= dev_list
;
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
);
146 } /* parport_attach */
148 /*======================================================================
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.
155 ======================================================================*/
157 static void parport_detach(dev_link_t
*link
)
162 DEBUG(0, "parport_detach(0x%p)\n", link
);
164 /* Locate device structure */
165 for (linkp
= &dev_list
; *linkp
; linkp
= &(*linkp
)->next
)
166 if (*linkp
== link
) break;
170 if (link
->state
& DEV_CONFIG
)
171 parport_cs_release(link
);
174 ret
= pcmcia_deregister_client(link
->handle
);
175 if (ret
!= CS_SUCCESS
)
176 cs_error(link
->handle
, DeregisterClient
, ret
);
179 /* Unlink, free device structure */
183 } /* parport_detach */
185 /*======================================================================
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.
191 ======================================================================*/
193 #define CS_CHECK(fn, ret) \
194 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
196 void parport_config(dev_link_t
*link
)
198 client_handle_t handle
= link
->handle
;
199 parport_info_t
*info
= link
->priv
;
204 cistpl_cftable_entry_t
*cfg
= &parse
.cftable_entry
;
205 cistpl_cftable_entry_t dflt
= { 0 };
207 int last_ret
, last_fn
;
209 DEBUG(0, "parport_config(0x%p)\n", link
);
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];
222 link
->state
|= DEV_CONFIG
;
224 /* Not sure if this is right... look up the current Vcc */
225 CS_CHECK(GetConfigurationInfo
, pcmcia_get_configuration_info(handle
, &conf
));
227 tuple
.DesiredTuple
= CISTPL_CFTABLE_ENTRY
;
228 tuple
.Attributes
= 0;
229 CS_CHECK(GetFirstTuple
, pcmcia_get_first_tuple(handle
, &tuple
));
231 if (pcmcia_get_tuple_data(handle
, &tuple
) != 0 ||
232 pcmcia_parse_tuple(handle
, &tuple
, &parse
) != 0)
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
;
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
;
244 link
->io
.BasePort2
= io
->win
[1].base
;
245 link
->io
.NumPorts2
= io
->win
[1].len
;
247 if (pcmcia_request_io(link
->handle
, &link
->io
) != 0)
249 /* If we've got this far, we're done */
254 if (cfg
->flags
& CISTPL_CFTABLE_DEFAULT
) dflt
= *cfg
;
255 CS_CHECK(GetNextTuple
, pcmcia_get_next_tuple(handle
, &tuple
));
258 CS_CHECK(RequestIRQ
, pcmcia_request_irq(handle
, &link
->irq
));
259 CS_CHECK(RequestConfiguration
, pcmcia_request_configuration(handle
, &link
->conf
));
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
,
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
);
274 p
->modes
|= PARPORT_MODE_PCSPP
;
276 p
->modes
|= PARPORT_MODE_TRISTATE
| PARPORT_MODE_EPP
;
278 info
->node
.major
= LP_MAJOR
;
279 info
->node
.minor
= p
->number
;
281 strcpy(info
->node
.dev_name
, p
->name
);
282 link
->dev
= &info
->node
;
284 link
->state
&= ~DEV_CONFIG_PENDING
;
288 cs_error(link
->handle
, last_fn
, last_ret
);
290 parport_cs_release(link
);
291 link
->state
&= ~DEV_CONFIG_PENDING
;
293 } /* parport_config */
295 /*======================================================================
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.
301 ======================================================================*/
303 void parport_cs_release(dev_link_t
*link
)
305 parport_info_t
*info
= link
->priv
;
307 DEBUG(0, "parport_release(0x%p)\n", link
);
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
);
321 pcmcia_release_configuration(link
->handle
);
322 pcmcia_release_io(link
->handle
, &link
->io
);
323 pcmcia_release_irq(link
->handle
, &link
->irq
);
325 link
->state
&= ~DEV_CONFIG
;
327 } /* parport_cs_release */
329 /*======================================================================
331 The card status event handler. Mostly, this schedules other
332 stuff to run after an event is received.
334 ======================================================================*/
336 int parport_event(event_t event
, int priority
,
337 event_callback_args_t
*args
)
339 dev_link_t
*link
= args
->client_data
;
341 DEBUG(1, "parport_event(0x%06x)\n", event
);
344 case CS_EVENT_CARD_REMOVAL
:
345 link
->state
&= ~DEV_PRESENT
;
346 if (link
->state
& DEV_CONFIG
)
347 parport_cs_release(link
);
349 case CS_EVENT_CARD_INSERTION
:
350 link
->state
|= DEV_PRESENT
| DEV_CONFIG_PENDING
;
351 parport_config(link
);
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
);
360 case CS_EVENT_PM_RESUME
:
361 link
->state
&= ~DEV_SUSPEND
;
362 /* Fall through... */
363 case CS_EVENT_CARD_RESET
:
365 pcmcia_request_configuration(link
->handle
, &link
->conf
);
369 } /* parport_event */
371 static struct pcmcia_device_id parport_ids
[] = {
372 PCMCIA_DEVICE_FUNC_ID(3),
373 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003),
376 MODULE_DEVICE_TABLE(pcmcia
, parport_ids
);
378 static struct pcmcia_driver parport_cs_driver
= {
379 .owner
= THIS_MODULE
,
381 .name
= "parport_cs",
383 .attach
= parport_attach
,
384 .event
= parport_event
,
385 .detach
= parport_detach
,
386 .id_table
= parport_ids
,
390 static int __init
init_parport_cs(void)
392 return pcmcia_register_driver(&parport_cs_driver
);
395 static void __exit
exit_parport_cs(void)
397 pcmcia_unregister_driver(&parport_cs_driver
);
398 BUG_ON(dev_list
!= NULL
);
401 module_init(init_parport_cs
);
402 module_exit(exit_parport_cs
);