cregit-Linux how code gets into the kernel

Release 4.8 sound/ppc/pmac.c

Directory: sound/ppc
/*
 * PMac DBDMA lowlevel functions
 *
 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
 * code based on dmasound.c.
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */


#include <linux/io.h>
#include <asm/irq.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <sound/core.h>
#include "pmac.h"
#include <sound/pcm_params.h>
#include <asm/pmac_feature.h>


/* fixed frequency table for awacs, screamer, burgundy, DACA (44100 max) */

static int awacs_freqs[8] = {
	44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350
};
/* fixed frequency table for tumbler */

static int 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.
 */

static struct pmac_dbdma emergency_dbdma;

static int emergency_in_use;


/*
 * allocate DBDMA command arrays
 */

static int snd_pmac_dbdma_alloc(struct snd_pmac *chip, struct pmac_dbdma *rec, int size) { unsigned int rsize = sizeof(struct dbdma_cmd) * (size + 1); rec->space = dma_alloc_coherent(&chip->pdev->dev, rsize, &rec->dma_base, GFP_KERNEL); if (rec->space == NULL) return -ENOMEM; rec->size = size; memset(rec->space, 0, rsize); rec->cmds = (void __iomem *)DBDMA_ALIGN(rec->space); rec->addr = rec->dma_base + (unsigned long)((char *)rec->cmds - (char *)rec->space); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela8361.03%125.00%
benjamin herrenschmidtbenjamin herrenschmidt4835.29%125.00%
takashi iwaitakashi iwai42.94%125.00%
al viroal viro10.74%125.00%
Total136100.00%4100.00%


static void snd_pmac_dbdma_free(struct snd_pmac *chip, struct pmac_dbdma *rec) { if (rec->space) { unsigned int rsize = sizeof(struct dbdma_cmd) * (rec->size + 1); dma_free_coherent(&chip->pdev->dev, rsize, rec->space, rec->dma_base); } }

Contributors

PersonTokensPropCommitsCommitProp
benjamin herrenschmidtbenjamin herrenschmidt3962.90%250.00%
jaroslav kyselajaroslav kysela1930.65%125.00%
takashi iwaitakashi iwai46.45%125.00%
Total62100.00%4100.00%

/* * pcm stuff */ /* * look up frequency table */
unsigned int snd_pmac_rate_index(struct snd_pmac *chip, struct pmac_stream *rec, unsigned int 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; }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela9796.04%150.00%
takashi iwaitakashi iwai43.96%150.00%
Total101100.00%2100.00%

/* * check whether another stream is active */
static inline int another_stream(int stream) { return (stream == SNDRV_PCM_STREAM_PLAYBACK) ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela21100.00%1100.00%
Total21100.00%1100.00%

/* * allocate buffers */
static int snd_pmac_pcm_hw_params(struct snd_pcm_substream *subs, struct snd_pcm_hw_params *hw_params) { return snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw_params)); }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela2385.19%150.00%
takashi iwaitakashi iwai414.81%150.00%
Total27100.00%2100.00%

/* * release buffers */
static int snd_pmac_pcm_hw_free(struct snd_pcm_substream *subs) { snd_pcm_lib_free_pages(subs); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela1789.47%150.00%
takashi iwaitakashi iwai210.53%150.00%
Total19100.00%2100.00%

/* * get a stream of the opposite direction */
static struct 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; } }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela4391.49%150.00%
takashi iwaitakashi iwai48.51%150.00%
Total47100.00%2100.00%

/* * wait while run status is on */
static inline void snd_pmac_wait_ack(struct pmac_stream *rec) { int timeout = 50000; while ((in_le32(&rec->dma->status) & RUN) && timeout-- > 0) udelay(1); }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela4093.02%133.33%
takashi iwaitakashi iwai24.65%133.33%
jesper juhljesper juhl12.33%133.33%
Total43100.00%3100.00%

/* * set the format and rate to the chip. * call the lowlevel function if defined (e.g. for AWACS). */
static void 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); }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela6597.01%266.67%
takashi iwaitakashi iwai22.99%133.33%
Total67100.00%3100.00%

/* * stop the DMA transfer */
static inline void snd_pmac_dma_stop(struct pmac_stream *rec) { out_le32(&rec->dma->control, (RUN|WAKE|FLUSH|PAUSE) << 16); snd_pmac_wait_ack(rec); }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela3692.31%133.33%
takashi iwaitakashi iwai25.13%133.33%
jesper juhljesper juhl12.56%133.33%
Total39100.00%3100.00%

/* * set the command pointer address */
static inline void snd_pmac_dma_set_command(struct pmac_stream *rec, struct pmac_dbdma *cmd) { out_le32(&rec->dma->cmdptr, cmd->addr); }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela2683.87%133.33%
takashi iwaitakashi iwai412.90%133.33%
jesper juhljesper juhl13.23%133.33%
Total31100.00%3100.00%

/* * start the DMA */
static inline void snd_pmac_dma_run(struct pmac_stream *rec, int status) { out_le32(&rec->dma->control, status | (status << 16)); }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela3090.91%133.33%
takashi iwaitakashi iwai26.06%133.33%
jesper juhljesper juhl13.03%133.33%
Total33100.00%3100.00%

/* * prepare playback/capture stream */
static int snd_pmac_pcm_prepare(struct snd_pmac *chip, struct pmac_stream *rec, struct snd_pcm_substream *subs) { int i; volatile struct dbdma_cmd __iomem *cp; struct snd_pcm_runtime *runtime = subs->runtime; int rate_index; long offset; struct pmac_stream *astr; rec->dma_size = snd_pcm_lib_buffer_bytes(subs); rec->period_size = snd_pcm_lib_period_bytes(subs); rec->nperiods = rec->dma_size / rec->period_size; rec->cur_period = 0; rate_index = snd_pmac_rate_index(chip, rec, runtime->rate); /* 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); snd_pmac_dma_stop(rec); snd_pmac_dma_set_command(rec, &rec->cmd); spin_unlock_irq(&chip->reg_lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela30388.34%550.00%
david gibsondavid gibson195.54%110.00%
takashi iwaitakashi iwai195.54%220.00%
al viroal viro10.29%110.00%
benjamin herrenschmidtbenjamin herrenschmidt10.29%110.00%
Total343100.00%10100.00%

/* * PCM trigger/stop */
static int snd_pmac_pcm_trigger(struct snd_pmac *chip, struct pmac_stream *rec, struct snd_pcm_substream *subs, int cmd) { volatile struct 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; /*printk(KERN_DEBUG "stopped!!\n");*/ 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; }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela24696.85%240.00%
takashi iwaitakashi iwai72.76%240.00%
al viroal viro10.39%120.00%
Total254100.00%5100.00%

/* * 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; volatile struct 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; /*printk(KERN_DEBUG "pointer=%d\n", count);*/ return bytes_to_frames(subs->runtime, count); }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela11092.44%342.86%
takashi iwaitakashi iwai75.88%228.57%
david gibsondavid gibson10.84%114.29%
al viroal viro10.84%114.29%
Total119100.00%7100.00%

/* * playback */
static int snd_pmac_playback_prepare(struct snd_pcm_substream *subs) { struct snd_pmac *chip = snd_pcm_substream_chip(subs); return snd_pmac_pcm_prepare(chip, &chip->playback, subs); }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela3088.24%150.00%
takashi iwaitakashi iwai411.76%150.00%
Total34100.00%2100.00%


static int snd_pmac_playback_trigger(struct snd_pcm_substream *subs, int cmd) { struct snd_pmac *chip = snd_pcm_substream_chip(subs); return snd_pmac_pcm_trigger(chip, &chip->playback, subs, cmd); }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela3589.74%150.00%
takashi iwaitakashi iwai410.26%150.00%
Total39100.00%2100.00%


static snd_pcm_uframes_t snd_pmac_playback_pointer(struct snd_pcm_substream *subs) { struct snd_pmac *chip = snd_pcm_substream_chip(subs); return snd_pmac_pcm_pointer(chip, &chip->playback, subs); }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela3088.24%150.00%
takashi iwaitakashi iwai411.76%150.00%
Total34100.00%2100.00%

/* * capture */
static int snd_pmac_capture_prepare(struct snd_pcm_substream *subs) { struct snd_pmac *chip = snd_pcm_substream_chip(subs); return snd_pmac_pcm_prepare(chip, &chip->capture, subs); }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela3088.24%150.00%
takashi iwaitakashi iwai411.76%150.00%
Total34100.00%2100.00%


static int snd_pmac_capture_trigger(struct snd_pcm_substream *subs, int cmd) { struct snd_pmac *chip = snd_pcm_substream_chip(subs); return snd_pmac_pcm_trigger(chip, &chip->capture, subs, cmd); }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela3589.74%150.00%
takashi iwaitakashi iwai410.26%150.00%
Total39100.00%2100.00%


static snd_pcm_uframes_t snd_pmac_capture_pointer(struct snd_pcm_substream *subs) { struct snd_pmac *chip = snd_pcm_substream_chip(subs); return snd_pmac_pcm_pointer(chip, &chip->capture, subs); }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela3088.24%150.00%
takashi iwaitakashi iwai411.76%150.00%
Total34100.00%2100.00%

/* * 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. */
static inline void snd_pmac_pcm_dead_xfer(struct pmac_stream *rec, volatile struct dbdma_cmd __iomem *cp) { unsigned short req, res ; unsigned int phy ; /* printk(KERN_WARNING "snd-powermac: DMA died - patching it up!\n"); */ /* 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); cp->cmd_dep = cpu_to_le32(rec->cmd.addr + sizeof(struct dbdma_cmd)*((rec->cur_period+1)%rec->nperiods)); cp->command = cpu_to_le16(OUTPUT_MORE | BR_ALWAYS | INTR_ALWAYS); /* 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)); }

Contributors

PersonTokensPropCommitsCommitProp
t. h. hutht. h. huth27491.03%150.00%
david gibsondavid gibson278.97%150.00%
Total301100.00%2100.00%

/* * update playback/capture pointer from interrupts */
static void snd_pmac_pcm_update(struct snd_pmac *chip, struct pmac_stream *rec) { volatile struct 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 */ if (! (stat & ACTIVE)) break; /*printk(KERN_DEBUG "update frag %d\n", rec->cur_period);*/ cp->xfer_status = cpu_to_le16(0); cp->req_count = cpu_to_le16(rec->period_size); /*cp->res_count = cpu_to_le16(0);*/ rec->cur_period++; if (rec->cur_period >= rec->nperiods) { rec->cur_period = 0; } spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(rec->substream); spin_lock(&chip->reg_lock); } } spin_unlock(&chip->reg_lock); }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela14468.57%116.67%
t. h. hutht. h. huth5224.76%116.67%
david gibsondavid gibson83.81%116.67%
takashi iwaitakashi iwai52.38%233.33%
al viroal viro10.48%116.67%
Total210100.00%6100.00%

/* * hw info */ static struct snd_pcm_hardware snd_pmac_playback = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_RESUME), .formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_8000_44100, .rate_min = 7350, .rate_max = 44100, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = 131072, .period_bytes_min = 256, .period_bytes_max = 16384, .periods_min = 3, .periods_max = PMAC_MAX_FRAGS, }; static struct snd_pcm_hardware snd_pmac_capture = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_RESUME), .formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_8000_44100, .rate_min = 7350, .rate_max = 44100, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = 131072, .period_bytes_min = 256, .period_bytes_max = 16384, .periods_min = 3, .periods_max = PMAC_MAX_FRAGS, }; #if 0 // NYI static int snd_pmac_hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_pmac *chip = rule->private; struct pmac_stream *rec = snd_pmac_get_stream(chip, rule->deps[0]); int i, freq_table[8], num_freqs; if (! rec) return -EINVAL; num_freqs = 0; for (i = chip->num_freqs - 1; i >= 0; i--) { if (rec->cur_freqs & (1 << i)) freq_table[num_freqs++] = chip->freq_table[i]; } return snd_interval_list(hw_param_interval(params, rule->var), num_freqs, freq_table, 0); } static int snd_pmac_hw_rule_format(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_pmac *chip = rule->private; struct pmac_stream *rec = snd_pmac_get_stream(chip, rule->deps[0]); if (! rec) return -EINVAL; return snd_mask_refine_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), rec->cur_formats); } #endif // NYI
static int snd_pmac_pcm_open(struct snd_pmac *chip, struct pmac_stream *rec, struct snd_pcm_substream *subs) { struct snd_pcm_runtime *runtime = subs->runtime; int i; /* 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 0 /* FIXME: still under development.. */ snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, snd_pmac_hw_rule_rate, chip, rec->stream, -1); snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, snd_pmac_hw_rule_format, chip, rec->stream, -1); #endif runtime->hw.periods_max = rec->cmd.size - 1; /* constraints to fix choppy sound */ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela24793.92%360.00%
clemens ladischclemens ladisch83.04%120.00%
takashi iwaitakashi iwai83.04%120.00%
Total263100.00%5100.00%


static int snd_pmac_pcm_close(struct snd_pmac *chip, struct pmac_stream *rec, struct snd_pcm_substream *subs) { struct pmac_stream *astr; snd_pmac_dma_stop(rec); astr = snd_pmac_get_stream(chip, another_stream(rec->stream)); if (! astr) return -EINVAL; /* reset constraints */ astr->cur_freqs = chip->freqs_ok; astr->cur_formats = chip->formats_ok; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela5777.03%133.33%
takashi iwaitakashi iwai1722.97%266.67%
Total74100.00%3100.00%


static int snd_pmac_playback_open(struct snd_pcm_substream *subs) { struct snd_pmac *chip = snd_pcm_substream_chip(subs); subs->runtime->hw = snd_pmac_playback; return snd_pmac_pcm_open(chip, &chip->playback, subs); }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela3890.48%150.00%
takashi iwaitakashi iwai49.52%150.00%
Total42100.00%2100.00%


static int snd_pmac_capture_open(struct snd_pcm_substream *subs) { struct snd_pmac *chip = snd_pcm_substream_chip(subs); subs->runtime->hw = snd_pmac_capture; return snd_pmac_pcm_open(chip, &chip->capture, subs); }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela3890.48%150.00%
takashi iwaitakashi iwai49.52%150.00%
Total42100.00%2100.00%


static int snd_pmac_playback_close(struct snd_pcm_substream *subs) { struct snd_pmac *chip = snd_pcm_substream_chip(subs); return snd_pmac_pcm_close(chip, &chip->playback, subs); }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela3088.24%150.00%
takashi iwaitakashi iwai411.76%150.00%
Total34100.00%2100.00%


static int snd_pmac_capture_close(struct snd_pcm_substream *subs) { struct snd_pmac *chip = snd_pcm_substream_chip(subs); return snd_pmac_pcm_close(chip, &chip->capture, subs); }

Contributors

PersonTokensPropCommitsCommitProp
jaroslav kyselajaroslav kysela3088.24%150.00%
takashi iwaitakashi iwai411.76%150.00%
Total34100.00%2100.00%

/* */ static struct snd_pcm_ops snd_pmac_playback_ops = { .open = snd_pmac_playback_open, .close = snd_pmac_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_pmac_pcm_hw_params, .hw_free = snd_pmac_pcm_hw_free, .prepare = snd_pmac_playback_prepare, .trigger = snd_pmac_playback_trigger, .pointer = snd_pmac_playback_pointer, }; static struct snd_pcm_ops snd_pmac_capture_ops = { .open = snd_pmac_capture_open, .close = snd_pmac_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_pmac_pcm_hw_params, .hw_free = snd_pmac_pcm_hw_free, .prepare = snd_pmac_capture_prepare, .trigger = snd_pmac_capture_trigger, .pointer = snd_pmac_capture_pointer, };
int snd_pmac_pcm_new(struct snd_pmac *chip) { struct snd_pcm *pcm; int err; int num_captures = 1; if (! chip->can_capture) num_captures = 0; err