xref: /openbmc/linux/drivers/parport/parport_cs.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
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