1/* 2 3 Broadcom B43 wireless driver 4 5 Copyright (c) 2007 Michael Buesch <m@bues.ch> 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; see the file COPYING. If not, write to 19 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 20 Boston, MA 02110-1301, USA. 21 22*/ 23 24#include "pcmcia.h" 25 26#include <linux/ssb/ssb.h> 27#include <linux/slab.h> 28#include <linux/module.h> 29 30#include <pcmcia/cistpl.h> 31#include <pcmcia/ciscode.h> 32#include <pcmcia/ds.h> 33#include <pcmcia/cisreg.h> 34 35 36static const struct pcmcia_device_id b43_pcmcia_tbl[] = { 37 PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448), 38 PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476), 39 PCMCIA_DEVICE_NULL, 40}; 41 42MODULE_DEVICE_TABLE(pcmcia, b43_pcmcia_tbl); 43 44#ifdef CONFIG_PM 45static int b43_pcmcia_suspend(struct pcmcia_device *dev) 46{ 47 struct ssb_bus *ssb = dev->priv; 48 49 return ssb_bus_suspend(ssb); 50} 51 52static int b43_pcmcia_resume(struct pcmcia_device *dev) 53{ 54 struct ssb_bus *ssb = dev->priv; 55 56 return ssb_bus_resume(ssb); 57} 58#else /* CONFIG_PM */ 59# define b43_pcmcia_suspend NULL 60# define b43_pcmcia_resume NULL 61#endif /* CONFIG_PM */ 62 63static int b43_pcmcia_probe(struct pcmcia_device *dev) 64{ 65 struct ssb_bus *ssb; 66 int err = -ENOMEM; 67 int res = 0; 68 69 ssb = kzalloc(sizeof(*ssb), GFP_KERNEL); 70 if (!ssb) 71 goto out_error; 72 73 err = -ENODEV; 74 75 dev->config_flags |= CONF_ENABLE_IRQ; 76 77 dev->resource[2]->flags |= WIN_ENABLE | WIN_DATA_WIDTH_16 | 78 WIN_USE_WAIT; 79 dev->resource[2]->start = 0; 80 dev->resource[2]->end = SSB_CORE_SIZE; 81 res = pcmcia_request_window(dev, dev->resource[2], 250); 82 if (res != 0) 83 goto err_kfree_ssb; 84 85 res = pcmcia_map_mem_page(dev, dev->resource[2], 0); 86 if (res != 0) 87 goto err_disable; 88 89 if (!dev->irq) 90 goto err_disable; 91 92 res = pcmcia_enable_device(dev); 93 if (res != 0) 94 goto err_disable; 95 96 err = ssb_bus_pcmciabus_register(ssb, dev, dev->resource[2]->start); 97 if (err) 98 goto err_disable; 99 dev->priv = ssb; 100 101 return 0; 102 103err_disable: 104 pcmcia_disable_device(dev); 105err_kfree_ssb: 106 kfree(ssb); 107out_error: 108 printk(KERN_ERR "b43-pcmcia: Initialization failed (%d, %d)\n", 109 res, err); 110 return err; 111} 112 113static void b43_pcmcia_remove(struct pcmcia_device *dev) 114{ 115 struct ssb_bus *ssb = dev->priv; 116 117 ssb_bus_unregister(ssb); 118 pcmcia_disable_device(dev); 119 kfree(ssb); 120 dev->priv = NULL; 121} 122 123static struct pcmcia_driver b43_pcmcia_driver = { 124 .owner = THIS_MODULE, 125 .name = "b43-pcmcia", 126 .id_table = b43_pcmcia_tbl, 127 .probe = b43_pcmcia_probe, 128 .remove = b43_pcmcia_remove, 129 .suspend = b43_pcmcia_suspend, 130 .resume = b43_pcmcia_resume, 131}; 132 133/* 134 * These are not module init/exit functions! 135 * The module_pcmcia_driver() helper cannot be used here. 136 */ 137int b43_pcmcia_init(void) 138{ 139 return pcmcia_register_driver(&b43_pcmcia_driver); 140} 141 142void b43_pcmcia_exit(void) 143{ 144 pcmcia_unregister_driver(&b43_pcmcia_driver); 145} 146