[PATCH] alpha: fix "statement with no effect" warnings
[pandora-kernel.git] / drivers / parport / parport_cs.c
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);