📄 pmac.c
字号:
chip->freqs_ok = 0xff; /* all ok */ chip->model = PMAC_AWACS; chip->can_byte_swap = 1; chip->can_duplex = 1; chip->can_capture = 1; chip->num_freqs = ARRAY_SIZE(awacs_freqs); chip->freq_table = awacs_freqs; chip->control_mask = MASK_IEPC | MASK_IEE | 0x11; /* default */ /* check machine type */ if (machine_is_compatible("AAPL,3400/2400") || machine_is_compatible("AAPL,3500")) chip->is_pbook_3400 = 1; else if (machine_is_compatible("PowerBook1,1") || machine_is_compatible("AAPL,PowerBook1998")) chip->is_pbook_G3 = 1; chip->node = find_devices("awacs"); if (chip->node) return 0; /* ok */ /* * powermac G3 models have a node called "davbus" * with a child called "sound". */ chip->node = find_devices("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 = find_devices("i2s-a"); if (! chip->node) return -ENODEV; sound = find_devices("sound"); while (sound && sound->parent != chip->node) sound = sound->next; if (! sound) return -ENODEV; prop = (unsigned int *) get_property(sound, "sub-frame", NULL); if (prop && *prop < 16) chip->subframe = *prop; /* This should be verified on older screamers */ if (device_is_compatible(sound, "screamer")) { chip->model = PMAC_SCREAMER; // chip->can_byte_swap = 0; /* FIXME: check this */ } if (device_is_compatible(sound, "burgundy")) { chip->model = PMAC_BURGUNDY; chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */ } if (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 (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 (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 */ } if (device_is_compatible(sound, "AOAKeylargo")) { /* Seems to support the stock AWACS frequencies, but has a snapper mixer */ chip->model = PMAC_SNAPPER; // chip->can_byte_swap = 0; /* FIXME: check this */ chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */ } prop = (unsigned int *)get_property(sound, "device-id", NULL); if (prop) chip->device_id = *prop; chip->has_iic = (find_devices("perch") != NULL); detect_byte_swap(chip); /* look for a property saying what sample rates are available */ prop = (unsigned int *) get_property(sound, "sample-rates", &l); if (! prop) prop = (unsigned int *) 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; } return 0;}/* * exported - boolean info callbacks for ease of programming */int snd_pmac_boolean_stereo_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 2; uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; return 0;}int snd_pmac_boolean_mono_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; return 0;}#ifdef PMAC_SUPPORT_AUTOMUTE/* * auto-mute */static int pmac_auto_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ pmac_t *chip = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = chip->auto_mute; return 0;}static int pmac_auto_mute_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ pmac_t *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(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ pmac_t *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 snd_kcontrol_new_t 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(pmac_t *chip){ int err; chip->auto_mute = 1; err = snd_ctl_add(chip->card, snd_ctl_new1(&auto_mute_controls[0], chip)); if (err < 0) 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(snd_card_t *card, pmac_t **chip_return){ pmac_t *chip; struct device_node *np; int i, err; static snd_device_ops_t ops = { .dev_free = snd_pmac_dev_free, }; snd_runtime_check(chip_return, return -EINVAL); *chip_return = NULL; chip = kcalloc(1, 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->playback.cmd, PMAC_MAX_FRAGS + 1) < 0 || snd_pmac_dbdma_alloc(&chip->capture.cmd, PMAC_MAX_FRAGS + 1) < 0 || snd_pmac_dbdma_alloc(&chip->extra_dma, 2) < 0) { err = -ENOMEM; goto __error; } np = chip->node; if (np->n_addrs < 3 || np->n_intrs < 3) { err = -ENODEV; goto __error; } for (i = 0; i < 3; i++) { static char *name[3] = { NULL, "- Tx DMA", "- Rx DMA" }; if (! request_OF_resource(np, i, name[i])) { snd_printk(KERN_ERR "pmac: can't request resource %d!\n", i); err = -ENODEV; goto __error; } chip->of_requested |= (1 << i); } chip->awacs = (volatile struct awacs_regs *) ioremap(np->addrs[0].address, 0x1000); chip->playback.dma = (volatile struct dbdma_regs *) ioremap(np->addrs[1].address, 0x100); chip->capture.dma = (volatile struct dbdma_regs *) ioremap(np->addrs[2].address, 0x100); if (chip->model <= PMAC_BURGUNDY) { if (request_irq(np->intrs[0].line, snd_pmac_ctrl_intr, 0, "PMac", (void*)chip)) { snd_printk(KERN_ERR "pmac: unable to grab IRQ %d\n", np->intrs[0].line); err = -EBUSY; goto __error; } chip->irq = np->intrs[0].line; } if (request_irq(np->intrs[1].line, snd_pmac_tx_intr, 0, "PMac Output", (void*)chip)) { snd_printk(KERN_ERR "pmac: unable to grab IRQ %d\n", np->intrs[1].line); err = -EBUSY; goto __error; } chip->tx_irq = np->intrs[1].line; if (request_irq(np->intrs[2].line, snd_pmac_rx_intr, 0, "PMac Input", (void*)chip)) { snd_printk(KERN_ERR "pmac: unable to grab IRQ %d\n", np->intrs[2].line); err = -EBUSY; goto __error; } chip->rx_irq = np->intrs[2].line; snd_pmac_sound_feature(chip, 1); /* reset */ 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 = (unsigned char *) 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 && mio->n_addrs > 0) { chip->macio_base = (unsigned char *) ioremap (mio->addrs[0].address, 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 defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK) /* add sleep notifier */ if (! snd_pmac_register_sleep_notifier(chip)) snd_card_set_pm_callback(chip->card, snd_pmac_suspend, snd_pmac_resume, chip);#endif 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 */#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)/* * Save state when going to sleep, restore it afterwards. */static int snd_pmac_suspend(snd_card_t *card, unsigned int state){ pmac_t *chip = card->pm_private_data; unsigned long flags; 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); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); return 0;}static int snd_pmac_resume(snd_card_t *card, unsigned int state){ pmac_t *chip = card->pm_private_data; 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(card, SNDRV_CTL_POWER_D0); return 0;}/* the chip is stored statically by snd_pmac_register_sleep_notifier * because we can't have any private data for notify callback. */static pmac_t *sleeping_pmac = NULL;static int snd_pmac_sleep_notify(struct pmu_sleep_notifier *self, int when){ pmac_t *chip; chip = sleeping_pmac; snd_runtime_check(chip, return 0); switch (when) { case PBOOK_SLEEP_NOW: snd_pmac_suspend(chip->card, 0); break; case PBOOK_WAKE: snd_pmac_resume(chip->card, 0); break; } return PBOOK_SLEEP_OK;}static struct pmu_sleep_notifier snd_pmac_sleep_notifier = { snd_pmac_sleep_notify, SLEEP_LEVEL_SOUND,};static int __init snd_pmac_register_sleep_notifier(pmac_t *chip){ /* should be protected here.. */ snd_assert(! sleeping_pmac, return -EBUSY); sleeping_pmac = chip; pmu_register_sleep_notifier(&snd_pmac_sleep_notifier); return 0;} static int snd_pmac_unregister_sleep_notifier(pmac_t *chip){ /* should be protected here.. */ snd_assert(sleeping_pmac == chip, return -ENODEV); pmu_unregister_sleep_notifier(&snd_pmac_sleep_notifier); sleeping_pmac = NULL; return 0;}#endif /* CONFIG_PM && CONFIG_PMAC_PBOOK */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -