diff options
Diffstat (limited to 'kernel/drivers/parport/parport_cs.c')
-rw-r--r-- | kernel/drivers/parport/parport_cs.c | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/kernel/drivers/parport/parport_cs.c b/kernel/drivers/parport/parport_cs.c new file mode 100644 index 000000000..e9b52e4a4 --- /dev/null +++ b/kernel/drivers/parport/parport_cs.c @@ -0,0 +1,196 @@ +/*====================================================================== + + A driver for PCMCIA parallel port adapters + + (specifically, for the Quatech SPP-100 EPP card: other cards will + probably require driver tweaks) + + parport_cs.c 1.29 2002/10/11 06:57:41 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + <dahinds@users.sourceforge.net>. Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU General Public License version 2 (the "GPL"), in + which case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/ioport.h> +#include <linux/major.h> +#include <linux/interrupt.h> + +#include <linux/parport.h> +#include <linux/parport_pc.h> + +#include <pcmcia/cistpl.h> +#include <pcmcia/ds.h> +#include <pcmcia/cisreg.h> +#include <pcmcia/ciscode.h> + +/*====================================================================*/ + +/* Module parameters */ + +MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); +MODULE_DESCRIPTION("PCMCIA parallel port card driver"); +MODULE_LICENSE("Dual MPL/GPL"); + +#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0) + +INT_MODULE_PARM(epp_mode, 1); + + +/*====================================================================*/ + +#define FORCE_EPP_MODE 0x08 + +typedef struct parport_info_t { + struct pcmcia_device *p_dev; + int ndev; + struct parport *port; +} parport_info_t; + +static void parport_detach(struct pcmcia_device *p_dev); +static int parport_config(struct pcmcia_device *link); +static void parport_cs_release(struct pcmcia_device *); + +static int parport_probe(struct pcmcia_device *link) +{ + parport_info_t *info; + + dev_dbg(&link->dev, "parport_attach()\n"); + + /* Create new parport device */ + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) return -ENOMEM; + link->priv = info; + info->p_dev = link; + + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; + + return parport_config(link); +} /* parport_attach */ + +static void parport_detach(struct pcmcia_device *link) +{ + dev_dbg(&link->dev, "parport_detach\n"); + + parport_cs_release(link); + + kfree(link->priv); +} /* parport_detach */ + +static int parport_config_check(struct pcmcia_device *p_dev, void *priv_data) +{ + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; + + return pcmcia_request_io(p_dev); +} + +static int parport_config(struct pcmcia_device *link) +{ + parport_info_t *info = link->priv; + struct parport *p; + int ret; + + dev_dbg(&link->dev, "parport_config\n"); + + if (epp_mode) + link->config_index |= FORCE_EPP_MODE; + + ret = pcmcia_loop_config(link, parport_config_check, NULL); + if (ret) + goto failed; + + if (!link->irq) + goto failed; + ret = pcmcia_enable_device(link); + if (ret) + goto failed; + + p = parport_pc_probe_port(link->resource[0]->start, + link->resource[1]->start, + link->irq, PARPORT_DMA_NONE, + &link->dev, IRQF_SHARED); + if (p == NULL) { + printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at " + "0x%3x, irq %u failed\n", + (unsigned int) link->resource[0]->start, + link->irq); + goto failed; + } + + p->modes |= PARPORT_MODE_PCSPP; + if (epp_mode) + p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP; + info->ndev = 1; + info->port = p; + + return 0; + +failed: + parport_cs_release(link); + return -ENODEV; +} /* parport_config */ + +static void parport_cs_release(struct pcmcia_device *link) +{ + parport_info_t *info = link->priv; + + dev_dbg(&link->dev, "parport_release\n"); + + if (info->ndev) { + struct parport *p = info->port; + parport_pc_unregister_port(p); + } + info->ndev = 0; + + pcmcia_disable_device(link); +} /* parport_cs_release */ + + +static const struct pcmcia_device_id parport_ids[] = { + PCMCIA_DEVICE_FUNC_ID(3), + PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc), + PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003), + PCMCIA_DEVICE_NULL +}; +MODULE_DEVICE_TABLE(pcmcia, parport_ids); + +static struct pcmcia_driver parport_cs_driver = { + .owner = THIS_MODULE, + .name = "parport_cs", + .probe = parport_probe, + .remove = parport_detach, + .id_table = parport_ids, +}; +module_pcmcia_driver(parport_cs_driver); |