linux/drivers/ssb/bridge_pcmcia_80211.c
<<
>>
Prefs
   1/*
   2 * Broadcom 43xx PCMCIA-SSB bridge module
   3 *
   4 * Copyright (c) 2007 Michael Buesch <m@bues.ch>
   5 *
   6 * Licensed under the GNU/GPL. See COPYING for details.
   7 */
   8
   9#include "ssb_private.h"
  10
  11#include <linux/ssb/ssb.h>
  12#include <linux/slab.h>
  13#include <linux/module.h>
  14
  15#include <pcmcia/cistpl.h>
  16#include <pcmcia/ciscode.h>
  17#include <pcmcia/ds.h>
  18#include <pcmcia/cisreg.h>
  19
  20static const struct pcmcia_device_id ssb_host_pcmcia_tbl[] = {
  21        PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),
  22        PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476),
  23        PCMCIA_DEVICE_NULL,
  24};
  25
  26MODULE_DEVICE_TABLE(pcmcia, ssb_host_pcmcia_tbl);
  27
  28static int ssb_host_pcmcia_probe(struct pcmcia_device *dev)
  29{
  30        struct ssb_bus *ssb;
  31        int err = -ENOMEM;
  32        int res = 0;
  33
  34        ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
  35        if (!ssb)
  36                goto out_error;
  37
  38        err = -ENODEV;
  39
  40        dev->config_flags |= CONF_ENABLE_IRQ;
  41
  42        dev->resource[2]->flags |=  WIN_ENABLE | WIN_DATA_WIDTH_16 |
  43                         WIN_USE_WAIT;
  44        dev->resource[2]->start = 0;
  45        dev->resource[2]->end = SSB_CORE_SIZE;
  46        res = pcmcia_request_window(dev, dev->resource[2], 250);
  47        if (res != 0)
  48                goto err_kfree_ssb;
  49
  50        res = pcmcia_map_mem_page(dev, dev->resource[2], 0);
  51        if (res != 0)
  52                goto err_disable;
  53
  54        if (!dev->irq)
  55                goto err_disable;
  56
  57        res = pcmcia_enable_device(dev);
  58        if (res != 0)
  59                goto err_disable;
  60
  61        err = ssb_bus_pcmciabus_register(ssb, dev, dev->resource[2]->start);
  62        if (err)
  63                goto err_disable;
  64        dev->priv = ssb;
  65
  66        return 0;
  67
  68err_disable:
  69        pcmcia_disable_device(dev);
  70err_kfree_ssb:
  71        kfree(ssb);
  72out_error:
  73        dev_err(&dev->dev, "Initialization failed (%d, %d)\n", res, err);
  74        return err;
  75}
  76
  77static void ssb_host_pcmcia_remove(struct pcmcia_device *dev)
  78{
  79        struct ssb_bus *ssb = dev->priv;
  80
  81        ssb_bus_unregister(ssb);
  82        pcmcia_disable_device(dev);
  83        kfree(ssb);
  84        dev->priv = NULL;
  85}
  86
  87#ifdef CONFIG_PM
  88static int ssb_host_pcmcia_suspend(struct pcmcia_device *dev)
  89{
  90        struct ssb_bus *ssb = dev->priv;
  91
  92        return ssb_bus_suspend(ssb);
  93}
  94
  95static int ssb_host_pcmcia_resume(struct pcmcia_device *dev)
  96{
  97        struct ssb_bus *ssb = dev->priv;
  98
  99        return ssb_bus_resume(ssb);
 100}
 101#else /* CONFIG_PM */
 102# define ssb_host_pcmcia_suspend                NULL
 103# define ssb_host_pcmcia_resume         NULL
 104#endif /* CONFIG_PM */
 105
 106static struct pcmcia_driver ssb_host_pcmcia_driver = {
 107        .owner          = THIS_MODULE,
 108        .name           = "ssb-pcmcia",
 109        .id_table       = ssb_host_pcmcia_tbl,
 110        .probe          = ssb_host_pcmcia_probe,
 111        .remove         = ssb_host_pcmcia_remove,
 112        .suspend        = ssb_host_pcmcia_suspend,
 113        .resume         = ssb_host_pcmcia_resume,
 114};
 115
 116static int pcmcia_init_failed;
 117
 118/*
 119 * These are not module init/exit functions!
 120 * The module_pcmcia_driver() helper cannot be used here.
 121 */
 122int ssb_host_pcmcia_init(void)
 123{
 124        pcmcia_init_failed = pcmcia_register_driver(&ssb_host_pcmcia_driver);
 125
 126        return pcmcia_init_failed;
 127}
 128
 129void ssb_host_pcmcia_exit(void)
 130{
 131        if (!pcmcia_init_failed)
 132                pcmcia_unregister_driver(&ssb_host_pcmcia_driver);
 133}
 134