rt2x00pci.c 5.1 KB
Newer Older
1
/*
2
	Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
	<http://rt2x00.serialmonkey.com>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the
	Free Software Foundation, Inc.,
	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/*
	Module: rt2x00pci
	Abstract: rt2x00 generic pci device routines.
 */

#include <linux/dma-mapping.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
30
#include <linux/slab.h>
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45

#include "rt2x00.h"
#include "rt2x00pci.h"

/*
 * PCI driver handlers.
 */
static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev)
{
	kfree(rt2x00dev->rf);
	rt2x00dev->rf = NULL;

	kfree(rt2x00dev->eeprom);
	rt2x00dev->eeprom = NULL;

46 47 48
	if (rt2x00dev->csr.base) {
		iounmap(rt2x00dev->csr.base);
		rt2x00dev->csr.base = NULL;
49 50 51 52 53
	}
}

static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev)
{
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 59 60 61 62 63 64 65 66 67 68 69 70
		goto exit;

	rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
	if (!rt2x00dev->eeprom)
		goto exit;

	rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
	if (!rt2x00dev->rf)
		goto exit;

	return 0;

exit:
71
	rt2x00_probe_err("Failed to allocate registers\n");
72 73 74 75 76 77

	rt2x00pci_free_reg(rt2x00dev);

	return -ENOMEM;
}

78
int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)
79 80 81 82
{
	struct ieee80211_hw *hw;
	struct rt2x00_dev *rt2x00dev;
	int retval;
W
Woody Hung 已提交
83
	u16 chip;
84

85
	retval = pci_enable_device(pci_dev);
86
	if (retval) {
87
		rt2x00_probe_err("Enable device failed\n");
88 89 90
		return retval;
	}

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 98 99
	}

	pci_set_master(pci_dev);

	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 109
	}

	hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
	if (!hw) {
110
		rt2x00_probe_err("Failed to allocate hardware\n");
111
		retval = -ENOMEM;
112
		goto exit_release_regions;
113 114 115 116 117
	}

	pci_set_drvdata(pci_dev, hw);

	rt2x00dev = hw->priv;
118
	rt2x00dev->dev = &pci_dev->dev;
119 120
	rt2x00dev->ops = ops;
	rt2x00dev->hw = hw;
121
	rt2x00dev->irq = pci_dev->irq;
122
	rt2x00dev->name = ops->name;
123

H
Hauke Mehrtens 已提交
124
	if (pci_is_pcie(pci_dev))
125 126 127
		rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE);
	else
		rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
128

129 130 131 132
	retval = rt2x00pci_alloc_reg(rt2x00dev);
	if (retval)
		goto exit_free_device;

W
Woody Hung 已提交
133 134 135 136 137 138 139 140
	/*
	 * Because rt3290 chip use different efuse offset to read efuse data.
	 * So before read efuse it need to indicate it is the
	 * rt3290 or not.
	 */
	pci_read_config_word(pci_dev, PCI_DEVICE_ID, &chip);
	rt2x00dev->chip.rt = chip;

141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
	retval = rt2x00lib_probe_dev(rt2x00dev);
	if (retval)
		goto exit_free_reg;

	return 0;

exit_free_reg:
	rt2x00pci_free_reg(rt2x00dev);

exit_free_device:
	ieee80211_free_hw(hw);

exit_release_regions:
	pci_release_regions(pci_dev);

156 157 158
exit_disable_device:
	pci_disable_device(pci_dev);

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
	return retval;
}
EXPORT_SYMBOL_GPL(rt2x00pci_probe);

void rt2x00pci_remove(struct pci_dev *pci_dev)
{
	struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
	struct rt2x00_dev *rt2x00dev = hw->priv;

	/*
	 * Free all allocated data.
	 */
	rt2x00lib_remove_dev(rt2x00dev);
	rt2x00pci_free_reg(rt2x00dev);
	ieee80211_free_hw(hw);

	/*
	 * Free the PCI device data.
	 */
	pci_disable_device(pci_dev);
	pci_release_regions(pci_dev);
}
EXPORT_SYMBOL_GPL(rt2x00pci_remove);

#ifdef CONFIG_PM
int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state)
{
	struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
	struct rt2x00_dev *rt2x00dev = hw->priv;
	int retval;

	retval = rt2x00lib_suspend(rt2x00dev, state);
	if (retval)
		return retval;

	pci_save_state(pci_dev);
	pci_disable_device(pci_dev);
	return pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
}
EXPORT_SYMBOL_GPL(rt2x00pci_suspend);

int rt2x00pci_resume(struct pci_dev *pci_dev)
{
	struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
	struct rt2x00_dev *rt2x00dev = hw->priv;

	if (pci_set_power_state(pci_dev, PCI_D0) ||
206
	    pci_enable_device(pci_dev)) {
207
		rt2x00_err(rt2x00dev, "Failed to resume device\n");
208 209 210
		return -EIO;
	}

211
	pci_restore_state(pci_dev);
212
	return rt2x00lib_resume(rt2x00dev);
213 214 215 216 217 218 219 220 221
}
EXPORT_SYMBOL_GPL(rt2x00pci_resume);
#endif /* CONFIG_PM */

/*
 * rt2x00pci module information.
 */
MODULE_AUTHOR(DRV_PROJECT);
MODULE_VERSION(DRV_VERSION);
I
Ivo van Doorn 已提交
222
MODULE_DESCRIPTION("rt2x00 pci library");
223
MODULE_LICENSE("GPL");