Merge git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia-2.6
[linux-2.6-block.git] / drivers / parport / parport_cs.c
CommitLineData
1da177e4
LT
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>
1da177e4
LT
40#include <linux/ptrace.h>
41#include <linux/slab.h>
42#include <linux/string.h>
43#include <linux/timer.h>
44#include <linux/ioport.h>
45#include <linux/major.h>
46
47#include <linux/parport.h>
48#include <linux/parport_pc.h>
49
1da177e4
LT
50#include <pcmcia/cs_types.h>
51#include <pcmcia/cs.h>
52#include <pcmcia/cistpl.h>
53#include <pcmcia/ds.h>
54#include <pcmcia/cisreg.h>
55#include <pcmcia/ciscode.h>
56
57/*====================================================================*/
58
59/* Module parameters */
60
61MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
62MODULE_DESCRIPTION("PCMCIA parallel port card driver");
63MODULE_LICENSE("Dual MPL/GPL");
64
65#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
66
67INT_MODULE_PARM(epp_mode, 1);
68
69#ifdef PCMCIA_DEBUG
70INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
71#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
72static char *version =
73"parport_cs.c 1.29 2002/10/11 06:57:41 (David Hinds)";
74#else
75#define DEBUG(n, args...)
76#endif
77
78/*====================================================================*/
79
80#define FORCE_EPP_MODE 0x08
81
82typedef struct parport_info_t {
fd238232 83 struct pcmcia_device *p_dev;
1da177e4
LT
84 int ndev;
85 dev_node_t node;
86 struct parport *port;
87} parport_info_t;
88
cc3b4866 89static void parport_detach(struct pcmcia_device *p_dev);
15b99ac1 90static int parport_config(struct pcmcia_device *link);
fba395ee 91static void parport_cs_release(struct pcmcia_device *);
1da177e4
LT
92
93/*======================================================================
94
95 parport_attach() creates an "instance" of the driver, allocating
96 local data structures for one device. The device is registered
97 with Card Services.
98
99======================================================================*/
100
15b99ac1 101static int parport_probe(struct pcmcia_device *link)
1da177e4
LT
102{
103 parport_info_t *info;
f8cfa618 104
1da177e4
LT
105 DEBUG(0, "parport_attach()\n");
106
107 /* Create new parport device */
dd00cc48 108 info = kzalloc(sizeof(*info), GFP_KERNEL);
f8cfa618 109 if (!info) return -ENOMEM;
fd238232 110 link->priv = info;
fba395ee 111 info->p_dev = link;
1da177e4
LT
112
113 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
114 link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
115 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
116 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
117 link->conf.Attributes = CONF_ENABLE_IRQ;
1da177e4 118 link->conf.IntType = INT_MEMORY_AND_IO;
f8cfa618 119
15b99ac1 120 return parport_config(link);
1da177e4
LT
121} /* parport_attach */
122
123/*======================================================================
124
125 This deletes a driver "instance". The device is de-registered
126 with Card Services. If it has been released, all local data
127 structures are freed. Otherwise, the structures will be freed
128 when the device is released.
129
130======================================================================*/
131
fba395ee 132static void parport_detach(struct pcmcia_device *link)
1da177e4 133{
1da177e4 134 DEBUG(0, "parport_detach(0x%p)\n", link);
cc3b4866 135
e2d40963 136 parport_cs_release(link);
cc3b4866 137
1da177e4 138 kfree(link->priv);
1da177e4
LT
139} /* parport_detach */
140
141/*======================================================================
142
143 parport_config() is scheduled to run after a CARD_INSERTION event
144 is received, to configure the PCMCIA socket, and to make the
145 parport device available to the system.
146
147======================================================================*/
148
149#define CS_CHECK(fn, ret) \
150do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
151
84e2d340
DB
152static int parport_config_check(struct pcmcia_device *p_dev,
153 cistpl_cftable_entry_t *cfg,
8e2fc39d 154 cistpl_cftable_entry_t *dflt,
ad913c11 155 unsigned int vcc,
84e2d340
DB
156 void *priv_data)
157{
84e2d340
DB
158 if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
159 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
84e2d340
DB
160 if (epp_mode)
161 p_dev->conf.ConfigIndex |= FORCE_EPP_MODE;
162 p_dev->io.BasePort1 = io->win[0].base;
163 p_dev->io.NumPorts1 = io->win[0].len;
164 p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
165 if (io->nwin == 2) {
166 p_dev->io.BasePort2 = io->win[1].base;
167 p_dev->io.NumPorts2 = io->win[1].len;
168 }
169 if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
8e2fc39d 170 return -ENODEV;
84e2d340
DB
171 return 0;
172 }
ad913c11 173 return -ENODEV;
84e2d340
DB
174}
175
15b99ac1 176static int parport_config(struct pcmcia_device *link)
1da177e4 177{
1da177e4 178 parport_info_t *info = link->priv;
1da177e4
LT
179 struct parport *p;
180 int last_ret, last_fn;
84e2d340 181
1da177e4 182 DEBUG(0, "parport_config(0x%p)\n", link);
84e2d340 183
8e2fc39d 184 last_ret = pcmcia_loop_config(link, parport_config_check, NULL);
84e2d340
DB
185 if (last_ret) {
186 cs_error(link, RequestIO, last_ret);
187 goto failed;
1da177e4 188 }
84e2d340 189
fba395ee
DB
190 CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
191 CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
1da177e4 192
1da177e4
LT
193 p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2,
194 link->irq.AssignedIRQ, PARPORT_DMA_NONE,
c15a3837 195 &link->dev);
1da177e4
LT
196 if (p == NULL) {
197 printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at "
198 "0x%3x, irq %u failed\n", link->io.BasePort1,
199 link->irq.AssignedIRQ);
200 goto failed;
201 }
202
203 p->modes |= PARPORT_MODE_PCSPP;
204 if (epp_mode)
205 p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP;
206 info->ndev = 1;
207 info->node.major = LP_MAJOR;
208 info->node.minor = p->number;
209 info->port = p;
210 strcpy(info->node.dev_name, p->name);
fd238232 211 link->dev_node = &info->node;
1da177e4 212
15b99ac1
DB
213 return 0;
214
1da177e4 215cs_failed:
fba395ee 216 cs_error(link, last_fn, last_ret);
1da177e4
LT
217failed:
218 parport_cs_release(link);
15b99ac1 219 return -ENODEV;
1da177e4
LT
220} /* parport_config */
221
222/*======================================================================
223
224 After a card is removed, parport_cs_release() will unregister the
225 device, and release the PCMCIA configuration. If the device is
226 still open, this will be postponed until it is closed.
227
228======================================================================*/
229
23d5f96c 230static void parport_cs_release(struct pcmcia_device *link)
1da177e4 231{
5f2a71fc 232 parport_info_t *info = link->priv;
1da177e4 233
5f2a71fc
DB
234 DEBUG(0, "parport_release(0x%p)\n", link);
235
236 if (info->ndev) {
237 struct parport *p = info->port;
238 parport_pc_unregister_port(p);
239 }
240 info->ndev = 0;
1da177e4 241
fba395ee 242 pcmcia_disable_device(link);
1da177e4
LT
243} /* parport_cs_release */
244
98e4c28b 245
476835af
DB
246static struct pcmcia_device_id parport_ids[] = {
247 PCMCIA_DEVICE_FUNC_ID(3),
44e5e33e 248 PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
476835af
DB
249 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003),
250 PCMCIA_DEVICE_NULL
251};
252MODULE_DEVICE_TABLE(pcmcia, parport_ids);
253
1da177e4
LT
254static struct pcmcia_driver parport_cs_driver = {
255 .owner = THIS_MODULE,
256 .drv = {
257 .name = "parport_cs",
258 },
15b99ac1 259 .probe = parport_probe,
cc3b4866 260 .remove = parport_detach,
476835af 261 .id_table = parport_ids,
1da177e4
LT
262};
263
264static int __init init_parport_cs(void)
265{
266 return pcmcia_register_driver(&parport_cs_driver);
267}
268
269static void __exit exit_parport_cs(void)
270{
271 pcmcia_unregister_driver(&parport_cs_driver);
1da177e4
LT
272}
273
274module_init(init_parport_cs);
275module_exit(exit_parport_cs);