11da177e4SLinus Torvalds /*======================================================================
21da177e4SLinus Torvalds
31da177e4SLinus Torvalds A driver for PCMCIA parallel port adapters
41da177e4SLinus Torvalds
51da177e4SLinus Torvalds (specifically, for the Quatech SPP-100 EPP card: other cards will
61da177e4SLinus Torvalds probably require driver tweaks)
71da177e4SLinus Torvalds
81da177e4SLinus Torvalds parport_cs.c 1.29 2002/10/11 06:57:41
91da177e4SLinus Torvalds
101da177e4SLinus Torvalds The contents of this file are subject to the Mozilla Public
111da177e4SLinus Torvalds License Version 1.1 (the "License"); you may not use this file
121da177e4SLinus Torvalds except in compliance with the License. You may obtain a copy of
131da177e4SLinus Torvalds the License at http://www.mozilla.org/MPL/
141da177e4SLinus Torvalds
151da177e4SLinus Torvalds Software distributed under the License is distributed on an "AS
161da177e4SLinus Torvalds IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
171da177e4SLinus Torvalds implied. See the License for the specific language governing
181da177e4SLinus Torvalds rights and limitations under the License.
191da177e4SLinus Torvalds
201da177e4SLinus Torvalds The initial developer of the original code is David A. Hinds
211da177e4SLinus Torvalds <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
221da177e4SLinus Torvalds are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
231da177e4SLinus Torvalds
241da177e4SLinus Torvalds Alternatively, the contents of this file may be used under the
251da177e4SLinus Torvalds terms of the GNU General Public License version 2 (the "GPL"), in
261da177e4SLinus Torvalds which case the provisions of the GPL are applicable instead of the
271da177e4SLinus Torvalds above. If you wish to allow the use of your version of this file
281da177e4SLinus Torvalds only under the terms of the GPL and not to allow others to use
291da177e4SLinus Torvalds your version of this file under the MPL, indicate your decision
301da177e4SLinus Torvalds by deleting the provisions above and replace them with the notice
311da177e4SLinus Torvalds and other provisions required by the GPL. If you do not delete
321da177e4SLinus Torvalds the provisions above, a recipient may use your version of this
331da177e4SLinus Torvalds file under either the MPL or the GPL.
341da177e4SLinus Torvalds
351da177e4SLinus Torvalds ======================================================================*/
361da177e4SLinus Torvalds
371da177e4SLinus Torvalds #include <linux/kernel.h>
381da177e4SLinus Torvalds #include <linux/module.h>
391da177e4SLinus Torvalds #include <linux/init.h>
401da177e4SLinus Torvalds #include <linux/ptrace.h>
411da177e4SLinus Torvalds #include <linux/slab.h>
421da177e4SLinus Torvalds #include <linux/string.h>
431da177e4SLinus Torvalds #include <linux/timer.h>
441da177e4SLinus Torvalds #include <linux/ioport.h>
451da177e4SLinus Torvalds #include <linux/major.h>
4651dcdfecSAlan Cox #include <linux/interrupt.h>
471da177e4SLinus Torvalds
481da177e4SLinus Torvalds #include <linux/parport.h>
491da177e4SLinus Torvalds #include <linux/parport_pc.h>
501da177e4SLinus Torvalds
511da177e4SLinus Torvalds #include <pcmcia/cistpl.h>
521da177e4SLinus Torvalds #include <pcmcia/ds.h>
531da177e4SLinus Torvalds #include <pcmcia/cisreg.h>
541da177e4SLinus Torvalds #include <pcmcia/ciscode.h>
551da177e4SLinus Torvalds
561da177e4SLinus Torvalds /*====================================================================*/
571da177e4SLinus Torvalds
581da177e4SLinus Torvalds /* Module parameters */
591da177e4SLinus Torvalds
601da177e4SLinus Torvalds MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
611da177e4SLinus Torvalds MODULE_DESCRIPTION("PCMCIA parallel port card driver");
621da177e4SLinus Torvalds MODULE_LICENSE("Dual MPL/GPL");
631da177e4SLinus Torvalds
641da177e4SLinus Torvalds #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
651da177e4SLinus Torvalds
661da177e4SLinus Torvalds INT_MODULE_PARM(epp_mode, 1);
671da177e4SLinus Torvalds
681da177e4SLinus Torvalds
691da177e4SLinus Torvalds /*====================================================================*/
701da177e4SLinus Torvalds
711da177e4SLinus Torvalds #define FORCE_EPP_MODE 0x08
721da177e4SLinus Torvalds
731da177e4SLinus Torvalds typedef struct parport_info_t {
74fd238232SDominik Brodowski struct pcmcia_device *p_dev;
751da177e4SLinus Torvalds int ndev;
761da177e4SLinus Torvalds struct parport *port;
771da177e4SLinus Torvalds } parport_info_t;
781da177e4SLinus Torvalds
79cc3b4866SDominik Brodowski static void parport_detach(struct pcmcia_device *p_dev);
8015b99ac1SDominik Brodowski static int parport_config(struct pcmcia_device *link);
81fba395eeSDominik Brodowski static void parport_cs_release(struct pcmcia_device *);
821da177e4SLinus Torvalds
parport_probe(struct pcmcia_device * link)8315b99ac1SDominik Brodowski static int parport_probe(struct pcmcia_device *link)
841da177e4SLinus Torvalds {
851da177e4SLinus Torvalds parport_info_t *info;
861da177e4SLinus Torvalds
879b44de20SDominik Brodowski dev_dbg(&link->dev, "parport_attach()\n");
881da177e4SLinus Torvalds
891da177e4SLinus Torvalds /* Create new parport device */
90dd00cc48SYoann Padioleau info = kzalloc(sizeof(*info), GFP_KERNEL);
91f8cfa618SDominik Brodowski if (!info) return -ENOMEM;
92fd238232SDominik Brodowski link->priv = info;
93fba395eeSDominik Brodowski info->p_dev = link;
941da177e4SLinus Torvalds
9500990e7cSDominik Brodowski link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
961da177e4SLinus Torvalds
9715b99ac1SDominik Brodowski return parport_config(link);
981da177e4SLinus Torvalds } /* parport_attach */
991da177e4SLinus Torvalds
parport_detach(struct pcmcia_device * link)100fba395eeSDominik Brodowski static void parport_detach(struct pcmcia_device *link)
1011da177e4SLinus Torvalds {
1029b44de20SDominik Brodowski dev_dbg(&link->dev, "parport_detach\n");
1031da177e4SLinus Torvalds
1041da177e4SLinus Torvalds parport_cs_release(link);
1051da177e4SLinus Torvalds
1061da177e4SLinus Torvalds kfree(link->priv);
1071da177e4SLinus Torvalds } /* parport_detach */
1081da177e4SLinus Torvalds
parport_config_check(struct pcmcia_device * p_dev,void * priv_data)10900990e7cSDominik Brodowski static int parport_config_check(struct pcmcia_device *p_dev, void *priv_data)
11084e2d340SDominik Brodowski {
11100990e7cSDominik Brodowski p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
11200990e7cSDominik Brodowski p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
11300990e7cSDominik Brodowski p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
11400990e7cSDominik Brodowski p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
11500990e7cSDominik Brodowski
11600990e7cSDominik Brodowski return pcmcia_request_io(p_dev);
11784e2d340SDominik Brodowski }
11884e2d340SDominik Brodowski
parport_config(struct pcmcia_device * link)11915b99ac1SDominik Brodowski static int parport_config(struct pcmcia_device *link)
1201da177e4SLinus Torvalds {
1211da177e4SLinus Torvalds parport_info_t *info = link->priv;
1221da177e4SLinus Torvalds struct parport *p;
1239b44de20SDominik Brodowski int ret;
1241da177e4SLinus Torvalds
1259b44de20SDominik Brodowski dev_dbg(&link->dev, "parport_config\n");
1261da177e4SLinus Torvalds
12700990e7cSDominik Brodowski if (epp_mode)
12800990e7cSDominik Brodowski link->config_index |= FORCE_EPP_MODE;
12900990e7cSDominik Brodowski
1309b44de20SDominik Brodowski ret = pcmcia_loop_config(link, parport_config_check, NULL);
1319b44de20SDominik Brodowski if (ret)
13284e2d340SDominik Brodowski goto failed;
1331da177e4SLinus Torvalds
134eb14120fSDominik Brodowski if (!link->irq)
1359b44de20SDominik Brodowski goto failed;
1361ac71e5aSDominik Brodowski ret = pcmcia_enable_device(link);
1379b44de20SDominik Brodowski if (ret)
1389b44de20SDominik Brodowski goto failed;
1391da177e4SLinus Torvalds
1409a017a91SDominik Brodowski p = parport_pc_probe_port(link->resource[0]->start,
1419a017a91SDominik Brodowski link->resource[1]->start,
142eb14120fSDominik Brodowski link->irq, PARPORT_DMA_NONE,
14351dcdfecSAlan Cox &link->dev, IRQF_SHARED);
1441da177e4SLinus Torvalds if (p == NULL) {
145*decf26f6SJoe Perches pr_notice("parport_cs: parport_pc_probe_port() at 0x%3x, irq %u failed\n",
146*decf26f6SJoe Perches (unsigned int)link->resource[0]->start, link->irq);
1471da177e4SLinus Torvalds goto failed;
1481da177e4SLinus Torvalds }
1491da177e4SLinus Torvalds
1501da177e4SLinus Torvalds p->modes |= PARPORT_MODE_PCSPP;
1511da177e4SLinus Torvalds if (epp_mode)
1521da177e4SLinus Torvalds p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP;
1531da177e4SLinus Torvalds info->ndev = 1;
1541da177e4SLinus Torvalds info->port = p;
1551da177e4SLinus Torvalds
15615b99ac1SDominik Brodowski return 0;
1571da177e4SLinus Torvalds
1581da177e4SLinus Torvalds failed:
1591da177e4SLinus Torvalds parport_cs_release(link);
16021c75ad6SYueHaibing kfree(link->priv);
16115b99ac1SDominik Brodowski return -ENODEV;
1621da177e4SLinus Torvalds } /* parport_config */
1631da177e4SLinus Torvalds
parport_cs_release(struct pcmcia_device * link)16423d5f96cSAdrian Bunk static void parport_cs_release(struct pcmcia_device *link)
1651da177e4SLinus Torvalds {
1661da177e4SLinus Torvalds parport_info_t *info = link->priv;
1671da177e4SLinus Torvalds
1689b44de20SDominik Brodowski dev_dbg(&link->dev, "parport_release\n");
1691da177e4SLinus Torvalds
1701da177e4SLinus Torvalds if (info->ndev) {
1711da177e4SLinus Torvalds struct parport *p = info->port;
1721da177e4SLinus Torvalds parport_pc_unregister_port(p);
1731da177e4SLinus Torvalds }
1741da177e4SLinus Torvalds info->ndev = 0;
1751da177e4SLinus Torvalds
176fba395eeSDominik Brodowski pcmcia_disable_device(link);
1771da177e4SLinus Torvalds } /* parport_cs_release */
1781da177e4SLinus Torvalds
17998e4c28bSDominik Brodowski
18025f8f54fSJoe Perches static const struct pcmcia_device_id parport_ids[] = {
181476835afSDominik Brodowski PCMCIA_DEVICE_FUNC_ID(3),
18244e5e33eSTony Olech PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
183476835afSDominik Brodowski PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003),
184476835afSDominik Brodowski PCMCIA_DEVICE_NULL
185476835afSDominik Brodowski };
186476835afSDominik Brodowski MODULE_DEVICE_TABLE(pcmcia, parport_ids);
187476835afSDominik Brodowski
1881da177e4SLinus Torvalds static struct pcmcia_driver parport_cs_driver = {
1891da177e4SLinus Torvalds .owner = THIS_MODULE,
1901da177e4SLinus Torvalds .name = "parport_cs",
19115b99ac1SDominik Brodowski .probe = parport_probe,
192cc3b4866SDominik Brodowski .remove = parport_detach,
193476835afSDominik Brodowski .id_table = parport_ids,
1941da177e4SLinus Torvalds };
195f23e7968SH Hartley Sweeten module_pcmcia_driver(parport_cs_driver);
196