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