diff options
Diffstat (limited to 'sound/pci/oxygen/oxygen_lib.c')
-rw-r--r-- | sound/pci/oxygen/oxygen_lib.c | 76 |
1 files changed, 56 insertions, 20 deletions
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index fad03d64e3ad..e5ebe56fb0c5 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c | |||
@@ -308,25 +308,46 @@ static void oxygen_restore_eeprom(struct oxygen *chip, | |||
308 | } | 308 | } |
309 | } | 309 | } |
310 | 310 | ||
311 | static void pci_bridge_magic(void) | 311 | static void configure_pcie_bridge(struct pci_dev *pci) |
312 | { | 312 | { |
313 | struct pci_dev *pci = NULL; | 313 | enum { PEX811X, PI7C9X110 }; |
314 | static const struct pci_device_id bridge_ids[] = { | ||
315 | { PCI_VDEVICE(PLX, 0x8111), .driver_data = PEX811X }, | ||
316 | { PCI_VDEVICE(PLX, 0x8112), .driver_data = PEX811X }, | ||
317 | { PCI_DEVICE(0x12d8, 0xe110), .driver_data = PI7C9X110 }, | ||
318 | { } | ||
319 | }; | ||
320 | struct pci_dev *bridge; | ||
321 | const struct pci_device_id *id; | ||
314 | u32 tmp; | 322 | u32 tmp; |
315 | 323 | ||
316 | for (;;) { | 324 | if (!pci->bus || !pci->bus->self) |
317 | /* If there is any Pericom PI7C9X110 PCI-E/PCI bridge ... */ | 325 | return; |
318 | pci = pci_get_device(0x12d8, 0xe110, pci); | 326 | bridge = pci->bus->self; |
319 | if (!pci) | 327 | |
320 | break; | 328 | id = pci_match_id(bridge_ids, bridge); |
321 | /* | 329 | if (!id) |
322 | * ... configure its secondary internal arbiter to park to | 330 | return; |
323 | * the secondary port, instead of to the last master. | 331 | |
324 | */ | 332 | switch (id->driver_data) { |
325 | if (!pci_read_config_dword(pci, 0x40, &tmp)) { | 333 | case PEX811X: /* PLX PEX8111/PEX8112 PCIe/PCI bridge */ |
326 | tmp |= 1; | 334 | pci_read_config_dword(bridge, 0x48, &tmp); |
327 | pci_write_config_dword(pci, 0x40, tmp); | 335 | tmp |= 1; /* enable blind prefetching */ |
328 | } | 336 | tmp |= 1 << 11; /* enable beacon generation */ |
329 | /* Why? Try asking C-Media. */ | 337 | pci_write_config_dword(bridge, 0x48, tmp); |
338 | |||
339 | pci_write_config_dword(bridge, 0x84, 0x0c); | ||
340 | pci_read_config_dword(bridge, 0x88, &tmp); | ||
341 | tmp &= ~(7 << 27); | ||
342 | tmp |= 2 << 27; /* set prefetch size to 128 bytes */ | ||
343 | pci_write_config_dword(bridge, 0x88, tmp); | ||
344 | break; | ||
345 | |||
346 | case PI7C9X110: /* Pericom PI7C9X110 PCIe/PCI bridge */ | ||
347 | pci_read_config_dword(bridge, 0x40, &tmp); | ||
348 | tmp |= 1; /* park the PCI arbiter to the sound chip */ | ||
349 | pci_write_config_dword(bridge, 0x40, tmp); | ||
350 | break; | ||
330 | } | 351 | } |
331 | } | 352 | } |
332 | 353 | ||
@@ -519,16 +540,21 @@ static void oxygen_init(struct oxygen *chip) | |||
519 | } | 540 | } |
520 | } | 541 | } |
521 | 542 | ||
522 | static void oxygen_card_free(struct snd_card *card) | 543 | static void oxygen_shutdown(struct oxygen *chip) |
523 | { | 544 | { |
524 | struct oxygen *chip = card->private_data; | ||
525 | |||
526 | spin_lock_irq(&chip->reg_lock); | 545 | spin_lock_irq(&chip->reg_lock); |
527 | chip->interrupt_mask = 0; | 546 | chip->interrupt_mask = 0; |
528 | chip->pcm_running = 0; | 547 | chip->pcm_running = 0; |
529 | oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); | 548 | oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); |
530 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); | 549 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); |
531 | spin_unlock_irq(&chip->reg_lock); | 550 | spin_unlock_irq(&chip->reg_lock); |
551 | } | ||
552 | |||
553 | static void oxygen_card_free(struct snd_card *card) | ||
554 | { | ||
555 | struct oxygen *chip = card->private_data; | ||
556 | |||
557 | oxygen_shutdown(chip); | ||
532 | if (chip->irq >= 0) | 558 | if (chip->irq >= 0) |
533 | free_irq(chip->irq, chip); | 559 | free_irq(chip->irq, chip); |
534 | flush_scheduled_work(); | 560 | flush_scheduled_work(); |
@@ -608,7 +634,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, | |||
608 | snd_card_set_dev(card, &pci->dev); | 634 | snd_card_set_dev(card, &pci->dev); |
609 | card->private_free = oxygen_card_free; | 635 | card->private_free = oxygen_card_free; |
610 | 636 | ||
611 | pci_bridge_magic(); | 637 | configure_pcie_bridge(pci); |
612 | oxygen_init(chip); | 638 | oxygen_init(chip); |
613 | chip->model.init(chip); | 639 | chip->model.init(chip); |
614 | 640 | ||
@@ -778,3 +804,13 @@ int oxygen_pci_resume(struct pci_dev *pci) | |||
778 | } | 804 | } |
779 | EXPORT_SYMBOL(oxygen_pci_resume); | 805 | EXPORT_SYMBOL(oxygen_pci_resume); |
780 | #endif /* CONFIG_PM */ | 806 | #endif /* CONFIG_PM */ |
807 | |||
808 | void oxygen_pci_shutdown(struct pci_dev *pci) | ||
809 | { | ||
810 | struct snd_card *card = pci_get_drvdata(pci); | ||
811 | struct oxygen *chip = card->private_data; | ||
812 | |||
813 | oxygen_shutdown(chip); | ||
814 | chip->model.cleanup(chip); | ||
815 | } | ||
816 | EXPORT_SYMBOL(oxygen_pci_shutdown); | ||