Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v3.13 226 lines 5.3 kB view raw
1/* 2 Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> 3 <http://rt2x00.serialmonkey.com> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the 17 Free Software Foundation, Inc., 18 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 */ 20 21/* 22 Module: rt2x00pci 23 Abstract: rt2x00 generic pci device routines. 24 */ 25 26#include <linux/dma-mapping.h> 27#include <linux/kernel.h> 28#include <linux/module.h> 29#include <linux/pci.h> 30#include <linux/slab.h> 31 32#include "rt2x00.h" 33#include "rt2x00pci.h" 34 35/* 36 * PCI driver handlers. 37 */ 38static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev) 39{ 40 kfree(rt2x00dev->rf); 41 rt2x00dev->rf = NULL; 42 43 kfree(rt2x00dev->eeprom); 44 rt2x00dev->eeprom = NULL; 45 46 if (rt2x00dev->csr.base) { 47 iounmap(rt2x00dev->csr.base); 48 rt2x00dev->csr.base = NULL; 49 } 50} 51 52static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev) 53{ 54 struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev); 55 56 rt2x00dev->csr.base = pci_ioremap_bar(pci_dev, 0); 57 if (!rt2x00dev->csr.base) 58 goto exit; 59 60 rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL); 61 if (!rt2x00dev->eeprom) 62 goto exit; 63 64 rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL); 65 if (!rt2x00dev->rf) 66 goto exit; 67 68 return 0; 69 70exit: 71 rt2x00_probe_err("Failed to allocate registers\n"); 72 73 rt2x00pci_free_reg(rt2x00dev); 74 75 return -ENOMEM; 76} 77 78int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops) 79{ 80 struct ieee80211_hw *hw; 81 struct rt2x00_dev *rt2x00dev; 82 int retval; 83 u16 chip; 84 85 retval = pci_enable_device(pci_dev); 86 if (retval) { 87 rt2x00_probe_err("Enable device failed\n"); 88 return retval; 89 } 90 91 retval = pci_request_regions(pci_dev, pci_name(pci_dev)); 92 if (retval) { 93 rt2x00_probe_err("PCI request regions failed\n"); 94 goto exit_disable_device; 95 } 96 97 pci_set_master(pci_dev); 98 99 if (pci_set_mwi(pci_dev)) 100 rt2x00_probe_err("MWI not available\n"); 101 102 if (dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32))) { 103 rt2x00_probe_err("PCI DMA not supported\n"); 104 retval = -EIO; 105 goto exit_release_regions; 106 } 107 108 hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw); 109 if (!hw) { 110 rt2x00_probe_err("Failed to allocate hardware\n"); 111 retval = -ENOMEM; 112 goto exit_release_regions; 113 } 114 115 pci_set_drvdata(pci_dev, hw); 116 117 rt2x00dev = hw->priv; 118 rt2x00dev->dev = &pci_dev->dev; 119 rt2x00dev->ops = ops; 120 rt2x00dev->hw = hw; 121 rt2x00dev->irq = pci_dev->irq; 122 rt2x00dev->name = ops->name; 123 124 if (pci_is_pcie(pci_dev)) 125 rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE); 126 else 127 rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI); 128 129 retval = rt2x00pci_alloc_reg(rt2x00dev); 130 if (retval) 131 goto exit_free_device; 132 133 /* 134 * Because rt3290 chip use different efuse offset to read efuse data. 135 * So before read efuse it need to indicate it is the 136 * rt3290 or not. 137 */ 138 pci_read_config_word(pci_dev, PCI_DEVICE_ID, &chip); 139 rt2x00dev->chip.rt = chip; 140 141 retval = rt2x00lib_probe_dev(rt2x00dev); 142 if (retval) 143 goto exit_free_reg; 144 145 return 0; 146 147exit_free_reg: 148 rt2x00pci_free_reg(rt2x00dev); 149 150exit_free_device: 151 ieee80211_free_hw(hw); 152 153exit_release_regions: 154 pci_release_regions(pci_dev); 155 156exit_disable_device: 157 pci_disable_device(pci_dev); 158 159 pci_set_drvdata(pci_dev, NULL); 160 161 return retval; 162} 163EXPORT_SYMBOL_GPL(rt2x00pci_probe); 164 165void rt2x00pci_remove(struct pci_dev *pci_dev) 166{ 167 struct ieee80211_hw *hw = pci_get_drvdata(pci_dev); 168 struct rt2x00_dev *rt2x00dev = hw->priv; 169 170 /* 171 * Free all allocated data. 172 */ 173 rt2x00lib_remove_dev(rt2x00dev); 174 rt2x00pci_free_reg(rt2x00dev); 175 ieee80211_free_hw(hw); 176 177 /* 178 * Free the PCI device data. 179 */ 180 pci_set_drvdata(pci_dev, NULL); 181 pci_disable_device(pci_dev); 182 pci_release_regions(pci_dev); 183} 184EXPORT_SYMBOL_GPL(rt2x00pci_remove); 185 186#ifdef CONFIG_PM 187int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state) 188{ 189 struct ieee80211_hw *hw = pci_get_drvdata(pci_dev); 190 struct rt2x00_dev *rt2x00dev = hw->priv; 191 int retval; 192 193 retval = rt2x00lib_suspend(rt2x00dev, state); 194 if (retval) 195 return retval; 196 197 pci_save_state(pci_dev); 198 pci_disable_device(pci_dev); 199 return pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); 200} 201EXPORT_SYMBOL_GPL(rt2x00pci_suspend); 202 203int rt2x00pci_resume(struct pci_dev *pci_dev) 204{ 205 struct ieee80211_hw *hw = pci_get_drvdata(pci_dev); 206 struct rt2x00_dev *rt2x00dev = hw->priv; 207 208 if (pci_set_power_state(pci_dev, PCI_D0) || 209 pci_enable_device(pci_dev)) { 210 rt2x00_err(rt2x00dev, "Failed to resume device\n"); 211 return -EIO; 212 } 213 214 pci_restore_state(pci_dev); 215 return rt2x00lib_resume(rt2x00dev); 216} 217EXPORT_SYMBOL_GPL(rt2x00pci_resume); 218#endif /* CONFIG_PM */ 219 220/* 221 * rt2x00pci module information. 222 */ 223MODULE_AUTHOR(DRV_PROJECT); 224MODULE_VERSION(DRV_VERSION); 225MODULE_DESCRIPTION("rt2x00 pci library"); 226MODULE_LICENSE("GPL");