Back to home page

OSCL-LXR

 
 

    


0001 /*======================================================================
0002 
0003     A driver for PCMCIA parallel port adapters
0004 
0005     (specifically, for the Quatech SPP-100 EPP card: other cards will
0006     probably require driver tweaks)
0007     
0008     parport_cs.c 1.29 2002/10/11 06:57:41
0009 
0010     The contents of this file are subject to the Mozilla Public
0011     License Version 1.1 (the "License"); you may not use this file
0012     except in compliance with the License. You may obtain a copy of
0013     the License at http://www.mozilla.org/MPL/
0014 
0015     Software distributed under the License is distributed on an "AS
0016     IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
0017     implied. See the License for the specific language governing
0018     rights and limitations under the License.
0019 
0020     The initial developer of the original code is David A. Hinds
0021     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
0022     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
0023 
0024     Alternatively, the contents of this file may be used under the
0025     terms of the GNU General Public License version 2 (the "GPL"), in
0026     which case the provisions of the GPL are applicable instead of the
0027     above.  If you wish to allow the use of your version of this file
0028     only under the terms of the GPL and not to allow others to use
0029     your version of this file under the MPL, indicate your decision
0030     by deleting the provisions above and replace them with the notice
0031     and other provisions required by the GPL.  If you do not delete
0032     the provisions above, a recipient may use your version of this
0033     file under either the MPL or the GPL.
0034     
0035 ======================================================================*/
0036 
0037 #include <linux/kernel.h>
0038 #include <linux/module.h>
0039 #include <linux/init.h>
0040 #include <linux/ptrace.h>
0041 #include <linux/slab.h>
0042 #include <linux/string.h>
0043 #include <linux/timer.h>
0044 #include <linux/ioport.h>
0045 #include <linux/major.h>
0046 #include <linux/interrupt.h>
0047 
0048 #include <linux/parport.h>
0049 #include <linux/parport_pc.h>
0050 
0051 #include <pcmcia/cistpl.h>
0052 #include <pcmcia/ds.h>
0053 #include <pcmcia/cisreg.h>
0054 #include <pcmcia/ciscode.h>
0055 
0056 /*====================================================================*/
0057 
0058 /* Module parameters */
0059 
0060 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
0061 MODULE_DESCRIPTION("PCMCIA parallel port card driver");
0062 MODULE_LICENSE("Dual MPL/GPL");
0063 
0064 #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
0065 
0066 INT_MODULE_PARM(epp_mode, 1);
0067 
0068 
0069 /*====================================================================*/
0070 
0071 #define FORCE_EPP_MODE  0x08
0072 
0073 typedef struct parport_info_t {
0074     struct pcmcia_device    *p_dev;
0075     int         ndev;
0076     struct parport  *port;
0077 } parport_info_t;
0078 
0079 static void parport_detach(struct pcmcia_device *p_dev);
0080 static int parport_config(struct pcmcia_device *link);
0081 static void parport_cs_release(struct pcmcia_device *);
0082 
0083 static int parport_probe(struct pcmcia_device *link)
0084 {
0085     parport_info_t *info;
0086 
0087     dev_dbg(&link->dev, "parport_attach()\n");
0088 
0089     /* Create new parport device */
0090     info = kzalloc(sizeof(*info), GFP_KERNEL);
0091     if (!info) return -ENOMEM;
0092     link->priv = info;
0093     info->p_dev = link;
0094 
0095     link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
0096 
0097     return parport_config(link);
0098 } /* parport_attach */
0099 
0100 static void parport_detach(struct pcmcia_device *link)
0101 {
0102     dev_dbg(&link->dev, "parport_detach\n");
0103 
0104     parport_cs_release(link);
0105 
0106     kfree(link->priv);
0107 } /* parport_detach */
0108 
0109 static int parport_config_check(struct pcmcia_device *p_dev, void *priv_data)
0110 {
0111     p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
0112     p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
0113     p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
0114     p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
0115 
0116     return pcmcia_request_io(p_dev);
0117 }
0118 
0119 static int parport_config(struct pcmcia_device *link)
0120 {
0121     parport_info_t *info = link->priv;
0122     struct parport *p;
0123     int ret;
0124 
0125     dev_dbg(&link->dev, "parport_config\n");
0126 
0127     if (epp_mode)
0128         link->config_index |= FORCE_EPP_MODE;
0129 
0130     ret = pcmcia_loop_config(link, parport_config_check, NULL);
0131     if (ret)
0132         goto failed;
0133 
0134     if (!link->irq)
0135         goto failed;
0136     ret = pcmcia_enable_device(link);
0137     if (ret)
0138         goto failed;
0139 
0140     p = parport_pc_probe_port(link->resource[0]->start,
0141                   link->resource[1]->start,
0142                   link->irq, PARPORT_DMA_NONE,
0143                   &link->dev, IRQF_SHARED);
0144     if (p == NULL) {
0145         pr_notice("parport_cs: parport_pc_probe_port() at 0x%3x, irq %u failed\n",
0146               (unsigned int)link->resource[0]->start, link->irq);
0147     goto failed;
0148     }
0149 
0150     p->modes |= PARPORT_MODE_PCSPP;
0151     if (epp_mode)
0152     p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP;
0153     info->ndev = 1;
0154     info->port = p;
0155 
0156     return 0;
0157 
0158 failed:
0159     parport_cs_release(link);
0160     kfree(link->priv);
0161     return -ENODEV;
0162 } /* parport_config */
0163 
0164 static void parport_cs_release(struct pcmcia_device *link)
0165 {
0166     parport_info_t *info = link->priv;
0167 
0168     dev_dbg(&link->dev, "parport_release\n");
0169 
0170     if (info->ndev) {
0171         struct parport *p = info->port;
0172         parport_pc_unregister_port(p);
0173     }
0174     info->ndev = 0;
0175 
0176     pcmcia_disable_device(link);
0177 } /* parport_cs_release */
0178 
0179 
0180 static const struct pcmcia_device_id parport_ids[] = {
0181     PCMCIA_DEVICE_FUNC_ID(3),
0182     PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
0183     PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003),
0184     PCMCIA_DEVICE_NULL
0185 };
0186 MODULE_DEVICE_TABLE(pcmcia, parport_ids);
0187 
0188 static struct pcmcia_driver parport_cs_driver = {
0189     .owner      = THIS_MODULE,
0190     .name       = "parport_cs",
0191     .probe      = parport_probe,
0192     .remove     = parport_detach,
0193     .id_table   = parport_ids,
0194 };
0195 module_pcmcia_driver(parport_cs_driver);