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