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.24 2001/10/13 14:04:05
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
38#include <linux/kernel.h>
39#include <linux/version.h>
40#include <linux/module.h>
41#include <linux/init.h>
42#include <linux/sched.h>
43#include <linux/ptrace.h>
44#include <linux/slab.h>
45#include <linux/string.h>
46#include <linux/timer.h>
47#include <linux/ioport.h>
48
49#include <linux/parport.h>
50#include <linux/parport_pc.h>
51
52#include <pcmcia/version.h>
53#include <pcmcia/cs_types.h>
54#include <pcmcia/cs.h>
55#include <pcmcia/cistpl.h>
56#include <pcmcia/ds.h>
57#include <pcmcia/cisreg.h>
58#include <pcmcia/ciscode.h>
59
60/*====================================================================*/
61
62/* Module parameters */
63
64MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
65MODULE_DESCRIPTION("PCMCIA parallel port card driver");
66MODULE_LICENSE("Dual MPL/GPL");
67
68#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
69
70/* Bit map of interrupts to choose from */
71INT_MODULE_PARM(irq_mask, 0xdeb8);
72static int irq_list[4] = { -1 };
73MODULE_PARM(irq_list, "1-4i");
74
75INT_MODULE_PARM(epp_mode, 1);
76
77#ifdef PCMCIA_DEBUG
78INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
79#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
80static char *version =
81"parport_cs.c 1.24 2001/10/13 14:04:05 (David Hinds)";
82#else
83#define DEBUG(n, args...)
84#endif
85
86/*====================================================================*/
87
88#define FORCE_EPP_MODE	0x08
89
90typedef struct parport_info_t {
91    dev_link_t		link;
92    int			ndev;
93    dev_node_t		node;
94    struct parport	*port;
95} parport_info_t;
96
97static dev_link_t *parport_attach(void);
98static void parport_detach(dev_link_t *);
99static void parport_config(dev_link_t *link);
100static void parport_cs_release(u_long arg);
101static int parport_event(event_t event, int priority,
102			 event_callback_args_t *args);
103
104static dev_info_t dev_info = "parport_cs";
105static dev_link_t *dev_list = NULL;
106
107/*====================================================================*/
108
109static void cs_error(client_handle_t handle, int func, int ret)
110{
111    error_info_t err = { func, ret };
112    CardServices(ReportError, handle, &err);
113}
114
115/*======================================================================
116
117    parport_attach() creates an "instance" of the driver, allocating
118    local data structures for one device.  The device is registered
119    with Card Services.
120
121======================================================================*/
122
123static dev_link_t *parport_attach(void)
124{
125    parport_info_t *info;
126    dev_link_t *link;
127    client_reg_t client_reg;
128    int i, ret;
129
130    DEBUG(0, "parport_attach()\n");
131
132    /* Create new parport device */
133    info = kmalloc(sizeof(*info), GFP_KERNEL);
134    if (!info) return NULL;
135    memset(info, 0, sizeof(*info));
136    link = &info->link; link->priv = info;
137
138    link->release.function = &parport_cs_release;
139    link->release.data = (u_long)link;
140    link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
141    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
142    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
143    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
144    if (irq_list[0] == -1)
145	link->irq.IRQInfo2 = irq_mask;
146    else
147	for (i = 0; i < 4; i++)
148	    link->irq.IRQInfo2 |= 1 << irq_list[i];
149    link->conf.Attributes = CONF_ENABLE_IRQ;
150    link->conf.Vcc = 50;
151    link->conf.IntType = INT_MEMORY_AND_IO;
152
153    /* Register with Card Services */
154    link->next = dev_list;
155    dev_list = link;
156    client_reg.dev_info = &dev_info;
157    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
158    client_reg.EventMask =
159	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
160	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
161	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
162    client_reg.event_handler = &parport_event;
163    client_reg.Version = 0x0210;
164    client_reg.event_callback_args.client_data = link;
165    ret = CardServices(RegisterClient, &link->handle, &client_reg);
166    if (ret != CS_SUCCESS) {
167	cs_error(link->handle, RegisterClient, ret);
168	parport_detach(link);
169	return NULL;
170    }
171
172    return link;
173} /* parport_attach */
174
175/*======================================================================
176
177    This deletes a driver "instance".  The device is de-registered
178    with Card Services.  If it has been released, all local data
179    structures are freed.  Otherwise, the structures will be freed
180    when the device is released.
181
182======================================================================*/
183
184static void parport_detach(dev_link_t *link)
185{
186    dev_link_t **linkp;
187    int ret;
188
189    DEBUG(0, "parport_detach(0x%p)\n", link);
190
191    /* Locate device structure */
192    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
193	if (*linkp == link) break;
194    if (*linkp == NULL)
195	return;
196
197    del_timer(&link->release);
198    if (link->state & DEV_CONFIG)
199	parport_cs_release((u_long)link);
200
201    if (link->handle) {
202	ret = CardServices(DeregisterClient, link->handle);
203	if (ret != CS_SUCCESS)
204	    cs_error(link->handle, DeregisterClient, ret);
205    }
206
207    /* Unlink, free device structure */
208    *linkp = link->next;
209    kfree(link->priv);
210
211} /* parport_detach */
212
213/*======================================================================
214
215    parport_config() is scheduled to run after a CARD_INSERTION event
216    is received, to configure the PCMCIA socket, and to make the
217    parport device available to the system.
218
219======================================================================*/
220
221#define CS_CHECK(fn, args...) \
222while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
223
224#define CFG_CHECK(fn, args...) \
225if (CardServices(fn, args) != 0) goto next_entry
226
227static struct { u_int flag; char *name; } mode[] = {
228    { PARPORT_MODE_TRISTATE, "PS2" },
229    { PARPORT_MODE_EPP, "EPP" },
230    { PARPORT_MODE_ECP, "ECP" },
231};
232
233void parport_config(dev_link_t *link)
234{
235    client_handle_t handle = link->handle;
236    parport_info_t *info = link->priv;
237    tuple_t tuple;
238    u_short buf[128];
239    cisparse_t parse;
240    config_info_t conf;
241    cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
242    cistpl_cftable_entry_t dflt = { 0 };
243    struct parport *p;
244    int i, last_ret, last_fn;
245
246    DEBUG(0, "parport_config(0x%p)\n", link);
247
248    tuple.TupleData = (cisdata_t *)buf;
249    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
250    tuple.Attributes = 0;
251    tuple.DesiredTuple = CISTPL_CONFIG;
252    CS_CHECK(GetFirstTuple, handle, &tuple);
253    CS_CHECK(GetTupleData, handle, &tuple);
254    CS_CHECK(ParseTuple, handle, &tuple, &parse);
255    link->conf.ConfigBase = parse.config.base;
256    link->conf.Present = parse.config.rmask[0];
257
258    /* Configure card */
259    link->state |= DEV_CONFIG;
260
261    /* Not sure if this is right... look up the current Vcc */
262    CS_CHECK(GetConfigurationInfo, handle, &conf);
263
264    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
265    tuple.Attributes = 0;
266    CS_CHECK(GetFirstTuple, handle, &tuple);
267    while (1) {
268	CFG_CHECK(GetTupleData, handle, &tuple);
269	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
270
271	if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
272	    cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
273	    link->conf.ConfigIndex = cfg->index;
274	    if (epp_mode)
275		link->conf.ConfigIndex |= FORCE_EPP_MODE;
276	    link->io.BasePort1 = io->win[0].base;
277	    link->io.NumPorts1 = io->win[0].len;
278	    link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
279	    if (io->nwin == 2) {
280		link->io.BasePort2 = io->win[1].base;
281		link->io.NumPorts2 = io->win[1].len;
282	    }
283	    CFG_CHECK(RequestIO, link->handle, &link->io);
284	    /* If we've got this far, we're done */
285	    break;
286	}
287
288    next_entry:
289	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
290	CS_CHECK(GetNextTuple, handle, &tuple);
291    }
292
293    CS_CHECK(RequestIRQ, handle, &link->irq);
294    CS_CHECK(RequestConfiguration, handle, &link->conf);
295
296    p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2,
297			      link->irq.AssignedIRQ, PARPORT_DMA_NONE,
298			      NULL);
299    if (p == NULL) {
300	printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at "
301	       "0x%3x, irq %u failed\n", link->io.BasePort1,
302	       link->irq.AssignedIRQ);
303	goto failed;
304    }
305
306    p->modes |= PARPORT_MODE_PCSPP;
307    if (epp_mode)
308	p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP;
309    info->ndev = 1;
310    info->node.major = LP_MAJOR;
311    info->node.minor = p->number;
312    info->port = p;
313    strcpy(info->node.dev_name, p->name);
314    link->dev = &info->node;
315    printk(KERN_INFO "%s: PC-style PCMCIA at %#x", p->name,
316	   link->io.BasePort1);
317    if (link->io.NumPorts2)
318	printk(" & %#x", link->io.BasePort2);
319    printk(", irq %u [SPP", link->irq.AssignedIRQ);
320    for (i = 0; i < 5; i++)
321	if (p->modes & mode[i].flag) printk(",%s", mode[i].name);
322    printk("]\n");
323
324    link->state &= ~DEV_CONFIG_PENDING;
325    return;
326
327cs_failed:
328    cs_error(link->handle, last_fn, last_ret);
329failed:
330    parport_cs_release((u_long)link);
331
332} /* parport_config */
333
334/*======================================================================
335
336    After a card is removed, parport_cs_release() will unregister the
337    device, and release the PCMCIA configuration.  If the device is
338    still open, this will be postponed until it is closed.
339
340======================================================================*/
341
342void parport_cs_release(u_long arg)
343{
344    dev_link_t *link = (dev_link_t *)arg;
345    parport_info_t *info = link->priv;
346
347    DEBUG(0, "parport_release(0x%p)\n", link);
348
349    if (info->ndev) {
350	struct parport *p = info->port;
351	parport_proc_unregister(p);
352	kfree(p->private_data);
353	parport_unregister_port(p);
354    }
355    info->ndev = 0;
356    link->dev = NULL;
357
358    CardServices(ReleaseConfiguration, link->handle);
359    CardServices(ReleaseIO, link->handle, &link->io);
360    CardServices(ReleaseIRQ, link->handle, &link->irq);
361
362    link->state &= ~DEV_CONFIG;
363
364} /* parport_cs_release */
365
366/*======================================================================
367
368    The card status event handler.  Mostly, this schedules other
369    stuff to run after an event is received.
370
371======================================================================*/
372
373int parport_event(event_t event, int priority,
374		  event_callback_args_t *args)
375{
376    dev_link_t *link = args->client_data;
377
378    DEBUG(1, "parport_event(0x%06x)\n", event);
379
380    switch (event) {
381    case CS_EVENT_CARD_REMOVAL:
382	link->state &= ~DEV_PRESENT;
383	if (link->state & DEV_CONFIG)
384	    mod_timer(&link->release, jiffies + HZ/20);
385	break;
386    case CS_EVENT_CARD_INSERTION:
387	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
388	parport_config(link);
389	break;
390    case CS_EVENT_PM_SUSPEND:
391	link->state |= DEV_SUSPEND;
392	/* Fall through... */
393    case CS_EVENT_RESET_PHYSICAL:
394	if (link->state & DEV_CONFIG)
395	    CardServices(ReleaseConfiguration, link->handle);
396	break;
397    case CS_EVENT_PM_RESUME:
398	link->state &= ~DEV_SUSPEND;
399	/* Fall through... */
400    case CS_EVENT_CARD_RESET:
401	if (DEV_OK(link))
402	    CardServices(RequestConfiguration, link->handle, &link->conf);
403	break;
404    }
405    return 0;
406} /* parport_event */
407
408/*====================================================================*/
409
410static int __init init_parport_cs(void)
411{
412    servinfo_t serv;
413    DEBUG(0, "%s\n", version);
414    CardServices(GetCardServicesInfo, &serv);
415    if (serv.Revision != CS_RELEASE_CODE) {
416	printk(KERN_NOTICE "parport_cs: Card Services release "
417	       "does not match!\n");
418	return -1;
419    }
420
421    register_pccard_driver(&dev_info, &parport_attach, &parport_detach);
422    return 0;
423}
424
425static void __exit exit_parport_cs(void)
426{
427    DEBUG(0, "parport_cs: unloading\n");
428    unregister_pccard_driver(&dev_info);
429    while (dev_list != NULL)
430	parport_detach(dev_list);
431}
432
433module_init(init_parport_cs);
434module_exit(exit_parport_cs);
435