diff options
Diffstat (limited to 'drivers/misc/tifm_7xx1.c')
-rw-r--r-- | drivers/misc/tifm_7xx1.c | 402 |
1 files changed, 213 insertions, 189 deletions
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 2ab7add78f94..e21e490fedb0 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c | |||
@@ -11,66 +11,25 @@ | |||
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> | ||
14 | 15 | ||
15 | #define DRIVER_NAME "tifm_7xx1" | 16 | #define DRIVER_NAME "tifm_7xx1" |
16 | #define DRIVER_VERSION "0.6" | 17 | #define DRIVER_VERSION "0.7" |
17 | 18 | ||
18 | static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) | 19 | static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) |
19 | { | 20 | { |
20 | int cnt; | ||
21 | unsigned long flags; | ||
22 | |||
23 | spin_lock_irqsave(&fm->lock, flags); | ||
24 | if (!fm->inhibit_new_cards) { | ||
25 | for (cnt = 0; cnt < fm->max_sockets; cnt++) { | ||
26 | if (fm->sockets[cnt] == sock) { | ||
27 | fm->remove_mask |= (1 << cnt); | ||
28 | queue_work(fm->wq, &fm->media_remover); | ||
29 | break; | ||
30 | } | ||
31 | } | ||
32 | } | ||
33 | spin_unlock_irqrestore(&fm->lock, flags); | ||
34 | } | ||
35 | |||
36 | static void tifm_7xx1_remove_media(struct work_struct *work) | ||
37 | { | ||
38 | struct tifm_adapter *fm = | ||
39 | container_of(work, struct tifm_adapter, media_remover); | ||
40 | unsigned long flags; | 21 | unsigned long flags; |
41 | int cnt; | ||
42 | struct tifm_dev *sock; | ||
43 | 22 | ||
44 | if (!class_device_get(&fm->cdev)) | ||
45 | return; | ||
46 | spin_lock_irqsave(&fm->lock, flags); | 23 | spin_lock_irqsave(&fm->lock, flags); |
47 | for (cnt = 0; cnt < fm->max_sockets; cnt++) { | 24 | fm->socket_change_set |= 1 << sock->socket_id; |
48 | if (fm->sockets[cnt] && (fm->remove_mask & (1 << cnt))) { | 25 | wake_up_all(&fm->change_set_notify); |
49 | printk(KERN_INFO DRIVER_NAME | ||
50 | ": demand removing card from socket %d\n", cnt); | ||
51 | sock = fm->sockets[cnt]; | ||
52 | fm->sockets[cnt] = NULL; | ||
53 | fm->remove_mask &= ~(1 << cnt); | ||
54 | |||
55 | writel(0x0e00, sock->addr + SOCK_CONTROL); | ||
56 | |||
57 | writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, | ||
58 | fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | ||
59 | writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, | ||
60 | fm->addr + FM_SET_INTERRUPT_ENABLE); | ||
61 | |||
62 | spin_unlock_irqrestore(&fm->lock, flags); | ||
63 | device_unregister(&sock->dev); | ||
64 | spin_lock_irqsave(&fm->lock, flags); | ||
65 | } | ||
66 | } | ||
67 | spin_unlock_irqrestore(&fm->lock, flags); | 26 | spin_unlock_irqrestore(&fm->lock, flags); |
68 | class_device_put(&fm->cdev); | ||
69 | } | 27 | } |
70 | 28 | ||
71 | static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) | 29 | static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) |
72 | { | 30 | { |
73 | struct tifm_adapter *fm = dev_id; | 31 | struct tifm_adapter *fm = dev_id; |
32 | struct tifm_dev *sock; | ||
74 | unsigned int irq_status; | 33 | unsigned int irq_status; |
75 | unsigned int sock_irq_status, cnt; | 34 | unsigned int sock_irq_status, cnt; |
76 | 35 | ||
@@ -84,42 +43,32 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) | |||
84 | if (irq_status & TIFM_IRQ_ENABLE) { | 43 | if (irq_status & TIFM_IRQ_ENABLE) { |
85 | writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | 44 | writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); |
86 | 45 | ||
87 | for (cnt = 0; cnt < fm->max_sockets; cnt++) { | 46 | for (cnt = 0; cnt < fm->num_sockets; cnt++) { |
88 | sock_irq_status = (irq_status >> cnt) & | 47 | sock = fm->sockets[cnt]; |
89 | (TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK); | 48 | sock_irq_status = (irq_status >> cnt) |
90 | 49 | & (TIFM_IRQ_FIFOMASK(1) | |
91 | if (fm->sockets[cnt]) { | 50 | | TIFM_IRQ_CARDMASK(1)); |
92 | if (sock_irq_status && | ||
93 | fm->sockets[cnt]->signal_irq) | ||
94 | sock_irq_status = fm->sockets[cnt]-> | ||
95 | signal_irq(fm->sockets[cnt], | ||
96 | sock_irq_status); | ||
97 | 51 | ||
98 | if (irq_status & (1 << cnt)) | 52 | if (sock && sock_irq_status) |
99 | fm->remove_mask |= 1 << cnt; | 53 | sock->signal_irq(sock, sock_irq_status); |
100 | } else { | ||
101 | if (irq_status & (1 << cnt)) | ||
102 | fm->insert_mask |= 1 << cnt; | ||
103 | } | ||
104 | } | 54 | } |
55 | |||
56 | fm->socket_change_set |= irq_status | ||
57 | & ((1 << fm->num_sockets) - 1); | ||
105 | } | 58 | } |
106 | writel(irq_status, fm->addr + FM_INTERRUPT_STATUS); | 59 | writel(irq_status, fm->addr + FM_INTERRUPT_STATUS); |
107 | 60 | ||
108 | if (!fm->inhibit_new_cards) { | 61 | if (!fm->socket_change_set) |
109 | if (!fm->remove_mask && !fm->insert_mask) { | 62 | writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); |
110 | writel(TIFM_IRQ_ENABLE, | 63 | else |
111 | fm->addr + FM_SET_INTERRUPT_ENABLE); | 64 | wake_up_all(&fm->change_set_notify); |
112 | } else { | ||
113 | queue_work(fm->wq, &fm->media_remover); | ||
114 | queue_work(fm->wq, &fm->media_inserter); | ||
115 | } | ||
116 | } | ||
117 | 65 | ||
118 | spin_unlock(&fm->lock); | 66 | spin_unlock(&fm->lock); |
119 | return IRQ_HANDLED; | 67 | return IRQ_HANDLED; |
120 | } | 68 | } |
121 | 69 | ||
122 | static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is_x2) | 70 | static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, |
71 | int is_x2) | ||
123 | { | 72 | { |
124 | unsigned int s_state; | 73 | unsigned int s_state; |
125 | int cnt; | 74 | int cnt; |
@@ -127,8 +76,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is | |||
127 | writel(0x0e00, sock_addr + SOCK_CONTROL); | 76 | writel(0x0e00, sock_addr + SOCK_CONTROL); |
128 | 77 | ||
129 | for (cnt = 0; cnt < 100; cnt++) { | 78 | for (cnt = 0; cnt < 100; cnt++) { |
130 | if (!(TIFM_SOCK_STATE_POWERED & | 79 | if (!(TIFM_SOCK_STATE_POWERED |
131 | readl(sock_addr + SOCK_PRESENT_STATE))) | 80 | & readl(sock_addr + SOCK_PRESENT_STATE))) |
132 | break; | 81 | break; |
133 | msleep(10); | 82 | msleep(10); |
134 | } | 83 | } |
@@ -151,8 +100,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is | |||
151 | } | 100 | } |
152 | 101 | ||
153 | for (cnt = 0; cnt < 100; cnt++) { | 102 | for (cnt = 0; cnt < 100; cnt++) { |
154 | if ((TIFM_SOCK_STATE_POWERED & | 103 | if ((TIFM_SOCK_STATE_POWERED |
155 | readl(sock_addr + SOCK_PRESENT_STATE))) | 104 | & readl(sock_addr + SOCK_PRESENT_STATE))) |
156 | break; | 105 | break; |
157 | msleep(10); | 106 | msleep(10); |
158 | } | 107 | } |
@@ -170,130 +119,209 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num) | |||
170 | return base_addr + ((sock_num + 1) << 10); | 119 | return base_addr + ((sock_num + 1) << 10); |
171 | } | 120 | } |
172 | 121 | ||
173 | static void tifm_7xx1_insert_media(struct work_struct *work) | 122 | static int tifm_7xx1_switch_media(void *data) |
174 | { | 123 | { |
175 | struct tifm_adapter *fm = | 124 | struct tifm_adapter *fm = data; |
176 | container_of(work, struct tifm_adapter, media_inserter); | ||
177 | unsigned long flags; | 125 | unsigned long flags; |
178 | tifm_media_id media_id; | 126 | tifm_media_id media_id; |
179 | char *card_name = "xx"; | 127 | char *card_name = "xx"; |
180 | int cnt, ok_to_register; | 128 | int cnt, rc; |
181 | unsigned int insert_mask; | 129 | struct tifm_dev *sock; |
182 | struct tifm_dev *new_sock = NULL; | 130 | unsigned int socket_change_set; |
183 | 131 | ||
184 | if (!class_device_get(&fm->cdev)) | 132 | while (1) { |
185 | return; | 133 | rc = wait_event_interruptible(fm->change_set_notify, |
186 | spin_lock_irqsave(&fm->lock, flags); | 134 | fm->socket_change_set); |
187 | insert_mask = fm->insert_mask; | 135 | if (rc == -ERESTARTSYS) |
188 | fm->insert_mask = 0; | 136 | try_to_freeze(); |
189 | if (fm->inhibit_new_cards) { | 137 | |
138 | spin_lock_irqsave(&fm->lock, flags); | ||
139 | socket_change_set = fm->socket_change_set; | ||
140 | fm->socket_change_set = 0; | ||
141 | |||
142 | dev_dbg(fm->dev, "checking media set %x\n", | ||
143 | socket_change_set); | ||
144 | |||
145 | if (kthread_should_stop()) | ||
146 | socket_change_set = (1 << fm->num_sockets) - 1; | ||
190 | spin_unlock_irqrestore(&fm->lock, flags); | 147 | spin_unlock_irqrestore(&fm->lock, flags); |
191 | class_device_put(&fm->cdev); | ||
192 | return; | ||
193 | } | ||
194 | spin_unlock_irqrestore(&fm->lock, flags); | ||
195 | 148 | ||
196 | for (cnt = 0; cnt < fm->max_sockets; cnt++) { | 149 | if (!socket_change_set) |
197 | if (!(insert_mask & (1 << cnt))) | ||
198 | continue; | 150 | continue; |
199 | 151 | ||
200 | media_id = tifm_7xx1_toggle_sock_power(tifm_7xx1_sock_addr(fm->addr, cnt), | 152 | spin_lock_irqsave(&fm->lock, flags); |
201 | fm->max_sockets == 2); | 153 | for (cnt = 0; cnt < fm->num_sockets; cnt++) { |
202 | if (media_id) { | 154 | if (!(socket_change_set & (1 << cnt))) |
203 | ok_to_register = 0; | 155 | continue; |
204 | new_sock = tifm_alloc_device(fm, cnt); | 156 | sock = fm->sockets[cnt]; |
205 | if (new_sock) { | 157 | if (sock) { |
206 | new_sock->addr = tifm_7xx1_sock_addr(fm->addr, | ||
207 | cnt); | ||
208 | new_sock->media_id = media_id; | ||
209 | switch (media_id) { | ||
210 | case 1: | ||
211 | card_name = "xd"; | ||
212 | break; | ||
213 | case 2: | ||
214 | card_name = "ms"; | ||
215 | break; | ||
216 | case 3: | ||
217 | card_name = "sd"; | ||
218 | break; | ||
219 | default: | ||
220 | break; | ||
221 | } | ||
222 | snprintf(new_sock->dev.bus_id, BUS_ID_SIZE, | ||
223 | "tifm_%s%u:%u", card_name, fm->id, cnt); | ||
224 | printk(KERN_INFO DRIVER_NAME | 158 | printk(KERN_INFO DRIVER_NAME |
225 | ": %s card detected in socket %d\n", | 159 | ": demand removing card from socket %d\n", |
226 | card_name, cnt); | 160 | cnt); |
161 | fm->sockets[cnt] = NULL; | ||
162 | spin_unlock_irqrestore(&fm->lock, flags); | ||
163 | device_unregister(&sock->dev); | ||
227 | spin_lock_irqsave(&fm->lock, flags); | 164 | spin_lock_irqsave(&fm->lock, flags); |
228 | if (!fm->sockets[cnt]) { | 165 | writel(0x0e00, |
229 | fm->sockets[cnt] = new_sock; | 166 | tifm_7xx1_sock_addr(fm->addr, cnt) |
230 | ok_to_register = 1; | 167 | + SOCK_CONTROL); |
168 | } | ||
169 | if (kthread_should_stop()) | ||
170 | continue; | ||
171 | |||
172 | spin_unlock_irqrestore(&fm->lock, flags); | ||
173 | media_id = tifm_7xx1_toggle_sock_power( | ||
174 | tifm_7xx1_sock_addr(fm->addr, cnt), | ||
175 | fm->num_sockets == 2); | ||
176 | if (media_id) { | ||
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); | ||
231 | } | 214 | } |
215 | spin_lock_irqsave(&fm->lock, flags); | ||
216 | } | ||
217 | } | ||
218 | |||
219 | if (!kthread_should_stop()) { | ||
220 | writel(TIFM_IRQ_FIFOMASK(socket_change_set) | ||
221 | | TIFM_IRQ_CARDMASK(socket_change_set), | ||
222 | fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | ||
223 | writel(TIFM_IRQ_FIFOMASK(socket_change_set) | ||
224 | | TIFM_IRQ_CARDMASK(socket_change_set), | ||
225 | fm->addr + FM_SET_INTERRUPT_ENABLE); | ||
226 | writel(TIFM_IRQ_ENABLE, | ||
227 | fm->addr + FM_SET_INTERRUPT_ENABLE); | ||
228 | spin_unlock_irqrestore(&fm->lock, flags); | ||
229 | } else { | ||
230 | for (cnt = 0; cnt < fm->num_sockets; cnt++) { | ||
231 | if (fm->sockets[cnt]) | ||
232 | fm->socket_change_set |= 1 << cnt; | ||
233 | } | ||
234 | if (!fm->socket_change_set) { | ||
235 | spin_unlock_irqrestore(&fm->lock, flags); | ||
236 | return 0; | ||
237 | } else { | ||
232 | spin_unlock_irqrestore(&fm->lock, flags); | 238 | spin_unlock_irqrestore(&fm->lock, flags); |
233 | if (!ok_to_register || | ||
234 | device_register(&new_sock->dev)) { | ||
235 | spin_lock_irqsave(&fm->lock, flags); | ||
236 | fm->sockets[cnt] = NULL; | ||
237 | spin_unlock_irqrestore(&fm->lock, | ||
238 | flags); | ||
239 | tifm_free_device(&new_sock->dev); | ||
240 | } | ||
241 | } | 239 | } |
242 | } | 240 | } |
243 | writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, | ||
244 | fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | ||
245 | writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, | ||
246 | fm->addr + FM_SET_INTERRUPT_ENABLE); | ||
247 | } | 241 | } |
248 | 242 | return 0; | |
249 | writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); | ||
250 | class_device_put(&fm->cdev); | ||
251 | } | 243 | } |
252 | 244 | ||
245 | #ifdef CONFIG_PM | ||
246 | |||
253 | static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state) | 247 | static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state) |
254 | { | 248 | { |
255 | struct tifm_adapter *fm = pci_get_drvdata(dev); | 249 | dev_dbg(&dev->dev, "suspending host\n"); |
256 | unsigned long flags; | ||
257 | 250 | ||
258 | spin_lock_irqsave(&fm->lock, flags); | 251 | pci_save_state(dev); |
259 | fm->inhibit_new_cards = 1; | 252 | pci_enable_wake(dev, pci_choose_state(dev, state), 0); |
260 | fm->remove_mask = 0xf; | 253 | pci_disable_device(dev); |
261 | fm->insert_mask = 0; | 254 | pci_set_power_state(dev, pci_choose_state(dev, state)); |
262 | writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | ||
263 | spin_unlock_irqrestore(&fm->lock, flags); | ||
264 | flush_workqueue(fm->wq); | ||
265 | |||
266 | tifm_7xx1_remove_media(&fm->media_remover); | ||
267 | |||
268 | pci_set_power_state(dev, PCI_D3hot); | ||
269 | pci_disable_device(dev); | ||
270 | pci_save_state(dev); | ||
271 | return 0; | 255 | return 0; |
272 | } | 256 | } |
273 | 257 | ||
274 | static int tifm_7xx1_resume(struct pci_dev *dev) | 258 | static int tifm_7xx1_resume(struct pci_dev *dev) |
275 | { | 259 | { |
276 | struct tifm_adapter *fm = pci_get_drvdata(dev); | 260 | struct tifm_adapter *fm = pci_get_drvdata(dev); |
261 | int cnt, rc; | ||
277 | unsigned long flags; | 262 | unsigned long flags; |
263 | tifm_media_id new_ids[fm->num_sockets]; | ||
278 | 264 | ||
265 | pci_set_power_state(dev, PCI_D0); | ||
279 | pci_restore_state(dev); | 266 | pci_restore_state(dev); |
280 | pci_enable_device(dev); | 267 | rc = pci_enable_device(dev); |
281 | pci_set_power_state(dev, PCI_D0); | 268 | if (rc) |
282 | pci_set_master(dev); | 269 | return rc; |
270 | pci_set_master(dev); | ||
283 | 271 | ||
272 | dev_dbg(&dev->dev, "resuming host\n"); | ||
273 | |||
274 | for (cnt = 0; cnt < fm->num_sockets; cnt++) | ||
275 | new_ids[cnt] = tifm_7xx1_toggle_sock_power( | ||
276 | tifm_7xx1_sock_addr(fm->addr, cnt), | ||
277 | fm->num_sockets == 2); | ||
284 | spin_lock_irqsave(&fm->lock, flags); | 278 | spin_lock_irqsave(&fm->lock, flags); |
285 | fm->inhibit_new_cards = 0; | 279 | fm->socket_change_set = 0; |
286 | writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS); | 280 | for (cnt = 0; cnt < fm->num_sockets; cnt++) { |
287 | writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | 281 | if (fm->sockets[cnt]) { |
288 | writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK, | 282 | if (fm->sockets[cnt]->media_id == new_ids[cnt]) |
289 | fm->addr + FM_SET_INTERRUPT_ENABLE); | 283 | fm->socket_change_set |= 1 << cnt; |
290 | fm->insert_mask = 0xf; | 284 | |
285 | fm->sockets[cnt]->media_id = new_ids[cnt]; | ||
286 | } | ||
287 | } | ||
288 | |||
289 | writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), | ||
290 | fm->addr + FM_SET_INTERRUPT_ENABLE); | ||
291 | if (!fm->socket_change_set) { | ||
292 | spin_unlock_irqrestore(&fm->lock, flags); | ||
293 | return 0; | ||
294 | } else { | ||
295 | fm->socket_change_set = 0; | ||
296 | spin_unlock_irqrestore(&fm->lock, flags); | ||
297 | } | ||
298 | |||
299 | wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ); | ||
300 | |||
301 | spin_lock_irqsave(&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, | ||
309 | fm->addr + FM_SET_INTERRUPT_ENABLE); | ||
310 | fm->socket_change_set = 0; | ||
311 | |||
291 | spin_unlock_irqrestore(&fm->lock, flags); | 312 | spin_unlock_irqrestore(&fm->lock, flags); |
292 | return 0; | 313 | return 0; |
293 | } | 314 | } |
294 | 315 | ||
316 | #else | ||
317 | |||
318 | #define tifm_7xx1_suspend NULL | ||
319 | #define tifm_7xx1_resume NULL | ||
320 | |||
321 | #endif /* CONFIG_PM */ | ||
322 | |||
295 | static int tifm_7xx1_probe(struct pci_dev *dev, | 323 | static int tifm_7xx1_probe(struct pci_dev *dev, |
296 | const struct pci_device_id *dev_id) | 324 | const struct pci_device_id *dev_id) |
297 | { | 325 | { |
298 | struct tifm_adapter *fm; | 326 | struct tifm_adapter *fm; |
299 | int pci_dev_busy = 0; | 327 | int pci_dev_busy = 0; |
@@ -324,19 +352,18 @@ static int tifm_7xx1_probe(struct pci_dev *dev, | |||
324 | } | 352 | } |
325 | 353 | ||
326 | fm->dev = &dev->dev; | 354 | fm->dev = &dev->dev; |
327 | fm->max_sockets = (dev->device == 0x803B) ? 2 : 4; | 355 | fm->num_sockets = (dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM) |
328 | fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->max_sockets, | 356 | ? 4 : 2; |
329 | GFP_KERNEL); | 357 | fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets, |
358 | GFP_KERNEL); | ||
330 | if (!fm->sockets) | 359 | if (!fm->sockets) |
331 | goto err_out_free; | 360 | goto err_out_free; |
332 | 361 | ||
333 | INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media); | ||
334 | INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media); | ||
335 | fm->eject = tifm_7xx1_eject; | 362 | fm->eject = tifm_7xx1_eject; |
336 | pci_set_drvdata(dev, fm); | 363 | pci_set_drvdata(dev, fm); |
337 | 364 | ||
338 | fm->addr = ioremap(pci_resource_start(dev, 0), | 365 | fm->addr = ioremap(pci_resource_start(dev, 0), |
339 | pci_resource_len(dev, 0)); | 366 | pci_resource_len(dev, 0)); |
340 | if (!fm->addr) | 367 | if (!fm->addr) |
341 | goto err_out_free; | 368 | goto err_out_free; |
342 | 369 | ||
@@ -344,16 +371,15 @@ static int tifm_7xx1_probe(struct pci_dev *dev, | |||
344 | if (rc) | 371 | if (rc) |
345 | goto err_out_unmap; | 372 | goto err_out_unmap; |
346 | 373 | ||
347 | rc = tifm_add_adapter(fm); | 374 | init_waitqueue_head(&fm->change_set_notify); |
375 | rc = tifm_add_adapter(fm, tifm_7xx1_switch_media); | ||
348 | if (rc) | 376 | if (rc) |
349 | goto err_out_irq; | 377 | goto err_out_irq; |
350 | 378 | ||
351 | writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | 379 | writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); |
352 | writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK, | 380 | writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), |
353 | fm->addr + FM_SET_INTERRUPT_ENABLE); | 381 | fm->addr + FM_SET_INTERRUPT_ENABLE); |
354 | 382 | wake_up_process(fm->media_switcher); | |
355 | fm->insert_mask = 0xf; | ||
356 | |||
357 | return 0; | 383 | return 0; |
358 | 384 | ||
359 | err_out_irq: | 385 | err_out_irq: |
@@ -377,19 +403,15 @@ static void tifm_7xx1_remove(struct pci_dev *dev) | |||
377 | struct tifm_adapter *fm = pci_get_drvdata(dev); | 403 | struct tifm_adapter *fm = pci_get_drvdata(dev); |
378 | unsigned long flags; | 404 | unsigned long flags; |
379 | 405 | ||
406 | writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | ||
407 | mmiowb(); | ||
408 | free_irq(dev->irq, fm); | ||
409 | |||
380 | spin_lock_irqsave(&fm->lock, flags); | 410 | spin_lock_irqsave(&fm->lock, flags); |
381 | fm->inhibit_new_cards = 1; | 411 | fm->socket_change_set = (1 << fm->num_sockets) - 1; |
382 | fm->remove_mask = 0xf; | ||
383 | fm->insert_mask = 0; | ||
384 | writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | ||
385 | spin_unlock_irqrestore(&fm->lock, flags); | 412 | spin_unlock_irqrestore(&fm->lock, flags); |
386 | 413 | ||
387 | flush_workqueue(fm->wq); | 414 | kthread_stop(fm->media_switcher); |
388 | |||
389 | tifm_7xx1_remove_media(&fm->media_remover); | ||
390 | |||
391 | writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); | ||
392 | free_irq(dev->irq, fm); | ||
393 | 415 | ||
394 | tifm_remove_adapter(fm); | 416 | tifm_remove_adapter(fm); |
395 | 417 | ||
@@ -404,10 +426,12 @@ static void tifm_7xx1_remove(struct pci_dev *dev) | |||
404 | } | 426 | } |
405 | 427 | ||
406 | static struct pci_device_id tifm_7xx1_pci_tbl [] = { | 428 | static struct pci_device_id tifm_7xx1_pci_tbl [] = { |
407 | { PCI_VENDOR_ID_TI, 0x8033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 429 | { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11_FM, PCI_ANY_ID, |
408 | 0 }, /* xx21 - the one I have */ | 430 | PCI_ANY_ID, 0, 0, 0 }, /* xx21 - the one I have */ |
409 | { PCI_VENDOR_ID_TI, 0x803B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 431 | { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12_FM, PCI_ANY_ID, |
410 | 0 }, /* xx12 - should be also supported */ | 432 | PCI_ANY_ID, 0, 0, 0 }, |
433 | { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX20_FM, PCI_ANY_ID, | ||
434 | PCI_ANY_ID, 0, 0, 0 }, | ||
411 | { } | 435 | { } |
412 | }; | 436 | }; |
413 | 437 | ||