11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*======================================================================
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    A driver for PCMCIA parallel port adapters
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    (specifically, for the Quatech SPP-100 EPP card: other cards will
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    probably require driver tweaks)
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    parport_cs.c 1.29 2002/10/11 06:57:41
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    The contents of this file are subject to the Mozilla Public
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    License Version 1.1 (the "License"); you may not use this file
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    except in compliance with the License. You may obtain a copy of
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    the License at http://www.mozilla.org/MPL/
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Software distributed under the License is distributed on an "AS
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    implied. See the License for the specific language governing
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    rights and limitations under the License.
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    The initial developer of the original code is David A. Hinds
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Alternatively, the contents of this file may be used under the
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    terms of the GNU General Public License version 2 (the "GPL"), in
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    which case the provisions of the GPL are applicable instead of the
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    above.  If you wish to allow the use of your version of this file
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    only under the terms of the GPL and not to allow others to use
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    your version of this file under the MPL, indicate your decision
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    by deleting the provisions above and replace them with the notice
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    and other provisions required by the GPL.  If you do not delete
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    the provisions above, a recipient may use your version of this
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    file under either the MPL or the GPL.
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds======================================================================*/
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/major.h>
4651dcdfec6a274afc1c6fce180d582add9ff512c0Alan Cox#include <linux/interrupt.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/parport.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/parport_pc.h>
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/cistpl.h>
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/ds.h>
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/cisreg.h>
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/ciscode.h>
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Module parameters */
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("PCMCIA parallel port card driver");
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("Dual MPL/GPL");
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsINT_MODULE_PARM(epp_mode, 1);
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FORCE_EPP_MODE	0x08
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct parport_info_t {
74fd238232cd0ff4840ae6946bb338502154096d88Dominik Brodowski	struct pcmcia_device	*p_dev;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    int			ndev;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    struct parport	*port;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} parport_info_t;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
79cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowskistatic void parport_detach(struct pcmcia_device *p_dev);
8015b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowskistatic int parport_config(struct pcmcia_device *link);
81fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowskistatic void parport_cs_release(struct pcmcia_device *);
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8315b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowskistatic int parport_probe(struct pcmcia_device *link)
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    parport_info_t *info;
86f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowski
879b44de2015ff4a2ed1d56efedfcc72b917d356a6Dominik Brodowski    dev_dbg(&link->dev, "parport_attach()\n");
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Create new parport device */
90dd00cc486ab1c17049a535413d1751ef3482141cYoann Padioleau    info = kzalloc(sizeof(*info), GFP_KERNEL);
91f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowski    if (!info) return -ENOMEM;
92fd238232cd0ff4840ae6946bb338502154096d88Dominik Brodowski    link->priv = info;
93fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowski    info->p_dev = link;
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9500990e7ce0b0e596fe41d9c64d6933ea70084003Dominik Brodowski    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
96f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowski
9715b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowski    return parport_config(link);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* parport_attach */
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
100fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowskistatic void parport_detach(struct pcmcia_device *link)
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1029b44de2015ff4a2ed1d56efedfcc72b917d356a6Dominik Brodowski    dev_dbg(&link->dev, "parport_detach\n");
103cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski
104e2d4096365e06b9a3799afbadc28b4519c0b3526Dominik Brodowski    parport_cs_release(link);
105cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    kfree(link->priv);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* parport_detach */
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10900990e7ce0b0e596fe41d9c64d6933ea70084003Dominik Brodowskistatic int parport_config_check(struct pcmcia_device *p_dev, void *priv_data)
11084e2d34004dcd0c90d1af43a143511b334f11a4dDominik Brodowski{
11100990e7ce0b0e596fe41d9c64d6933ea70084003Dominik Brodowski	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
11200990e7ce0b0e596fe41d9c64d6933ea70084003Dominik Brodowski	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
11300990e7ce0b0e596fe41d9c64d6933ea70084003Dominik Brodowski	p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
11400990e7ce0b0e596fe41d9c64d6933ea70084003Dominik Brodowski	p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
11500990e7ce0b0e596fe41d9c64d6933ea70084003Dominik Brodowski
11600990e7ce0b0e596fe41d9c64d6933ea70084003Dominik Brodowski	return pcmcia_request_io(p_dev);
11784e2d34004dcd0c90d1af43a143511b334f11a4dDominik Brodowski}
11884e2d34004dcd0c90d1af43a143511b334f11a4dDominik Brodowski
11915b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowskistatic int parport_config(struct pcmcia_device *link)
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    parport_info_t *info = link->priv;
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    struct parport *p;
1239b44de2015ff4a2ed1d56efedfcc72b917d356a6Dominik Brodowski    int ret;
12484e2d34004dcd0c90d1af43a143511b334f11a4dDominik Brodowski
1259b44de2015ff4a2ed1d56efedfcc72b917d356a6Dominik Brodowski    dev_dbg(&link->dev, "parport_config\n");
12684e2d34004dcd0c90d1af43a143511b334f11a4dDominik Brodowski
12700990e7ce0b0e596fe41d9c64d6933ea70084003Dominik Brodowski    if (epp_mode)
12800990e7ce0b0e596fe41d9c64d6933ea70084003Dominik Brodowski	    link->config_index |= FORCE_EPP_MODE;
12900990e7ce0b0e596fe41d9c64d6933ea70084003Dominik Brodowski
1309b44de2015ff4a2ed1d56efedfcc72b917d356a6Dominik Brodowski    ret = pcmcia_loop_config(link, parport_config_check, NULL);
1319b44de2015ff4a2ed1d56efedfcc72b917d356a6Dominik Brodowski    if (ret)
13284e2d34004dcd0c90d1af43a143511b334f11a4dDominik Brodowski	    goto failed;
13384e2d34004dcd0c90d1af43a143511b334f11a4dDominik Brodowski
134eb14120f743d29744d9475bffec56ff4ad43a749Dominik Brodowski    if (!link->irq)
1359b44de2015ff4a2ed1d56efedfcc72b917d356a6Dominik Brodowski	    goto failed;
1361ac71e5a35eebee60cdcf15b3980bd94498f037bDominik Brodowski    ret = pcmcia_enable_device(link);
1379b44de2015ff4a2ed1d56efedfcc72b917d356a6Dominik Brodowski    if (ret)
1389b44de2015ff4a2ed1d56efedfcc72b917d356a6Dominik Brodowski	    goto failed;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1409a017a910346afd88ec2e065989903bf211a7d37Dominik Brodowski    p = parport_pc_probe_port(link->resource[0]->start,
1419a017a910346afd88ec2e065989903bf211a7d37Dominik Brodowski			      link->resource[1]->start,
142eb14120f743d29744d9475bffec56ff4ad43a749Dominik Brodowski			      link->irq, PARPORT_DMA_NONE,
14351dcdfec6a274afc1c6fce180d582add9ff512c0Alan Cox			      &link->dev, IRQF_SHARED);
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (p == NULL) {
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at "
1469a017a910346afd88ec2e065989903bf211a7d37Dominik Brodowski	       "0x%3x, irq %u failed\n",
1479a017a910346afd88ec2e065989903bf211a7d37Dominik Brodowski	       (unsigned int) link->resource[0]->start,
148eb14120f743d29744d9475bffec56ff4ad43a749Dominik Brodowski	       link->irq);
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto failed;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    p->modes |= PARPORT_MODE_PCSPP;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (epp_mode)
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    info->ndev = 1;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    info->port = p;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15815b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowski    return 0;
15915b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowski
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed:
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    parport_cs_release(link);
16215b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowski    return -ENODEV;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* parport_config */
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16523d5f96ce6571da51c0f6bfa7361e5f91f314b2bAdrian Bunkstatic void parport_cs_release(struct pcmcia_device *link)
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1675f2a71fcb7995633b335a1e380ac63a968e61320Dominik Brodowski	parport_info_t *info = link->priv;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1699b44de2015ff4a2ed1d56efedfcc72b917d356a6Dominik Brodowski	dev_dbg(&link->dev, "parport_release\n");
1705f2a71fcb7995633b335a1e380ac63a968e61320Dominik Brodowski
1715f2a71fcb7995633b335a1e380ac63a968e61320Dominik Brodowski	if (info->ndev) {
1725f2a71fcb7995633b335a1e380ac63a968e61320Dominik Brodowski		struct parport *p = info->port;
1735f2a71fcb7995633b335a1e380ac63a968e61320Dominik Brodowski		parport_pc_unregister_port(p);
1745f2a71fcb7995633b335a1e380ac63a968e61320Dominik Brodowski	}
1755f2a71fcb7995633b335a1e380ac63a968e61320Dominik Brodowski	info->ndev = 0;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
177fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowski	pcmcia_disable_device(link);
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* parport_cs_release */
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18098e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski
18125f8f54f6e178acfd503a95441b0ea05c525f751Joe Perchesstatic const struct pcmcia_device_id parport_ids[] = {
182476835afd7fefa353e932e160c14effc67e2ba6eDominik Brodowski	PCMCIA_DEVICE_FUNC_ID(3),
18344e5e33e99e1b955ac6f0bb26abd9380629b48a9Tony Olech	PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
184476835afd7fefa353e932e160c14effc67e2ba6eDominik Brodowski	PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003),
185476835afd7fefa353e932e160c14effc67e2ba6eDominik Brodowski	PCMCIA_DEVICE_NULL
186476835afd7fefa353e932e160c14effc67e2ba6eDominik Brodowski};
187476835afd7fefa353e932e160c14effc67e2ba6eDominik BrodowskiMODULE_DEVICE_TABLE(pcmcia, parport_ids);
188476835afd7fefa353e932e160c14effc67e2ba6eDominik Brodowski
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pcmcia_driver parport_cs_driver = {
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		= THIS_MODULE,
1912e9b981a7c63ee8278df6823f8389d69dad1a499Dominik Brodowski	.name		= "parport_cs",
19215b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowski	.probe		= parport_probe,
193cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski	.remove		= parport_detach,
194476835afd7fefa353e932e160c14effc67e2ba6eDominik Brodowski	.id_table	= parport_ids,
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init_parport_cs(void)
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return pcmcia_register_driver(&parport_cs_driver);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit exit_parport_cs(void)
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pcmcia_unregister_driver(&parport_cs_driver);
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(init_parport_cs);
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(exit_parport_cs);
209