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#ifdef PCMCIA_DEBUG
  71INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
  72#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
  73static char *version =
  74"parport_cs.c 1.29 2002/10/11 06:57:41 (David Hinds)";
  75#else
  76#define DEBUG(n, args...)
  77#endif
  78
  79/*====================================================================*/
  80
  81#define FORCE_EPP_MODE  0x08
  82
  83typedef struct parport_info_t {
  84        struct pcmcia_device    *p_dev;
  85    int                 ndev;
  86    dev_node_t          node;
  87    struct parport      *port;
  88} parport_info_t;
  89
  90static void parport_detach(struct pcmcia_device *p_dev);
  91static int parport_config(struct pcmcia_device *link);
  92static void parport_cs_release(struct pcmcia_device *);
  93
  94/*======================================================================
  95
  96    parport_attach() creates an "instance" of the driver, allocating
  97    local data structures for one device.  The device is registered
  98    with Card Services.
  99
 100======================================================================*/
 101
 102static int parport_probe(struct pcmcia_device *link)
 103{
 104    parport_info_t *info;
 105
 106    DEBUG(0, "parport_attach()\n");
 107
 108    /* Create new parport device */
 109    info = kzalloc(sizeof(*info), GFP_KERNEL);
 110    if (!info) return -ENOMEM;
 111    link->priv = info;
 112    info->p_dev = link;
 113
 114    link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
 115    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
 116    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
 117    link->irq.IRQInfo1 = IRQ_LEVEL_ID;
 118    link->conf.Attributes = CONF_ENABLE_IRQ;
 119    link->conf.IntType = INT_MEMORY_AND_IO;
 120
 121    return parport_config(link);
 122} /* parport_attach */
 123
 124/*======================================================================
 125
 126    This deletes a driver "instance".  The device is de-registered
 127    with Card Services.  If it has been released, all local data
 128    structures are freed.  Otherwise, the structures will be freed
 129    when the device is released.
 130
 131======================================================================*/
 132
 133static void parport_detach(struct pcmcia_device *link)
 134{
 135    DEBUG(0, "parport_detach(0x%p)\n", link);
 136
 137    parport_cs_release(link);
 138
 139    kfree(link->priv);
 140} /* parport_detach */
 141
 142/*======================================================================
 143
 144    parport_config() is scheduled to run after a CARD_INSERTION event
 145    is received, to configure the PCMCIA socket, and to make the
 146    parport device available to the system.
 147
 148======================================================================*/
 149
 150#define CS_CHECK(fn, ret) \
 151do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 152
 153static int parport_config_check(struct pcmcia_device *p_dev,
 154                                cistpl_cftable_entry_t *cfg,
 155                                cistpl_cftable_entry_t *dflt,
 156                                unsigned int vcc,
 157                                void *priv_data)
 158{
 159        if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
 160                cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
 161                if (epp_mode)
 162                        p_dev->conf.ConfigIndex |= FORCE_EPP_MODE;
 163                p_dev->io.BasePort1 = io->win[0].base;
 164                p_dev->io.NumPorts1 = io->win[0].len;
 165                p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
 166                if (io->nwin == 2) {
 167                        p_dev->io.BasePort2 = io->win[1].base;
 168                        p_dev->io.NumPorts2 = io->win[1].len;
 169                }
 170                if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
 171                        return -ENODEV;
 172                return 0;
 173        }
 174        return -ENODEV;
 175}
 176
 177static int parport_config(struct pcmcia_device *link)
 178{
 179    parport_info_t *info = link->priv;
 180    struct parport *p;
 181    int last_ret, last_fn;
 182
 183    DEBUG(0, "parport_config(0x%p)\n", link);
 184
 185    last_ret = pcmcia_loop_config(link, parport_config_check, NULL);
 186    if (last_ret) {
 187            cs_error(link, RequestIO, last_ret);
 188            goto failed;
 189    }
 190
 191    CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
 192    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 193
 194    p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2,
 195                              link->irq.AssignedIRQ, PARPORT_DMA_NONE,
 196                              &link->dev, IRQF_SHARED);
 197    if (p == NULL) {
 198        printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at "
 199               "0x%3x, irq %u failed\n", link->io.BasePort1,
 200               link->irq.AssignedIRQ);
 201        goto failed;
 202    }
 203
 204    p->modes |= PARPORT_MODE_PCSPP;
 205    if (epp_mode)
 206        p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP;
 207    info->ndev = 1;
 208    info->node.major = LP_MAJOR;
 209    info->node.minor = p->number;
 210    info->port = p;
 211    strcpy(info->node.dev_name, p->name);
 212    link->dev_node = &info->node;
 213
 214    return 0;
 215
 216cs_failed:
 217    cs_error(link, last_fn, last_ret);
 218failed:
 219    parport_cs_release(link);
 220    return -ENODEV;
 221} /* parport_config */
 222
 223/*======================================================================
 224
 225    After a card is removed, parport_cs_release() will unregister the
 226    device, and release the PCMCIA configuration.  If the device is
 227    still open, this will be postponed until it is closed.
 228    
 229======================================================================*/
 230
 231static void parport_cs_release(struct pcmcia_device *link)
 232{
 233        parport_info_t *info = link->priv;
 234
 235        DEBUG(0, "parport_release(0x%p)\n", link);
 236
 237        if (info->ndev) {
 238                struct parport *p = info->port;
 239                parport_pc_unregister_port(p);
 240        }
 241        info->ndev = 0;
 242
 243        pcmcia_disable_device(link);
 244} /* parport_cs_release */
 245
 246
 247static struct pcmcia_device_id parport_ids[] = {
 248        PCMCIA_DEVICE_FUNC_ID(3),
 249        PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
 250        PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003),
 251        PCMCIA_DEVICE_NULL
 252};
 253MODULE_DEVICE_TABLE(pcmcia, parport_ids);
 254
 255static struct pcmcia_driver parport_cs_driver = {
 256        .owner          = THIS_MODULE,
 257        .drv            = {
 258                .name   = "parport_cs",
 259        },
 260        .probe          = parport_probe,
 261        .remove         = parport_detach,
 262        .id_table       = parport_ids,
 263};
 264
 265static int __init init_parport_cs(void)
 266{
 267        return pcmcia_register_driver(&parport_cs_driver);
 268}
 269
 270static void __exit exit_parport_cs(void)
 271{
 272        pcmcia_unregister_driver(&parport_cs_driver);
 273}
 274
 275module_init(init_parport_cs);
 276module_exit(exit_parport_cs);
 277