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