linux/drivers/parport/parport_cs.c
<<
>>
Prefs
   1/*======================================================================
   2
   3    A driver for PCMCIA parallel port adapters
   4
   5    (specifically, for the Quatech SPP-100 EPP card: other cards will
   6    probably require driver tweaks)
   7    
   8    parport_cs.c 1.29 2002/10/11 06:57:41
   9
  10    The contents of this file are subject to the Mozilla Public
  11    License Version 1.1 (the "License"); you may not use this file
  12    except in compliance with the License. You may obtain a copy of
  13    the License at http://www.mozilla.org/MPL/
  14
  15    Software distributed under the License is distributed on an "AS
  16    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  17    implied. See the License for the specific language governing
  18    rights and limitations under the License.
  19
  20    The initial developer of the original code is David A. Hinds
  21    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  22    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  23
  24    Alternatively, the contents of this file may be used under the
  25    terms of the GNU General Public License version 2 (the "GPL"), in
  26    which case the provisions of the GPL are applicable instead of the
  27    above.  If you wish to allow the use of your version of this file
  28    only under the terms of the GPL and not to allow others to use
  29    your version of this file under the MPL, indicate your decision
  30    by deleting the provisions above and replace them with the notice
  31    and other provisions required by the GPL.  If you do not delete
  32    the provisions above, a recipient may use your version of this
  33    file under either the MPL or the GPL.
  34    
  35======================================================================*/
  36
  37#include <linux/kernel.h>
  38#include <linux/module.h>
  39#include <linux/init.h>
  40#include <linux/ptrace.h>
  41#include <linux/slab.h>
  42#include <linux/string.h>
  43#include <linux/timer.h>
  44#include <linux/ioport.h>
  45#include <linux/major.h>
  46#include <linux/interrupt.h>
  47
  48#include <linux/parport.h>
  49#include <linux/parport_pc.h>
  50
  51#include <pcmcia/cs_types.h>
  52#include <pcmcia/cs.h>
  53#include <pcmcia/cistpl.h>
  54#include <pcmcia/ds.h>
  55#include <pcmcia/cisreg.h>
  56#include <pcmcia/ciscode.h>
  57
  58/*====================================================================*/
  59
  60/* Module parameters */
  61
  62MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
  63MODULE_DESCRIPTION("PCMCIA parallel port card driver");
  64MODULE_LICENSE("Dual MPL/GPL");
  65
  66#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
  67
  68INT_MODULE_PARM(epp_mode, 1);
  69
  70
  71/*====================================================================*/
  72
  73#define FORCE_EPP_MODE  0x08
  74
  75typedef struct parport_info_t {
  76        struct pcmcia_device    *p_dev;
  77    int                 ndev;
  78    struct parport      *port;
  79} parport_info_t;
  80
  81static void parport_detach(struct pcmcia_device *p_dev);
  82static int parport_config(struct pcmcia_device *link);
  83static void parport_cs_release(struct pcmcia_device *);
  84
  85/*======================================================================
  86
  87    parport_attach() creates an "instance" of the driver, allocating
  88    local data structures for one device.  The device is registered
  89    with Card Services.
  90
  91======================================================================*/
  92
  93static int parport_probe(struct pcmcia_device *link)
  94{
  95    parport_info_t *info;
  96
  97    dev_dbg(&link->dev, "parport_attach()\n");
  98
  99    /* Create new parport device */
 100    info = kzalloc(sizeof(*info), GFP_KERNEL);
 101    if (!info) return -ENOMEM;
 102    link->priv = info;
 103    info->p_dev = link;
 104
 105    link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
 106    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
 107    link->conf.Attributes = CONF_ENABLE_IRQ;
 108    link->conf.IntType = INT_MEMORY_AND_IO;
 109
 110    return parport_config(link);
 111} /* parport_attach */
 112
 113/*======================================================================
 114
 115    This deletes a driver "instance".  The device is de-registered
 116    with Card Services.  If it has been released, all local data
 117    structures are freed.  Otherwise, the structures will be freed
 118    when the device is released.
 119
 120======================================================================*/
 121
 122static void parport_detach(struct pcmcia_device *link)
 123{
 124    dev_dbg(&link->dev, "parport_detach\n");
 125
 126    parport_cs_release(link);
 127
 128    kfree(link->priv);
 129} /* parport_detach */
 130
 131/*======================================================================
 132
 133    parport_config() is scheduled to run after a CARD_INSERTION event
 134    is received, to configure the PCMCIA socket, and to make the
 135    parport device available to the system.
 136
 137======================================================================*/
 138
 139static int parport_config_check(struct pcmcia_device *p_dev,
 140                                cistpl_cftable_entry_t *cfg,
 141                                cistpl_cftable_entry_t *dflt,
 142                                unsigned int vcc,
 143                                void *priv_data)
 144{
 145        if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
 146                cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
 147                if (epp_mode)
 148                        p_dev->conf.ConfigIndex |= FORCE_EPP_MODE;
 149                p_dev->io.BasePort1 = io->win[0].base;
 150                p_dev->io.NumPorts1 = io->win[0].len;
 151                p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
 152                if (io->nwin == 2) {
 153                        p_dev->io.BasePort2 = io->win[1].base;
 154                        p_dev->io.NumPorts2 = io->win[1].len;
 155                }
 156                if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
 157                        return -ENODEV;
 158                return 0;
 159        }
 160        return -ENODEV;
 161}
 162
 163static int parport_config(struct pcmcia_device *link)
 164{
 165    parport_info_t *info = link->priv;
 166    struct parport *p;
 167    int ret;
 168
 169    dev_dbg(&link->dev, "parport_config\n");
 170
 171    ret = pcmcia_loop_config(link, parport_config_check, NULL);
 172    if (ret)
 173            goto failed;
 174
 175    if (!link->irq)
 176            goto failed;
 177    ret = pcmcia_request_configuration(link, &link->conf);
 178    if (ret)
 179            goto failed;
 180
 181    p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2,
 182                              link->irq, PARPORT_DMA_NONE,
 183                              &link->dev, IRQF_SHARED);
 184    if (p == NULL) {
 185        printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at "
 186               "0x%3x, irq %u failed\n", link->io.BasePort1,
 187               link->irq);
 188        goto failed;
 189    }
 190
 191    p->modes |= PARPORT_MODE_PCSPP;
 192    if (epp_mode)
 193        p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP;
 194    info->ndev = 1;
 195    info->port = p;
 196
 197    return 0;
 198
 199failed:
 200    parport_cs_release(link);
 201    return -ENODEV;
 202} /* parport_config */
 203
 204/*======================================================================
 205
 206    After a card is removed, parport_cs_release() will unregister the
 207    device, and release the PCMCIA configuration.  If the device is
 208    still open, this will be postponed until it is closed.
 209    
 210======================================================================*/
 211
 212static void parport_cs_release(struct pcmcia_device *link)
 213{
 214        parport_info_t *info = link->priv;
 215
 216        dev_dbg(&link->dev, "parport_release\n");
 217
 218        if (info->ndev) {
 219                struct parport *p = info->port;
 220                parport_pc_unregister_port(p);
 221        }
 222        info->ndev = 0;
 223
 224        pcmcia_disable_device(link);
 225} /* parport_cs_release */
 226
 227
 228static struct pcmcia_device_id parport_ids[] = {
 229        PCMCIA_DEVICE_FUNC_ID(3),
 230        PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
 231        PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003),
 232        PCMCIA_DEVICE_NULL
 233};
 234MODULE_DEVICE_TABLE(pcmcia, parport_ids);
 235
 236static struct pcmcia_driver parport_cs_driver = {
 237        .owner          = THIS_MODULE,
 238        .drv            = {
 239                .name   = "parport_cs",
 240        },
 241        .probe          = parport_probe,
 242        .remove         = parport_detach,
 243        .id_table       = parport_ids,
 244};
 245
 246static int __init init_parport_cs(void)
 247{
 248        return pcmcia_register_driver(&parport_cs_driver);
 249}
 250
 251static void __exit exit_parport_cs(void)
 252{
 253        pcmcia_unregister_driver(&parport_cs_driver);
 254}
 255
 256module_init(init_parport_cs);
 257module_exit(exit_parport_cs);
 258