1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37#include <linux/kernel.h>
38#include <linux/module.h>
39#include <linux/init.h>
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#include <linux/interrupt.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
61
62MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
63MODULE_DESCRIPTION("PCMCIA parallel port card driver");
64MODULE_LICENSE("Dual MPL/GPL");
65
66#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
67
68INT_MODULE_PARM(epp_mode, 1);
69
70
71
72
73#define FORCE_EPP_MODE 0x08
74
75typedef struct parport_info_t {
76 struct pcmcia_device *p_dev;
77 int ndev;
78 struct parport *port;
79} parport_info_t;
80
81static void parport_detach(struct pcmcia_device *p_dev);
82static int parport_config(struct pcmcia_device *link);
83static void parport_cs_release(struct pcmcia_device *);
84
85
86
87
88
89
90
91
92
93static int parport_probe(struct pcmcia_device *link)
94{
95 parport_info_t *info;
96
97 dev_dbg(&link->dev, "parport_attach()\n");
98
99
100 info = kzalloc(sizeof(*info), GFP_KERNEL);
101 if (!info) return -ENOMEM;
102 link->priv = info;
103 info->p_dev = link;
104
105 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
106 link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
107 link->conf.Attributes = CONF_ENABLE_IRQ;
108 link->conf.IntType = INT_MEMORY_AND_IO;
109
110 return parport_config(link);
111}
112
113
114
115
116
117
118
119
120
121
122static void parport_detach(struct pcmcia_device *link)
123{
124 dev_dbg(&link->dev, "parport_detach\n");
125
126 parport_cs_release(link);
127
128 kfree(link->priv);
129}
130
131
132
133
134
135
136
137
138
139static int parport_config_check(struct pcmcia_device *p_dev,
140 cistpl_cftable_entry_t *cfg,
141 cistpl_cftable_entry_t *dflt,
142 unsigned int vcc,
143 void *priv_data)
144{
145 if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
146 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
147 if (epp_mode)
148 p_dev->conf.ConfigIndex |= FORCE_EPP_MODE;
149 p_dev->io.BasePort1 = io->win[0].base;
150 p_dev->io.NumPorts1 = io->win[0].len;
151 p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
152 if (io->nwin == 2) {
153 p_dev->io.BasePort2 = io->win[1].base;
154 p_dev->io.NumPorts2 = io->win[1].len;
155 }
156 if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
157 return -ENODEV;
158 return 0;
159 }
160 return -ENODEV;
161}
162
163static int parport_config(struct pcmcia_device *link)
164{
165 parport_info_t *info = link->priv;
166 struct parport *p;
167 int ret;
168
169 dev_dbg(&link->dev, "parport_config\n");
170
171 ret = pcmcia_loop_config(link, parport_config_check, NULL);
172 if (ret)
173 goto failed;
174
175 if (!link->irq)
176 goto failed;
177 ret = pcmcia_request_configuration(link, &link->conf);
178 if (ret)
179 goto failed;
180
181 p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2,
182 link->irq, PARPORT_DMA_NONE,
183 &link->dev, IRQF_SHARED);
184 if (p == NULL) {
185 printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at "
186 "0x%3x, irq %u failed\n", link->io.BasePort1,
187 link->irq);
188 goto failed;
189 }
190
191 p->modes |= PARPORT_MODE_PCSPP;
192 if (epp_mode)
193 p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP;
194 info->ndev = 1;
195 info->port = p;
196
197 return 0;
198
199failed:
200 parport_cs_release(link);
201 return -ENODEV;
202}
203
204
205
206
207
208
209
210
211
212static void parport_cs_release(struct pcmcia_device *link)
213{
214 parport_info_t *info = link->priv;
215
216 dev_dbg(&link->dev, "parport_release\n");
217
218 if (info->ndev) {
219 struct parport *p = info->port;
220 parport_pc_unregister_port(p);
221 }
222 info->ndev = 0;
223
224 pcmcia_disable_device(link);
225}
226
227
228static struct pcmcia_device_id parport_ids[] = {
229 PCMCIA_DEVICE_FUNC_ID(3),
230 PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
231 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003),
232 PCMCIA_DEVICE_NULL
233};
234MODULE_DEVICE_TABLE(pcmcia, parport_ids);
235
236static struct pcmcia_driver parport_cs_driver = {
237 .owner = THIS_MODULE,
238 .drv = {
239 .name = "parport_cs",
240 },
241 .probe = parport_probe,
242 .remove = parport_detach,
243 .id_table = parport_ids,
244};
245
246static int __init init_parport_cs(void)
247{
248 return pcmcia_register_driver(&parport_cs_driver);
249}
250
251static void __exit exit_parport_cs(void)
252{
253 pcmcia_unregister_driver(&parport_cs_driver);
254}
255
256module_init(init_parport_cs);
257module_exit(exit_parport_cs);
258