Commit | Line | Data |
---|---|---|
0b99d589 LL |
1 | /* |
2 | * Copyright 2003 Digi International (www.digi.com) | |
3 | * Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option) | |
8 | * any later version. | |
817b7847 | 9 | * |
0b99d589 | 10 | * This program is distributed in the hope that it will be useful, |
817b7847 LL |
11 | * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the |
12 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR | |
0b99d589 | 13 | * PURPOSE. See the GNU General Public License for more details. |
0b99d589 LL |
14 | */ |
15 | ||
0b99d589 | 16 | #include <linux/kernel.h> |
0b99d589 LL |
17 | #include <linux/module.h> |
18 | #include <linux/pci.h> | |
68a5a5f3 | 19 | #include <linux/slab.h> |
0b99d589 | 20 | #include <linux/sched.h> |
0b99d589 LL |
21 | #include "dgnc_driver.h" |
22 | #include "dgnc_pci.h" | |
0b99d589 LL |
23 | #include "dgnc_mgmt.h" |
24 | #include "dgnc_tty.h" | |
0b99d589 LL |
25 | #include "dgnc_cls.h" |
26 | #include "dgnc_neo.h" | |
27 | #include "dgnc_sysfs.h" | |
28 | ||
29 | MODULE_LICENSE("GPL"); | |
30 | MODULE_AUTHOR("Digi International, http://www.digi.com"); | |
31 | MODULE_DESCRIPTION("Driver for the Digi International Neo and Classic PCI based product line"); | |
32 | MODULE_SUPPORTED_DEVICE("dgnc"); | |
33 | ||
0b99d589 LL |
34 | /************************************************************************** |
35 | * | |
36 | * protos for this file | |
37 | * | |
38 | */ | |
39 | static int dgnc_start(void); | |
0d79f59d | 40 | static int dgnc_request_irq(struct dgnc_board *brd); |
5897914f | 41 | static void dgnc_free_irq(struct dgnc_board *brd); |
f20ae478 | 42 | static struct dgnc_board *dgnc_found_board(struct pci_dev *pdev, int id); |
03425f55 | 43 | static void dgnc_cleanup_board(struct dgnc_board *brd); |
0b99d589 | 44 | static void dgnc_poll_handler(ulong dummy); |
65da04c1 GS |
45 | static int dgnc_init_one(struct pci_dev *pdev, |
46 | const struct pci_device_id *ent); | |
b09f0cd5 | 47 | static int dgnc_do_remap(struct dgnc_board *brd); |
0b99d589 | 48 | |
0b99d589 LL |
49 | /* |
50 | * File operations permitted on Control/Management major. | |
51 | */ | |
80e3e241 | 52 | static const struct file_operations dgnc_board_fops = { |
0b99d589 | 53 | .owner = THIS_MODULE, |
338fd80f | 54 | .unlocked_ioctl = dgnc_mgmt_ioctl, |
0b99d589 LL |
55 | .open = dgnc_mgmt_open, |
56 | .release = dgnc_mgmt_close | |
57 | }; | |
58 | ||
0b99d589 LL |
59 | /* |
60 | * Globals | |
61 | */ | |
80e3e241 DY |
62 | uint dgnc_num_boards; |
63 | struct dgnc_board *dgnc_board[MAXBOARDS]; | |
0b99d589 | 64 | DEFINE_SPINLOCK(dgnc_global_lock); |
51abf45c | 65 | DEFINE_SPINLOCK(dgnc_poll_lock); /* Poll scheduling lock */ |
80e3e241 | 66 | uint dgnc_major; |
0b99d589 LL |
67 | int dgnc_poll_tick = 20; /* Poll interval - 20 ms */ |
68 | ||
69 | /* | |
70 | * Static vars. | |
71 | */ | |
0b99d589 LL |
72 | static struct class *dgnc_class; |
73 | ||
74 | /* | |
75 | * Poller stuff | |
76 | */ | |
65da04c1 GS |
77 | static ulong dgnc_poll_time; /* Time of next poll */ |
78 | static uint dgnc_poll_stop; /* Used to tell poller to stop */ | |
0b99d589 LL |
79 | static struct timer_list dgnc_poll_timer; |
80 | ||
60e27886 KA |
81 | static const struct pci_device_id dgnc_pci_tbl[] = { |
82 | {PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_4_DID), .driver_data = 0}, | |
83 | {PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_4_422_DID), .driver_data = 1}, | |
84 | {PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_8_DID), .driver_data = 2}, | |
85 | {PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_8_422_DID), .driver_data = 3}, | |
86 | {0,} | |
0b99d589 LL |
87 | }; |
88 | MODULE_DEVICE_TABLE(pci, dgnc_pci_tbl); | |
89 | ||
90 | struct board_id { | |
446393e9 | 91 | unsigned char *name; |
0b99d589 LL |
92 | uint maxports; |
93 | unsigned int is_pci_express; | |
94 | }; | |
95 | ||
80e3e241 | 96 | static struct board_id dgnc_ids[] = { |
0b99d589 LL |
97 | { PCI_DEVICE_CLASSIC_4_PCI_NAME, 4, 0 }, |
98 | { PCI_DEVICE_CLASSIC_4_422_PCI_NAME, 4, 0 }, | |
99 | { PCI_DEVICE_CLASSIC_8_PCI_NAME, 8, 0 }, | |
100 | { PCI_DEVICE_CLASSIC_8_422_PCI_NAME, 8, 0 }, | |
101 | { PCI_DEVICE_NEO_4_PCI_NAME, 4, 0 }, | |
102 | { PCI_DEVICE_NEO_8_PCI_NAME, 8, 0 }, | |
103 | { PCI_DEVICE_NEO_2DB9_PCI_NAME, 2, 0 }, | |
104 | { PCI_DEVICE_NEO_2DB9PRI_PCI_NAME, 2, 0 }, | |
105 | { PCI_DEVICE_NEO_2RJ45_PCI_NAME, 2, 0 }, | |
106 | { PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME, 2, 0 }, | |
107 | { PCI_DEVICE_NEO_1_422_PCI_NAME, 1, 0 }, | |
108 | { PCI_DEVICE_NEO_1_422_485_PCI_NAME, 1, 0 }, | |
109 | { PCI_DEVICE_NEO_2_422_485_PCI_NAME, 2, 0 }, | |
110 | { PCI_DEVICE_NEO_EXPRESS_8_PCI_NAME, 8, 1 }, | |
111 | { PCI_DEVICE_NEO_EXPRESS_4_PCI_NAME, 4, 1 }, | |
112 | { PCI_DEVICE_NEO_EXPRESS_4RJ45_PCI_NAME, 4, 1 }, | |
113 | { PCI_DEVICE_NEO_EXPRESS_8RJ45_PCI_NAME, 8, 1 }, | |
114 | { NULL, 0, 0 } | |
115 | }; | |
116 | ||
117 | static struct pci_driver dgnc_driver = { | |
118 | .name = "dgnc", | |
119 | .probe = dgnc_init_one, | |
120 | .id_table = dgnc_pci_tbl, | |
0b99d589 LL |
121 | }; |
122 | ||
0b99d589 LL |
123 | /************************************************************************ |
124 | * | |
125 | * Driver load/unload functions | |
126 | * | |
127 | ************************************************************************/ | |
128 | ||
18f038e6 | 129 | static void cleanup(bool sysfiles) |
1e881002 KZ |
130 | { |
131 | int i; | |
66663dc1 | 132 | unsigned long flags; |
1e881002 | 133 | |
66663dc1 | 134 | spin_lock_irqsave(&dgnc_poll_lock, flags); |
1e881002 | 135 | dgnc_poll_stop = 1; |
66663dc1 | 136 | spin_unlock_irqrestore(&dgnc_poll_lock, flags); |
1e881002 KZ |
137 | |
138 | /* Turn off poller right away. */ | |
139 | del_timer_sync(&dgnc_poll_timer); | |
140 | ||
18f038e6 SM |
141 | if (sysfiles) |
142 | dgnc_remove_driver_sysfiles(&dgnc_driver); | |
1e881002 | 143 | |
80e3e241 | 144 | device_destroy(dgnc_class, MKDEV(dgnc_major, 0)); |
ed7f92da | 145 | class_destroy(dgnc_class); |
80e3e241 | 146 | unregister_chrdev(dgnc_major, "dgnc"); |
1e881002 | 147 | |
80e3e241 DY |
148 | for (i = 0; i < dgnc_num_boards; ++i) { |
149 | dgnc_remove_ports_sysfiles(dgnc_board[i]); | |
33ccb442 | 150 | dgnc_cleanup_tty(dgnc_board[i]); |
80e3e241 | 151 | dgnc_cleanup_board(dgnc_board[i]); |
1e881002 KZ |
152 | } |
153 | ||
154 | dgnc_tty_post_uninit(); | |
18f038e6 | 155 | } |
1e881002 | 156 | |
18f038e6 SM |
157 | /* |
158 | * dgnc_cleanup_module() | |
159 | * | |
160 | * Module unload. This is where it all ends. | |
161 | */ | |
598b1529 | 162 | static void __exit dgnc_cleanup_module(void) |
18f038e6 SM |
163 | { |
164 | cleanup(true); | |
b3ca2e08 | 165 | pci_unregister_driver(&dgnc_driver); |
1e881002 | 166 | } |
0b99d589 LL |
167 | |
168 | /* | |
169 | * init_module() | |
170 | * | |
171 | * Module load. This is where it all starts. | |
172 | */ | |
1e881002 | 173 | static int __init dgnc_init_module(void) |
0b99d589 | 174 | { |
f4edff52 | 175 | int rc; |
0b99d589 | 176 | |
0b99d589 LL |
177 | /* |
178 | * Initialize global stuff | |
179 | */ | |
180 | rc = dgnc_start(); | |
181 | ||
3f288962 | 182 | if (rc < 0) |
8f90ef80 | 183 | return rc; |
0b99d589 LL |
184 | |
185 | /* | |
186 | * Find and configure all the cards | |
187 | */ | |
bbecbacb | 188 | rc = pci_register_driver(&dgnc_driver); |
e9961fc1 SM |
189 | if (rc) { |
190 | pr_warn("WARNING: dgnc driver load failed. No Digi Neo or Classic boards found.\n"); | |
18f038e6 | 191 | cleanup(false); |
e9961fc1 | 192 | return rc; |
0b99d589 | 193 | } |
e9961fc1 | 194 | dgnc_create_driver_sysfiles(&dgnc_driver); |
0b99d589 | 195 | |
e9961fc1 | 196 | return 0; |
0b99d589 LL |
197 | } |
198 | ||
1e881002 KZ |
199 | module_init(dgnc_init_module); |
200 | module_exit(dgnc_cleanup_module); | |
0b99d589 LL |
201 | |
202 | /* | |
203 | * Start of driver. | |
204 | */ | |
205 | static int dgnc_start(void) | |
206 | { | |
207 | int rc = 0; | |
208 | unsigned long flags; | |
d7312aab | 209 | struct device *dev; |
0b99d589 | 210 | |
6d99d6a3 SM |
211 | /* make sure timer is initialized before we do anything else */ |
212 | init_timer(&dgnc_poll_timer); | |
0b99d589 | 213 | |
92ded48c KZ |
214 | /* |
215 | * Register our base character device into the kernel. | |
216 | * This allows the download daemon to connect to the downld device | |
217 | * before any of the boards are init'ed. | |
ed7f92da KZ |
218 | * |
219 | * Register management/dpa devices | |
92ded48c | 220 | */ |
80e3e241 | 221 | rc = register_chrdev(0, "dgnc", &dgnc_board_fops); |
5f9dca1e | 222 | if (rc < 0) { |
1f26adc9 | 223 | pr_err(DRVSTR ": Can't register dgnc driver device (%d)\n", rc); |
5f9dca1e | 224 | return rc; |
92ded48c | 225 | } |
80e3e241 | 226 | dgnc_major = rc; |
ed7f92da KZ |
227 | |
228 | dgnc_class = class_create(THIS_MODULE, "dgnc_mgmt"); | |
d7312aab AK |
229 | if (IS_ERR(dgnc_class)) { |
230 | rc = PTR_ERR(dgnc_class); | |
231 | pr_err(DRVSTR ": Can't create dgnc_mgmt class (%d)\n", rc); | |
232 | goto failed_class; | |
233 | } | |
234 | ||
235 | dev = device_create(dgnc_class, NULL, | |
80e3e241 | 236 | MKDEV(dgnc_major, 0), |
d7312aab AK |
237 | NULL, "dgnc_mgmt"); |
238 | if (IS_ERR(dev)) { | |
239 | rc = PTR_ERR(dev); | |
240 | pr_err(DRVSTR ": Can't create device (%d)\n", rc); | |
241 | goto failed_device; | |
242 | } | |
0b99d589 | 243 | |
92ded48c KZ |
244 | /* |
245 | * Init any global tty stuff. | |
246 | */ | |
247 | rc = dgnc_tty_preinit(); | |
0b99d589 | 248 | |
92ded48c | 249 | if (rc < 0) { |
1f26adc9 | 250 | pr_err(DRVSTR ": tty preinit - not enough memory (%d)\n", rc); |
d7312aab | 251 | goto failed_tty; |
92ded48c | 252 | } |
0b99d589 | 253 | |
92ded48c | 254 | /* Start the poller */ |
66663dc1 | 255 | spin_lock_irqsave(&dgnc_poll_lock, flags); |
38e0c9d2 | 256 | setup_timer(&dgnc_poll_timer, dgnc_poll_handler, 0); |
92ded48c KZ |
257 | dgnc_poll_time = jiffies + dgnc_jiffies_from_ms(dgnc_poll_tick); |
258 | dgnc_poll_timer.expires = dgnc_poll_time; | |
66663dc1 | 259 | spin_unlock_irqrestore(&dgnc_poll_lock, flags); |
0b99d589 | 260 | |
92ded48c KZ |
261 | add_timer(&dgnc_poll_timer); |
262 | ||
d7312aab AK |
263 | return 0; |
264 | ||
265 | failed_tty: | |
80e3e241 | 266 | device_destroy(dgnc_class, MKDEV(dgnc_major, 0)); |
d7312aab AK |
267 | failed_device: |
268 | class_destroy(dgnc_class); | |
269 | failed_class: | |
80e3e241 | 270 | unregister_chrdev(dgnc_major, "dgnc"); |
8f90ef80 | 271 | return rc; |
0b99d589 LL |
272 | } |
273 | ||
0b99d589 LL |
274 | /* returns count (>= 0), or negative on error */ |
275 | static int dgnc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |
817b7847 | 276 | { |
0b99d589 | 277 | int rc; |
f20ae478 | 278 | struct dgnc_board *brd; |
0b99d589 LL |
279 | |
280 | /* wake up and enable device */ | |
281 | rc = pci_enable_device(pdev); | |
282 | ||
757b816e SM |
283 | if (rc) |
284 | return -EIO; | |
285 | ||
f20ae478 DY |
286 | brd = dgnc_found_board(pdev, ent->driver_data); |
287 | if (IS_ERR(brd)) | |
288 | return PTR_ERR(brd); | |
289 | ||
290 | /* | |
291 | * Do tty device initialization. | |
292 | */ | |
293 | ||
294 | rc = dgnc_tty_register(brd); | |
295 | if (rc < 0) { | |
296 | pr_err(DRVSTR ": Can't register tty devices (%d)\n", rc); | |
297 | goto failed; | |
298 | } | |
299 | ||
0d79f59d | 300 | rc = dgnc_request_irq(brd); |
f20ae478 DY |
301 | if (rc < 0) { |
302 | pr_err(DRVSTR ": Can't finalize board init (%d)\n", rc); | |
eea5fd11 | 303 | goto unregister_tty; |
f20ae478 DY |
304 | } |
305 | ||
306 | rc = dgnc_tty_init(brd); | |
307 | if (rc < 0) { | |
308 | pr_err(DRVSTR ": Can't init tty devices (%d)\n", rc); | |
5897914f | 309 | goto free_irq; |
f20ae478 DY |
310 | } |
311 | ||
312 | brd->state = BOARD_READY; | |
313 | brd->dpastatus = BD_RUNNING; | |
314 | ||
315 | dgnc_create_ports_sysfiles(brd); | |
316 | ||
317 | dgnc_board[dgnc_num_boards++] = brd; | |
318 | ||
319 | return 0; | |
320 | ||
5897914f DY |
321 | free_irq: |
322 | dgnc_free_irq(brd); | |
eea5fd11 DY |
323 | unregister_tty: |
324 | dgnc_tty_unregister(brd); | |
325 | ||
f20ae478 DY |
326 | failed: |
327 | kfree(brd); | |
757b816e | 328 | |
0b99d589 LL |
329 | return rc; |
330 | } | |
331 | ||
0b99d589 LL |
332 | /* |
333 | * dgnc_cleanup_board() | |
334 | * | |
335 | * Free all the memory associated with a board | |
336 | */ | |
03425f55 | 337 | static void dgnc_cleanup_board(struct dgnc_board *brd) |
0b99d589 LL |
338 | { |
339 | int i = 0; | |
340 | ||
78adbb28 | 341 | if (!brd || brd->magic != DGNC_BOARD_MAGIC) |
eae9842a | 342 | return; |
0b99d589 LL |
343 | |
344 | switch (brd->device) { | |
345 | case PCI_DEVICE_CLASSIC_4_DID: | |
346 | case PCI_DEVICE_CLASSIC_8_DID: | |
347 | case PCI_DEVICE_CLASSIC_4_422_DID: | |
348 | case PCI_DEVICE_CLASSIC_8_422_DID: | |
349 | ||
350 | /* Tell card not to interrupt anymore. */ | |
351 | outb(0, brd->iobase + 0x4c); | |
352 | break; | |
353 | ||
354 | default: | |
355 | break; | |
356 | } | |
357 | ||
358 | if (brd->irq) | |
359 | free_irq(brd->irq, brd); | |
360 | ||
361 | tasklet_kill(&brd->helper_tasklet); | |
362 | ||
363 | if (brd->re_map_membase) { | |
364 | iounmap(brd->re_map_membase); | |
365 | brd->re_map_membase = NULL; | |
366 | } | |
367 | ||
0b99d589 LL |
368 | /* Free all allocated channels structs */ |
369 | for (i = 0; i < MAXPORTS ; i++) { | |
370 | if (brd->channels[i]) { | |
36aa10aa VO |
371 | kfree(brd->channels[i]->ch_rqueue); |
372 | kfree(brd->channels[i]->ch_equeue); | |
373 | kfree(brd->channels[i]->ch_wqueue); | |
0b99d589 LL |
374 | kfree(brd->channels[i]); |
375 | brd->channels[i] = NULL; | |
376 | } | |
377 | } | |
378 | ||
80e3e241 | 379 | dgnc_board[brd->boardnum] = NULL; |
0b99d589 | 380 | |
eae9842a | 381 | kfree(brd); |
0b99d589 LL |
382 | } |
383 | ||
0b99d589 LL |
384 | /* |
385 | * dgnc_found_board() | |
386 | * | |
387 | * A board has been found, init it. | |
388 | */ | |
f20ae478 | 389 | static struct dgnc_board *dgnc_found_board(struct pci_dev *pdev, int id) |
0b99d589 | 390 | { |
03425f55 | 391 | struct dgnc_board *brd; |
0b99d589 LL |
392 | unsigned int pci_irq; |
393 | int i = 0; | |
394 | int rc = 0; | |
0b99d589 | 395 | |
eae9842a | 396 | /* get the board structure and prep it */ |
467132b0 | 397 | brd = kzalloc(sizeof(*brd), GFP_KERNEL); |
78adbb28 | 398 | if (!brd) |
f20ae478 | 399 | return ERR_PTR(-ENOMEM); |
0b99d589 | 400 | |
0b99d589 LL |
401 | /* store the info for the board we've found */ |
402 | brd->magic = DGNC_BOARD_MAGIC; | |
80e3e241 | 403 | brd->boardnum = dgnc_num_boards; |
0b99d589 LL |
404 | brd->vendor = dgnc_pci_tbl[id].vendor; |
405 | brd->device = dgnc_pci_tbl[id].device; | |
406 | brd->pdev = pdev; | |
407 | brd->pci_bus = pdev->bus->number; | |
408 | brd->pci_slot = PCI_SLOT(pdev->devfn); | |
80e3e241 DY |
409 | brd->name = dgnc_ids[id].name; |
410 | brd->maxports = dgnc_ids[id].maxports; | |
411 | if (dgnc_ids[i].is_pci_express) | |
0b99d589 LL |
412 | brd->bd_flags |= BD_IS_PCI_EXPRESS; |
413 | brd->dpastatus = BD_NOFEP; | |
414 | init_waitqueue_head(&brd->state_wait); | |
415 | ||
66663dc1 RD |
416 | spin_lock_init(&brd->bd_lock); |
417 | spin_lock_init(&brd->bd_intr_lock); | |
0b99d589 LL |
418 | |
419 | brd->state = BOARD_FOUND; | |
420 | ||
0b99d589 LL |
421 | /* store which card & revision we have */ |
422 | pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &brd->subvendor); | |
423 | pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &brd->subdevice); | |
424 | pci_read_config_byte(pdev, PCI_REVISION_ID, &brd->rev); | |
425 | ||
426 | pci_irq = pdev->irq; | |
427 | brd->irq = pci_irq; | |
428 | ||
78adbb28 | 429 | switch (brd->device) { |
0b99d589 LL |
430 | case PCI_DEVICE_CLASSIC_4_DID: |
431 | case PCI_DEVICE_CLASSIC_8_DID: | |
432 | case PCI_DEVICE_CLASSIC_4_422_DID: | |
433 | case PCI_DEVICE_CLASSIC_8_422_DID: | |
434 | ||
435 | brd->dpatype = T_CLASSIC | T_PCIBUS; | |
436 | ||
0b99d589 LL |
437 | /* |
438 | * For PCI ClassicBoards | |
439 | * PCI Local Address (i.e. "resource" number) space | |
eae9842a LL |
440 | * 0 PLX Memory Mapped Config |
441 | * 1 PLX I/O Mapped Config | |
442 | * 2 I/O Mapped UARTs and Status | |
443 | * 3 Memory Mapped VPD | |
444 | * 4 Memory Mapped UARTs and Status | |
0b99d589 LL |
445 | */ |
446 | ||
0b99d589 LL |
447 | /* get the PCI Base Address Registers */ |
448 | brd->membase = pci_resource_start(pdev, 4); | |
449 | ||
450 | if (!brd->membase) { | |
1f26adc9 RD |
451 | dev_err(&brd->pdev->dev, |
452 | "Card has no PCI IO resources, failing.\n"); | |
467132b0 DY |
453 | rc = -ENODEV; |
454 | goto failed; | |
0b99d589 LL |
455 | } |
456 | ||
457 | brd->membase_end = pci_resource_end(pdev, 4); | |
458 | ||
459 | if (brd->membase & 1) | |
460 | brd->membase &= ~3; | |
461 | else | |
462 | brd->membase &= ~15; | |
463 | ||
eae9842a | 464 | brd->iobase = pci_resource_start(pdev, 1); |
0b99d589 | 465 | brd->iobase_end = pci_resource_end(pdev, 1); |
6f418259 | 466 | brd->iobase = ((unsigned int)(brd->iobase)) & 0xFFFE; |
0b99d589 LL |
467 | |
468 | /* Assign the board_ops struct */ | |
469 | brd->bd_ops = &dgnc_cls_ops; | |
470 | ||
471 | brd->bd_uart_offset = 0x8; | |
472 | brd->bd_dividend = 921600; | |
473 | ||
b09f0cd5 DY |
474 | rc = dgnc_do_remap(brd); |
475 | ||
476 | if (rc < 0) | |
477 | goto failed; | |
0b99d589 LL |
478 | |
479 | /* Get and store the board VPD, if it exists */ | |
480 | brd->bd_ops->vpd(brd); | |
481 | ||
482 | /* | |
483 | * Enable Local Interrupt 1 (0x1), | |
484 | * Local Interrupt 1 Polarity Active high (0x2), | |
485 | * Enable PCI interrupt (0x40) | |
486 | */ | |
487 | outb(0x43, brd->iobase + 0x4c); | |
488 | ||
489 | break; | |
490 | ||
0b99d589 LL |
491 | case PCI_DEVICE_NEO_4_DID: |
492 | case PCI_DEVICE_NEO_8_DID: | |
493 | case PCI_DEVICE_NEO_2DB9_DID: | |
494 | case PCI_DEVICE_NEO_2DB9PRI_DID: | |
495 | case PCI_DEVICE_NEO_2RJ45_DID: | |
496 | case PCI_DEVICE_NEO_2RJ45PRI_DID: | |
497 | case PCI_DEVICE_NEO_1_422_DID: | |
498 | case PCI_DEVICE_NEO_1_422_485_DID: | |
499 | case PCI_DEVICE_NEO_2_422_485_DID: | |
500 | case PCI_DEVICE_NEO_EXPRESS_8_DID: | |
501 | case PCI_DEVICE_NEO_EXPRESS_4_DID: | |
502 | case PCI_DEVICE_NEO_EXPRESS_4RJ45_DID: | |
503 | case PCI_DEVICE_NEO_EXPRESS_8RJ45_DID: | |
504 | ||
505 | /* | |
506 | * This chip is set up 100% when we get to it. | |
817b7847 | 507 | * No need to enable global interrupts or anything. |
0b99d589 LL |
508 | */ |
509 | if (brd->bd_flags & BD_IS_PCI_EXPRESS) | |
510 | brd->dpatype = T_NEO_EXPRESS | T_PCIBUS; | |
511 | else | |
512 | brd->dpatype = T_NEO | T_PCIBUS; | |
513 | ||
0b99d589 LL |
514 | /* get the PCI Base Address Registers */ |
515 | brd->membase = pci_resource_start(pdev, 0); | |
516 | brd->membase_end = pci_resource_end(pdev, 0); | |
517 | ||
518 | if (brd->membase & 1) | |
519 | brd->membase &= ~3; | |
520 | else | |
521 | brd->membase &= ~15; | |
522 | ||
523 | /* Assign the board_ops struct */ | |
524 | brd->bd_ops = &dgnc_neo_ops; | |
525 | ||
526 | brd->bd_uart_offset = 0x200; | |
527 | brd->bd_dividend = 921600; | |
528 | ||
b09f0cd5 | 529 | rc = dgnc_do_remap(brd); |
0b99d589 | 530 | |
b09f0cd5 DY |
531 | if (rc < 0) |
532 | goto failed; | |
533 | ||
534 | /* Read and store the dvid after remapping */ | |
535 | brd->dvid = readb(brd->re_map_membase + 0x8D); | |
536 | ||
537 | /* Get and store the board VPD, if it exists */ | |
538 | brd->bd_ops->vpd(brd); | |
0b99d589 | 539 | |
0b99d589 LL |
540 | break; |
541 | ||
542 | default: | |
1f26adc9 RD |
543 | dev_err(&brd->pdev->dev, |
544 | "Didn't find any compatible Neo/Classic PCI boards.\n"); | |
467132b0 DY |
545 | rc = -ENXIO; |
546 | goto failed; | |
0b99d589 LL |
547 | } |
548 | ||
0b99d589 | 549 | /* init our poll helper tasklet */ |
371ec403 VH |
550 | tasklet_init(&brd->helper_tasklet, |
551 | brd->bd_ops->tasklet, | |
6f418259 | 552 | (unsigned long)brd); |
0b99d589 | 553 | |
0b99d589 LL |
554 | wake_up_interruptible(&brd->state_wait); |
555 | ||
f20ae478 | 556 | return brd; |
0b99d589 LL |
557 | |
558 | failed: | |
467132b0 | 559 | kfree(brd); |
0b99d589 | 560 | |
f20ae478 | 561 | return ERR_PTR(rc); |
0b99d589 LL |
562 | } |
563 | ||
0d79f59d | 564 | static int dgnc_request_irq(struct dgnc_board *brd) |
07467e50 | 565 | { |
0b99d589 LL |
566 | int rc = 0; |
567 | ||
0b99d589 | 568 | if (brd->irq) { |
2b46be68 AS |
569 | rc = request_irq(brd->irq, brd->bd_ops->intr, |
570 | IRQF_SHARED, "DGNC", brd); | |
0b99d589 LL |
571 | |
572 | if (rc) { | |
2b46be68 AS |
573 | dev_err(&brd->pdev->dev, |
574 | "Failed to hook IRQ %d\n", brd->irq); | |
0b99d589 LL |
575 | brd->state = BOARD_FAILED; |
576 | brd->dpastatus = BD_NOFEP; | |
577 | rc = -ENODEV; | |
0b99d589 LL |
578 | } |
579 | } | |
8f90ef80 | 580 | return rc; |
0b99d589 LL |
581 | } |
582 | ||
5897914f DY |
583 | static void dgnc_free_irq(struct dgnc_board *brd) |
584 | { | |
585 | if (brd->irq) | |
586 | free_irq(brd->irq, brd); | |
587 | } | |
588 | ||
0b99d589 LL |
589 | /* |
590 | * Remap PCI memory. | |
591 | */ | |
b09f0cd5 | 592 | static int dgnc_do_remap(struct dgnc_board *brd) |
0b99d589 | 593 | { |
b09f0cd5 DY |
594 | int rc = 0; |
595 | ||
0b99d589 | 596 | brd->re_map_membase = ioremap(brd->membase, 0x1000); |
b09f0cd5 DY |
597 | if (!brd->re_map_membase) |
598 | rc = -ENOMEM; | |
599 | ||
600 | return rc; | |
0b99d589 LL |
601 | } |
602 | ||
970e82df FA |
603 | /* |
604 | * | |
605 | * Function: | |
606 | * | |
607 | * dgnc_poll_handler | |
608 | * | |
609 | * Author: | |
610 | * | |
611 | * Scott H Kilau | |
612 | * | |
613 | * Parameters: | |
614 | * | |
615 | * dummy -- ignored | |
616 | * | |
617 | * Return Values: | |
618 | * | |
619 | * none | |
620 | * | |
621 | * Description: | |
622 | * | |
623 | * As each timer expires, it determines (a) whether the "transmit" | |
624 | * waiter needs to be woken up, and (b) whether the poller needs to | |
625 | * be rescheduled. | |
626 | * | |
627 | */ | |
0b99d589 LL |
628 | |
629 | static void dgnc_poll_handler(ulong dummy) | |
630 | { | |
03425f55 | 631 | struct dgnc_board *brd; |
66663dc1 | 632 | unsigned long flags; |
0b99d589 LL |
633 | int i; |
634 | unsigned long new_time; | |
635 | ||
0b99d589 | 636 | /* Go thru each board, kicking off a tasklet for each if needed */ |
80e3e241 DY |
637 | for (i = 0; i < dgnc_num_boards; i++) { |
638 | brd = dgnc_board[i]; | |
0b99d589 | 639 | |
66663dc1 | 640 | spin_lock_irqsave(&brd->bd_lock, flags); |
0b99d589 | 641 | |
65da04c1 | 642 | /* If board is in a failed state don't schedule a tasklet */ |
0b99d589 | 643 | if (brd->state == BOARD_FAILED) { |
66663dc1 | 644 | spin_unlock_irqrestore(&brd->bd_lock, flags); |
0b99d589 LL |
645 | continue; |
646 | } | |
647 | ||
648 | /* Schedule a poll helper task */ | |
649 | tasklet_schedule(&brd->helper_tasklet); | |
650 | ||
66663dc1 | 651 | spin_unlock_irqrestore(&brd->bd_lock, flags); |
0b99d589 LL |
652 | } |
653 | ||
0b99d589 LL |
654 | /* |
655 | * Schedule ourself back at the nominal wakeup interval. | |
656 | */ | |
66663dc1 | 657 | spin_lock_irqsave(&dgnc_poll_lock, flags); |
0b99d589 LL |
658 | dgnc_poll_time += dgnc_jiffies_from_ms(dgnc_poll_tick); |
659 | ||
660 | new_time = dgnc_poll_time - jiffies; | |
661 | ||
6f418259 | 662 | if ((ulong)new_time >= 2 * dgnc_poll_tick) |
65da04c1 | 663 | dgnc_poll_time = jiffies + dgnc_jiffies_from_ms(dgnc_poll_tick); |
0b99d589 | 664 | |
38e0c9d2 | 665 | setup_timer(&dgnc_poll_timer, dgnc_poll_handler, 0); |
0b99d589 | 666 | dgnc_poll_timer.expires = dgnc_poll_time; |
66663dc1 | 667 | spin_unlock_irqrestore(&dgnc_poll_lock, flags); |
0b99d589 LL |
668 | |
669 | if (!dgnc_poll_stop) | |
670 | add_timer(&dgnc_poll_timer); | |
671 | } |