]>
Commit | Line | Data |
---|---|---|
95ea3627 | 1 | /* |
9c9a0d14 | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
95ea3627 ID |
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 | ||
95ea3627 ID |
26 | #include <linux/dma-mapping.h> |
27 | #include <linux/kernel.h> | |
28 | #include <linux/module.h> | |
29 | #include <linux/pci.h> | |
5a0e3ad6 | 30 | #include <linux/slab.h> |
95ea3627 ID |
31 | |
32 | #include "rt2x00.h" | |
33 | #include "rt2x00pci.h" | |
34 | ||
95ea3627 ID |
35 | /* |
36 | * PCI driver handlers. | |
37 | */ | |
38 | static 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 | ||
21795094 ID |
46 | if (rt2x00dev->csr.base) { |
47 | iounmap(rt2x00dev->csr.base); | |
48 | rt2x00dev->csr.base = NULL; | |
95ea3627 ID |
49 | } |
50 | } | |
51 | ||
52 | static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev) | |
53 | { | |
14a3bf89 | 54 | struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev); |
95ea3627 | 55 | |
275f165f | 56 | rt2x00dev->csr.base = pci_ioremap_bar(pci_dev, 0); |
21795094 | 57 | if (!rt2x00dev->csr.base) |
95ea3627 ID |
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 | ||
70 | exit: | |
ec9c4989 | 71 | rt2x00_probe_err("Failed to allocate registers\n"); |
95ea3627 ID |
72 | |
73 | rt2x00pci_free_reg(rt2x00dev); | |
74 | ||
75 | return -ENOMEM; | |
76 | } | |
77 | ||
e01ae27f | 78 | int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops) |
95ea3627 | 79 | { |
95ea3627 ID |
80 | struct ieee80211_hw *hw; |
81 | struct rt2x00_dev *rt2x00dev; | |
82 | int retval; | |
a89534ed | 83 | u16 chip; |
95ea3627 | 84 | |
47cb905d | 85 | retval = pci_enable_device(pci_dev); |
95ea3627 | 86 | if (retval) { |
ec9c4989 | 87 | rt2x00_probe_err("Enable device failed\n"); |
95ea3627 ID |
88 | return retval; |
89 | } | |
90 | ||
47cb905d | 91 | retval = pci_request_regions(pci_dev, pci_name(pci_dev)); |
95ea3627 | 92 | if (retval) { |
ec9c4989 | 93 | rt2x00_probe_err("PCI request regions failed\n"); |
47cb905d | 94 | goto exit_disable_device; |
95ea3627 ID |
95 | } |
96 | ||
97 | pci_set_master(pci_dev); | |
98 | ||
99 | if (pci_set_mwi(pci_dev)) | |
ec9c4989 | 100 | rt2x00_probe_err("MWI not available\n"); |
95ea3627 | 101 | |
284901a9 | 102 | if (dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32))) { |
ec9c4989 | 103 | rt2x00_probe_err("PCI DMA not supported\n"); |
95ea3627 | 104 | retval = -EIO; |
47cb905d | 105 | goto exit_release_regions; |
95ea3627 ID |
106 | } |
107 | ||
9483f40d JK |
108 | pci_enable_msi(pci_dev); |
109 | ||
95ea3627 ID |
110 | hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw); |
111 | if (!hw) { | |
ec9c4989 | 112 | rt2x00_probe_err("Failed to allocate hardware\n"); |
95ea3627 | 113 | retval = -ENOMEM; |
9483f40d | 114 | goto exit_disable_msi; |
95ea3627 ID |
115 | } |
116 | ||
117 | pci_set_drvdata(pci_dev, hw); | |
118 | ||
119 | rt2x00dev = hw->priv; | |
14a3bf89 | 120 | rt2x00dev->dev = &pci_dev->dev; |
95ea3627 ID |
121 | rt2x00dev->ops = ops; |
122 | rt2x00dev->hw = hw; | |
440ddada | 123 | rt2x00dev->irq = pci_dev->irq; |
21cf502a | 124 | rt2x00dev->name = ops->name; |
440ddada | 125 | |
2cdb9a42 | 126 | if (pci_is_pcie(pci_dev)) |
6e1fdd11 GW |
127 | rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE); |
128 | else | |
129 | rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI); | |
2015d192 | 130 | |
95ea3627 ID |
131 | retval = rt2x00pci_alloc_reg(rt2x00dev); |
132 | if (retval) | |
133 | goto exit_free_device; | |
134 | ||
a89534ed WH |
135 | /* |
136 | * Because rt3290 chip use different efuse offset to read efuse data. | |
137 | * So before read efuse it need to indicate it is the | |
138 | * rt3290 or not. | |
139 | */ | |
140 | pci_read_config_word(pci_dev, PCI_DEVICE_ID, &chip); | |
141 | rt2x00dev->chip.rt = chip; | |
142 | ||
95ea3627 ID |
143 | retval = rt2x00lib_probe_dev(rt2x00dev); |
144 | if (retval) | |
145 | goto exit_free_reg; | |
146 | ||
147 | return 0; | |
148 | ||
149 | exit_free_reg: | |
150 | rt2x00pci_free_reg(rt2x00dev); | |
151 | ||
152 | exit_free_device: | |
153 | ieee80211_free_hw(hw); | |
154 | ||
9483f40d JK |
155 | exit_disable_msi: |
156 | pci_disable_msi(pci_dev); | |
157 | ||
95ea3627 ID |
158 | exit_release_regions: |
159 | pci_release_regions(pci_dev); | |
160 | ||
47cb905d KV |
161 | exit_disable_device: |
162 | pci_disable_device(pci_dev); | |
163 | ||
95ea3627 ID |
164 | pci_set_drvdata(pci_dev, NULL); |
165 | ||
166 | return retval; | |
167 | } | |
168 | EXPORT_SYMBOL_GPL(rt2x00pci_probe); | |
169 | ||
170 | void rt2x00pci_remove(struct pci_dev *pci_dev) | |
171 | { | |
172 | struct ieee80211_hw *hw = pci_get_drvdata(pci_dev); | |
173 | struct rt2x00_dev *rt2x00dev = hw->priv; | |
174 | ||
175 | /* | |
176 | * Free all allocated data. | |
177 | */ | |
178 | rt2x00lib_remove_dev(rt2x00dev); | |
179 | rt2x00pci_free_reg(rt2x00dev); | |
180 | ieee80211_free_hw(hw); | |
181 | ||
9483f40d JK |
182 | pci_disable_msi(pci_dev); |
183 | ||
95ea3627 ID |
184 | /* |
185 | * Free the PCI device data. | |
186 | */ | |
187 | pci_set_drvdata(pci_dev, NULL); | |
188 | pci_disable_device(pci_dev); | |
189 | pci_release_regions(pci_dev); | |
190 | } | |
191 | EXPORT_SYMBOL_GPL(rt2x00pci_remove); | |
192 | ||
193 | #ifdef CONFIG_PM | |
194 | int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state) | |
195 | { | |
196 | struct ieee80211_hw *hw = pci_get_drvdata(pci_dev); | |
197 | struct rt2x00_dev *rt2x00dev = hw->priv; | |
198 | int retval; | |
199 | ||
200 | retval = rt2x00lib_suspend(rt2x00dev, state); | |
201 | if (retval) | |
202 | return retval; | |
203 | ||
95ea3627 ID |
204 | pci_save_state(pci_dev); |
205 | pci_disable_device(pci_dev); | |
206 | return pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); | |
207 | } | |
208 | EXPORT_SYMBOL_GPL(rt2x00pci_suspend); | |
209 | ||
210 | int rt2x00pci_resume(struct pci_dev *pci_dev) | |
211 | { | |
212 | struct ieee80211_hw *hw = pci_get_drvdata(pci_dev); | |
213 | struct rt2x00_dev *rt2x00dev = hw->priv; | |
95ea3627 ID |
214 | |
215 | if (pci_set_power_state(pci_dev, PCI_D0) || | |
1d3c16a8 | 216 | pci_enable_device(pci_dev)) { |
ec9c4989 | 217 | rt2x00_err(rt2x00dev, "Failed to resume device\n"); |
95ea3627 ID |
218 | return -EIO; |
219 | } | |
220 | ||
1d3c16a8 | 221 | pci_restore_state(pci_dev); |
499a214c | 222 | return rt2x00lib_resume(rt2x00dev); |
95ea3627 ID |
223 | } |
224 | EXPORT_SYMBOL_GPL(rt2x00pci_resume); | |
225 | #endif /* CONFIG_PM */ | |
226 | ||
227 | /* | |
228 | * rt2x00pci module information. | |
229 | */ | |
230 | MODULE_AUTHOR(DRV_PROJECT); | |
231 | MODULE_VERSION(DRV_VERSION); | |
181d6902 | 232 | MODULE_DESCRIPTION("rt2x00 pci library"); |
95ea3627 | 233 | MODULE_LICENSE("GPL"); |