diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-05 00:44:34 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-05 00:44:34 -0400 |
commit | 62ea6d80211ecc88ef516927ecebf64cb505be3f (patch) | |
tree | 1920de8cd3671aedcc912afb8e5ddb2a7c674b05 /drivers/misc/tifm_7xx1.c | |
parent | fa24aa561a3cf91cf25b5d4066470b08a2d24206 (diff) | |
parent | d3af5abe9a809becbe4b413144b607844560d445 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc: (46 commits)
mmc-omap: Clean up omap set_ios and make MMC_POWER_ON work
mmc-omap: Fix omap to use MMC_POWER_ON
mmc-omap: add missing '\n'
mmc: make tifm_sd_set_dma_data() static
mmc: remove old card states
mmc: support unsafe resume of cards
mmc: separate out reading EXT_CSD
mmc: break apart switch function
MMC: Fix handling of low-voltage cards
MMC: Consolidate voltage definitions
mmc: add bus handler
wbsd: check for data opcode earlier
mmc: Separate out protocol ops
mmc: Move core functions to subdir
mmc: deprecate mmc bus topology
mmc: remove card upon suspend
mmc: allow suspended block driver to be removed
mmc: Flush pending detects on host removal
mmc: Move host and card drivers to subdirs
mmc: Move queue functions to mmc_block
...
Diffstat (limited to 'drivers/misc/tifm_7xx1.c')
-rw-r--r-- | drivers/misc/tifm_7xx1.c | 332 |
1 files changed, 141 insertions, 191 deletions
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index bc60e2fc3c2c..1ba6c085419a 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c | |||
@@ -11,10 +11,20 @@ | |||
11 | 11 | ||
12 | #include <linux/tifm.h> | 12 | #include <linux/tifm.h> |
13 | #include <linux/dma-mapping.h> | 13 | #include <linux/dma-mapping.h> |
14 | #include <linux/freezer.h> | ||
15 | 14 | ||
16 | #define DRIVER_NAME "tifm_7xx1" | 15 | #define DRIVER_NAME "tifm_7xx1" |
17 | #define DRIVER_VERSION "0.7" | 16 | #define DRIVER_VERSION "0.8" |
17 | |||
18 | #define TIFM_IRQ_ENABLE 0x80000000 | ||
19 | #define TIFM_IRQ_SOCKMASK(x) (x) | ||
20 | #define TIFM_IRQ_CARDMASK(x) ((x) << 8) | ||
21 | #define TIFM_IRQ_FIFOMASK(x) ((x) << 16) | ||
22 | #define TIFM_IRQ_SETALL 0xffffffff | ||
23 | |||
24 | static void tifm_7xx1_dummy_eject(struct tifm_adapter *fm, | ||
25 | struct tifm_dev *sock) | ||
26 | { | ||
27 | } | ||
18 | 28 | ||
19 | static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) | 29 | static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) |
20 | { | 30 | { |
@@ -22,7 +32,7 @@ static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) | |||
22 | 32 | ||
23 | spin_lock_irqsave(&fm->lock, flags); | 33 | spin_lock_irqsave(&fm->lock, flags); |
24 | fm->socket_change_set |= 1 << sock->socket_id; | 34 | fm->socket_change_set |= 1 << sock->socket_id; |
25 | wake_up_all(&fm->change_set_notify); | 35 | tifm_queue_work(&fm->media_switcher); |
26 | spin_unlock_irqrestore(&fm->lock, flags); | 36 | spin_unlock_irqrestore(&fm->lock, flags); |
27 | } | 37 | } |
28 | 38 | ||
@@ -30,8 +40,7 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) | |||
30 | { | 40 | { |
31 | struct tifm_adapter *fm = dev_id; | 41 | struct tifm_adapter *fm = dev_id; |
32 | struct tifm_dev *sock; | 42 | struct tifm_dev *sock; |
33 | unsigned int irq_status; | 43 | unsigned int irq_status, cnt; |
34 | unsigned int sock_irq_status, cnt; | ||
35 | 44 | ||
36 | spin_lock(&fm->lock); | 45 | spin_lock(&fm->lock); |
37 | irq_status = readl(fm->addr + FM_INTERRUPT_STATUS); | 46 | irq_status = readl(fm->addr + FM_INTERRUPT_STATUS); |
@@ -45,12 +54,12 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) | |||
45 | 54 | ||
46 | for (cnt = 0; cnt < fm->num_sockets; cnt++) { | 55 | for (cnt = 0; cnt < fm->num_sockets; cnt++) { |
47 | sock = fm->sockets[cnt]; | 56 | sock = fm->sockets[cnt]; |
48 | sock_irq_status = (irq_status >> cnt) | 57 | if (sock) { |
49 | & (TIFM_IRQ_FIFOMASK(1) | 58 | if ((irq_status >> cnt) & TIFM_IRQ_FIFOMASK(1)) |
50 | | TIFM_IRQ_CARDMASK(1)); | 59 | sock->data_event(sock); |
51 | 60 | if ((irq_status >> cnt) & TIFM_IRQ_CARDMASK(1)) | |
52 | if (sock && sock_irq_status) | 61 | sock->card_event(sock); |
53 | sock->signal_irq(sock, sock_irq_status); | 62 | } |
54 | } | 63 | } |
55 | 64 | ||
56 | fm->socket_change_set |= irq_status | 65 | fm->socket_change_set |= irq_status |
@@ -58,57 +67,57 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) | |||
58 | } | 67 | } |
59 | writel(irq_status, fm->addr + FM_INTERRUPT_STATUS); | 68 | writel(irq_status, fm->addr + FM_INTERRUPT_STATUS); |
60 | 69 | ||
61 | if (!fm->socket_change_set) | 70 | if (fm->finish_me) |
71 | complete_all(fm->finish_me); | ||
72 | else if (!fm->socket_change_set) | ||
62 | writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); | 73 | writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); |
63 | else | 74 | else |
64 | wake_up_all(&fm->change_set_notify); | 75 | tifm_queue_work(&fm->media_switcher); |
65 | 76 | ||
66 | spin_unlock(&fm->lock); | 77 | spin_unlock(&fm->lock); |
67 | return IRQ_HANDLED; | 78 | return IRQ_HANDLED; |
68 | } | 79 | } |
69 | 80 | ||
70 | static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, | 81 | static unsigned char tifm_7xx1_toggle_sock_power(char __iomem *sock_addr) |
71 | int is_x2) | ||
72 | { | 82 | { |
73 | unsigned int s_state; | 83 | unsigned int s_state; |
74 | int cnt; | 84 | int cnt; |
75 | 85 | ||
76 | writel(0x0e00, sock_addr + SOCK_CONTROL); | 86 | writel(0x0e00, sock_addr + SOCK_CONTROL); |
77 | 87 | ||
78 | for (cnt = 0; cnt < 100; cnt++) { | 88 | for (cnt = 16; cnt <= 256; cnt <<= 1) { |
79 | if (!(TIFM_SOCK_STATE_POWERED | 89 | if (!(TIFM_SOCK_STATE_POWERED |
80 | & readl(sock_addr + SOCK_PRESENT_STATE))) | 90 | & readl(sock_addr + SOCK_PRESENT_STATE))) |
81 | break; | 91 | break; |
82 | msleep(10); | 92 | |
93 | msleep(cnt); | ||
83 | } | 94 | } |
84 | 95 | ||
85 | s_state = readl(sock_addr + SOCK_PRESENT_STATE); | 96 | s_state = readl(sock_addr + SOCK_PRESENT_STATE); |
86 | if (!(TIFM_SOCK_STATE_OCCUPIED & s_state)) | 97 | if (!(TIFM_SOCK_STATE_OCCUPIED & s_state)) |
87 | return FM_NULL; | 98 | return 0; |
88 | |||
89 | if (is_x2) { | ||
90 | writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL); | ||
91 | } else { | ||
92 | // SmartMedia cards need extra 40 msec | ||
93 | if (((readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7) == 1) | ||
94 | msleep(40); | ||
95 | writel(readl(sock_addr + SOCK_CONTROL) | TIFM_CTRL_LED, | ||
96 | sock_addr + SOCK_CONTROL); | ||
97 | msleep(10); | ||
98 | writel((s_state & 0x7) | 0x0c00 | TIFM_CTRL_LED, | ||
99 | sock_addr + SOCK_CONTROL); | ||
100 | } | ||
101 | 99 | ||
102 | for (cnt = 0; cnt < 100; cnt++) { | 100 | writel(readl(sock_addr + SOCK_CONTROL) | TIFM_CTRL_LED, |
101 | sock_addr + SOCK_CONTROL); | ||
102 | |||
103 | /* xd needs some extra time before power on */ | ||
104 | if (((readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7) | ||
105 | == TIFM_TYPE_XD) | ||
106 | msleep(40); | ||
107 | |||
108 | writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL); | ||
109 | /* wait for power to stabilize */ | ||
110 | msleep(20); | ||
111 | for (cnt = 16; cnt <= 256; cnt <<= 1) { | ||
103 | if ((TIFM_SOCK_STATE_POWERED | 112 | if ((TIFM_SOCK_STATE_POWERED |
104 | & readl(sock_addr + SOCK_PRESENT_STATE))) | 113 | & readl(sock_addr + SOCK_PRESENT_STATE))) |
105 | break; | 114 | break; |
106 | msleep(10); | 115 | |
116 | msleep(cnt); | ||
107 | } | 117 | } |
108 | 118 | ||
109 | if (!is_x2) | 119 | writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED), |
110 | writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED), | 120 | sock_addr + SOCK_CONTROL); |
111 | sock_addr + SOCK_CONTROL); | ||
112 | 121 | ||
113 | return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7; | 122 | return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7; |
114 | } | 123 | } |
@@ -119,127 +128,77 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num) | |||
119 | return base_addr + ((sock_num + 1) << 10); | 128 | return base_addr + ((sock_num + 1) << 10); |
120 | } | 129 | } |
121 | 130 | ||
122 | static int tifm_7xx1_switch_media(void *data) | 131 | static void tifm_7xx1_switch_media(struct work_struct *work) |
123 | { | 132 | { |
124 | struct tifm_adapter *fm = data; | 133 | struct tifm_adapter *fm = container_of(work, struct tifm_adapter, |
125 | unsigned long flags; | 134 | media_switcher); |
126 | tifm_media_id media_id; | ||
127 | char *card_name = "xx"; | ||
128 | int cnt, rc; | ||
129 | struct tifm_dev *sock; | 135 | struct tifm_dev *sock; |
130 | unsigned int socket_change_set; | 136 | unsigned long flags; |
131 | 137 | unsigned char media_id; | |
132 | while (1) { | 138 | unsigned int socket_change_set, cnt; |
133 | rc = wait_event_interruptible(fm->change_set_notify, | ||
134 | fm->socket_change_set); | ||
135 | if (rc == -ERESTARTSYS) | ||
136 | try_to_freeze(); | ||
137 | 139 | ||
138 | spin_lock_irqsave(&fm->lock, flags); | 140 | spin_lock_irqsave(&fm->lock, flags); |
139 | socket_change_set = fm->socket_change_set; | 141 | socket_change_set = fm->socket_change_set; |
140 | fm->socket_change_set = 0; | 142 | fm->socket_change_set = 0; |
141 | 143 | ||
142 | dev_dbg(fm->dev, "checking media set %x\n", | 144 | dev_dbg(fm->cdev.dev, "checking media set %x\n", |
143 | socket_change_set); | 145 | socket_change_set); |
144 | 146 | ||
145 | if (kthread_should_stop()) | 147 | if (!socket_change_set) { |
146 | socket_change_set = (1 << fm->num_sockets) - 1; | ||
147 | spin_unlock_irqrestore(&fm->lock, flags); | 148 | spin_unlock_irqrestore(&fm->lock, flags); |
149 | return; | ||
150 | } | ||
148 | 151 | ||
149 | if (!socket_change_set) | 152 | for (cnt = 0; cnt < fm->num_sockets; cnt++) { |
153 | if (!(socket_change_set & (1 << cnt))) | ||
150 | continue; | 154 | continue; |
151 | 155 | sock = fm->sockets[cnt]; | |
152 | spin_lock_irqsave(&fm->lock, flags); | 156 | if (sock) { |
153 | for (cnt = 0; cnt < fm->num_sockets; cnt++) { | 157 | printk(KERN_INFO |
154 | if (!(socket_change_set & (1 << cnt))) | 158 | "%s : demand removing card from socket %u:%u\n", |
155 | continue; | 159 | fm->cdev.class_id, fm->id, cnt); |
156 | sock = fm->sockets[cnt]; | 160 | fm->sockets[cnt] = NULL; |
157 | if (sock) { | ||
158 | printk(KERN_INFO DRIVER_NAME | ||
159 | ": demand removing card from socket %d\n", | ||
160 | cnt); | ||
161 | fm->sockets[cnt] = NULL; | ||
162 | spin_unlock_irqrestore(&fm->lock, flags); | ||
163 | device_unregister(&sock->dev); | ||
164 | spin_lock_irqsave(&fm->lock, flags); | ||
165 | writel(0x0e00, | ||
166 | tifm_7xx1_sock_addr(fm->addr, cnt) | ||
167 | + SOCK_CONTROL); | ||
168 | } | ||
169 | if (kthread_should_stop()) | ||
170 | continue; | ||
171 | |||
172 | spin_unlock_irqrestore(&fm->lock, flags); | 161 | spin_unlock_irqrestore(&fm->lock, flags); |
173 | media_id = tifm_7xx1_toggle_sock_power( | 162 | device_unregister(&sock->dev); |
174 | tifm_7xx1_sock_addr(fm->addr, cnt), | 163 | spin_lock_irqsave(&fm->lock, flags); |
175 | fm->num_sockets == 2); | 164 | writel(0x0e00, tifm_7xx1_sock_addr(fm->addr, cnt) |
176 | if (media_id) { | 165 | + SOCK_CONTROL); |
177 | sock = tifm_alloc_device(fm); | ||
178 | if (sock) { | ||
179 | sock->addr = tifm_7xx1_sock_addr(fm->addr, | ||
180 | cnt); | ||
181 | sock->media_id = media_id; | ||
182 | sock->socket_id = cnt; | ||
183 | switch (media_id) { | ||
184 | case 1: | ||
185 | card_name = "xd"; | ||
186 | break; | ||
187 | case 2: | ||
188 | card_name = "ms"; | ||
189 | break; | ||
190 | case 3: | ||
191 | card_name = "sd"; | ||
192 | break; | ||
193 | default: | ||
194 | tifm_free_device(&sock->dev); | ||
195 | spin_lock_irqsave(&fm->lock, flags); | ||
196 | continue; | ||
197 | } | ||
198 | snprintf(sock->dev.bus_id, BUS_ID_SIZE, | ||
199 | "tifm_%s%u:%u", card_name, | ||
200 | fm->id, cnt); | ||
201 | printk(KERN_INFO DRIVER_NAME | ||
202 | ": %s card detected in socket %d\n", | ||
203 | card_name, cnt); | ||
204 | if (!device_register(&sock->dev)) { | ||
205 | spin_lock_irqsave(&fm->lock, flags); | ||
206 | if (!fm->sockets[cnt]) { | ||
207 | fm->sockets[cnt] = sock; | ||
208 | sock = NULL; | ||
209 | } | ||
210 | spin_unlock_irqrestore(&fm->lock, flags); | ||
211 | } | ||
212 | if (sock) | ||
213 | tifm_free_device(&sock->dev); | ||
214 | } | ||
215 | spin_lock_irqsave(&fm->lock, flags); | ||
216 | } | ||
217 | } | 166 | } |
218 | 167 | ||
219 | if (!kthread_should_stop()) { | 168 | spin_unlock_irqrestore(&fm->lock, flags); |
220 | writel(TIFM_IRQ_FIFOMASK(socket_change_set) | 169 | |
221 | | TIFM_IRQ_CARDMASK(socket_change_set), | 170 | media_id = tifm_7xx1_toggle_sock_power( |
222 | fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | 171 | tifm_7xx1_sock_addr(fm->addr, cnt)); |
223 | writel(TIFM_IRQ_FIFOMASK(socket_change_set) | 172 | |
224 | | TIFM_IRQ_CARDMASK(socket_change_set), | 173 | // tifm_alloc_device will check if media_id is valid |
225 | fm->addr + FM_SET_INTERRUPT_ENABLE); | 174 | sock = tifm_alloc_device(fm, cnt, media_id); |
226 | writel(TIFM_IRQ_ENABLE, | 175 | if (sock) { |
227 | fm->addr + FM_SET_INTERRUPT_ENABLE); | 176 | sock->addr = tifm_7xx1_sock_addr(fm->addr, cnt); |
228 | spin_unlock_irqrestore(&fm->lock, flags); | 177 | |
229 | } else { | 178 | if (!device_register(&sock->dev)) { |
230 | for (cnt = 0; cnt < fm->num_sockets; cnt++) { | 179 | spin_lock_irqsave(&fm->lock, flags); |
231 | if (fm->sockets[cnt]) | 180 | if (!fm->sockets[cnt]) { |
232 | fm->socket_change_set |= 1 << cnt; | 181 | fm->sockets[cnt] = sock; |
233 | } | 182 | sock = NULL; |
234 | if (!fm->socket_change_set) { | 183 | } |
235 | spin_unlock_irqrestore(&fm->lock, flags); | ||
236 | return 0; | ||
237 | } else { | ||
238 | spin_unlock_irqrestore(&fm->lock, flags); | 184 | spin_unlock_irqrestore(&fm->lock, flags); |
239 | } | 185 | } |
186 | if (sock) | ||
187 | tifm_free_device(&sock->dev); | ||
240 | } | 188 | } |
189 | spin_lock_irqsave(&fm->lock, flags); | ||
241 | } | 190 | } |
242 | return 0; | 191 | |
192 | writel(TIFM_IRQ_FIFOMASK(socket_change_set) | ||
193 | | TIFM_IRQ_CARDMASK(socket_change_set), | ||
194 | fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | ||
195 | |||
196 | writel(TIFM_IRQ_FIFOMASK(socket_change_set) | ||
197 | | TIFM_IRQ_CARDMASK(socket_change_set), | ||
198 | fm->addr + FM_SET_INTERRUPT_ENABLE); | ||
199 | |||
200 | writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); | ||
201 | spin_unlock_irqrestore(&fm->lock, flags); | ||
243 | } | 202 | } |
244 | 203 | ||
245 | #ifdef CONFIG_PM | 204 | #ifdef CONFIG_PM |
@@ -258,9 +217,11 @@ static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state) | |||
258 | static int tifm_7xx1_resume(struct pci_dev *dev) | 217 | static int tifm_7xx1_resume(struct pci_dev *dev) |
259 | { | 218 | { |
260 | struct tifm_adapter *fm = pci_get_drvdata(dev); | 219 | struct tifm_adapter *fm = pci_get_drvdata(dev); |
261 | int cnt, rc; | 220 | int rc; |
221 | unsigned int good_sockets = 0, bad_sockets = 0; | ||
262 | unsigned long flags; | 222 | unsigned long flags; |
263 | tifm_media_id new_ids[fm->num_sockets]; | 223 | unsigned char new_ids[fm->num_sockets]; |
224 | DECLARE_COMPLETION_ONSTACK(finish_resume); | ||
264 | 225 | ||
265 | pci_set_power_state(dev, PCI_D0); | 226 | pci_set_power_state(dev, PCI_D0); |
266 | pci_restore_state(dev); | 227 | pci_restore_state(dev); |
@@ -271,45 +232,49 @@ static int tifm_7xx1_resume(struct pci_dev *dev) | |||
271 | 232 | ||
272 | dev_dbg(&dev->dev, "resuming host\n"); | 233 | dev_dbg(&dev->dev, "resuming host\n"); |
273 | 234 | ||
274 | for (cnt = 0; cnt < fm->num_sockets; cnt++) | 235 | for (rc = 0; rc < fm->num_sockets; rc++) |
275 | new_ids[cnt] = tifm_7xx1_toggle_sock_power( | 236 | new_ids[rc] = tifm_7xx1_toggle_sock_power( |
276 | tifm_7xx1_sock_addr(fm->addr, cnt), | 237 | tifm_7xx1_sock_addr(fm->addr, rc)); |
277 | fm->num_sockets == 2); | ||
278 | spin_lock_irqsave(&fm->lock, flags); | 238 | spin_lock_irqsave(&fm->lock, flags); |
279 | fm->socket_change_set = 0; | 239 | for (rc = 0; rc < fm->num_sockets; rc++) { |
280 | for (cnt = 0; cnt < fm->num_sockets; cnt++) { | 240 | if (fm->sockets[rc]) { |
281 | if (fm->sockets[cnt]) { | 241 | if (fm->sockets[rc]->type == new_ids[rc]) |
282 | if (fm->sockets[cnt]->media_id == new_ids[cnt]) | 242 | good_sockets |= 1 << rc; |
283 | fm->socket_change_set |= 1 << cnt; | 243 | else |
284 | 244 | bad_sockets |= 1 << rc; | |
285 | fm->sockets[cnt]->media_id = new_ids[cnt]; | ||
286 | } | 245 | } |
287 | } | 246 | } |
288 | 247 | ||
289 | writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), | 248 | writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), |
290 | fm->addr + FM_SET_INTERRUPT_ENABLE); | 249 | fm->addr + FM_SET_INTERRUPT_ENABLE); |
291 | if (!fm->socket_change_set) { | 250 | dev_dbg(&dev->dev, "change sets on resume: good %x, bad %x\n", |
292 | spin_unlock_irqrestore(&fm->lock, flags); | 251 | good_sockets, bad_sockets); |
293 | return 0; | 252 | |
294 | } else { | 253 | fm->socket_change_set = 0; |
295 | fm->socket_change_set = 0; | 254 | if (good_sockets) { |
255 | fm->finish_me = &finish_resume; | ||
296 | spin_unlock_irqrestore(&fm->lock, flags); | 256 | spin_unlock_irqrestore(&fm->lock, flags); |
257 | rc = wait_for_completion_timeout(&finish_resume, HZ); | ||
258 | dev_dbg(&dev->dev, "wait returned %d\n", rc); | ||
259 | writel(TIFM_IRQ_FIFOMASK(good_sockets) | ||
260 | | TIFM_IRQ_CARDMASK(good_sockets), | ||
261 | fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | ||
262 | writel(TIFM_IRQ_FIFOMASK(good_sockets) | ||
263 | | TIFM_IRQ_CARDMASK(good_sockets), | ||
264 | fm->addr + FM_SET_INTERRUPT_ENABLE); | ||
265 | spin_lock_irqsave(&fm->lock, flags); | ||
266 | fm->finish_me = NULL; | ||
267 | fm->socket_change_set ^= good_sockets & fm->socket_change_set; | ||
297 | } | 268 | } |
298 | 269 | ||
299 | wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ); | 270 | fm->socket_change_set |= bad_sockets; |
271 | if (fm->socket_change_set) | ||
272 | tifm_queue_work(&fm->media_switcher); | ||
300 | 273 | ||
301 | spin_lock_irqsave(&fm->lock, flags); | 274 | spin_unlock_irqrestore(&fm->lock, flags); |
302 | writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set) | ||
303 | | TIFM_IRQ_CARDMASK(fm->socket_change_set), | ||
304 | fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | ||
305 | writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set) | ||
306 | | TIFM_IRQ_CARDMASK(fm->socket_change_set), | ||
307 | fm->addr + FM_SET_INTERRUPT_ENABLE); | ||
308 | writel(TIFM_IRQ_ENABLE, | 275 | writel(TIFM_IRQ_ENABLE, |
309 | fm->addr + FM_SET_INTERRUPT_ENABLE); | 276 | fm->addr + FM_SET_INTERRUPT_ENABLE); |
310 | fm->socket_change_set = 0; | ||
311 | 277 | ||
312 | spin_unlock_irqrestore(&fm->lock, flags); | ||
313 | return 0; | 278 | return 0; |
314 | } | 279 | } |
315 | 280 | ||
@@ -345,20 +310,14 @@ static int tifm_7xx1_probe(struct pci_dev *dev, | |||
345 | 310 | ||
346 | pci_intx(dev, 1); | 311 | pci_intx(dev, 1); |
347 | 312 | ||
348 | fm = tifm_alloc_adapter(); | 313 | fm = tifm_alloc_adapter(dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM |
314 | ? 4 : 2, &dev->dev); | ||
349 | if (!fm) { | 315 | if (!fm) { |
350 | rc = -ENOMEM; | 316 | rc = -ENOMEM; |
351 | goto err_out_int; | 317 | goto err_out_int; |
352 | } | 318 | } |
353 | 319 | ||
354 | fm->dev = &dev->dev; | 320 | INIT_WORK(&fm->media_switcher, tifm_7xx1_switch_media); |
355 | fm->num_sockets = (dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM) | ||
356 | ? 4 : 2; | ||
357 | fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets, | ||
358 | GFP_KERNEL); | ||
359 | if (!fm->sockets) | ||
360 | goto err_out_free; | ||
361 | |||
362 | fm->eject = tifm_7xx1_eject; | 321 | fm->eject = tifm_7xx1_eject; |
363 | pci_set_drvdata(dev, fm); | 322 | pci_set_drvdata(dev, fm); |
364 | 323 | ||
@@ -367,19 +326,16 @@ static int tifm_7xx1_probe(struct pci_dev *dev, | |||
367 | if (!fm->addr) | 326 | if (!fm->addr) |
368 | goto err_out_free; | 327 | goto err_out_free; |
369 | 328 | ||
370 | rc = request_irq(dev->irq, tifm_7xx1_isr, IRQF_SHARED, DRIVER_NAME, fm); | 329 | rc = request_irq(dev->irq, tifm_7xx1_isr, SA_SHIRQ, DRIVER_NAME, fm); |
371 | if (rc) | 330 | if (rc) |
372 | goto err_out_unmap; | 331 | goto err_out_unmap; |
373 | 332 | ||
374 | init_waitqueue_head(&fm->change_set_notify); | 333 | rc = tifm_add_adapter(fm); |
375 | rc = tifm_add_adapter(fm, tifm_7xx1_switch_media); | ||
376 | if (rc) | 334 | if (rc) |
377 | goto err_out_irq; | 335 | goto err_out_irq; |
378 | 336 | ||
379 | writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | ||
380 | writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), | 337 | writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), |
381 | fm->addr + FM_SET_INTERRUPT_ENABLE); | 338 | fm->addr + FM_SET_INTERRUPT_ENABLE); |
382 | wake_up_process(fm->media_switcher); | ||
383 | return 0; | 339 | return 0; |
384 | 340 | ||
385 | err_out_irq: | 341 | err_out_irq: |
@@ -401,18 +357,12 @@ err_out: | |||
401 | static void tifm_7xx1_remove(struct pci_dev *dev) | 357 | static void tifm_7xx1_remove(struct pci_dev *dev) |
402 | { | 358 | { |
403 | struct tifm_adapter *fm = pci_get_drvdata(dev); | 359 | struct tifm_adapter *fm = pci_get_drvdata(dev); |
404 | unsigned long flags; | ||
405 | 360 | ||
361 | fm->eject = tifm_7xx1_dummy_eject; | ||
406 | writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | 362 | writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); |
407 | mmiowb(); | 363 | mmiowb(); |
408 | free_irq(dev->irq, fm); | 364 | free_irq(dev->irq, fm); |
409 | 365 | ||
410 | spin_lock_irqsave(&fm->lock, flags); | ||
411 | fm->socket_change_set = (1 << fm->num_sockets) - 1; | ||
412 | spin_unlock_irqrestore(&fm->lock, flags); | ||
413 | |||
414 | kthread_stop(fm->media_switcher); | ||
415 | |||
416 | tifm_remove_adapter(fm); | 366 | tifm_remove_adapter(fm); |
417 | 367 | ||
418 | pci_set_drvdata(dev, NULL); | 368 | pci_set_drvdata(dev, NULL); |