/* fixed frequency table for awacs, screamer, burgundy, DACA (44100 max) */ staticconstint awacs_freqs[8] = {
44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350
}; /* fixed frequency table for tumbler */ staticconstint tumbler_freqs[1] = {
44100
};
/* * we will allocate a single 'emergency' dbdma cmd block to use if the * tx status comes up "DEAD". This happens on some PowerComputing Pmac * clones, either owing to a bug in dbdma or some interaction between * IDE and sound. However, this measure would deal with DEAD status if * it appeared elsewhere.
*/ staticstruct pmac_dbdma emergency_dbdma; staticint emergency_in_use;
unsignedint snd_pmac_rate_index(struct snd_pmac *chip, struct pmac_stream *rec, unsignedint rate)
{ int i, ok, found;
ok = rec->cur_freqs; if (rate > chip->freq_table[0]) return 0;
found = 0; for (i = 0; i < chip->num_freqs; i++, ok >>= 1) { if (! (ok & 1)) continue;
found = i; if (rate >= chip->freq_table[i]) break;
} return found;
}
/* * check whether another stream is active
*/ staticinlineint another_stream(int stream)
{ return (stream == SNDRV_PCM_STREAM_PLAYBACK) ?
SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
}
/* * get a stream of the opposite direction
*/ staticstruct pmac_stream *snd_pmac_get_stream(struct snd_pmac *chip, int stream)
{ switch (stream) { case SNDRV_PCM_STREAM_PLAYBACK: return &chip->playback; case SNDRV_PCM_STREAM_CAPTURE: return &chip->capture; default:
snd_BUG(); return NULL;
}
}
/* * wait while run status is on
*/ staticinlinevoid
snd_pmac_wait_ack(struct pmac_stream *rec)
{ int timeout = 50000; while ((in_le32(&rec->dma->status) & RUN) && timeout-- > 0)
udelay(1);
}
/* * set the format and rate to the chip. * call the lowlevel function if defined (e.g. for AWACS).
*/ staticvoid snd_pmac_pcm_set_format(struct snd_pmac *chip)
{ /* set up frequency and format */
out_le32(&chip->awacs->control, chip->control_mask | (chip->rate_index << 8));
out_le32(&chip->awacs->byteswap, chip->format == SNDRV_PCM_FORMAT_S16_LE ? 1 : 0); if (chip->set_format)
chip->set_format(chip);
}
/* * stop the DMA transfer
*/ staticinlinevoid snd_pmac_dma_stop(struct pmac_stream *rec)
{
out_le32(&rec->dma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
snd_pmac_wait_ack(rec);
}
/* * set the command pointer address
*/ staticinlinevoid snd_pmac_dma_set_command(struct pmac_stream *rec, struct pmac_dbdma *cmd)
{
out_le32(&rec->dma->cmdptr, cmd->addr);
}
/* * start the DMA
*/ staticinlinevoid snd_pmac_dma_run(struct pmac_stream *rec, int status)
{
out_le32(&rec->dma->control, status | (status << 16));
}
/* set up constraints */
astr = snd_pmac_get_stream(chip, another_stream(rec->stream)); if (! astr) return -EINVAL;
astr->cur_freqs = 1 << rate_index;
astr->cur_formats = 1 << runtime->format;
chip->rate_index = rate_index;
chip->format = runtime->format;
/* We really want to execute a DMA stop command, after the AWACS * is initialized. * For reasons I don't understand, it stops the hissing noise * common to many PowerBook G3 systems and random noise otherwise * captured on iBook2's about every third time. -ReneR
*/
spin_lock_irq(&chip->reg_lock);
snd_pmac_dma_stop(rec);
chip->extra_dma.cmds->command = cpu_to_le16(DBDMA_STOP);
snd_pmac_dma_set_command(rec, &chip->extra_dma);
snd_pmac_dma_run(rec, RUN);
spin_unlock_irq(&chip->reg_lock);
mdelay(5);
spin_lock_irq(&chip->reg_lock); /* continuous DMA memory type doesn't provide the physical address, * so we need to resolve the address here...
*/
offset = runtime->dma_addr; for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++) {
cp->phy_addr = cpu_to_le32(offset);
cp->req_count = cpu_to_le16(rec->period_size); /*cp->res_count = cpu_to_le16(0);*/
cp->xfer_status = cpu_to_le16(0);
offset += rec->period_size;
} /* make loop */
cp->command = cpu_to_le16(DBDMA_NOP | BR_ALWAYS);
cp->cmd_dep = cpu_to_le32(rec->cmd.addr);
/* * PCM trigger/stop
*/ staticint snd_pmac_pcm_trigger(struct snd_pmac *chip, struct pmac_stream *rec, struct snd_pcm_substream *subs, int cmd)
{ volatilestruct dbdma_cmd __iomem *cp; int i, command;
switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: if (rec->running) return -EBUSY;
command = (subs->stream == SNDRV_PCM_STREAM_PLAYBACK ?
OUTPUT_MORE : INPUT_MORE) + INTR_ALWAYS;
spin_lock(&chip->reg_lock);
snd_pmac_beep_stop(chip);
snd_pmac_pcm_set_format(chip); for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++)
out_le16(&cp->command, command);
snd_pmac_dma_set_command(rec, &rec->cmd);
(void)in_le32(&rec->dma->status);
snd_pmac_dma_run(rec, RUN|WAKE);
rec->running = 1;
spin_unlock(&chip->reg_lock); break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND:
spin_lock(&chip->reg_lock);
rec->running = 0;
snd_pmac_dma_stop(rec); for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++)
out_le16(&cp->command, DBDMA_STOP);
spin_unlock(&chip->reg_lock); break;
default: return -EINVAL;
}
return 0;
}
/* * return the current pointer
*/ inline static snd_pcm_uframes_t snd_pmac_pcm_pointer(struct snd_pmac *chip, struct pmac_stream *rec, struct snd_pcm_substream *subs)
{ int count = 0;
#if 1 /* hmm.. how can we get the current dma pointer?? */ int stat; volatilestruct dbdma_cmd __iomem *cp = &rec->cmd.cmds[rec->cur_period];
stat = le16_to_cpu(cp->xfer_status); if (stat & (ACTIVE|DEAD)) {
count = in_le16(&cp->res_count); if (count)
count = rec->period_size - count;
} #endif
count += rec->cur_period * rec->period_size; return bytes_to_frames(subs->runtime, count);
}
/* * Handle DEAD DMA transfers: * if the TX status comes up "DEAD" - reported on some Power Computing machines * we need to re-start the dbdma - but from a different physical start address * and with a different transfer length. It would get very messy to do this * with the normal dbdma_cmd blocks - we would have to re-write the buffer start * addresses each time. So, we will keep a single dbdma_cmd block which can be * fiddled with. * When DEAD status is first reported the content of the faulted dbdma block is * copied into the emergency buffer and we note that the buffer is in use. * we then bump the start physical address by the amount that was successfully * output before it died. * On any subsequent DEAD result we just do the bump-ups (we know that we are * already using the emergency dbdma_cmd). * CHECK: this just tries to "do it". It is possible that we should abandon * xfers when the number of residual bytes gets below a certain value - I can * see that this might cause a loop-forever if a too small transfer causes * DEAD status. However this is a TODO for now - we'll see what gets reported. * When we get a successful transfer result with the emergency buffer we just * pretend that it completed using the original dmdma_cmd and carry on. The * 'next_cmd' field will already point back to the original loop of blocks.
*/ staticinlinevoid snd_pmac_pcm_dead_xfer(struct pmac_stream *rec, volatilestruct dbdma_cmd __iomem *cp)
{ unsignedshort req, res ; unsignedint phy ;
/* to clear DEAD status we must first clear RUN
set it to quiescent to be on the safe side */
(void)in_le32(&rec->dma->status);
out_le32(&rec->dma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
if (!emergency_in_use) { /* new problem */
memcpy((void *)emergency_dbdma.cmds, (void *)cp, sizeof(struct dbdma_cmd));
emergency_in_use = 1;
cp->xfer_status = cpu_to_le16(0);
cp->req_count = cpu_to_le16(rec->period_size);
cp = emergency_dbdma.cmds;
}
/* now bump the values to reflect the amount
we haven't yet shifted */
req = le16_to_cpu(cp->req_count);
res = le16_to_cpu(cp->res_count);
phy = le32_to_cpu(cp->phy_addr);
phy += (req - res);
cp->req_count = cpu_to_le16(res);
cp->res_count = cpu_to_le16(0);
cp->xfer_status = cpu_to_le16(0);
cp->phy_addr = cpu_to_le32(phy);
/* point at our patched up command block */
out_le32(&rec->dma->cmdptr, emergency_dbdma.addr);
/* we must re-start the controller */
(void)in_le32(&rec->dma->status); /* should complete clearing the DEAD status */
out_le32(&rec->dma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
}
/* * update playback/capture pointer from interrupts
*/ staticvoid snd_pmac_pcm_update(struct snd_pmac *chip, struct pmac_stream *rec)
{ volatilestruct dbdma_cmd __iomem *cp; int c; int stat;
spin_lock(&chip->reg_lock); if (rec->running) { for (c = 0; c < rec->nperiods; c++) { /* at most all fragments */
if (emergency_in_use) /* already using DEAD xfer? */
cp = emergency_dbdma.cmds; else
cp = &rec->cmd.cmds[rec->cur_period];
stat = le16_to_cpu(cp->xfer_status);
if (stat & DEAD) {
snd_pmac_pcm_dead_xfer(rec, cp); break; /* this block is still going */
}
if (emergency_in_use)
emergency_in_use = 0 ; /* done that */
/* look up frequency table and fill bit mask */
runtime->hw.rates = 0; for (i = 0; i < chip->num_freqs; i++) if (chip->freqs_ok & (1 << i))
runtime->hw.rates |=
snd_pcm_rate_to_rate_bit(chip->freq_table[i]);
/* check for minimum and maximum rates */ for (i = 0; i < chip->num_freqs; i++) { if (chip->freqs_ok & (1 << i)) {
runtime->hw.rate_max = chip->freq_table[i]; break;
}
} for (i = chip->num_freqs - 1; i >= 0; i--) { if (chip->freqs_ok & (1 << i)) {
runtime->hw.rate_min = chip->freq_table[i]; break;
}
}
runtime->hw.formats = chip->formats_ok; if (chip->can_capture) { if (! chip->can_duplex)
runtime->hw.info |= SNDRV_PCM_INFO_HALF_DUPLEX;
runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
}
runtime->private_data = rec;
rec->substream = subs;
if (ctrl & MASK_PORTCHG) { /* do something when headphone is plugged/unplugged? */ if (chip->update_automute)
chip->update_automute(chip, 1);
} if (ctrl & MASK_CNTLERR) { int err = (in_le32(&chip->awacs->codec_stat) & MASK_ERRCODE) >> 16; if (err && chip->model <= PMAC_SCREAMER)
dev_dbg(chip->card->dev, "%s: error %x\n", __func__, err);
} /* Writing 1s to the CNTLERR and PORTCHG bits clears them... */
out_le32(&chip->awacs->control, ctrl); return IRQ_HANDLED;
}
/* * a wrapper to feature call for compatibility
*/ staticvoid snd_pmac_sound_feature(struct snd_pmac *chip, int enable)
{ if (ppc_md.feature_call)
ppc_md.feature_call(PMAC_FTR_SOUND_CHIP_ENABLE, chip->node, 0, enable);
}
if (chip->node) { int i; for (i = 0; i < 3; i++) { if (chip->requested & (1 << i))
release_mem_region(chip->rsrc[i].start,
resource_size(&chip->rsrc[i]));
}
}
/* if seems that Keylargo can't byte-swap */ for (mio = chip->node->parent; mio; mio = mio->parent) { if (of_node_name_eq(mio, "mac-io")) { if (of_device_is_compatible(mio, "Keylargo"))
chip->can_byte_swap = 0; break;
}
}
/* it seems the Pismo & iBook can't byte-swap in hardware. */ if (of_machine_is_compatible("PowerBook3,1") ||
of_machine_is_compatible("PowerBook2,1"))
chip->can_byte_swap = 0 ;
if (of_machine_is_compatible("PowerBook2,1"))
chip->can_duplex = 0;
}
/* * powermac G3 models have a node called "davbus" * with a child called "sound".
*/ 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) {
for_each_node_by_name(sound, "sound") if (sound->parent == chip->node) break;
} 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 */
dev_info(chip->card->dev, "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 = of_machine_is_compatible("PowerMac4,2")
|| of_machine_is_compatible("PowerBook3,2")
|| of_machine_is_compatible("PowerBook3,3")
|| of_machine_is_compatible("PowerBook4,1")
|| of_machine_is_compatible("PowerBook4,2")
|| of_machine_is_compatible("PowerBook4,3");
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)
dev_warn(chip->card->dev, "snd-powermac: can't locate macio !\n"); else { struct pci_dev *pdev = NULL;
/* 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) { unsignedint 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;
}
/* 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);
} elseif (chip->is_pbook_G3) { struct device_node* mio; for (mio = chip->node->parent; mio; mio = mio->parent) { if (of_node_name_eq(mio, "mac-io")) { 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);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.