📄 pmac.c
字号:
*/ if (!chip->node) chip->node = of_find_node_by_name(NULL, "davbus"); /* * if we didn't find a davbus device, try 'i2s-a' since * this seems to be what iBooks have */ if (! chip->node) { chip->node = of_find_node_by_name(NULL, "i2s-a"); if (chip->node && chip->node->parent && chip->node->parent->parent) { if (of_device_is_compatible(chip->node->parent->parent, "K2-Keylargo")) chip->is_k2 = 1; } } if (! chip->node) return -ENODEV; if (!sound) { sound = of_find_node_by_name(NULL, "sound"); while (sound && sound->parent != chip->node) sound = of_find_node_by_name(sound, "sound"); } if (! sound) { of_node_put(chip->node); chip->node = NULL; return -ENODEV; } prop = of_get_property(sound, "sub-frame", NULL); if (prop && *prop < 16) chip->subframe = *prop; prop = of_get_property(sound, "layout-id", NULL); if (prop) { /* partly deprecate snd-powermac, for those machines * that have a layout-id property for now */ printk(KERN_INFO "snd-powermac no longer handles any " "machines with a layout-id property " "in the device-tree, use snd-aoa.\n"); of_node_put(sound); of_node_put(chip->node); chip->node = NULL; return -ENODEV; } /* This should be verified on older screamers */ if (of_device_is_compatible(sound, "screamer")) { chip->model = PMAC_SCREAMER; // chip->can_byte_swap = 0; /* FIXME: check this */ } if (of_device_is_compatible(sound, "burgundy")) { chip->model = PMAC_BURGUNDY; chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */ } if (of_device_is_compatible(sound, "daca")) { chip->model = PMAC_DACA; chip->can_capture = 0; /* no capture */ chip->can_duplex = 0; // chip->can_byte_swap = 0; /* FIXME: check this */ chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */ } if (of_device_is_compatible(sound, "tumbler")) { chip->model = PMAC_TUMBLER; chip->can_capture = 0; /* no capture */ chip->can_duplex = 0; // chip->can_byte_swap = 0; /* FIXME: check this */ chip->num_freqs = ARRAY_SIZE(tumbler_freqs); chip->freq_table = tumbler_freqs; chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */ } if (of_device_is_compatible(sound, "snapper")) { chip->model = PMAC_SNAPPER; // chip->can_byte_swap = 0; /* FIXME: check this */ chip->num_freqs = ARRAY_SIZE(tumbler_freqs); chip->freq_table = tumbler_freqs; chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */ } prop = of_get_property(sound, "device-id", NULL); if (prop) chip->device_id = *prop; dn = of_find_node_by_name(NULL, "perch"); chip->has_iic = (dn != NULL); of_node_put(dn); /* We need the PCI device for DMA allocations, let's use a crude method * for now ... */ macio = macio_find(chip->node, macio_unknown); if (macio == NULL) printk(KERN_WARNING "snd-powermac: can't locate macio !\n"); else { struct pci_dev *pdev = NULL; for_each_pci_dev(pdev) { struct device_node *np = pci_device_to_OF_node(pdev); if (np && np == macio->of_node) { chip->pdev = pdev; break; } } } if (chip->pdev == NULL) printk(KERN_WARNING "snd-powermac: can't locate macio PCI" " device !\n"); detect_byte_swap(chip); /* look for a property saying what sample rates are available */ prop = of_get_property(sound, "sample-rates", &l); if (! prop) prop = of_get_property(sound, "output-frame-rates", &l); if (prop) { int i; chip->freqs_ok = 0; for (l /= sizeof(int); l > 0; --l) { unsigned int r = *prop++; /* Apple 'Fixed' format */ if (r >= 0x10000) r >>= 16; for (i = 0; i < chip->num_freqs; ++i) { if (r == chip->freq_table[i]) { chip->freqs_ok |= (1 << i); break; } } } } else { /* assume only 44.1khz */ chip->freqs_ok = 1; } of_node_put(sound); return 0;}#ifdef PMAC_SUPPORT_AUTOMUTE/* * auto-mute */static int pmac_auto_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = chip->auto_mute; return 0;}static int pmac_auto_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); if (ucontrol->value.integer.value[0] != chip->auto_mute) { chip->auto_mute = ucontrol->value.integer.value[0]; if (chip->update_automute) chip->update_automute(chip, 1); return 1; } return 0;}static int pmac_hp_detect_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); if (chip->detect_headphone) ucontrol->value.integer.value[0] = chip->detect_headphone(chip); else ucontrol->value.integer.value[0] = 0; return 0;}static struct snd_kcontrol_new auto_mute_controls[] __initdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Auto Mute Switch", .info = snd_pmac_boolean_mono_info, .get = pmac_auto_mute_get, .put = pmac_auto_mute_put, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Detection", .access = SNDRV_CTL_ELEM_ACCESS_READ, .info = snd_pmac_boolean_mono_info, .get = pmac_hp_detect_get, },};int __init snd_pmac_add_automute(struct snd_pmac *chip){ int err; chip->auto_mute = 1; err = snd_ctl_add(chip->card, snd_ctl_new1(&auto_mute_controls[0], chip)); if (err < 0) { printk(KERN_ERR "snd-powermac: Failed to add automute control\n"); return err; } chip->hp_detect_ctl = snd_ctl_new1(&auto_mute_controls[1], chip); return snd_ctl_add(chip->card, chip->hp_detect_ctl);}#endif /* PMAC_SUPPORT_AUTOMUTE *//* * create and detect a pmac chip record */int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return){ struct snd_pmac *chip; struct device_node *np; int i, err; unsigned int irq; unsigned long ctrl_addr, txdma_addr, rxdma_addr; static struct snd_device_ops ops = { .dev_free = snd_pmac_dev_free, }; *chip_return = NULL; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->card = card; spin_lock_init(&chip->reg_lock); chip->irq = chip->tx_irq = chip->rx_irq = -1; chip->playback.stream = SNDRV_PCM_STREAM_PLAYBACK; chip->capture.stream = SNDRV_PCM_STREAM_CAPTURE; if ((err = snd_pmac_detect(chip)) < 0) goto __error; if (snd_pmac_dbdma_alloc(chip, &chip->playback.cmd, PMAC_MAX_FRAGS + 1) < 0 || snd_pmac_dbdma_alloc(chip, &chip->capture.cmd, PMAC_MAX_FRAGS + 1) < 0 || snd_pmac_dbdma_alloc(chip, &chip->extra_dma, 2) < 0) { err = -ENOMEM; goto __error; } np = chip->node; chip->requested = 0; if (chip->is_k2) { static char *rnames[] = { "Sound Control", "Sound DMA" }; for (i = 0; i < 2; i ++) { if (of_address_to_resource(np->parent, i, &chip->rsrc[i])) { printk(KERN_ERR "snd: can't translate rsrc " " %d (%s)\n", i, rnames[i]); err = -ENODEV; goto __error; } if (request_mem_region(chip->rsrc[i].start, chip->rsrc[i].end - chip->rsrc[i].start + 1, rnames[i]) == NULL) { printk(KERN_ERR "snd: can't request rsrc " " %d (%s: 0x%016llx:%016llx)\n", i, rnames[i], (unsigned long long)chip->rsrc[i].start, (unsigned long long)chip->rsrc[i].end); err = -ENODEV; goto __error; } chip->requested |= (1 << i); } ctrl_addr = chip->rsrc[0].start; txdma_addr = chip->rsrc[1].start; rxdma_addr = txdma_addr + 0x100; } else { static char *rnames[] = { "Sound Control", "Sound Tx DMA", "Sound Rx DMA" }; for (i = 0; i < 3; i ++) { if (of_address_to_resource(np, i, &chip->rsrc[i])) { printk(KERN_ERR "snd: can't translate rsrc " " %d (%s)\n", i, rnames[i]); err = -ENODEV; goto __error; } if (request_mem_region(chip->rsrc[i].start, chip->rsrc[i].end - chip->rsrc[i].start + 1, rnames[i]) == NULL) { printk(KERN_ERR "snd: can't request rsrc " " %d (%s: 0x%016llx:%016llx)\n", i, rnames[i], (unsigned long long)chip->rsrc[i].start, (unsigned long long)chip->rsrc[i].end); err = -ENODEV; goto __error; } chip->requested |= (1 << i); } ctrl_addr = chip->rsrc[0].start; txdma_addr = chip->rsrc[1].start; rxdma_addr = chip->rsrc[2].start; } chip->awacs = ioremap(ctrl_addr, 0x1000); chip->playback.dma = ioremap(txdma_addr, 0x100); chip->capture.dma = ioremap(rxdma_addr, 0x100); if (chip->model <= PMAC_BURGUNDY) { irq = irq_of_parse_and_map(np, 0); if (request_irq(irq, snd_pmac_ctrl_intr, 0, "PMac", (void*)chip)) { snd_printk(KERN_ERR "pmac: unable to grab IRQ %d\n", irq); err = -EBUSY; goto __error; } chip->irq = irq; } irq = irq_of_parse_and_map(np, 1); if (request_irq(irq, snd_pmac_tx_intr, 0, "PMac Output", (void*)chip)){ snd_printk(KERN_ERR "pmac: unable to grab IRQ %d\n", irq); err = -EBUSY; goto __error; } chip->tx_irq = irq; irq = irq_of_parse_and_map(np, 2); if (request_irq(irq, snd_pmac_rx_intr, 0, "PMac Input", (void*)chip)) { snd_printk(KERN_ERR "pmac: unable to grab IRQ %d\n", irq); err = -EBUSY; goto __error; } chip->rx_irq = irq; snd_pmac_sound_feature(chip, 1); /* reset */ if (chip->model == PMAC_AWACS) out_le32(&chip->awacs->control, 0x11); /* Powerbooks have odd ways of enabling inputs such as an expansion-bay CD or sound from an internal modem or a PC-card modem. */ if (chip->is_pbook_3400) { /* Enable CD and PC-card sound inputs. */ /* This is done by reading from address * f301a000, + 0x10 to enable the expansion-bay * CD sound input, + 0x80 to enable the PC-card * sound input. The 0x100 enables the SCSI bus * terminator power. */ chip->latch_base = ioremap (0xf301a000, 0x1000); in_8(chip->latch_base + 0x190); } else if (chip->is_pbook_G3) { struct device_node* mio; for (mio = chip->node->parent; mio; mio = mio->parent) { if (strcmp(mio->name, "mac-io") == 0) { struct resource r; if (of_address_to_resource(mio, 0, &r) == 0) chip->macio_base = ioremap(r.start, 0x40); break; } } /* Enable CD sound input. */ /* The relevant bits for writing to this byte are 0x8f. * I haven't found out what the 0x80 bit does. * For the 0xf bits, writing 3 or 7 enables the CD * input, any other value disables it. Values * 1, 3, 5, 7 enable the microphone. Values 0, 2, * 4, 6, 8 - f enable the input from the modem. */ if (chip->macio_base) out_8(chip->macio_base + 0x37, 3); } /* Reset dbdma channels */ snd_pmac_dbdma_reset(chip); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) goto __error; *chip_return = chip; return 0; __error: snd_pmac_free(chip); return err;}/* * sleep notify for powerbook */#ifdef CONFIG_PM/* * Save state when going to sleep, restore it afterwards. */void snd_pmac_suspend(struct snd_pmac *chip){ unsigned long flags; snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); if (chip->suspend) chip->suspend(chip); snd_pcm_suspend_all(chip->pcm); spin_lock_irqsave(&chip->reg_lock, flags); snd_pmac_beep_stop(chip); spin_unlock_irqrestore(&chip->reg_lock, flags); if (chip->irq >= 0) disable_irq(chip->irq); if (chip->tx_irq >= 0) disable_irq(chip->tx_irq); if (chip->rx_irq >= 0) disable_irq(chip->rx_irq); snd_pmac_sound_feature(chip, 0);}void snd_pmac_resume(struct snd_pmac *chip){ snd_pmac_sound_feature(chip, 1); if (chip->resume) chip->resume(chip); /* enable CD sound input */ if (chip->macio_base && chip->is_pbook_G3) out_8(chip->macio_base + 0x37, 3); else if (chip->is_pbook_3400) in_8(chip->latch_base + 0x190); snd_pmac_pcm_set_format(chip); if (chip->irq >= 0) enable_irq(chip->irq); if (chip->tx_irq >= 0) enable_irq(chip->tx_irq); if (chip->rx_irq >= 0) enable_irq(chip->rx_irq); snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);}#endif /* CONFIG_PM */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -