blob: fd8cfe95f0a3ab815902a4fd5043228ecd140703 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*======================================================================
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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#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>
Alan Cox51dcdfe2009-04-07 15:30:57 +010046#include <linux/interrupt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48#include <linux/parport.h>
49#include <linux/parport_pc.h>
50
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#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
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
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
71/*====================================================================*/
72
73#define FORCE_EPP_MODE 0x08
74
75typedef struct parport_info_t {
Dominik Brodowskifd238232006-03-05 10:45:09 +010076 struct pcmcia_device *p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 int ndev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 struct parport *port;
79} parport_info_t;
80
Dominik Brodowskicc3b4862005-11-14 21:23:14 +010081static void parport_detach(struct pcmcia_device *p_dev);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +020082static int parport_config(struct pcmcia_device *link);
Dominik Brodowskifba395e2006-03-31 17:21:06 +020083static void parport_cs_release(struct pcmcia_device *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85/*======================================================================
86
87 parport_attach() creates an "instance" of the driver, allocating
88 local data structures for one device. The device is registered
89 with Card Services.
90
91======================================================================*/
92
Dominik Brodowski15b99ac2006-03-31 17:26:06 +020093static int parport_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -070094{
95 parport_info_t *info;
Dominik Brodowskif8cfa612005-11-14 21:25:51 +010096
Dominik Brodowski9b44de22009-10-24 15:55:39 +020097 dev_dbg(&link->dev, "parport_attach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
99 /* Create new parport device */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700100 info = kzalloc(sizeof(*info), GFP_KERNEL);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100101 if (!info) return -ENOMEM;
Dominik Brodowskifd238232006-03-05 10:45:09 +0100102 link->priv = info;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200103 info->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
105 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
106 link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 link->conf.Attributes = CONF_ENABLE_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 link->conf.IntType = INT_MEMORY_AND_IO;
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100109
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200110 return parport_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111} /* parport_attach */
112
113/*======================================================================
114
115 This deletes a driver "instance". The device is de-registered
116 with Card Services. If it has been released, all local data
117 structures are freed. Otherwise, the structures will be freed
118 when the device is released.
119
120======================================================================*/
121
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200122static void parport_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123{
Dominik Brodowski9b44de22009-10-24 15:55:39 +0200124 dev_dbg(&link->dev, "parport_detach\n");
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100125
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100126 parport_cs_release(link);
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100127
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 kfree(link->priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129} /* parport_detach */
130
131/*======================================================================
132
133 parport_config() is scheduled to run after a CARD_INSERTION event
134 is received, to configure the PCMCIA socket, and to make the
135 parport device available to the system.
136
137======================================================================*/
138
Dominik Brodowski84e2d342008-07-29 08:38:55 +0200139static int parport_config_check(struct pcmcia_device *p_dev,
140 cistpl_cftable_entry_t *cfg,
Dominik Brodowski8e2fc392008-08-02 15:30:31 +0200141 cistpl_cftable_entry_t *dflt,
Dominik Brodowskiad913c12008-08-02 16:12:00 +0200142 unsigned int vcc,
Dominik Brodowski84e2d342008-07-29 08:38:55 +0200143 void *priv_data)
144{
Dominik Brodowski84e2d342008-07-29 08:38:55 +0200145 if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
146 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
Dominik Brodowski84e2d342008-07-29 08:38:55 +0200147 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)
Dominik Brodowski8e2fc392008-08-02 15:30:31 +0200157 return -ENODEV;
Dominik Brodowski84e2d342008-07-29 08:38:55 +0200158 return 0;
159 }
Dominik Brodowskiad913c12008-08-02 16:12:00 +0200160 return -ENODEV;
Dominik Brodowski84e2d342008-07-29 08:38:55 +0200161}
162
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200163static int parport_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 parport_info_t *info = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 struct parport *p;
Dominik Brodowski9b44de22009-10-24 15:55:39 +0200167 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
Dominik Brodowski9b44de22009-10-24 15:55:39 +0200169 dev_dbg(&link->dev, "parport_config\n");
Dominik Brodowski84e2d342008-07-29 08:38:55 +0200170
Dominik Brodowski9b44de22009-10-24 15:55:39 +0200171 ret = pcmcia_loop_config(link, parport_config_check, NULL);
172 if (ret)
Dominik Brodowski84e2d342008-07-29 08:38:55 +0200173 goto failed;
Dominik Brodowski84e2d342008-07-29 08:38:55 +0200174
Dominik Brodowskieb141202010-03-07 12:21:16 +0100175 if (!link->irq)
Dominik Brodowski9b44de22009-10-24 15:55:39 +0200176 goto failed;
177 ret = pcmcia_request_configuration(link, &link->conf);
178 if (ret)
179 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2,
Dominik Brodowskieb141202010-03-07 12:21:16 +0100182 link->irq, PARPORT_DMA_NONE,
Alan Cox51dcdfe2009-04-07 15:30:57 +0100183 &link->dev, IRQF_SHARED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 if (p == NULL) {
185 printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at "
186 "0x%3x, irq %u failed\n", link->io.BasePort1,
Dominik Brodowskieb141202010-03-07 12:21:16 +0100187 link->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 info->port = p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200197 return 0;
198
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199failed:
200 parport_cs_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200201 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202} /* parport_config */
203
204/*======================================================================
205
206 After a card is removed, parport_cs_release() will unregister the
207 device, and release the PCMCIA configuration. If the device is
208 still open, this will be postponed until it is closed.
209
210======================================================================*/
211
Adrian Bunk23d5f962008-07-25 19:46:22 -0700212static void parport_cs_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213{
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100214 parport_info_t *info = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
Dominik Brodowski9b44de22009-10-24 15:55:39 +0200216 dev_dbg(&link->dev, "parport_release\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +0100218 if (info->ndev) {
219 struct parport *p = info->port;
220 parport_pc_unregister_port(p);
221 }
222 info->ndev = 0;
223
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200224 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225} /* parport_cs_release */
226
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100227
Dominik Brodowski476835a2005-06-27 16:28:29 -0700228static struct pcmcia_device_id parport_ids[] = {
229 PCMCIA_DEVICE_FUNC_ID(3),
Tony Olech44e5e332006-11-29 08:54:51 +0000230 PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
Dominik Brodowski476835a2005-06-27 16:28:29 -0700231 PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003),
232 PCMCIA_DEVICE_NULL
233};
234MODULE_DEVICE_TABLE(pcmcia, parport_ids);
235
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236static struct pcmcia_driver parport_cs_driver = {
237 .owner = THIS_MODULE,
238 .drv = {
239 .name = "parport_cs",
240 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200241 .probe = parport_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100242 .remove = parport_detach,
Dominik Brodowski476835a2005-06-27 16:28:29 -0700243 .id_table = parport_ids,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244};
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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254}
255
256module_init(init_parport_cs);
257module_exit(exit_parport_cs);