diff --git a/target/linux/xburst/patches-2.6.28/500-sound.patch b/target/linux/xburst/patches-2.6.28/500-sound.patch index 365e85af7..5dc92aafd 100644 --- a/target/linux/xburst/patches-2.6.28/500-sound.patch +++ b/target/linux/xburst/patches-2.6.28/500-sound.patch @@ -3,3498 +3,34 @@ @@ -1780,12 +1780,13 @@ return snd_interval_refine(hw_param_interval(params, rule->var), &t); } - + -#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12 +#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 14 #error "Change this table" #endif - + -static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, - 48000, 64000, 88200, 96000, 176400, 192000 }; -+static unsigned int rates[] = { 5512, 8000, 11025, 12000, 16000, 22050, 24000, -+ 32000, 44100, 48000, 64000, 88200, 96000, ++static unsigned int rates[] = { 5512, 8000, 11025, 12000, 16000, 22050, 24000, ++ 32000, 44100, 48000, 64000, 88200, 96000, + 176400, 192000 }; - + const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = { .count = ARRAY_SIZE(rates), -@@ -1796,9 +1797,17 @@ - struct snd_pcm_hw_rule *rule) +@@ -1758,6 +1758,7 @@ + struct snd_pcm_hw_rule *rule) { - struct snd_pcm_hardware *hw = rule->private; -+#if 0 - return snd_interval_list(hw_param_interval(params, rule->var), + struct snd_pcm_hardware *hw = rule->private; ++ hw->rates = 0x3fe;//12KHz and 24KHz bits are all zero,you need set 1 + return snd_interval_list(hw_param_interval(params, rule->var), snd_pcm_known_rates.count, snd_pcm_known_rates.list, hw->rates); -+#else -+ //printk("hw->rates=0x%08x\n",hw->rates);//0x3b6 -+ hw->rates = 0x3fe;//12KHz and 24KHz bits are all zero,you need set 1 -+ return snd_interval_list(hw_param_interval(params, rule->var), -+ snd_pcm_known_rates.count, -+ snd_pcm_known_rates.list, hw->rates); -+#endif - } - - static int snd_pcm_hw_rule_buffer_bytes_max(struct snd_pcm_hw_params *params, ---- linux-2.6.24.7.old/sound/core/pcm_native.c.org 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/core/pcm_native.c.org 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,3451 @@ -+/* -+ * Digital Audio (PCM) abstract layer -+ * Copyright (c) by Jaroslav Kysela -+ * -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * Compatibility -+ */ -+ -+struct snd_pcm_hw_params_old { -+ unsigned int flags; -+ unsigned int masks[SNDRV_PCM_HW_PARAM_SUBFORMAT - -+ SNDRV_PCM_HW_PARAM_ACCESS + 1]; -+ struct snd_interval intervals[SNDRV_PCM_HW_PARAM_TICK_TIME - -+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1]; -+ unsigned int rmask; -+ unsigned int cmask; -+ unsigned int info; -+ unsigned int msbits; -+ unsigned int rate_num; -+ unsigned int rate_den; -+ snd_pcm_uframes_t fifo_size; -+ unsigned char reserved[64]; -+}; -+ -+#ifdef CONFIG_SND_SUPPORT_OLD_API -+#define SNDRV_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct snd_pcm_hw_params_old) -+#define SNDRV_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct snd_pcm_hw_params_old) -+ -+static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params_old __user * _oparams); -+static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params_old __user * _oparams); -+#endif -+static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream); -+ -+/* -+ * -+ */ -+ -+DEFINE_RWLOCK(snd_pcm_link_rwlock); -+EXPORT_SYMBOL(snd_pcm_link_rwlock); -+ -+static DECLARE_RWSEM(snd_pcm_link_rwsem); -+ -+static inline mm_segment_t snd_enter_user(void) -+{ -+ mm_segment_t fs = get_fs(); -+ set_fs(get_ds()); -+ return fs; -+} -+ -+static inline void snd_leave_user(mm_segment_t fs) -+{ -+ set_fs(fs); -+} -+ -+ -+ -+int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) -+{ -+ struct snd_pcm_runtime *runtime; -+ struct snd_pcm *pcm = substream->pcm; -+ struct snd_pcm_str *pstr = substream->pstr; -+ -+ snd_assert(substream != NULL, return -ENXIO); -+ memset(info, 0, sizeof(*info)); -+ info->card = pcm->card->number; -+ info->device = pcm->device; -+ info->stream = substream->stream; -+ info->subdevice = substream->number; -+ strlcpy(info->id, pcm->id, sizeof(info->id)); -+ strlcpy(info->name, pcm->name, sizeof(info->name)); -+ info->dev_class = pcm->dev_class; -+ info->dev_subclass = pcm->dev_subclass; -+ info->subdevices_count = pstr->substream_count; -+ info->subdevices_avail = pstr->substream_count - pstr->substream_opened; -+ strlcpy(info->subname, substream->name, sizeof(info->subname)); -+ runtime = substream->runtime; -+ /* AB: FIXME!!! This is definitely nonsense */ -+ if (runtime) { -+ info->sync = runtime->sync; -+ substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_INFO, info); -+ } -+ return 0; -+} -+ -+int snd_pcm_info_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_info __user * _info) -+{ -+ struct snd_pcm_info *info; -+ int err; -+ -+ info = kmalloc(sizeof(*info), GFP_KERNEL); -+ if (! info) -+ return -ENOMEM; -+ err = snd_pcm_info(substream, info); -+ if (err >= 0) { -+ if (copy_to_user(_info, info, sizeof(*info))) -+ err = -EFAULT; -+ } -+ kfree(info); -+ return err; -+} -+ -+#undef RULES_DEBUG -+ -+#ifdef RULES_DEBUG -+#define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v -+char *snd_pcm_hw_param_names[] = { -+ HW_PARAM(ACCESS), -+ HW_PARAM(FORMAT), -+ HW_PARAM(SUBFORMAT), -+ HW_PARAM(SAMPLE_BITS), -+ HW_PARAM(FRAME_BITS), -+ HW_PARAM(CHANNELS), -+ HW_PARAM(RATE), -+ HW_PARAM(PERIOD_TIME), -+ HW_PARAM(PERIOD_SIZE), -+ HW_PARAM(PERIOD_BYTES), -+ HW_PARAM(PERIODS), -+ HW_PARAM(BUFFER_TIME), -+ HW_PARAM(BUFFER_SIZE), -+ HW_PARAM(BUFFER_BYTES), -+ HW_PARAM(TICK_TIME), -+}; -+#endif -+ -+int snd_pcm_hw_refine(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ unsigned int k; -+ struct snd_pcm_hardware *hw; -+ struct snd_interval *i = NULL; -+ struct snd_mask *m = NULL; -+ struct snd_pcm_hw_constraints *constrs = &substream->runtime->hw_constraints; -+ unsigned int rstamps[constrs->rules_num]; -+ unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; -+ unsigned int stamp = 2; -+ int changed, again; -+ -+ params->info = 0; -+ params->fifo_size = 0; -+ if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS)) -+ params->msbits = 0; -+ if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) { -+ params->rate_num = 0; -+ params->rate_den = 0; -+ } -+ -+ for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) { -+ m = hw_param_mask(params, k); -+ if (snd_mask_empty(m)) -+ return -EINVAL; -+ if (!(params->rmask & (1 << k))) -+ continue; -+#ifdef RULES_DEBUG -+ printk("%s = ", snd_pcm_hw_param_names[k]); -+ printk("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]); -+#endif -+ changed = snd_mask_refine(m, constrs_mask(constrs, k)); -+#ifdef RULES_DEBUG -+ printk("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]); -+#endif -+ if (changed) -+ params->cmask |= 1 << k; -+ if (changed < 0) -+ return changed; -+ } -+ -+ for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) { -+ i = hw_param_interval(params, k); -+ if (snd_interval_empty(i)) -+ return -EINVAL; -+ if (!(params->rmask & (1 << k))) -+ continue; -+#ifdef RULES_DEBUG -+ printk("%s = ", snd_pcm_hw_param_names[k]); -+ if (i->empty) -+ printk("empty"); -+ else -+ printk("%c%u %u%c", -+ i->openmin ? '(' : '[', i->min, -+ i->max, i->openmax ? ')' : ']'); -+ printk(" -> "); -+#endif -+ changed = snd_interval_refine(i, constrs_interval(constrs, k)); -+#ifdef RULES_DEBUG -+ if (i->empty) -+ printk("empty\n"); -+ else -+ printk("%c%u %u%c\n", -+ i->openmin ? '(' : '[', i->min, -+ i->max, i->openmax ? ')' : ']'); -+#endif -+ if (changed) -+ params->cmask |= 1 << k; -+ if (changed < 0) -+ return changed; -+ } -+ -+ for (k = 0; k < constrs->rules_num; k++) -+ rstamps[k] = 0; -+ for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) -+ vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0; -+ do { -+ again = 0; -+ for (k = 0; k < constrs->rules_num; k++) { -+ struct snd_pcm_hw_rule *r = &constrs->rules[k]; -+ unsigned int d; -+ int doit = 0; -+ if (r->cond && !(r->cond & params->flags)) -+ continue; -+ for (d = 0; r->deps[d] >= 0; d++) { -+ if (vstamps[r->deps[d]] > rstamps[k]) { -+ doit = 1; -+ break; -+ } -+ } -+ if (!doit) -+ continue; -+#ifdef RULES_DEBUG -+ printk("Rule %d [%p]: ", k, r->func); -+ if (r->var >= 0) { -+ printk("%s = ", snd_pcm_hw_param_names[r->var]); -+ if (hw_is_mask(r->var)) { -+ m = hw_param_mask(params, r->var); -+ printk("%x", *m->bits); -+ } else { -+ i = hw_param_interval(params, r->var); -+ if (i->empty) -+ printk("empty"); -+ else -+ printk("%c%u %u%c", -+ i->openmin ? '(' : '[', i->min, -+ i->max, i->openmax ? ')' : ']'); -+ } -+ } -+#endif -+ changed = r->func(params, r); -+#ifdef RULES_DEBUG -+ if (r->var >= 0) { -+ printk(" -> "); -+ if (hw_is_mask(r->var)) -+ printk("%x", *m->bits); -+ else { -+ if (i->empty) -+ printk("empty"); -+ else -+ printk("%c%u %u%c", -+ i->openmin ? '(' : '[', i->min, -+ i->max, i->openmax ? ')' : ']'); -+ } -+ } -+ printk("\n"); -+#endif -+ rstamps[k] = stamp; -+ if (changed && r->var >= 0) { -+ params->cmask |= (1 << r->var); -+ vstamps[r->var] = stamp; -+ again = 1; -+ } -+ if (changed < 0) -+ return changed; -+ stamp++; -+ } -+ } while (again); -+ if (!params->msbits) { -+ i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); -+ if (snd_interval_single(i)) -+ params->msbits = snd_interval_value(i); -+ } -+ -+ if (!params->rate_den) { -+ i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); -+ if (snd_interval_single(i)) { -+ params->rate_num = snd_interval_value(i); -+ params->rate_den = 1; -+ } -+ } -+ -+ hw = &substream->runtime->hw; -+ if (!params->info) -+ params->info = hw->info; -+ if (!params->fifo_size) -+ params->fifo_size = hw->fifo_size; -+ params->rmask = 0; -+ return 0; -+} -+ -+EXPORT_SYMBOL(snd_pcm_hw_refine); -+ -+static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params __user * _params) -+{ -+ struct snd_pcm_hw_params *params; -+ int err; -+ -+ params = kmalloc(sizeof(*params), GFP_KERNEL); -+ if (!params) { -+ err = -ENOMEM; -+ goto out; -+ } -+ if (copy_from_user(params, _params, sizeof(*params))) { -+ err = -EFAULT; -+ goto out; -+ } -+ err = snd_pcm_hw_refine(substream, params); -+ if (copy_to_user(_params, params, sizeof(*params))) { -+ if (!err) -+ err = -EFAULT; -+ } -+out: -+ kfree(params); -+ return err; -+} -+ -+static int period_to_usecs(struct snd_pcm_runtime *runtime) -+{ -+ int usecs; -+ -+ if (! runtime->rate) -+ return -1; /* invalid */ -+ -+ /* take 75% of period time as the deadline */ -+ usecs = (750000 / runtime->rate) * runtime->period_size; -+ usecs += ((750000 % runtime->rate) * runtime->period_size) / -+ runtime->rate; -+ -+ return usecs; -+} -+ -+static int snd_pcm_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_pcm_runtime *runtime; -+ int err, usecs; -+ unsigned int bits; -+ snd_pcm_uframes_t frames; -+ -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ snd_assert(runtime != NULL, return -ENXIO); -+ snd_pcm_stream_lock_irq(substream); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_OPEN: -+ case SNDRV_PCM_STATE_SETUP: -+ case SNDRV_PCM_STATE_PREPARED: -+ break; -+ default: -+ snd_pcm_stream_unlock_irq(substream); -+ return -EBADFD; -+ } -+ snd_pcm_stream_unlock_irq(substream); -+#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) -+ if (!substream->oss.oss) -+#endif -+ if (atomic_read(&substream->mmap_count)) -+ return -EBADFD; -+ -+ params->rmask = ~0U; -+ err = snd_pcm_hw_refine(substream, params); -+ if (err < 0) -+ goto _error; -+ -+ err = snd_pcm_hw_params_choose(substream, params); -+ if (err < 0) -+ goto _error; -+ -+ if (substream->ops->hw_params != NULL) { -+ err = substream->ops->hw_params(substream, params); -+ if (err < 0) -+ goto _error; -+ } -+ -+ runtime->access = params_access(params); -+ runtime->format = params_format(params); -+ runtime->subformat = params_subformat(params); -+ runtime->channels = params_channels(params); -+ runtime->rate = params_rate(params); -+ runtime->period_size = params_period_size(params); -+ runtime->periods = params_periods(params); -+ runtime->buffer_size = params_buffer_size(params); -+ runtime->tick_time = params_tick_time(params); -+ runtime->info = params->info; -+ runtime->rate_num = params->rate_num; -+ runtime->rate_den = params->rate_den; -+ -+ bits = snd_pcm_format_physical_width(runtime->format); -+ runtime->sample_bits = bits; -+ bits *= runtime->channels; -+ runtime->frame_bits = bits; -+ frames = 1; -+ while (bits % 8 != 0) { -+ bits *= 2; -+ frames *= 2; -+ } -+ runtime->byte_align = bits / 8; -+ runtime->min_align = frames; -+ -+ /* Default sw params */ -+ runtime->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; -+ runtime->period_step = 1; -+ runtime->sleep_min = 0; -+ runtime->control->avail_min = runtime->period_size; -+ runtime->xfer_align = runtime->period_size; -+ runtime->start_threshold = 1; -+ runtime->stop_threshold = runtime->buffer_size; -+ runtime->silence_threshold = 0; -+ runtime->silence_size = 0; -+ runtime->boundary = runtime->buffer_size; -+ while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size) -+ runtime->boundary *= 2; -+ -+ snd_pcm_timer_resolution_change(substream); -+ runtime->status->state = SNDRV_PCM_STATE_SETUP; -+ -+ remove_acceptable_latency(substream->latency_id); -+ if ((usecs = period_to_usecs(runtime)) >= 0) -+ set_acceptable_latency(substream->latency_id, usecs); -+ return 0; -+ _error: -+ /* hardware might be unuseable from this time, -+ so we force application to retry to set -+ the correct hardware parameter settings */ -+ runtime->status->state = SNDRV_PCM_STATE_OPEN; -+ if (substream->ops->hw_free != NULL) -+ substream->ops->hw_free(substream); -+ return err; -+} -+ -+static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params __user * _params) -+{ -+ struct snd_pcm_hw_params *params; -+ int err; -+ -+ params = kmalloc(sizeof(*params), GFP_KERNEL); -+ if (!params) { -+ err = -ENOMEM; -+ goto out; -+ } -+ if (copy_from_user(params, _params, sizeof(*params))) { -+ err = -EFAULT; -+ goto out; -+ } -+ err = snd_pcm_hw_params(substream, params); -+ if (copy_to_user(_params, params, sizeof(*params))) { -+ if (!err) -+ err = -EFAULT; -+ } -+out: -+ kfree(params); -+ return err; -+} -+ -+static int snd_pcm_hw_free(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime; -+ int result = 0; -+ -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ snd_assert(runtime != NULL, return -ENXIO); -+ snd_pcm_stream_lock_irq(substream); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_SETUP: -+ case SNDRV_PCM_STATE_PREPARED: -+ break; -+ default: -+ snd_pcm_stream_unlock_irq(substream); -+ return -EBADFD; -+ } -+ snd_pcm_stream_unlock_irq(substream); -+ if (atomic_read(&substream->mmap_count)) -+ return -EBADFD; -+ if (substream->ops->hw_free) -+ result = substream->ops->hw_free(substream); -+ runtime->status->state = SNDRV_PCM_STATE_OPEN; -+ remove_acceptable_latency(substream->latency_id); -+ return result; -+} -+ -+static int snd_pcm_sw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_sw_params *params) -+{ -+ struct snd_pcm_runtime *runtime; -+ -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ snd_assert(runtime != NULL, return -ENXIO); -+ snd_pcm_stream_lock_irq(substream); -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { -+ snd_pcm_stream_unlock_irq(substream); -+ return -EBADFD; -+ } -+ snd_pcm_stream_unlock_irq(substream); -+ -+ if (params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST) -+ return -EINVAL; -+ if (params->avail_min == 0) -+ return -EINVAL; -+ if (params->xfer_align == 0 || -+ params->xfer_align % runtime->min_align != 0) -+ return -EINVAL; -+ if (params->silence_size >= runtime->boundary) { -+ if (params->silence_threshold != 0) -+ return -EINVAL; -+ } else { -+ if (params->silence_size > params->silence_threshold) -+ return -EINVAL; -+ if (params->silence_threshold > runtime->buffer_size) -+ return -EINVAL; -+ } -+ snd_pcm_stream_lock_irq(substream); -+ runtime->tstamp_mode = params->tstamp_mode; -+ runtime->sleep_min = params->sleep_min; -+ runtime->period_step = params->period_step; -+ runtime->control->avail_min = params->avail_min; -+ runtime->start_threshold = params->start_threshold; -+ runtime->stop_threshold = params->stop_threshold; -+ runtime->silence_threshold = params->silence_threshold; -+ runtime->silence_size = params->silence_size; -+ runtime->xfer_align = params->xfer_align; -+ params->boundary = runtime->boundary; -+ if (snd_pcm_running(substream)) { -+ if (runtime->sleep_min) -+ snd_pcm_tick_prepare(substream); -+ else -+ snd_pcm_tick_set(substream, 0); -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && -+ runtime->silence_size > 0) -+ snd_pcm_playback_silence(substream, ULONG_MAX); -+ wake_up(&runtime->sleep); -+ } -+ snd_pcm_stream_unlock_irq(substream); -+ return 0; -+} -+ -+static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_sw_params __user * _params) -+{ -+ struct snd_pcm_sw_params params; -+ int err; -+ if (copy_from_user(¶ms, _params, sizeof(params))) -+ return -EFAULT; -+ err = snd_pcm_sw_params(substream, ¶ms); -+ if (copy_to_user(_params, ¶ms, sizeof(params))) -+ return -EFAULT; -+ return err; -+} -+ -+int snd_pcm_status(struct snd_pcm_substream *substream, -+ struct snd_pcm_status *status) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ -+ snd_pcm_stream_lock_irq(substream); -+ status->state = runtime->status->state; -+ status->suspended_state = runtime->status->suspended_state; -+ if (status->state == SNDRV_PCM_STATE_OPEN) -+ goto _end; -+ status->trigger_tstamp = runtime->trigger_tstamp; -+ if (snd_pcm_running(substream)) { -+ snd_pcm_update_hw_ptr(substream); -+ if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP) -+ status->tstamp = runtime->status->tstamp; -+ else -+ getnstimeofday(&status->tstamp); -+ } else -+ getnstimeofday(&status->tstamp); -+ status->appl_ptr = runtime->control->appl_ptr; -+ status->hw_ptr = runtime->status->hw_ptr; -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ status->avail = snd_pcm_playback_avail(runtime); -+ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING || -+ runtime->status->state == SNDRV_PCM_STATE_DRAINING) -+ status->delay = runtime->buffer_size - status->avail; -+ else -+ status->delay = 0; -+ } else { -+ status->avail = snd_pcm_capture_avail(runtime); -+ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) -+ status->delay = status->avail; -+ else -+ status->delay = 0; -+ } -+ status->avail_max = runtime->avail_max; -+ status->overrange = runtime->overrange; -+ runtime->avail_max = 0; -+ runtime->overrange = 0; -+ _end: -+ snd_pcm_stream_unlock_irq(substream); -+ return 0; -+} -+ -+static int snd_pcm_status_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_status __user * _status) -+{ -+ struct snd_pcm_status status; -+ struct snd_pcm_runtime *runtime; -+ int res; -+ -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ memset(&status, 0, sizeof(status)); -+ res = snd_pcm_status(substream, &status); -+ if (res < 0) -+ return res; -+ if (copy_to_user(_status, &status, sizeof(status))) -+ return -EFAULT; -+ return 0; -+} -+ -+static int snd_pcm_channel_info(struct snd_pcm_substream *substream, -+ struct snd_pcm_channel_info * info) -+{ -+ struct snd_pcm_runtime *runtime; -+ unsigned int channel; -+ -+ snd_assert(substream != NULL, return -ENXIO); -+ channel = info->channel; -+ runtime = substream->runtime; -+ snd_pcm_stream_lock_irq(substream); -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { -+ snd_pcm_stream_unlock_irq(substream); -+ return -EBADFD; -+ } -+ snd_pcm_stream_unlock_irq(substream); -+ if (channel >= runtime->channels) -+ return -EINVAL; -+ memset(info, 0, sizeof(*info)); -+ info->channel = channel; -+ return substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_CHANNEL_INFO, info); -+} -+ -+static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_channel_info __user * _info) -+{ -+ struct snd_pcm_channel_info info; -+ int res; -+ -+ if (copy_from_user(&info, _info, sizeof(info))) -+ return -EFAULT; -+ res = snd_pcm_channel_info(substream, &info); -+ if (res < 0) -+ return res; -+ if (copy_to_user(_info, &info, sizeof(info))) -+ return -EFAULT; -+ return 0; -+} -+ -+static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (runtime->trigger_master == NULL) -+ return; -+ if (runtime->trigger_master == substream) { -+ getnstimeofday(&runtime->trigger_tstamp); -+ } else { -+ snd_pcm_trigger_tstamp(runtime->trigger_master); -+ runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp; -+ } -+ runtime->trigger_master = NULL; -+} -+ -+struct action_ops { -+ int (*pre_action)(struct snd_pcm_substream *substream, int state); -+ int (*do_action)(struct snd_pcm_substream *substream, int state); -+ void (*undo_action)(struct snd_pcm_substream *substream, int state); -+ void (*post_action)(struct snd_pcm_substream *substream, int state); -+}; -+ -+/* -+ * this functions is core for handling of linked stream -+ * Note: the stream state might be changed also on failure -+ * Note2: call with calling stream lock + link lock -+ */ -+static int snd_pcm_action_group(struct action_ops *ops, -+ struct snd_pcm_substream *substream, -+ int state, int do_lock) -+{ -+ struct snd_pcm_substream *s = NULL; -+ struct snd_pcm_substream *s1; -+ int res = 0; -+ -+ snd_pcm_group_for_each_entry(s, substream) { -+ if (do_lock && s != substream) -+ spin_lock_nested(&s->self_group.lock, -+ SINGLE_DEPTH_NESTING); -+ res = ops->pre_action(s, state); -+ if (res < 0) -+ goto _unlock; -+ } -+ snd_pcm_group_for_each_entry(s, substream) { -+ res = ops->do_action(s, state); -+ if (res < 0) { -+ if (ops->undo_action) { -+ snd_pcm_group_for_each_entry(s1, substream) { -+ if (s1 == s) /* failed stream */ -+ break; -+ ops->undo_action(s1, state); -+ } -+ } -+ s = NULL; /* unlock all */ -+ goto _unlock; -+ } -+ } -+ snd_pcm_group_for_each_entry(s, substream) { -+ ops->post_action(s, state); -+ } -+ _unlock: -+ if (do_lock) { -+ /* unlock streams */ -+ snd_pcm_group_for_each_entry(s1, substream) { -+ if (s1 != substream) -+ spin_unlock(&s1->self_group.lock); -+ if (s1 == s) /* end */ -+ break; -+ } -+ } -+ return res; -+} -+ -+/* -+ * Note: call with stream lock -+ */ -+static int snd_pcm_action_single(struct action_ops *ops, -+ struct snd_pcm_substream *substream, -+ int state) -+{ -+ int res; -+ -+ res = ops->pre_action(substream, state); -+ if (res < 0) -+ return res; -+ res = ops->do_action(substream, state); -+ if (res == 0) -+ ops->post_action(substream, state); -+ else if (ops->undo_action) -+ ops->undo_action(substream, state); -+ return res; -+} -+ -+/* -+ * Note: call with stream lock -+ */ -+static int snd_pcm_action(struct action_ops *ops, -+ struct snd_pcm_substream *substream, -+ int state) -+{ -+ int res; -+ -+ if (snd_pcm_stream_linked(substream)) { -+ if (!spin_trylock(&substream->group->lock)) { -+ spin_unlock(&substream->self_group.lock); -+ spin_lock(&substream->group->lock); -+ spin_lock(&substream->self_group.lock); -+ } -+ res = snd_pcm_action_group(ops, substream, state, 1); -+ spin_unlock(&substream->group->lock); -+ } else { -+ res = snd_pcm_action_single(ops, substream, state); -+ } -+ return res; -+} -+ -+/* -+ * Note: don't use any locks before -+ */ -+static int snd_pcm_action_lock_irq(struct action_ops *ops, -+ struct snd_pcm_substream *substream, -+ int state) -+{ -+ int res; -+ -+ read_lock_irq(&snd_pcm_link_rwlock); -+ if (snd_pcm_stream_linked(substream)) { -+ spin_lock(&substream->group->lock); -+ spin_lock(&substream->self_group.lock); -+ res = snd_pcm_action_group(ops, substream, state, 1); -+ spin_unlock(&substream->self_group.lock); -+ spin_unlock(&substream->group->lock); -+ } else { -+ spin_lock(&substream->self_group.lock); -+ res = snd_pcm_action_single(ops, substream, state); -+ spin_unlock(&substream->self_group.lock); -+ } -+ read_unlock_irq(&snd_pcm_link_rwlock); -+ return res; -+} -+ -+/* -+ */ -+static int snd_pcm_action_nonatomic(struct action_ops *ops, -+ struct snd_pcm_substream *substream, -+ int state) -+{ -+ int res; -+ -+ down_read(&snd_pcm_link_rwsem); -+ if (snd_pcm_stream_linked(substream)) -+ res = snd_pcm_action_group(ops, substream, state, 0); -+ else -+ res = snd_pcm_action_single(ops, substream, state); -+ up_read(&snd_pcm_link_rwsem); -+ return res; -+} -+ -+/* -+ * start callbacks -+ */ -+static int snd_pcm_pre_start(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (runtime->status->state != SNDRV_PCM_STATE_PREPARED) -+ return -EBADFD; -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && -+ !snd_pcm_playback_data(substream)) -+ return -EPIPE; -+ runtime->trigger_master = substream; -+ return 0; -+} -+ -+static int snd_pcm_do_start(struct snd_pcm_substream *substream, int state) -+{ -+ if (substream->runtime->trigger_master != substream) -+ return 0; -+ return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START); -+} -+ -+static void snd_pcm_undo_start(struct snd_pcm_substream *substream, int state) -+{ -+ if (substream->runtime->trigger_master == substream) -+ substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP); -+} -+ -+static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_trigger_tstamp(substream); -+ runtime->status->state = state; -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && -+ runtime->silence_size > 0) -+ snd_pcm_playback_silence(substream, ULONG_MAX); -+ if (runtime->sleep_min) -+ snd_pcm_tick_prepare(substream); -+ if (substream->timer) -+ snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTART, -+ &runtime->trigger_tstamp); -+} -+ -+static struct action_ops snd_pcm_action_start = { -+ .pre_action = snd_pcm_pre_start, -+ .do_action = snd_pcm_do_start, -+ .undo_action = snd_pcm_undo_start, -+ .post_action = snd_pcm_post_start -+}; -+ -+/** -+ * snd_pcm_start -+ * @substream: the PCM substream instance -+ * -+ * Start all linked streams. -+ */ -+int snd_pcm_start(struct snd_pcm_substream *substream) -+{ -+ return snd_pcm_action(&snd_pcm_action_start, substream, -+ SNDRV_PCM_STATE_RUNNING); -+} -+ -+/* -+ * stop callbacks -+ */ -+static int snd_pcm_pre_stop(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) -+ return -EBADFD; -+ runtime->trigger_master = substream; -+ return 0; -+} -+ -+static int snd_pcm_do_stop(struct snd_pcm_substream *substream, int state) -+{ -+ if (substream->runtime->trigger_master == substream && -+ snd_pcm_running(substream)) -+ substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP); -+ return 0; /* unconditonally stop all substreams */ -+} -+ -+static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (runtime->status->state != state) { -+ snd_pcm_trigger_tstamp(substream); -+ if (substream->timer) -+ snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTOP, -+ &runtime->trigger_tstamp); -+ runtime->status->state = state; -+ snd_pcm_tick_set(substream, 0); -+ } -+ wake_up(&runtime->sleep); -+} -+ -+static struct action_ops snd_pcm_action_stop = { -+ .pre_action = snd_pcm_pre_stop, -+ .do_action = snd_pcm_do_stop, -+ .post_action = snd_pcm_post_stop -+}; -+ -+/** -+ * snd_pcm_stop -+ * @substream: the PCM substream instance -+ * @state: PCM state after stopping the stream -+ * -+ * Try to stop all running streams in the substream group. -+ * The state of each stream is changed to the given value after that unconditionally. -+ */ -+int snd_pcm_stop(struct snd_pcm_substream *substream, int state) -+{ -+ return snd_pcm_action(&snd_pcm_action_stop, substream, state); -+} -+ -+EXPORT_SYMBOL(snd_pcm_stop); -+ -+/** -+ * snd_pcm_drain_done -+ * @substream: the PCM substream -+ * -+ * Stop the DMA only when the given stream is playback. -+ * The state is changed to SETUP. -+ * Unlike snd_pcm_stop(), this affects only the given stream. -+ */ -+int snd_pcm_drain_done(struct snd_pcm_substream *substream) -+{ -+ return snd_pcm_action_single(&snd_pcm_action_stop, substream, -+ SNDRV_PCM_STATE_SETUP); -+} -+ -+/* -+ * pause callbacks -+ */ -+static int snd_pcm_pre_pause(struct snd_pcm_substream *substream, int push) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (!(runtime->info & SNDRV_PCM_INFO_PAUSE)) -+ return -ENOSYS; -+ if (push) { -+ if (runtime->status->state != SNDRV_PCM_STATE_RUNNING) -+ return -EBADFD; -+ } else if (runtime->status->state != SNDRV_PCM_STATE_PAUSED) -+ return -EBADFD; -+ runtime->trigger_master = substream; -+ return 0; -+} -+ -+static int snd_pcm_do_pause(struct snd_pcm_substream *substream, int push) -+{ -+ if (substream->runtime->trigger_master != substream) -+ return 0; -+ return substream->ops->trigger(substream, -+ push ? SNDRV_PCM_TRIGGER_PAUSE_PUSH : -+ SNDRV_PCM_TRIGGER_PAUSE_RELEASE); -+} -+ -+static void snd_pcm_undo_pause(struct snd_pcm_substream *substream, int push) -+{ -+ if (substream->runtime->trigger_master == substream) -+ substream->ops->trigger(substream, -+ push ? SNDRV_PCM_TRIGGER_PAUSE_RELEASE : -+ SNDRV_PCM_TRIGGER_PAUSE_PUSH); -+} -+ -+static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_trigger_tstamp(substream); -+ if (push) { -+ runtime->status->state = SNDRV_PCM_STATE_PAUSED; -+ if (substream->timer) -+ snd_timer_notify(substream->timer, -+ SNDRV_TIMER_EVENT_MPAUSE, -+ &runtime->trigger_tstamp); -+ snd_pcm_tick_set(substream, 0); -+ wake_up(&runtime->sleep); -+ } else { -+ runtime->status->state = SNDRV_PCM_STATE_RUNNING; -+ if (runtime->sleep_min) -+ snd_pcm_tick_prepare(substream); -+ if (substream->timer) -+ snd_timer_notify(substream->timer, -+ SNDRV_TIMER_EVENT_MCONTINUE, -+ &runtime->trigger_tstamp); -+ } -+} -+ -+static struct action_ops snd_pcm_action_pause = { -+ .pre_action = snd_pcm_pre_pause, -+ .do_action = snd_pcm_do_pause, -+ .undo_action = snd_pcm_undo_pause, -+ .post_action = snd_pcm_post_pause -+}; -+ -+/* -+ * Push/release the pause for all linked streams. -+ */ -+static int snd_pcm_pause(struct snd_pcm_substream *substream, int push) -+{ -+ return snd_pcm_action(&snd_pcm_action_pause, substream, push); -+} -+ -+#ifdef CONFIG_PM -+/* suspend */ -+ -+static int snd_pcm_pre_suspend(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) -+ return -EBUSY; -+ runtime->trigger_master = substream; -+ return 0; -+} -+ -+static int snd_pcm_do_suspend(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (runtime->trigger_master != substream) -+ return 0; -+ if (! snd_pcm_running(substream)) -+ return 0; -+ substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND); -+ return 0; /* suspend unconditionally */ -+} -+ -+static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_trigger_tstamp(substream); -+ if (substream->timer) -+ snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSUSPEND, -+ &runtime->trigger_tstamp); -+ runtime->status->suspended_state = runtime->status->state; -+ runtime->status->state = SNDRV_PCM_STATE_SUSPENDED; -+ snd_pcm_tick_set(substream, 0); -+ wake_up(&runtime->sleep); -+} -+ -+static struct action_ops snd_pcm_action_suspend = { -+ .pre_action = snd_pcm_pre_suspend, -+ .do_action = snd_pcm_do_suspend, -+ .post_action = snd_pcm_post_suspend -+}; -+ -+/** -+ * snd_pcm_suspend -+ * @substream: the PCM substream -+ * -+ * Trigger SUSPEND to all linked streams. -+ * After this call, all streams are changed to SUSPENDED state. -+ */ -+int snd_pcm_suspend(struct snd_pcm_substream *substream) -+{ -+ int err; -+ unsigned long flags; -+ -+ if (! substream) -+ return 0; -+ -+ snd_pcm_stream_lock_irqsave(substream, flags); -+ err = snd_pcm_action(&snd_pcm_action_suspend, substream, 0); -+ snd_pcm_stream_unlock_irqrestore(substream, flags); -+ return err; -+} -+ -+EXPORT_SYMBOL(snd_pcm_suspend); -+ -+/** -+ * snd_pcm_suspend_all -+ * @pcm: the PCM instance -+ * -+ * Trigger SUSPEND to all substreams in the given pcm. -+ * After this call, all streams are changed to SUSPENDED state. -+ */ -+int snd_pcm_suspend_all(struct snd_pcm *pcm) -+{ -+ struct snd_pcm_substream *substream; -+ int stream, err = 0; -+ -+ if (! pcm) -+ return 0; -+ -+ for (stream = 0; stream < 2; stream++) { -+ for (substream = pcm->streams[stream].substream; -+ substream; substream = substream->next) { -+ /* FIXME: the open/close code should lock this as well */ -+ if (substream->runtime == NULL) -+ continue; -+ err = snd_pcm_suspend(substream); -+ if (err < 0 && err != -EBUSY) -+ return err; -+ } -+ } -+ return 0; -+} -+ -+EXPORT_SYMBOL(snd_pcm_suspend_all); -+ -+/* resume */ -+ -+static int snd_pcm_pre_resume(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (!(runtime->info & SNDRV_PCM_INFO_RESUME)) -+ return -ENOSYS; -+ runtime->trigger_master = substream; -+ return 0; -+} -+ -+static int snd_pcm_do_resume(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (runtime->trigger_master != substream) -+ return 0; -+ /* DMA not running previously? */ -+ if (runtime->status->suspended_state != SNDRV_PCM_STATE_RUNNING && -+ (runtime->status->suspended_state != SNDRV_PCM_STATE_DRAINING || -+ substream->stream != SNDRV_PCM_STREAM_PLAYBACK)) -+ return 0; -+ return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_RESUME); -+} -+ -+static void snd_pcm_undo_resume(struct snd_pcm_substream *substream, int state) -+{ -+ if (substream->runtime->trigger_master == substream && -+ snd_pcm_running(substream)) -+ substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND); -+} -+ -+static void snd_pcm_post_resume(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_trigger_tstamp(substream); -+ if (substream->timer) -+ snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MRESUME, -+ &runtime->trigger_tstamp); -+ runtime->status->state = runtime->status->suspended_state; -+ if (runtime->sleep_min) -+ snd_pcm_tick_prepare(substream); -+} -+ -+static struct action_ops snd_pcm_action_resume = { -+ .pre_action = snd_pcm_pre_resume, -+ .do_action = snd_pcm_do_resume, -+ .undo_action = snd_pcm_undo_resume, -+ .post_action = snd_pcm_post_resume -+}; -+ -+static int snd_pcm_resume(struct snd_pcm_substream *substream) -+{ -+ struct snd_card *card = substream->pcm->card; -+ int res; -+ -+ snd_power_lock(card); -+ if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) -+ res = snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0); -+ snd_power_unlock(card); -+ return res; -+} -+ -+#else -+ -+static int snd_pcm_resume(struct snd_pcm_substream *substream) -+{ -+ return -ENOSYS; -+} -+ -+#endif /* CONFIG_PM */ -+ -+/* -+ * xrun ioctl -+ * -+ * Change the RUNNING stream(s) to XRUN state. -+ */ -+static int snd_pcm_xrun(struct snd_pcm_substream *substream) -+{ -+ struct snd_card *card = substream->pcm->card; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ int result; -+ -+ snd_power_lock(card); -+ if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { -+ result = snd_power_wait(card, SNDRV_CTL_POWER_D0); -+ if (result < 0) -+ goto _unlock; -+ } -+ -+ snd_pcm_stream_lock_irq(substream); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_XRUN: -+ result = 0; /* already there */ -+ break; -+ case SNDRV_PCM_STATE_RUNNING: -+ result = snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); -+ break; -+ default: -+ result = -EBADFD; -+ } -+ snd_pcm_stream_unlock_irq(substream); -+ _unlock: -+ snd_power_unlock(card); -+ return result; -+} -+ -+/* -+ * reset ioctl -+ */ -+static int snd_pcm_pre_reset(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_RUNNING: -+ case SNDRV_PCM_STATE_PREPARED: -+ case SNDRV_PCM_STATE_PAUSED: -+ case SNDRV_PCM_STATE_SUSPENDED: -+ return 0; -+ default: -+ return -EBADFD; -+ } -+} -+ -+static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ int err = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL); -+ if (err < 0) -+ return err; -+ // snd_assert(runtime->status->hw_ptr < runtime->buffer_size, ); -+ runtime->hw_ptr_base = 0; -+ runtime->hw_ptr_interrupt = runtime->status->hw_ptr - -+ runtime->status->hw_ptr % runtime->period_size; -+ runtime->silence_start = runtime->status->hw_ptr; -+ runtime->silence_filled = 0; -+ return 0; -+} -+ -+static void snd_pcm_post_reset(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ runtime->control->appl_ptr = runtime->status->hw_ptr; -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && -+ runtime->silence_size > 0) -+ snd_pcm_playback_silence(substream, ULONG_MAX); -+} -+ -+static struct action_ops snd_pcm_action_reset = { -+ .pre_action = snd_pcm_pre_reset, -+ .do_action = snd_pcm_do_reset, -+ .post_action = snd_pcm_post_reset -+}; -+ -+static int snd_pcm_reset(struct snd_pcm_substream *substream) -+{ -+ return snd_pcm_action_nonatomic(&snd_pcm_action_reset, substream, 0); -+} -+ -+/* -+ * prepare ioctl -+ */ -+/* we use the second argument for updating f_flags */ -+static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream, -+ int f_flags) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN || -+ runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) -+ return -EBADFD; -+ if (snd_pcm_running(substream)) -+ return -EBUSY; -+ substream->f_flags = f_flags; -+ return 0; -+} -+ -+static int snd_pcm_do_prepare(struct snd_pcm_substream *substream, int state) -+{ -+ int err; -+ err = substream->ops->prepare(substream); -+ if (err < 0) -+ return err; -+ return snd_pcm_do_reset(substream, 0); -+} -+ -+static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ runtime->control->appl_ptr = runtime->status->hw_ptr; -+ runtime->status->state = SNDRV_PCM_STATE_PREPARED; -+} -+ -+static struct action_ops snd_pcm_action_prepare = { -+ .pre_action = snd_pcm_pre_prepare, -+ .do_action = snd_pcm_do_prepare, -+ .post_action = snd_pcm_post_prepare -+}; -+ -+/** -+ * snd_pcm_prepare -+ * @substream: the PCM substream instance -+ * @file: file to refer f_flags -+ * -+ * Prepare the PCM substream to be triggerable. -+ */ -+static int snd_pcm_prepare(struct snd_pcm_substream *substream, -+ struct file *file) -+{ -+ int res; -+ struct snd_card *card = substream->pcm->card; -+ int f_flags; -+ -+ if (file) -+ f_flags = file->f_flags; -+ else -+ f_flags = substream->f_flags; -+ -+ snd_power_lock(card); -+ if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) -+ res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, -+ substream, f_flags); -+ snd_power_unlock(card); -+ return res; -+} -+ -+/* -+ * drain ioctl -+ */ -+ -+static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state) -+{ -+ if (substream->f_flags & O_NONBLOCK) -+ return -EAGAIN; -+ substream->runtime->trigger_master = substream; -+ return 0; -+} -+ -+static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_PREPARED: -+ /* start playback stream if possible */ -+ if (! snd_pcm_playback_empty(substream)) { -+ snd_pcm_do_start(substream, SNDRV_PCM_STATE_DRAINING); -+ snd_pcm_post_start(substream, SNDRV_PCM_STATE_DRAINING); -+ } -+ break; -+ case SNDRV_PCM_STATE_RUNNING: -+ runtime->status->state = SNDRV_PCM_STATE_DRAINING; -+ break; -+ default: -+ break; -+ } -+ } else { -+ /* stop running stream */ -+ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) { -+ int state = snd_pcm_capture_avail(runtime) > 0 ? -+ SNDRV_PCM_STATE_DRAINING : SNDRV_PCM_STATE_SETUP; -+ snd_pcm_do_stop(substream, state); -+ snd_pcm_post_stop(substream, state); -+ } -+ } -+ return 0; -+} -+ -+static void snd_pcm_post_drain_init(struct snd_pcm_substream *substream, int state) -+{ -+} -+ -+static struct action_ops snd_pcm_action_drain_init = { -+ .pre_action = snd_pcm_pre_drain_init, -+ .do_action = snd_pcm_do_drain_init, -+ .post_action = snd_pcm_post_drain_init -+}; -+ -+struct drain_rec { -+ struct snd_pcm_substream *substream; -+ wait_queue_t wait; -+ snd_pcm_uframes_t stop_threshold; -+}; -+ -+static int snd_pcm_drop(struct snd_pcm_substream *substream); -+ -+/* -+ * Drain the stream(s). -+ * When the substream is linked, sync until the draining of all playback streams -+ * is finished. -+ * After this call, all streams are supposed to be either SETUP or DRAINING -+ * (capture only) state. -+ */ -+static int snd_pcm_drain(struct snd_pcm_substream *substream) -+{ -+ struct snd_card *card; -+ struct snd_pcm_runtime *runtime; -+ struct snd_pcm_substream *s; -+ int result = 0; -+ int i, num_drecs; -+ struct drain_rec *drec, drec_tmp, *d; -+ -+ snd_assert(substream != NULL, return -ENXIO); -+ card = substream->pcm->card; -+ runtime = substream->runtime; -+ -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) -+ return -EBADFD; -+ -+ snd_power_lock(card); -+ if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { -+ result = snd_power_wait(card, SNDRV_CTL_POWER_D0); -+ if (result < 0) { -+ snd_power_unlock(card); -+ return result; -+ } -+ } -+ -+ /* allocate temporary record for drain sync */ -+ down_read(&snd_pcm_link_rwsem); -+ if (snd_pcm_stream_linked(substream)) { -+ drec = kmalloc(substream->group->count * sizeof(*drec), GFP_KERNEL); -+ if (! drec) { -+ up_read(&snd_pcm_link_rwsem); -+ snd_power_unlock(card); -+ return -ENOMEM; -+ } -+ } else -+ drec = &drec_tmp; -+ -+ /* count only playback streams */ -+ num_drecs = 0; -+ snd_pcm_group_for_each_entry(s, substream) { -+ runtime = s->runtime; -+ if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ d = &drec[num_drecs++]; -+ d->substream = s; -+ init_waitqueue_entry(&d->wait, current); -+ add_wait_queue(&runtime->sleep, &d->wait); -+ /* stop_threshold fixup to avoid endless loop when -+ * stop_threshold > buffer_size -+ */ -+ d->stop_threshold = runtime->stop_threshold; -+ if (runtime->stop_threshold > runtime->buffer_size) -+ runtime->stop_threshold = runtime->buffer_size; -+ } -+ } -+ up_read(&snd_pcm_link_rwsem); -+ -+ snd_pcm_stream_lock_irq(substream); -+ /* resume pause */ -+ if (substream->runtime->status->state == SNDRV_PCM_STATE_PAUSED) -+ snd_pcm_pause(substream, 0); -+ -+ /* pre-start/stop - all running streams are changed to DRAINING state */ -+ result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0); -+ if (result < 0) { -+ snd_pcm_stream_unlock_irq(substream); -+ goto _error; -+ } -+ -+ for (;;) { -+ long tout; -+ if (signal_pending(current)) { -+ result = -ERESTARTSYS; -+ break; -+ } -+ /* all finished? */ -+ for (i = 0; i < num_drecs; i++) { -+ runtime = drec[i].substream->runtime; -+ if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) -+ break; -+ } -+ if (i == num_drecs) -+ break; /* yes, all drained */ -+ -+ set_current_state(TASK_INTERRUPTIBLE); -+ snd_pcm_stream_unlock_irq(substream); -+ snd_power_unlock(card); -+ tout = schedule_timeout(10 * HZ); -+ snd_power_lock(card); -+ snd_pcm_stream_lock_irq(substream); -+ if (tout == 0) { -+ if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) -+ result = -ESTRPIPE; -+ else { -+ snd_printd("playback drain error (DMA or IRQ trouble?)\n"); -+ snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); -+ result = -EIO; -+ } -+ break; -+ } -+ } -+ -+ snd_pcm_stream_unlock_irq(substream); -+ -+ _error: -+ for (i = 0; i < num_drecs; i++) { -+ d = &drec[i]; -+ runtime = d->substream->runtime; -+ remove_wait_queue(&runtime->sleep, &d->wait); -+ runtime->stop_threshold = d->stop_threshold; -+ } -+ -+ if (drec != &drec_tmp) -+ kfree(drec); -+ snd_power_unlock(card); -+ -+ return result; -+} -+ -+/* -+ * drop ioctl -+ * -+ * Immediately put all linked substreams into SETUP state. -+ */ -+static int snd_pcm_drop(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime; -+ struct snd_card *card; -+ int result = 0; -+ -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ card = substream->pcm->card; -+ -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN || -+ runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) -+ return -EBADFD; -+ -+ snd_power_lock(card); -+ if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { -+ result = snd_power_wait(card, SNDRV_CTL_POWER_D0); -+ if (result < 0) -+ goto _unlock; -+ } -+ -+ snd_pcm_stream_lock_irq(substream); -+ /* resume pause */ -+ if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) -+ snd_pcm_pause(substream, 0); -+ -+ snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); -+ /* runtime->control->appl_ptr = runtime->status->hw_ptr; */ -+ snd_pcm_stream_unlock_irq(substream); -+ _unlock: -+ snd_power_unlock(card); -+ return result; -+} -+ -+ -+/* WARNING: Don't forget to fput back the file */ -+static struct file *snd_pcm_file_fd(int fd) -+{ -+ struct file *file; -+ struct inode *inode; -+ unsigned int minor; -+ -+ file = fget(fd); -+ if (!file) -+ return NULL; -+ inode = file->f_path.dentry->d_inode; -+ if (!S_ISCHR(inode->i_mode) || -+ imajor(inode) != snd_major) { -+ fput(file); -+ return NULL; -+ } -+ minor = iminor(inode); -+ if (!snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK) && -+ !snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE)) { -+ fput(file); -+ return NULL; -+ } -+ return file; -+} -+ -+/* -+ * PCM link handling -+ */ -+static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) -+{ -+ int res = 0; -+ struct file *file; -+ struct snd_pcm_file *pcm_file; -+ struct snd_pcm_substream *substream1; -+ -+ file = snd_pcm_file_fd(fd); -+ if (!file) -+ return -EBADFD; -+ pcm_file = file->private_data; -+ substream1 = pcm_file->substream; -+ down_write(&snd_pcm_link_rwsem); -+ write_lock_irq(&snd_pcm_link_rwlock); -+ if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || -+ substream->runtime->status->state != substream1->runtime->status->state) { -+ res = -EBADFD; -+ goto _end; -+ } -+ if (snd_pcm_stream_linked(substream1)) { -+ res = -EALREADY; -+ goto _end; -+ } -+ if (!snd_pcm_stream_linked(substream)) { -+ substream->group = kmalloc(sizeof(struct snd_pcm_group), GFP_ATOMIC); -+ if (substream->group == NULL) { -+ res = -ENOMEM; -+ goto _end; -+ } -+ spin_lock_init(&substream->group->lock); -+ INIT_LIST_HEAD(&substream->group->substreams); -+ list_add_tail(&substream->link_list, &substream->group->substreams); -+ substream->group->count = 1; -+ } -+ list_add_tail(&substream1->link_list, &substream->group->substreams); -+ substream->group->count++; -+ substream1->group = substream->group; -+ _end: -+ write_unlock_irq(&snd_pcm_link_rwlock); -+ up_write(&snd_pcm_link_rwsem); -+ fput(file); -+ return res; -+} -+ -+static void relink_to_local(struct snd_pcm_substream *substream) -+{ -+ substream->group = &substream->self_group; -+ INIT_LIST_HEAD(&substream->self_group.substreams); -+ list_add_tail(&substream->link_list, &substream->self_group.substreams); -+} -+ -+static int snd_pcm_unlink(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_substream *s; -+ int res = 0; -+ -+ down_write(&snd_pcm_link_rwsem); -+ write_lock_irq(&snd_pcm_link_rwlock); -+ if (!snd_pcm_stream_linked(substream)) { -+ res = -EALREADY; -+ goto _end; -+ } -+ list_del(&substream->link_list); -+ substream->group->count--; -+ if (substream->group->count == 1) { /* detach the last stream, too */ -+ snd_pcm_group_for_each_entry(s, substream) { -+ relink_to_local(s); -+ break; -+ } -+ kfree(substream->group); -+ } -+ relink_to_local(substream); -+ _end: -+ write_unlock_irq(&snd_pcm_link_rwlock); -+ up_write(&snd_pcm_link_rwsem); -+ return res; -+} -+ -+/* -+ * hw configurator -+ */ -+static int snd_pcm_hw_rule_mul(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_rule *rule) -+{ -+ struct snd_interval t; -+ snd_interval_mul(hw_param_interval_c(params, rule->deps[0]), -+ hw_param_interval_c(params, rule->deps[1]), &t); -+ return snd_interval_refine(hw_param_interval(params, rule->var), &t); -+} -+ -+static int snd_pcm_hw_rule_div(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_rule *rule) -+{ -+ struct snd_interval t; -+ snd_interval_div(hw_param_interval_c(params, rule->deps[0]), -+ hw_param_interval_c(params, rule->deps[1]), &t); -+ return snd_interval_refine(hw_param_interval(params, rule->var), &t); -+} -+ -+static int snd_pcm_hw_rule_muldivk(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_rule *rule) -+{ -+ struct snd_interval t; -+ snd_interval_muldivk(hw_param_interval_c(params, rule->deps[0]), -+ hw_param_interval_c(params, rule->deps[1]), -+ (unsigned long) rule->private, &t); -+ return snd_interval_refine(hw_param_interval(params, rule->var), &t); -+} -+ -+static int snd_pcm_hw_rule_mulkdiv(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_rule *rule) -+{ -+ struct snd_interval t; -+ snd_interval_mulkdiv(hw_param_interval_c(params, rule->deps[0]), -+ (unsigned long) rule->private, -+ hw_param_interval_c(params, rule->deps[1]), &t); -+ return snd_interval_refine(hw_param_interval(params, rule->var), &t); -+} -+ -+static int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_rule *rule) -+{ -+ unsigned int k; -+ struct snd_interval *i = hw_param_interval(params, rule->deps[0]); -+ struct snd_mask m; -+ struct snd_mask *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); -+ snd_mask_any(&m); -+ for (k = 0; k <= SNDRV_PCM_FORMAT_LAST; ++k) { -+ int bits; -+ if (! snd_mask_test(mask, k)) -+ continue; -+ bits = snd_pcm_format_physical_width(k); -+ if (bits <= 0) -+ continue; /* ignore invalid formats */ -+ if ((unsigned)bits < i->min || (unsigned)bits > i->max) -+ snd_mask_reset(&m, k); -+ } -+ return snd_mask_refine(mask, &m); -+} -+ -+static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_rule *rule) -+{ -+ struct snd_interval t; -+ unsigned int k; -+ t.min = UINT_MAX; -+ t.max = 0; -+ t.openmin = 0; -+ t.openmax = 0; -+ for (k = 0; k <= SNDRV_PCM_FORMAT_LAST; ++k) { -+ int bits; -+ if (! snd_mask_test(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), k)) -+ continue; -+ bits = snd_pcm_format_physical_width(k); -+ if (bits <= 0) -+ continue; /* ignore invalid formats */ -+ if (t.min > (unsigned)bits) -+ t.min = bits; -+ if (t.max < (unsigned)bits) -+ t.max = bits; -+ } -+ t.integer = 1; -+ return snd_interval_refine(hw_param_interval(params, rule->var), &t); -+} -+ -+#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12 -+#error "Change this table" -+#endif -+ -+static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, -+ 48000, 64000, 88200, 96000, 176400, 192000 }; -+ -+const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = { -+ .count = ARRAY_SIZE(rates), -+ .list = rates, -+}; -+ -+static int snd_pcm_hw_rule_rate(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_rule *rule) -+{ -+ struct snd_pcm_hardware *hw = rule->private; -+ return snd_interval_list(hw_param_interval(params, rule->var), -+ snd_pcm_known_rates.count, -+ snd_pcm_known_rates.list, hw->rates); -+} -+ -+static int snd_pcm_hw_rule_buffer_bytes_max(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_rule *rule) -+{ -+ struct snd_interval t; -+ struct snd_pcm_substream *substream = rule->private; -+ t.min = 0; -+ t.max = substream->buffer_bytes_max; -+ t.openmin = 0; -+ t.openmax = 0; -+ t.integer = 1; -+ return snd_interval_refine(hw_param_interval(params, rule->var), &t); -+} -+ -+int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints; -+ int k, err; -+ -+ for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) { -+ snd_mask_any(constrs_mask(constrs, k)); -+ } -+ -+ for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) { -+ snd_interval_any(constrs_interval(constrs, k)); -+ } -+ -+ snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_CHANNELS)); -+ snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_BUFFER_SIZE)); -+ snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_BUFFER_BYTES)); -+ snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)); -+ snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_FRAME_BITS)); -+ -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, -+ snd_pcm_hw_rule_format, NULL, -+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -+ snd_pcm_hw_rule_sample_bits, NULL, -+ SNDRV_PCM_HW_PARAM_FORMAT, -+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -+ snd_pcm_hw_rule_div, NULL, -+ SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS, -+ snd_pcm_hw_rule_mul, NULL, -+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS, -+ snd_pcm_hw_rule_mulkdiv, (void*) 8, -+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS, -+ snd_pcm_hw_rule_mulkdiv, (void*) 8, -+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, -+ snd_pcm_hw_rule_div, NULL, -+ SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, -+ snd_pcm_hw_rule_mulkdiv, (void*) 1000000, -+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_TIME, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, -+ snd_pcm_hw_rule_mulkdiv, (void*) 1000000, -+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_BUFFER_TIME, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS, -+ snd_pcm_hw_rule_div, NULL, -+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -+ snd_pcm_hw_rule_div, NULL, -+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_PERIODS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -+ snd_pcm_hw_rule_mulkdiv, (void*) 8, -+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -+ snd_pcm_hw_rule_muldivk, (void*) 1000000, -+ SNDRV_PCM_HW_PARAM_PERIOD_TIME, SNDRV_PCM_HW_PARAM_RATE, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -+ snd_pcm_hw_rule_mul, NULL, -+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIODS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -+ snd_pcm_hw_rule_mulkdiv, (void*) 8, -+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -+ snd_pcm_hw_rule_muldivk, (void*) 1000000, -+ SNDRV_PCM_HW_PARAM_BUFFER_TIME, SNDRV_PCM_HW_PARAM_RATE, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -+ snd_pcm_hw_rule_muldivk, (void*) 8, -+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -+ snd_pcm_hw_rule_muldivk, (void*) 8, -+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_TIME, -+ snd_pcm_hw_rule_mulkdiv, (void*) 1000000, -+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_RATE, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_TIME, -+ snd_pcm_hw_rule_mulkdiv, (void*) 1000000, -+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_RATE, -1); -+ if (err < 0) -+ return err; -+ return 0; -+} -+ -+int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct snd_pcm_hardware *hw = &runtime->hw; -+ int err; -+ unsigned int mask = 0; -+ -+ if (hw->info & SNDRV_PCM_INFO_INTERLEAVED) -+ mask |= 1 << SNDRV_PCM_ACCESS_RW_INTERLEAVED; -+ if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED) -+ mask |= 1 << SNDRV_PCM_ACCESS_RW_NONINTERLEAVED; -+ if (hw->info & SNDRV_PCM_INFO_MMAP) { -+ if (hw->info & SNDRV_PCM_INFO_INTERLEAVED) -+ mask |= 1 << SNDRV_PCM_ACCESS_MMAP_INTERLEAVED; -+ if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED) -+ mask |= 1 << SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED; -+ if (hw->info & SNDRV_PCM_INFO_COMPLEX) -+ mask |= 1 << SNDRV_PCM_ACCESS_MMAP_COMPLEX; -+ } -+ err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_ACCESS, mask); -+ snd_assert(err >= 0, return -EINVAL); -+ -+ err = snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT, hw->formats); -+ snd_assert(err >= 0, return -EINVAL); -+ -+ err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT, 1 << SNDRV_PCM_SUBFORMAT_STD); -+ snd_assert(err >= 0, return -EINVAL); -+ -+ err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, -+ hw->channels_min, hw->channels_max); -+ snd_assert(err >= 0, return -EINVAL); -+ -+ err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE, -+ hw->rate_min, hw->rate_max); -+ snd_assert(err >= 0, return -EINVAL); -+ -+ err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -+ hw->period_bytes_min, hw->period_bytes_max); -+ snd_assert(err >= 0, return -EINVAL); -+ -+ err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIODS, -+ hw->periods_min, hw->periods_max); -+ snd_assert(err >= 0, return -EINVAL); -+ -+ err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -+ hw->period_bytes_min, hw->buffer_bytes_max); -+ snd_assert(err >= 0, return -EINVAL); -+ -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -+ snd_pcm_hw_rule_buffer_bytes_max, substream, -+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -1); -+ if (err < 0) -+ return err; -+ -+ /* FIXME: remove */ -+ if (runtime->dma_bytes) { -+ err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, runtime->dma_bytes); -+ snd_assert(err >= 0, return -EINVAL); -+ } -+ -+ if (!(hw->rates & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))) { -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, -+ snd_pcm_hw_rule_rate, hw, -+ SNDRV_PCM_HW_PARAM_RATE, -1); -+ if (err < 0) -+ return err; -+ } -+ -+ /* FIXME: this belong to lowlevel */ -+ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_TICK_TIME, -+ 1000000 / HZ, 1000000 / HZ); -+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); -+ -+ return 0; -+} -+ -+static void pcm_release_private(struct snd_pcm_substream *substream) -+{ -+ snd_pcm_unlink(substream); -+} -+ -+void snd_pcm_release_substream(struct snd_pcm_substream *substream) -+{ -+ substream->ref_count--; -+ if (substream->ref_count > 0) -+ return; -+ -+ snd_pcm_drop(substream); -+ if (substream->hw_opened) { -+ if (substream->ops->hw_free != NULL) -+ substream->ops->hw_free(substream); -+ substream->ops->close(substream); -+ substream->hw_opened = 0; -+ } -+ if (substream->pcm_release) { -+ substream->pcm_release(substream); -+ substream->pcm_release = NULL; -+ } -+ snd_pcm_detach_substream(substream); -+} -+ -+EXPORT_SYMBOL(snd_pcm_release_substream); -+ -+int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, -+ struct file *file, -+ struct snd_pcm_substream **rsubstream) -+{ -+ struct snd_pcm_substream *substream; -+ int err; -+ -+ err = snd_pcm_attach_substream(pcm, stream, file, &substream); -+ if (err < 0) -+ return err; -+ if (substream->ref_count > 1) { -+ *rsubstream = substream; -+ return 0; -+ } -+ -+ err = snd_pcm_hw_constraints_init(substream); -+ if (err < 0) { -+ snd_printd("snd_pcm_hw_constraints_init failed\n"); -+ goto error; -+ } -+ -+ if ((err = substream->ops->open(substream)) < 0) -+ goto error; -+ -+ substream->hw_opened = 1; -+ -+ err = snd_pcm_hw_constraints_complete(substream); -+ if (err < 0) { -+ snd_printd("snd_pcm_hw_constraints_complete failed\n"); -+ goto error; -+ } -+ -+ *rsubstream = substream; -+ return 0; -+ -+ error: -+ snd_pcm_release_substream(substream); -+ return err; -+} -+ -+EXPORT_SYMBOL(snd_pcm_open_substream); -+ -+static int snd_pcm_open_file(struct file *file, -+ struct snd_pcm *pcm, -+ int stream, -+ struct snd_pcm_file **rpcm_file) -+{ -+ struct snd_pcm_file *pcm_file; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_str *str; -+ int err; -+ -+ snd_assert(rpcm_file != NULL, return -EINVAL); -+ *rpcm_file = NULL; -+ -+ err = snd_pcm_open_substream(pcm, stream, file, &substream); -+ if (err < 0) -+ return err; -+ -+ pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL); -+ if (pcm_file == NULL) { -+ snd_pcm_release_substream(substream); -+ return -ENOMEM; -+ } -+ pcm_file->substream = substream; -+ if (substream->ref_count == 1) { -+ str = substream->pstr; -+ substream->file = pcm_file; -+ substream->pcm_release = pcm_release_private; -+ } -+ file->private_data = pcm_file; -+ *rpcm_file = pcm_file; -+ return 0; -+} -+ -+static int snd_pcm_playback_open(struct inode *inode, struct file *file) -+{ -+ struct snd_pcm *pcm; -+ -+ pcm = snd_lookup_minor_data(iminor(inode), -+ SNDRV_DEVICE_TYPE_PCM_PLAYBACK); -+ return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK); -+} -+ -+static int snd_pcm_capture_open(struct inode *inode, struct file *file) -+{ -+ struct snd_pcm *pcm; -+ -+ pcm = snd_lookup_minor_data(iminor(inode), -+ SNDRV_DEVICE_TYPE_PCM_CAPTURE); -+ return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE); -+} -+ -+static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream) -+{ -+ int err; -+ struct snd_pcm_file *pcm_file; -+ wait_queue_t wait; -+ -+ if (pcm == NULL) { -+ err = -ENODEV; -+ goto __error1; -+ } -+ err = snd_card_file_add(pcm->card, file); -+ if (err < 0) -+ goto __error1; -+ if (!try_module_get(pcm->card->module)) { -+ err = -EFAULT; -+ goto __error2; -+ } -+ init_waitqueue_entry(&wait, current); -+ add_wait_queue(&pcm->open_wait, &wait); -+ mutex_lock(&pcm->open_mutex); -+ while (1) { -+ err = snd_pcm_open_file(file, pcm, stream, &pcm_file); -+ if (err >= 0) -+ break; -+ if (err == -EAGAIN) { -+ if (file->f_flags & O_NONBLOCK) { -+ err = -EBUSY; -+ break; -+ } -+ } else -+ break; -+ set_current_state(TASK_INTERRUPTIBLE); -+ mutex_unlock(&pcm->open_mutex); -+ schedule(); -+ mutex_lock(&pcm->open_mutex); -+ if (signal_pending(current)) { -+ err = -ERESTARTSYS; -+ break; -+ } -+ } -+ remove_wait_queue(&pcm->open_wait, &wait); -+ mutex_unlock(&pcm->open_mutex); -+ if (err < 0) -+ goto __error; -+ return err; -+ -+ __error: -+ module_put(pcm->card->module); -+ __error2: -+ snd_card_file_remove(pcm->card, file); -+ __error1: -+ return err; -+} -+ -+static int snd_pcm_release(struct inode *inode, struct file *file) -+{ -+ struct snd_pcm *pcm; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_file *pcm_file; -+ -+ pcm_file = file->private_data; -+ substream = pcm_file->substream; -+ snd_assert(substream != NULL, return -ENXIO); -+ pcm = substream->pcm; -+ fasync_helper(-1, file, 0, &substream->runtime->fasync); -+ mutex_lock(&pcm->open_mutex); -+ snd_pcm_release_substream(substream); -+ kfree(pcm_file); -+ mutex_unlock(&pcm->open_mutex); -+ wake_up(&pcm->open_wait); -+ module_put(pcm->card->module); -+ snd_card_file_remove(pcm->card, file); -+ return 0; -+} -+ -+static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream, -+ snd_pcm_uframes_t frames) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_sframes_t appl_ptr; -+ snd_pcm_sframes_t ret; -+ snd_pcm_sframes_t hw_avail; -+ -+ if (frames == 0) -+ return 0; -+ -+ snd_pcm_stream_lock_irq(substream); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_PREPARED: -+ break; -+ case SNDRV_PCM_STATE_DRAINING: -+ case SNDRV_PCM_STATE_RUNNING: -+ if (snd_pcm_update_hw_ptr(substream) >= 0) -+ break; -+ /* Fall through */ -+ case SNDRV_PCM_STATE_XRUN: -+ ret = -EPIPE; -+ goto __end; -+ default: -+ ret = -EBADFD; -+ goto __end; -+ } -+ -+ hw_avail = snd_pcm_playback_hw_avail(runtime); -+ if (hw_avail <= 0) { -+ ret = 0; -+ goto __end; -+ } -+ if (frames > (snd_pcm_uframes_t)hw_avail) -+ frames = hw_avail; -+ else -+ frames -= frames % runtime->xfer_align; -+ appl_ptr = runtime->control->appl_ptr - frames; -+ if (appl_ptr < 0) -+ appl_ptr += runtime->boundary; -+ runtime->control->appl_ptr = appl_ptr; -+ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && -+ runtime->sleep_min) -+ snd_pcm_tick_prepare(substream); -+ ret = frames; -+ __end: -+ snd_pcm_stream_unlock_irq(substream); -+ return ret; -+} -+ -+static snd_pcm_sframes_t snd_pcm_capture_rewind(struct snd_pcm_substream *substream, -+ snd_pcm_uframes_t frames) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_sframes_t appl_ptr; -+ snd_pcm_sframes_t ret; -+ snd_pcm_sframes_t hw_avail; -+ -+ if (frames == 0) -+ return 0; -+ -+ snd_pcm_stream_lock_irq(substream); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_PREPARED: -+ case SNDRV_PCM_STATE_DRAINING: -+ break; -+ case SNDRV_PCM_STATE_RUNNING: -+ if (snd_pcm_update_hw_ptr(substream) >= 0) -+ break; -+ /* Fall through */ -+ case SNDRV_PCM_STATE_XRUN: -+ ret = -EPIPE; -+ goto __end; -+ default: -+ ret = -EBADFD; -+ goto __end; -+ } -+ -+ hw_avail = snd_pcm_capture_hw_avail(runtime); -+ if (hw_avail <= 0) { -+ ret = 0; -+ goto __end; -+ } -+ if (frames > (snd_pcm_uframes_t)hw_avail) -+ frames = hw_avail; -+ else -+ frames -= frames % runtime->xfer_align; -+ appl_ptr = runtime->control->appl_ptr - frames; -+ if (appl_ptr < 0) -+ appl_ptr += runtime->boundary; -+ runtime->control->appl_ptr = appl_ptr; -+ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && -+ runtime->sleep_min) -+ snd_pcm_tick_prepare(substream); -+ ret = frames; -+ __end: -+ snd_pcm_stream_unlock_irq(substream); -+ return ret; -+} -+ -+static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *substream, -+ snd_pcm_uframes_t frames) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_sframes_t appl_ptr; -+ snd_pcm_sframes_t ret; -+ snd_pcm_sframes_t avail; -+ -+ if (frames == 0) -+ return 0; -+ -+ snd_pcm_stream_lock_irq(substream); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_PREPARED: -+ case SNDRV_PCM_STATE_PAUSED: -+ break; -+ case SNDRV_PCM_STATE_DRAINING: -+ case SNDRV_PCM_STATE_RUNNING: -+ if (snd_pcm_update_hw_ptr(substream) >= 0) -+ break; -+ /* Fall through */ -+ case SNDRV_PCM_STATE_XRUN: -+ ret = -EPIPE; -+ goto __end; -+ default: -+ ret = -EBADFD; -+ goto __end; -+ } -+ -+ avail = snd_pcm_playback_avail(runtime); -+ if (avail <= 0) { -+ ret = 0; -+ goto __end; -+ } -+ if (frames > (snd_pcm_uframes_t)avail) -+ frames = avail; -+ else -+ frames -= frames % runtime->xfer_align; -+ appl_ptr = runtime->control->appl_ptr + frames; -+ if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) -+ appl_ptr -= runtime->boundary; -+ runtime->control->appl_ptr = appl_ptr; -+ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && -+ runtime->sleep_min) -+ snd_pcm_tick_prepare(substream); -+ ret = frames; -+ __end: -+ snd_pcm_stream_unlock_irq(substream); -+ return ret; -+} -+ -+static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *substream, -+ snd_pcm_uframes_t frames) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_sframes_t appl_ptr; -+ snd_pcm_sframes_t ret; -+ snd_pcm_sframes_t avail; -+ -+ if (frames == 0) -+ return 0; -+ -+ snd_pcm_stream_lock_irq(substream); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_PREPARED: -+ case SNDRV_PCM_STATE_DRAINING: -+ case SNDRV_PCM_STATE_PAUSED: -+ break; -+ case SNDRV_PCM_STATE_RUNNING: -+ if (snd_pcm_update_hw_ptr(substream) >= 0) -+ break; -+ /* Fall through */ -+ case SNDRV_PCM_STATE_XRUN: -+ ret = -EPIPE; -+ goto __end; -+ default: -+ ret = -EBADFD; -+ goto __end; -+ } -+ -+ avail = snd_pcm_capture_avail(runtime); -+ if (avail <= 0) { -+ ret = 0; -+ goto __end; -+ } -+ if (frames > (snd_pcm_uframes_t)avail) -+ frames = avail; -+ else -+ frames -= frames % runtime->xfer_align; -+ appl_ptr = runtime->control->appl_ptr + frames; -+ if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) -+ appl_ptr -= runtime->boundary; -+ runtime->control->appl_ptr = appl_ptr; -+ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && -+ runtime->sleep_min) -+ snd_pcm_tick_prepare(substream); -+ ret = frames; -+ __end: -+ snd_pcm_stream_unlock_irq(substream); -+ return ret; -+} -+ -+static int snd_pcm_hwsync(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ int err; -+ -+ snd_pcm_stream_lock_irq(substream); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_DRAINING: -+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) -+ goto __badfd; -+ case SNDRV_PCM_STATE_RUNNING: -+ if ((err = snd_pcm_update_hw_ptr(substream)) < 0) -+ break; -+ /* Fall through */ -+ case SNDRV_PCM_STATE_PREPARED: -+ case SNDRV_PCM_STATE_SUSPENDED: -+ err = 0; -+ break; -+ case SNDRV_PCM_STATE_XRUN: -+ err = -EPIPE; -+ break; -+ default: -+ __badfd: -+ err = -EBADFD; -+ break; -+ } -+ snd_pcm_stream_unlock_irq(substream); -+ return err; -+} -+ -+static int snd_pcm_delay(struct snd_pcm_substream *substream, -+ snd_pcm_sframes_t __user *res) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ int err; -+ snd_pcm_sframes_t n = 0; -+ -+ snd_pcm_stream_lock_irq(substream); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_DRAINING: -+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) -+ goto __badfd; -+ case SNDRV_PCM_STATE_RUNNING: -+ if ((err = snd_pcm_update_hw_ptr(substream)) < 0) -+ break; -+ /* Fall through */ -+ case SNDRV_PCM_STATE_PREPARED: -+ case SNDRV_PCM_STATE_SUSPENDED: -+ err = 0; -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -+ n = snd_pcm_playback_hw_avail(runtime); -+ else -+ n = snd_pcm_capture_avail(runtime); -+ break; -+ case SNDRV_PCM_STATE_XRUN: -+ err = -EPIPE; -+ break; -+ default: -+ __badfd: -+ err = -EBADFD; -+ break; -+ } -+ snd_pcm_stream_unlock_irq(substream); -+ if (!err) -+ if (put_user(n, res)) -+ err = -EFAULT; -+ return err; -+} -+ -+static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, -+ struct snd_pcm_sync_ptr __user *_sync_ptr) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct snd_pcm_sync_ptr sync_ptr; -+ volatile struct snd_pcm_mmap_status *status; -+ volatile struct snd_pcm_mmap_control *control; -+ int err; -+ -+ memset(&sync_ptr, 0, sizeof(sync_ptr)); -+ if (get_user(sync_ptr.flags, (unsigned __user *)&(_sync_ptr->flags))) -+ return -EFAULT; -+ if (copy_from_user(&sync_ptr.c.control, &(_sync_ptr->c.control), sizeof(struct snd_pcm_mmap_control))) -+ return -EFAULT; -+ status = runtime->status; -+ control = runtime->control; -+ if (sync_ptr.flags & SNDRV_PCM_SYNC_PTR_HWSYNC) { -+ err = snd_pcm_hwsync(substream); -+ if (err < 0) -+ return err; -+ } -+ snd_pcm_stream_lock_irq(substream); -+ if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) -+ control->appl_ptr = sync_ptr.c.control.appl_ptr; -+ else -+ sync_ptr.c.control.appl_ptr = control->appl_ptr; -+ if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) -+ control->avail_min = sync_ptr.c.control.avail_min; -+ else -+ sync_ptr.c.control.avail_min = control->avail_min; -+ sync_ptr.s.status.state = status->state; -+ sync_ptr.s.status.hw_ptr = status->hw_ptr; -+ sync_ptr.s.status.tstamp = status->tstamp; -+ sync_ptr.s.status.suspended_state = status->suspended_state; -+ snd_pcm_stream_unlock_irq(substream); -+ if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr))) -+ return -EFAULT; -+ return 0; -+} -+ -+static int snd_pcm_common_ioctl1(struct file *file, -+ struct snd_pcm_substream *substream, -+ unsigned int cmd, void __user *arg) -+{ -+ snd_assert(substream != NULL, return -ENXIO); -+ -+ switch (cmd) { -+ case SNDRV_PCM_IOCTL_PVERSION: -+ return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0; -+ case SNDRV_PCM_IOCTL_INFO: -+ return snd_pcm_info_user(substream, arg); -+ case SNDRV_PCM_IOCTL_TSTAMP: /* just for compatibility */ -+ return 0; -+ case SNDRV_PCM_IOCTL_HW_REFINE: -+ return snd_pcm_hw_refine_user(substream, arg); -+ case SNDRV_PCM_IOCTL_HW_PARAMS: -+ return snd_pcm_hw_params_user(substream, arg); -+ case SNDRV_PCM_IOCTL_HW_FREE: -+ return snd_pcm_hw_free(substream); -+ case SNDRV_PCM_IOCTL_SW_PARAMS: -+ return snd_pcm_sw_params_user(substream, arg); -+ case SNDRV_PCM_IOCTL_STATUS: -+ return snd_pcm_status_user(substream, arg); -+ case SNDRV_PCM_IOCTL_CHANNEL_INFO: -+ return snd_pcm_channel_info_user(substream, arg); -+ case SNDRV_PCM_IOCTL_PREPARE: -+ return snd_pcm_prepare(substream, file); -+ case SNDRV_PCM_IOCTL_RESET: -+ return snd_pcm_reset(substream); -+ case SNDRV_PCM_IOCTL_START: -+ return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING); -+ case SNDRV_PCM_IOCTL_LINK: -+ return snd_pcm_link(substream, (int)(unsigned long) arg); -+ case SNDRV_PCM_IOCTL_UNLINK: -+ return snd_pcm_unlink(substream); -+ case SNDRV_PCM_IOCTL_RESUME: -+ return snd_pcm_resume(substream); -+ case SNDRV_PCM_IOCTL_XRUN: -+ return snd_pcm_xrun(substream); -+ case SNDRV_PCM_IOCTL_HWSYNC: -+ return snd_pcm_hwsync(substream); -+ case SNDRV_PCM_IOCTL_DELAY: -+ return snd_pcm_delay(substream, arg); -+ case SNDRV_PCM_IOCTL_SYNC_PTR: -+ return snd_pcm_sync_ptr(substream, arg); -+#ifdef CONFIG_SND_SUPPORT_OLD_API -+ case SNDRV_PCM_IOCTL_HW_REFINE_OLD: -+ return snd_pcm_hw_refine_old_user(substream, arg); -+ case SNDRV_PCM_IOCTL_HW_PARAMS_OLD: -+ return snd_pcm_hw_params_old_user(substream, arg); -+#endif -+ case SNDRV_PCM_IOCTL_DRAIN: -+ return snd_pcm_drain(substream); -+ case SNDRV_PCM_IOCTL_DROP: -+ return snd_pcm_drop(substream); -+ case SNDRV_PCM_IOCTL_PAUSE: -+ { -+ int res; -+ snd_pcm_stream_lock_irq(substream); -+ res = snd_pcm_pause(substream, (int)(unsigned long)arg); -+ snd_pcm_stream_unlock_irq(substream); -+ return res; -+ } -+ } -+ snd_printd("unknown ioctl = 0x%x\n", cmd); -+ return -ENOTTY; -+} -+ -+static int snd_pcm_playback_ioctl1(struct file *file, -+ struct snd_pcm_substream *substream, -+ unsigned int cmd, void __user *arg) -+{ -+ snd_assert(substream != NULL, return -ENXIO); -+ snd_assert(substream->stream == SNDRV_PCM_STREAM_PLAYBACK, return -EINVAL); -+ switch (cmd) { -+ case SNDRV_PCM_IOCTL_WRITEI_FRAMES: -+ { -+ struct snd_xferi xferi; -+ struct snd_xferi __user *_xferi = arg; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_sframes_t result; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) -+ return -EBADFD; -+ if (put_user(0, &_xferi->result)) -+ return -EFAULT; -+ if (copy_from_user(&xferi, _xferi, sizeof(xferi))) -+ return -EFAULT; -+ result = snd_pcm_lib_write(substream, xferi.buf, xferi.frames); -+ __put_user(result, &_xferi->result); -+ return result < 0 ? result : 0; -+ } -+ case SNDRV_PCM_IOCTL_WRITEN_FRAMES: -+ { -+ struct snd_xfern xfern; -+ struct snd_xfern __user *_xfern = arg; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ void __user **bufs; -+ snd_pcm_sframes_t result; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) -+ return -EBADFD; -+ if (runtime->channels > 128) -+ return -EINVAL; -+ if (put_user(0, &_xfern->result)) -+ return -EFAULT; -+ if (copy_from_user(&xfern, _xfern, sizeof(xfern))) -+ return -EFAULT; -+ bufs = kmalloc(sizeof(void *) * runtime->channels, GFP_KERNEL); -+ if (bufs == NULL) -+ return -ENOMEM; -+ if (copy_from_user(bufs, xfern.bufs, sizeof(void *) * runtime->channels)) { -+ kfree(bufs); -+ return -EFAULT; -+ } -+ result = snd_pcm_lib_writev(substream, bufs, xfern.frames); -+ kfree(bufs); -+ __put_user(result, &_xfern->result); -+ return result < 0 ? result : 0; -+ } -+ case SNDRV_PCM_IOCTL_REWIND: -+ { -+ snd_pcm_uframes_t frames; -+ snd_pcm_uframes_t __user *_frames = arg; -+ snd_pcm_sframes_t result; -+ if (get_user(frames, _frames)) -+ return -EFAULT; -+ if (put_user(0, _frames)) -+ return -EFAULT; -+ result = snd_pcm_playback_rewind(substream, frames); -+ __put_user(result, _frames); -+ return result < 0 ? result : 0; -+ } -+ case SNDRV_PCM_IOCTL_FORWARD: -+ { -+ snd_pcm_uframes_t frames; -+ snd_pcm_uframes_t __user *_frames = arg; -+ snd_pcm_sframes_t result; -+ if (get_user(frames, _frames)) -+ return -EFAULT; -+ if (put_user(0, _frames)) -+ return -EFAULT; -+ result = snd_pcm_playback_forward(substream, frames); -+ __put_user(result, _frames); -+ return result < 0 ? result : 0; -+ } -+ } -+ return snd_pcm_common_ioctl1(file, substream, cmd, arg); -+} -+ -+static int snd_pcm_capture_ioctl1(struct file *file, -+ struct snd_pcm_substream *substream, -+ unsigned int cmd, void __user *arg) -+{ -+ snd_assert(substream != NULL, return -ENXIO); -+ snd_assert(substream->stream == SNDRV_PCM_STREAM_CAPTURE, return -EINVAL); -+ switch (cmd) { -+ case SNDRV_PCM_IOCTL_READI_FRAMES: -+ { -+ struct snd_xferi xferi; -+ struct snd_xferi __user *_xferi = arg; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_sframes_t result; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) -+ return -EBADFD; -+ if (put_user(0, &_xferi->result)) -+ return -EFAULT; -+ if (copy_from_user(&xferi, _xferi, sizeof(xferi))) -+ return -EFAULT; -+ result = snd_pcm_lib_read(substream, xferi.buf, xferi.frames); -+ __put_user(result, &_xferi->result); -+ return result < 0 ? result : 0; -+ } -+ case SNDRV_PCM_IOCTL_READN_FRAMES: -+ { -+ struct snd_xfern xfern; -+ struct snd_xfern __user *_xfern = arg; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ void *bufs; -+ snd_pcm_sframes_t result; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) -+ return -EBADFD; -+ if (runtime->channels > 128) -+ return -EINVAL; -+ if (put_user(0, &_xfern->result)) -+ return -EFAULT; -+ if (copy_from_user(&xfern, _xfern, sizeof(xfern))) -+ return -EFAULT; -+ bufs = kmalloc(sizeof(void *) * runtime->channels, GFP_KERNEL); -+ if (bufs == NULL) -+ return -ENOMEM; -+ if (copy_from_user(bufs, xfern.bufs, sizeof(void *) * runtime->channels)) { -+ kfree(bufs); -+ return -EFAULT; -+ } -+ result = snd_pcm_lib_readv(substream, bufs, xfern.frames); -+ kfree(bufs); -+ __put_user(result, &_xfern->result); -+ return result < 0 ? result : 0; -+ } -+ case SNDRV_PCM_IOCTL_REWIND: -+ { -+ snd_pcm_uframes_t frames; -+ snd_pcm_uframes_t __user *_frames = arg; -+ snd_pcm_sframes_t result; -+ if (get_user(frames, _frames)) -+ return -EFAULT; -+ if (put_user(0, _frames)) -+ return -EFAULT; -+ result = snd_pcm_capture_rewind(substream, frames); -+ __put_user(result, _frames); -+ return result < 0 ? result : 0; -+ } -+ case SNDRV_PCM_IOCTL_FORWARD: -+ { -+ snd_pcm_uframes_t frames; -+ snd_pcm_uframes_t __user *_frames = arg; -+ snd_pcm_sframes_t result; -+ if (get_user(frames, _frames)) -+ return -EFAULT; -+ if (put_user(0, _frames)) -+ return -EFAULT; -+ result = snd_pcm_capture_forward(substream, frames); -+ __put_user(result, _frames); -+ return result < 0 ? result : 0; -+ } -+ } -+ return snd_pcm_common_ioctl1(file, substream, cmd, arg); -+} -+ -+static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ struct snd_pcm_file *pcm_file; -+ -+ pcm_file = file->private_data; -+ -+ if (((cmd >> 8) & 0xff) != 'A') -+ return -ENOTTY; -+ -+ return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd, -+ (void __user *)arg); -+} -+ -+static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ struct snd_pcm_file *pcm_file; -+ -+ pcm_file = file->private_data; -+ -+ if (((cmd >> 8) & 0xff) != 'A') -+ return -ENOTTY; -+ -+ return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd, -+ (void __user *)arg); -+} -+ -+int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, -+ unsigned int cmd, void *arg) -+{ -+ mm_segment_t fs; -+ int result; -+ -+ fs = snd_enter_user(); -+ switch (substream->stream) { -+ case SNDRV_PCM_STREAM_PLAYBACK: -+ result = snd_pcm_playback_ioctl1(NULL, substream, cmd, -+ (void __user *)arg); -+ break; -+ case SNDRV_PCM_STREAM_CAPTURE: -+ result = snd_pcm_capture_ioctl1(NULL, substream, cmd, -+ (void __user *)arg); -+ break; -+ default: -+ result = -EINVAL; -+ break; -+ } -+ snd_leave_user(fs); -+ return result; -+} -+ -+EXPORT_SYMBOL(snd_pcm_kernel_ioctl); -+ -+static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, -+ loff_t * offset) -+{ -+ struct snd_pcm_file *pcm_file; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_runtime *runtime; -+ snd_pcm_sframes_t result; -+ -+ pcm_file = file->private_data; -+ substream = pcm_file->substream; -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) -+ return -EBADFD; -+ if (!frame_aligned(runtime, count)) -+ return -EINVAL; -+ count = bytes_to_frames(runtime, count); -+ result = snd_pcm_lib_read(substream, buf, count); -+ if (result > 0) -+ result = frames_to_bytes(runtime, result); -+ return result; -+} -+ -+static ssize_t snd_pcm_write(struct file *file, const char __user *buf, -+ size_t count, loff_t * offset) -+{ -+ struct snd_pcm_file *pcm_file; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_runtime *runtime; -+ snd_pcm_sframes_t result; -+ -+ pcm_file = file->private_data; -+ substream = pcm_file->substream; -+ snd_assert(substream != NULL, result = -ENXIO; goto end); -+ runtime = substream->runtime; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { -+ result = -EBADFD; -+ goto end; -+ } -+ if (!frame_aligned(runtime, count)) { -+ result = -EINVAL; -+ goto end; -+ } -+ count = bytes_to_frames(runtime, count); -+ result = snd_pcm_lib_write(substream, buf, count); -+ if (result > 0) -+ result = frames_to_bytes(runtime, result); -+ end: -+ return result; -+} -+ -+static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov, -+ unsigned long nr_segs, loff_t pos) -+ -+{ -+ struct snd_pcm_file *pcm_file; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_runtime *runtime; -+ snd_pcm_sframes_t result; -+ unsigned long i; -+ void __user **bufs; -+ snd_pcm_uframes_t frames; -+ -+ pcm_file = iocb->ki_filp->private_data; -+ substream = pcm_file->substream; -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) -+ return -EBADFD; -+ if (nr_segs > 1024 || nr_segs != runtime->channels) -+ return -EINVAL; -+ if (!frame_aligned(runtime, iov->iov_len)) -+ return -EINVAL; -+ frames = bytes_to_samples(runtime, iov->iov_len); -+ bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL); -+ if (bufs == NULL) -+ return -ENOMEM; -+ for (i = 0; i < nr_segs; ++i) -+ bufs[i] = iov[i].iov_base; -+ result = snd_pcm_lib_readv(substream, bufs, frames); -+ if (result > 0) -+ result = frames_to_bytes(runtime, result); -+ kfree(bufs); -+ return result; -+} -+ -+static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov, -+ unsigned long nr_segs, loff_t pos) -+{ -+ struct snd_pcm_file *pcm_file; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_runtime *runtime; -+ snd_pcm_sframes_t result; -+ unsigned long i; -+ void __user **bufs; -+ snd_pcm_uframes_t frames; -+ -+ pcm_file = iocb->ki_filp->private_data; -+ substream = pcm_file->substream; -+ snd_assert(substream != NULL, result = -ENXIO; goto end); -+ runtime = substream->runtime; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { -+ result = -EBADFD; -+ goto end; -+ } -+ if (nr_segs > 128 || nr_segs != runtime->channels || -+ !frame_aligned(runtime, iov->iov_len)) { -+ result = -EINVAL; -+ goto end; -+ } -+ frames = bytes_to_samples(runtime, iov->iov_len); -+ bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL); -+ if (bufs == NULL) -+ return -ENOMEM; -+ for (i = 0; i < nr_segs; ++i) -+ bufs[i] = iov[i].iov_base; -+ result = snd_pcm_lib_writev(substream, bufs, frames); -+ if (result > 0) -+ result = frames_to_bytes(runtime, result); -+ kfree(bufs); -+ end: -+ return result; -+} -+ -+static unsigned int snd_pcm_playback_poll(struct file *file, poll_table * wait) -+{ -+ struct snd_pcm_file *pcm_file; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_runtime *runtime; -+ unsigned int mask; -+ snd_pcm_uframes_t avail; -+ -+ pcm_file = file->private_data; -+ -+ substream = pcm_file->substream; -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ -+ poll_wait(file, &runtime->sleep, wait); -+ -+ snd_pcm_stream_lock_irq(substream); -+ avail = snd_pcm_playback_avail(runtime); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_RUNNING: -+ case SNDRV_PCM_STATE_PREPARED: -+ case SNDRV_PCM_STATE_PAUSED: -+ if (avail >= runtime->control->avail_min) { -+ mask = POLLOUT | POLLWRNORM; -+ break; -+ } -+ /* Fall through */ -+ case SNDRV_PCM_STATE_DRAINING: -+ mask = 0; -+ break; -+ default: -+ mask = POLLOUT | POLLWRNORM | POLLERR; -+ break; -+ } -+ snd_pcm_stream_unlock_irq(substream); -+ return mask; -+} -+ -+static unsigned int snd_pcm_capture_poll(struct file *file, poll_table * wait) -+{ -+ struct snd_pcm_file *pcm_file; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_runtime *runtime; -+ unsigned int mask; -+ snd_pcm_uframes_t avail; -+ -+ pcm_file = file->private_data; -+ -+ substream = pcm_file->substream; -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ -+ poll_wait(file, &runtime->sleep, wait); -+ -+ snd_pcm_stream_lock_irq(substream); -+ avail = snd_pcm_capture_avail(runtime); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_RUNNING: -+ case SNDRV_PCM_STATE_PREPARED: -+ case SNDRV_PCM_STATE_PAUSED: -+ if (avail >= runtime->control->avail_min) { -+ mask = POLLIN | POLLRDNORM; -+ break; -+ } -+ mask = 0; -+ break; -+ case SNDRV_PCM_STATE_DRAINING: -+ if (avail > 0) { -+ mask = POLLIN | POLLRDNORM; -+ break; -+ } -+ /* Fall through */ -+ default: -+ mask = POLLIN | POLLRDNORM | POLLERR; -+ break; -+ } -+ snd_pcm_stream_unlock_irq(substream); -+ return mask; -+} -+ -+/* -+ * mmap support -+ */ -+ -+/* -+ * Only on coherent architectures, we can mmap the status and the control records -+ * for effcient data transfer. On others, we have to use HWSYNC ioctl... -+ */ -+#if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_ALPHA) -+/* -+ * mmap status record -+ */ -+static struct page * snd_pcm_mmap_status_nopage(struct vm_area_struct *area, -+ unsigned long address, int *type) -+{ -+ struct snd_pcm_substream *substream = area->vm_private_data; -+ struct snd_pcm_runtime *runtime; -+ struct page * page; -+ -+ if (substream == NULL) -+ return NOPAGE_SIGBUS; -+ runtime = substream->runtime; -+ page = virt_to_page(runtime->status); -+ get_page(page); -+ if (type) -+ *type = VM_FAULT_MINOR; -+ return page; -+} -+ -+static struct vm_operations_struct snd_pcm_vm_ops_status = -+{ -+ .nopage = snd_pcm_mmap_status_nopage, -+}; -+ -+static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file, -+ struct vm_area_struct *area) -+{ -+ struct snd_pcm_runtime *runtime; -+ long size; -+ if (!(area->vm_flags & VM_READ)) -+ return -EINVAL; -+ runtime = substream->runtime; -+ snd_assert(runtime != NULL, return -EAGAIN); -+ size = area->vm_end - area->vm_start; -+ if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status))) -+ return -EINVAL; -+ area->vm_ops = &snd_pcm_vm_ops_status; -+ area->vm_private_data = substream; -+ area->vm_flags |= VM_RESERVED; -+ return 0; -+} -+ -+/* -+ * mmap control record -+ */ -+static struct page * snd_pcm_mmap_control_nopage(struct vm_area_struct *area, -+ unsigned long address, int *type) -+{ -+ struct snd_pcm_substream *substream = area->vm_private_data; -+ struct snd_pcm_runtime *runtime; -+ struct page * page; -+ -+ if (substream == NULL) -+ return NOPAGE_SIGBUS; -+ runtime = substream->runtime; -+ page = virt_to_page(runtime->control); -+ get_page(page); -+ if (type) -+ *type = VM_FAULT_MINOR; -+ return page; -+} -+ -+static struct vm_operations_struct snd_pcm_vm_ops_control = -+{ -+ .nopage = snd_pcm_mmap_control_nopage, -+}; -+ -+static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file, -+ struct vm_area_struct *area) -+{ -+ struct snd_pcm_runtime *runtime; -+ long size; -+ if (!(area->vm_flags & VM_READ)) -+ return -EINVAL; -+ runtime = substream->runtime; -+ snd_assert(runtime != NULL, return -EAGAIN); -+ size = area->vm_end - area->vm_start; -+ if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))) -+ return -EINVAL; -+ area->vm_ops = &snd_pcm_vm_ops_control; -+ area->vm_private_data = substream; -+ area->vm_flags |= VM_RESERVED; -+ return 0; -+} -+#else /* ! coherent mmap */ -+/* -+ * don't support mmap for status and control records. -+ */ -+static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file, -+ struct vm_area_struct *area) -+{ -+ return -ENXIO; -+} -+static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file, -+ struct vm_area_struct *area) -+{ -+ return -ENXIO; -+} -+#endif /* coherent mmap */ -+ -+/* -+ * nopage callback for mmapping a RAM page -+ */ -+static struct page *snd_pcm_mmap_data_nopage(struct vm_area_struct *area, -+ unsigned long address, int *type) -+{ -+ struct snd_pcm_substream *substream = area->vm_private_data; -+ struct snd_pcm_runtime *runtime; -+ unsigned long offset; -+ struct page * page; -+ void *vaddr; -+ size_t dma_bytes; -+ -+ if (substream == NULL) -+ return NOPAGE_SIGBUS; -+ runtime = substream->runtime; -+ offset = area->vm_pgoff << PAGE_SHIFT; -+ offset += address - area->vm_start; -+ snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_SIGBUS); -+ dma_bytes = PAGE_ALIGN(runtime->dma_bytes); -+ if (offset > dma_bytes - PAGE_SIZE) -+ return NOPAGE_SIGBUS; -+ if (substream->ops->page) { -+ page = substream->ops->page(substream, offset); -+ if (! page) -+ return NOPAGE_OOM; /* XXX: is this really due to OOM? */ -+ } else { -+ vaddr = runtime->dma_area + offset; -+ page = virt_to_page(vaddr); -+ } -+ get_page(page); -+ if (type) -+ *type = VM_FAULT_MINOR; -+ return page; -+} -+ -+static struct vm_operations_struct snd_pcm_vm_ops_data = -+{ -+ .open = snd_pcm_mmap_data_open, -+ .close = snd_pcm_mmap_data_close, -+ .nopage = snd_pcm_mmap_data_nopage, -+}; -+ -+/* -+ * mmap the DMA buffer on RAM -+ */ -+static int snd_pcm_default_mmap(struct snd_pcm_substream *substream, -+ struct vm_area_struct *area) -+{ -+ area->vm_ops = &snd_pcm_vm_ops_data; -+ area->vm_private_data = substream; -+ area->vm_flags |= VM_RESERVED; -+ atomic_inc(&substream->mmap_count); -+ return 0; -+} -+ -+/* -+ * mmap the DMA buffer on I/O memory area -+ */ -+#if SNDRV_PCM_INFO_MMAP_IOMEM -+static struct vm_operations_struct snd_pcm_vm_ops_data_mmio = -+{ -+ .open = snd_pcm_mmap_data_open, -+ .close = snd_pcm_mmap_data_close, -+}; -+ -+int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, -+ struct vm_area_struct *area) -+{ -+ long size; -+ unsigned long offset; -+ -+#ifdef pgprot_noncached -+ area->vm_page_prot = pgprot_noncached(area->vm_page_prot); -+#endif -+ area->vm_ops = &snd_pcm_vm_ops_data_mmio; -+ area->vm_private_data = substream; -+ area->vm_flags |= VM_IO; -+ size = area->vm_end - area->vm_start; -+ offset = area->vm_pgoff << PAGE_SHIFT; -+ if (io_remap_pfn_range(area, area->vm_start, -+ (substream->runtime->dma_addr + offset) >> PAGE_SHIFT, -+ size, area->vm_page_prot)) -+ return -EAGAIN; -+ atomic_inc(&substream->mmap_count); -+ return 0; -+} -+ -+EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); -+#endif /* SNDRV_PCM_INFO_MMAP */ -+ -+/* -+ * mmap DMA buffer -+ */ -+int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, -+ struct vm_area_struct *area) -+{ -+ struct snd_pcm_runtime *runtime; -+ long size; -+ unsigned long offset; -+ size_t dma_bytes; -+ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ if (!(area->vm_flags & (VM_WRITE|VM_READ))) -+ return -EINVAL; -+ } else { -+ if (!(area->vm_flags & VM_READ)) -+ return -EINVAL; -+ } -+ runtime = substream->runtime; -+ snd_assert(runtime != NULL, return -EAGAIN); -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) -+ return -EBADFD; -+ if (!(runtime->info & SNDRV_PCM_INFO_MMAP)) -+ return -ENXIO; -+ if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || -+ runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) -+ return -EINVAL; -+ size = area->vm_end - area->vm_start; -+ offset = area->vm_pgoff << PAGE_SHIFT; -+ dma_bytes = PAGE_ALIGN(runtime->dma_bytes); -+ if ((size_t)size > dma_bytes) -+ return -EINVAL; -+ if (offset > dma_bytes - size) -+ return -EINVAL; -+ -+ if (substream->ops->mmap) -+ return substream->ops->mmap(substream, area); -+ else -+ return snd_pcm_default_mmap(substream, area); -+} -+ -+EXPORT_SYMBOL(snd_pcm_mmap_data); -+ -+static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) -+{ -+ struct snd_pcm_file * pcm_file; -+ struct snd_pcm_substream *substream; -+ unsigned long offset; -+ -+ pcm_file = file->private_data; -+ substream = pcm_file->substream; -+ snd_assert(substream != NULL, return -ENXIO); -+ -+ offset = area->vm_pgoff << PAGE_SHIFT; -+ switch (offset) { -+ case SNDRV_PCM_MMAP_OFFSET_STATUS: -+ if (pcm_file->no_compat_mmap) -+ return -ENXIO; -+ return snd_pcm_mmap_status(substream, file, area); -+ case SNDRV_PCM_MMAP_OFFSET_CONTROL: -+ if (pcm_file->no_compat_mmap) -+ return -ENXIO; -+ return snd_pcm_mmap_control(substream, file, area); -+ default: -+ return snd_pcm_mmap_data(substream, file, area); -+ } -+ return 0; -+} -+ -+static int snd_pcm_fasync(int fd, struct file * file, int on) -+{ -+ struct snd_pcm_file * pcm_file; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_runtime *runtime; -+ int err; -+ -+ pcm_file = file->private_data; -+ substream = pcm_file->substream; -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ -+ err = fasync_helper(fd, file, on, &runtime->fasync); -+ if (err < 0) -+ return err; -+ return 0; -+} -+ -+/* -+ * ioctl32 compat -+ */ -+#ifdef CONFIG_COMPAT -+#include "pcm_compat.c" -+#else -+#define snd_pcm_ioctl_compat NULL -+#endif -+ -+/* -+ * To be removed helpers to keep binary compatibility -+ */ -+ -+#ifdef CONFIG_SND_SUPPORT_OLD_API -+#define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5)) -+#define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5)) -+ -+static void snd_pcm_hw_convert_from_old_params(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_params_old *oparams) -+{ -+ unsigned int i; -+ -+ memset(params, 0, sizeof(*params)); -+ params->flags = oparams->flags; -+ for (i = 0; i < ARRAY_SIZE(oparams->masks); i++) -+ params->masks[i].bits[0] = oparams->masks[i]; -+ memcpy(params->intervals, oparams->intervals, sizeof(oparams->intervals)); -+ params->rmask = __OLD_TO_NEW_MASK(oparams->rmask); -+ params->cmask = __OLD_TO_NEW_MASK(oparams->cmask); -+ params->info = oparams->info; -+ params->msbits = oparams->msbits; -+ params->rate_num = oparams->rate_num; -+ params->rate_den = oparams->rate_den; -+ params->fifo_size = oparams->fifo_size; -+} -+ -+static void snd_pcm_hw_convert_to_old_params(struct snd_pcm_hw_params_old *oparams, -+ struct snd_pcm_hw_params *params) -+{ -+ unsigned int i; -+ -+ memset(oparams, 0, sizeof(*oparams)); -+ oparams->flags = params->flags; -+ for (i = 0; i < ARRAY_SIZE(oparams->masks); i++) -+ oparams->masks[i] = params->masks[i].bits[0]; -+ memcpy(oparams->intervals, params->intervals, sizeof(oparams->intervals)); -+ oparams->rmask = __NEW_TO_OLD_MASK(params->rmask); -+ oparams->cmask = __NEW_TO_OLD_MASK(params->cmask); -+ oparams->info = params->info; -+ oparams->msbits = params->msbits; -+ oparams->rate_num = params->rate_num; -+ oparams->rate_den = params->rate_den; -+ oparams->fifo_size = params->fifo_size; -+} -+ -+static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params_old __user * _oparams) -+{ -+ struct snd_pcm_hw_params *params; -+ struct snd_pcm_hw_params_old *oparams = NULL; -+ int err; -+ -+ params = kmalloc(sizeof(*params), GFP_KERNEL); -+ if (!params) { -+ err = -ENOMEM; -+ goto out; -+ } -+ oparams = kmalloc(sizeof(*oparams), GFP_KERNEL); -+ if (!oparams) { -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ if (copy_from_user(oparams, _oparams, sizeof(*oparams))) { -+ err = -EFAULT; -+ goto out; -+ } -+ snd_pcm_hw_convert_from_old_params(params, oparams); -+ err = snd_pcm_hw_refine(substream, params); -+ snd_pcm_hw_convert_to_old_params(oparams, params); -+ if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { -+ if (!err) -+ err = -EFAULT; -+ } -+out: -+ kfree(params); -+ kfree(oparams); -+ return err; -+} -+ -+static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params_old __user * _oparams) -+{ -+ struct snd_pcm_hw_params *params; -+ struct snd_pcm_hw_params_old *oparams = NULL; -+ int err; -+ -+ params = kmalloc(sizeof(*params), GFP_KERNEL); -+ if (!params) { -+ err = -ENOMEM; -+ goto out; -+ } -+ oparams = kmalloc(sizeof(*oparams), GFP_KERNEL); -+ if (!oparams) { -+ err = -ENOMEM; -+ goto out; -+ } -+ if (copy_from_user(oparams, _oparams, sizeof(*oparams))) { -+ err = -EFAULT; -+ goto out; -+ } -+ snd_pcm_hw_convert_from_old_params(params, oparams); -+ err = snd_pcm_hw_params(substream, params); -+ snd_pcm_hw_convert_to_old_params(oparams, params); -+ if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { -+ if (!err) -+ err = -EFAULT; -+ } -+out: -+ kfree(params); -+ kfree(oparams); -+ return err; -+} -+#endif /* CONFIG_SND_SUPPORT_OLD_API */ -+ -+/* -+ * Register section -+ */ -+ -+const struct file_operations snd_pcm_f_ops[2] = { -+ { -+ .owner = THIS_MODULE, -+ .write = snd_pcm_write, -+ .aio_write = snd_pcm_aio_write, -+ .open = snd_pcm_playback_open, -+ .release = snd_pcm_release, -+ .poll = snd_pcm_playback_poll, -+ .unlocked_ioctl = snd_pcm_playback_ioctl, -+ .compat_ioctl = snd_pcm_ioctl_compat, -+ .mmap = snd_pcm_mmap, -+ .fasync = snd_pcm_fasync, -+ }, -+ { -+ .owner = THIS_MODULE, -+ .read = snd_pcm_read, -+ .aio_read = snd_pcm_aio_read, -+ .open = snd_pcm_capture_open, -+ .release = snd_pcm_release, -+ .poll = snd_pcm_capture_poll, -+ .unlocked_ioctl = snd_pcm_capture_ioctl, -+ .compat_ioctl = snd_pcm_ioctl_compat, -+ .mmap = snd_pcm_mmap, -+ .fasync = snd_pcm_fasync, -+ } -+}; --- linux-2.6.24.7.old/sound/oss/Kconfig 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/sound/oss/Kconfig 2009-04-12 18:13:57.000000000 +0200 @@ -5,6 +5,91 @@ # # Prompt user for primary drivers. - + +config OSS_OBSOLETE + bool "Obsolete OSS drivers" + depends on SOUND_PRIME @@ -3561,7 +97,7 @@ + bool "TLV320AIC1106" + help + Answer Y if you have an TI tlv320aic 1106 codec. -+ ++ +endchoice + +config SOUND_BT878 @@ -3586,7 +122,7 @@ @@ -15,6 +100,13 @@ note that CONFIG_KGDB should not be enabled at the same time, since it also attempts to use this UART port. - + +config SOUND_ICH + tristate "Intel ICH (i8xx) audio support" + depends on SOUND_PRIME && PCI && OSS_OBSOLETE @@ -3600,7 +136,7 @@ @@ -31,6 +123,14 @@ Say Y or M if you have an SGI Indy or Indigo2 system and want to be able to use its on-board A2 audio system. - + +config SOUND_VRC5477 + tristate "NEC Vrc5477 AC97 sound" + depends on SOUND_PRIME && DDB5477 @@ -3612,19 +148,10 @@ config SOUND_AU1550_AC97 tristate "Au1550/Au1200 AC97 Sound" select SND_AC97_CODEC -@@ -75,7 +175,7 @@ - - - This driver differs slightly from OSS/Free, so PLEASE READ the -- comments at the top of . -+ comments at the top of . - - config SOUND_MSNDCLAS - tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey" -@@ -302,9 +402,29 @@ +@@ -253,9 +253,29 @@ and Pinnacle). Larger values reduce the chance of data overruns at the expense of overall latency. If unsure, use the default. - + +config SOUND_VIA82CXXX + tristate "VIA 82C686 Audio Codec" + depends on SOUND_PRIME && PCI && OSS_OBSOLETE @@ -3645,17 +172,17 @@ + to external MIDI hardware, and is not required for software playback + of MIDI files. + - config SOUND_OSS + menuconfig SOUND_OSS tristate "OSS sound modules" -- depends on SOUND_PRIME && ISA_DMA_API && VIRT_TO_BUS +- depends on ISA_DMA_API && VIRT_TO_BUS + depends on SOUND_PRIME && ISA_DMA_API help OSS is the Open Sound System suite of sound card drivers. They make sound programming easier since they provide a common API. Say Y or -@@ -336,10 +456,23 @@ - +@@ -336,6 +456,20 @@ + Say Y unless you have 16MB or more RAM or a PCI sound card. - + +config SOUND_CS4232 + tristate "Crystal CS4232 based (PnP) cards" + depends on SOUND_OSS && OSS_OBSOLETE @@ -3673,23 +200,10 @@ config SOUND_SSCAPE tristate "Ensoniq SoundScape support" depends on SOUND_OSS -- depends on VIRT_TO_BUS - help - Answer Y if you have a sound card based on the Ensoniq SoundScape - chipset. Such cards are being manufactured at least by Ensoniq, Spea -@@ -564,7 +697,7 @@ - questions. - - Read the file and the head of -- as well as -+ as well as - to get more information - about this driver and its configuration. - @@ -642,6 +775,13 @@ Say Y here to include support for the Rockwell WaveArtist sound system. This driver is mainly for the NetWinder. - + +config SOUND_TVMIXER + tristate "TV card (bt848) mixer support" + depends on SOUND_PRIME && I2C && VIDEO_V4L1 && OSS_OBSOLETE @@ -3703,9 +217,9 @@ --- linux-2.6.24.7.old/sound/oss/Makefile 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/sound/oss/Makefile 2009-04-12 18:13:57.000000000 +0200 @@ -10,6 +10,12 @@ - + # Please leave it as is, cause the link order is significant ! - + +obj-$(CONFIG_SOUND_JZ_AC97) += jz_ac97.o ac97_codec.o +obj-$(CONFIG_I2S_AK4642EN) += ak4642en.o +obj-$(CONFIG_I2S_ICODEC) += jzcodec.o jz_i2s.o @@ -3718,718 +232,718 @@ --- linux-2.6.24.7.old/sound/oss/ak4642en.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7/sound/oss/ak4642en.c 2009-04-12 18:13:57.000000000 +0200 @@ -0,0 +1,712 @@ -+/* -+ * linux/sound/oss/ak4642en.c -+ * -+ * AKM ak4642en codec chip driver to I2S interface -+ * -+ * Copyright (c) 2005-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Because the normal application of AUDIO devices are focused on Little_endian, -+ * then we only perform the little endian data format in driver. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "sound_config.h" -+ -+extern mixer_info info; -+extern _old_mixer_info old_info; -+extern int abnormal_data_count; -+ -+extern void (*clear_codec_mode)(void); -+extern void (*set_codec_gpio_pin)(void); -+extern void (*each_time_init_codec)(void); -+extern void (*set_codec_record)(void); -+extern void (*set_codec_replay)(void); -+extern void (*clear_codec_record)(void); -+extern void (*clear_codec_replay)(void); -+extern void (*set_codec_speed)(int range); -+extern void (*codec_mixer_old_info_id_name)(void); -+extern void (*codec_mixer_info_id_name)(void); -+extern void (*set_codec_volume)(int val); -+extern void (*set_codec_mic)(int val); -+extern void (*i2s_resume_codec)(void); -+extern void (*i2s_suspend_codec)(int wr,int rd); -+extern void (*set_replay_hp_or_speaker)(void); -+ -+#define I2S_PDN 68 -+#define JACK_PLUG_PIN 83 -+#define JACK_PLUG_IRQ (IRQ_GPIO_0 + JACK_PLUG_PIN) -+ -+static int jack_plug_level, old_level; -+static unsigned int i2c_addr = 0x26; //AK4642EN device address at I2C bus -+static unsigned int i2c_clk = 100000;//AK4642EN 400kHz max,but 100kHz here -+static unsigned int spk_hp = 0; -+static int codec_volume; -+ -+void set_ak4642en_gpio_pin(void); -+void each_time_init_ak4642en(void); -+void set_ak4642en_replay(void); -+void set_ak4642en_record(void); -+void turn_on_ak4642en(void); -+void turn_off_ak4642en(void); -+void set_ak4642en_speed(int rate); -+void reset_ak4642en(void); -+void ak4642en_mixer_old_info_id_name(void); -+void ak4642en_mixer_info_id_name(void); -+void set_ak4642en_bass(int val); -+void set_ak4642en_volume(int val); -+void set_ak4642en_mic(int val); -+void resume_ak4642en(void); -+void suspend_ak4642en(int wr,int rd); -+ -+static void write_reg(u8 reg, u8 val) -+{ -+ i2c_open(); -+ i2c_setclk(i2c_clk); -+ i2c_write((i2c_addr >> 1), &val, reg, 1); -+ i2c_close(); -+} -+ -+#if 0 -+static u8 read_reg(u8 reg) -+{ -+ u8 val; -+ i2c_open(); -+ i2c_setclk(i2c_clk); -+ i2c_read((i2c_addr >> 1), &val, reg, 1); -+ i2c_close(); -+ return val; -+} -+ -+static u16 i2s_codec_read(u8 reg) -+{ -+ u16 value; -+ value = read_reg(reg); -+ return value; -+} -+#endif -+ -+static void i2s_codec_write(u8 reg, u16 data) -+{ -+ u8 val = data & 0xff; -+ write_reg(reg, val); -+} -+ -+void set_ak4642en_gpio_pin(void) -+{ -+ //set AIC pin to I2S slave mode,only GPIO70,71,77,78 -+ __gpio_as_output(68); -+ __gpio_clear_pin(68); -+ __gpio_as_output(69); -+ __gpio_clear_pin(69); -+ __gpio_as_output(70); -+ __gpio_clear_pin(70); -+ __gpio_as_input(71); -+ __gpio_clear_pin(71); -+ __gpio_as_input(77); -+ __gpio_clear_pin(77); -+ __gpio_as_input(78); -+ __gpio_clear_pin(78); -+ REG_GPIO_GPALR(2) &= 0xC3FF0CFF; -+ REG_GPIO_GPALR(2) |= 0x14005000; -+ //set SCC clock initialization -+ REG_SCC1_CR(SCC1_BASE) = 0x00000000; -+ udelay(2); -+ REG_SCC1_CR(SCC1_BASE) |= 1 << 31; -+ udelay(2); -+ -+ __gpio_as_output(I2S_PDN); -+ __gpio_set_pin(I2S_PDN); -+ udelay(5); -+ __gpio_clear_pin(I2S_PDN); -+ ndelay(300);//>150ns -+ __gpio_set_pin(I2S_PDN); -+ mdelay(1); -+ //set PLL Master mode -+ i2s_codec_write(0x01, 0x0008);//master -+ i2s_codec_write(0x04, 0x006b);//ref:12MHz;BITCLK:64fs;I2S compli -+ i2s_codec_write(0x05, 0x000b);//sync:48KHz; -+ i2s_codec_write(0x00, 0x0040);//PMVCM -+ i2s_codec_write(0x01, 0x0009);//master,PLL enable -+ mdelay(40); -+ jack_plug_level = 10; -+ old_level = 100; -+ spk_hp = 0; -+ __gpio_disable_pull(JACK_PLUG_PIN); -+ udelay(10); -+ __gpio_as_input(JACK_PLUG_PIN); -+ jack_plug_level = __gpio_get_pin(JACK_PLUG_PIN); -+ //i suppose jack_plug_lvel is 1 indicate with HPO -+ if (jack_plug_level > 1 || jack_plug_level <0) -+ printk("Audio ak4642en codec Jack plug level is wrong!\n"); -+ if (jack_plug_level) -+ __gpio_as_irq_fall_edge(JACK_PLUG_PIN); -+ else -+ __gpio_as_irq_rise_edge(JACK_PLUG_PIN); -+} -+ -+void clear_ak4642en_mode(void) -+{ -+ spk_hp = 0; -+ i2s_codec_write(0x01, 0x0008);//master,PLL disable -+ //free_irq(JACK_PLUG_IRQ, i2s_controller); -+ __gpio_clear_pin(I2S_PDN); -+ udelay(2); -+ REG_SCC1_CR(SCC1_BASE) &= 0 << 31; -+ udelay(2); -+} -+ -+void set_ak4642en_replay(void) -+{ -+ //for poll -+ /*jack_plug_level is H for SPK,is L for HP*/ -+ jack_plug_level = __gpio_get_pin(JACK_PLUG_PIN); -+ if(old_level == jack_plug_level) -+ return; -+ old_level = jack_plug_level; -+ if(spk_hp == 1) -+ { -+ if(jack_plug_level == 1) -+ { -+ //now HeadPhone output,so clear SPK -+ i2s_codec_write(0x02, 0x0020); -+ i2s_codec_write(0x02, 0x0000); -+ i2s_codec_write(0x00, 0x0040); -+ } -+ else -+ { -+ //now Speaker output,so clear HP -+ i2s_codec_write(0x01, 0x0039); -+ i2s_codec_write(0x01, 0x0009); -+ i2s_codec_write(0x00, 0x0040); -+ i2s_codec_write(0x0e, 0x0000); -+ i2s_codec_write(0x0f, 0x0008); -+ } -+ } -+ spk_hp = 1; -+ if(jack_plug_level == 1) -+ { -+ //for HeadPhone output -+ i2s_codec_write(0x00, 0x0060); // -+ i2s_codec_write(0x0f, 0x0009); //5-10 -+ -+ i2s_codec_write(0x00, 0x0064); // -+ i2s_codec_write(0x09, 0x0091);// volume control 0dB -+ i2s_codec_write(0x0c, 0x0091);// 0dB(right) -+ //eq off -+ i2s_codec_write(0x11, 0x0000);//5-10 -+ i2s_codec_write(0x01, 0x0039); // -+ -+ i2s_codec_write(0x01, 0x0079); // -+ } -+ else -+ { -+ //for Speaker output -+ i2s_codec_write(0x00, 0x0040); -+ i2s_codec_write(0x02, 0x0020); -+ -+ i2s_codec_write(0x03, 0x0018);//5-10 -+ i2s_codec_write(0x06, 0x003c); -+ -+ i2s_codec_write(0x08, 0x00A1);//5-10 -+ -+ i2s_codec_write(0x0b, 0x0040); //5-10 -+ -+ i2s_codec_write(0x07, 0x002d); //5-10 -+ i2s_codec_write(0x09, 0x0091); -+ i2s_codec_write(0x0c, 0x0091); -+ //HP volume output value -+ -+ i2s_codec_write(0x0a, codec_volume);//5-10 -+ i2s_codec_write(0x0d, codec_volume);//5-10 -+ -+ i2s_codec_write(0x00, 0x0074); -+ i2s_codec_write(0x02, 0x00a0); -+ } -+} -+ -+void set_ak4642en_record(void) -+{ -+ abnormal_data_count = 0; -+ i2s_codec_write(0x02, 0x0004); -+ i2s_codec_write(0x03, 0x0038);// recording volume add -+ i2s_codec_write(0x06, 0x0000);//for ALC short waiting time -+ i2s_codec_write(0x08, 0x00e1); -+ i2s_codec_write(0x0b, 0x0000); -+ i2s_codec_write(0x07, 0x0021); // ALC on -+ -+ i2s_codec_write(0x10, 0x0000);//0x0001 -+ //i2s_codec_write(0x10, 0x0001);//0x0001 -+ i2s_codec_write(0x01, 0x0039); //for open pop noise -+ i2s_codec_write(0x01, 0x0079); -+ i2s_codec_write(0x00, 0x0065); -+ mdelay(300); -+} -+ -+void clear_ak4642en_replay(void) -+{ -+ //for poll -+ old_level = 100; -+ spk_hp = 0; -+ if(jack_plug_level == 1) -+ { -+ //for HeadPhone output -+ i2s_codec_write(0x01, 0x0039); // for close pop noise -+ mdelay(300); -+ i2s_codec_write(0x01, 0x0009); //PLL on I2S -+ i2s_codec_write(0x07, 0x0001); -+ i2s_codec_write(0x11, 0x0000); -+ i2s_codec_write(0x00, 0x0040); -+ i2s_codec_write(0x0f, 0x0008); // for open pop noise -+ } -+ else -+ { -+ //for Speaker output -+ i2s_codec_write(0x02, 0x0020); -+ i2s_codec_write(0x07, 0x0001); -+ i2s_codec_write(0x11, 0x0000); -+ i2s_codec_write(0x02, 0x0000); -+ i2s_codec_write(0x00, 0x0040); // for close pop noise -+ } -+} -+ -+void clear_ak4642en_record(void) -+{ -+ //for Mic input(Stereo) -+ i2s_codec_write(0x02, 0x0001); -+ i2s_codec_write(0x07, 0x0001); -+ i2s_codec_write(0x11, 0x0000); -+} -+ -+void each_time_init_ak4642en(void) -+{ -+ __i2s_disable(); -+ __i2s_as_slave(); -+ __i2s_set_sample_size(16); -+} -+ -+void set_ak4642en_speed(int rate) -+{ -+ //codec work at frequency -+ unsigned short speed = 0; -+ unsigned short val = 0; -+ switch (rate) -+ { -+ case 8000: -+ speed = 0x00; -+ if(jack_plug_level == 1) //speaker -+ { -+ i2s_codec_write(0x16, 0x0000); -+ i2s_codec_write(0x17, 0x0000); -+ i2s_codec_write(0x18, 0x0000); -+ i2s_codec_write(0x19, 0x0000); -+ i2s_codec_write(0x1A, 0x0000); -+ i2s_codec_write(0x1B, 0x0000); -+ i2s_codec_write(0x1C, 0x0027);//800hz -+ i2s_codec_write(0x1D, 0x0018); -+ i2s_codec_write(0x1E, 0x00b2); -+ i2s_codec_write(0x1F, 0x002f); -+ i2s_codec_write(0x11, 0x0010); //eq on -+ } -+ break; -+ case 12000: -+ speed = 0x01; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x0000); -+ i2s_codec_write(0x17, 0x0000); -+ i2s_codec_write(0x18, 0x0000); -+ i2s_codec_write(0x19, 0x0000); -+ i2s_codec_write(0x1A, 0x0000); -+ i2s_codec_write(0x1B, 0x0000); -+ i2s_codec_write(0x1C, 0x0064); -+ i2s_codec_write(0x1D, 0x001a); -+ i2s_codec_write(0x1E, 0x0038); -+ i2s_codec_write(0x1F, 0x002b); -+ i2s_codec_write(0x11, 0x0010); //eq on -+ } -+ break; -+ case 16000: -+ speed = 0x02; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x00af); -+ i2s_codec_write(0x17, 0x0020); -+ i2s_codec_write(0x18, 0x0043); -+ i2s_codec_write(0x19, 0x001a); -+ i2s_codec_write(0x1A, 0x00af); -+ i2s_codec_write(0x1B, 0x0020); -+ i2s_codec_write(0x1C, 0x00a0); -+ i2s_codec_write(0x1D, 0x001b); -+ i2s_codec_write(0x1E, 0x00c0); -+ i2s_codec_write(0x1F, 0x0028); -+ i2s_codec_write(0x11, 0x0018); //eq on -+ } -+ break; -+ case 24000: -+ speed = 0x03; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x0086); -+ i2s_codec_write(0x17, 0x0015); -+ i2s_codec_write(0x18, 0x005d); -+ i2s_codec_write(0x19, 0x0006); -+ i2s_codec_write(0x1A, 0x0086); -+ i2s_codec_write(0x1B, 0x0015); -+ i2s_codec_write(0x1C, 0x00f5); -+ i2s_codec_write(0x1D, 0x001c); -+ i2s_codec_write(0x1E, 0x0016); -+ i2s_codec_write(0x1F, 0x0026); -+ i2s_codec_write(0x11, 0x0018); //eq on -+ } -+ break; -+ case 7350: -+ speed = 0x04; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x0000); -+ i2s_codec_write(0x17, 0x0000); -+ i2s_codec_write(0x18, 0x0000); -+ i2s_codec_write(0x19, 0x0000); -+ i2s_codec_write(0x1A, 0x0000); -+ i2s_codec_write(0x1B, 0x0000); -+ i2s_codec_write(0x1C, 0x0027); -+ i2s_codec_write(0x1D, 0x0018); -+ i2s_codec_write(0x1E, 0x00b2); -+ i2s_codec_write(0x1F, 0x002f); -+ i2s_codec_write(0x11, 0x0010); //eq on -+ } -+ break; -+ case 11025: -+ speed = 0x05; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x0059); -+ i2s_codec_write(0x17, 0x000d); -+ i2s_codec_write(0x18, 0x00cb); -+ i2s_codec_write(0x19, 0x0037); -+ i2s_codec_write(0x1A, 0x0059); -+ i2s_codec_write(0x1B, 0x000d); -+ i2s_codec_write(0x1C, 0x0046); -+ i2s_codec_write(0x1D, 0x001e); -+ i2s_codec_write(0x1E, 0x0074); -+ i2s_codec_write(0x1F, 0x0023); -+ i2s_codec_write(0x11, 0x0018); //eq on -+ } -+ break; -+ case 14700: -+ speed = 0x06; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x0000); -+ i2s_codec_write(0x17, 0x0000); -+ i2s_codec_write(0x18, 0x0000); -+ i2s_codec_write(0x19, 0x0000); -+ i2s_codec_write(0x1A, 0x0000); -+ i2s_codec_write(0x1B, 0x0000); -+ i2s_codec_write(0x1C, 0x004a); -+ i2s_codec_write(0x1D, 0x001b); -+ i2s_codec_write(0x1E, 0x006c); -+ i2s_codec_write(0x1F, 0x0029); -+ i2s_codec_write(0x11, 0x0010); //eq on -+ } -+ break; -+ case 22050: -+ speed = 0x07; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x002d); -+ i2s_codec_write(0x17, 0x0017); -+ i2s_codec_write(0x18, 0x0050); -+ i2s_codec_write(0x19, 0x0009); -+ i2s_codec_write(0x1A, 0x002d); -+ i2s_codec_write(0x1B, 0x0017); -+ i2s_codec_write(0x1C, 0x00d7); -+ i2s_codec_write(0x1D, 0x001c); -+ i2s_codec_write(0x1E, 0x0093); -+ i2s_codec_write(0x1F, 0x0026); -+ i2s_codec_write(0x11, 0x0018); //eq on -+ } -+ break; -+ case 32000: -+ speed = 0x0a; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x0012); -+ i2s_codec_write(0x17, 0x0011); -+ i2s_codec_write(0x18, 0x006e); -+ i2s_codec_write(0x19, 0x003e); -+ i2s_codec_write(0x1A, 0x0012); -+ i2s_codec_write(0x1B, 0x0011); -+ i2s_codec_write(0x1C, 0x00aa); -+ i2s_codec_write(0x1D, 0x001d); -+ i2s_codec_write(0x1E, 0x00ab); -+ i2s_codec_write(0x1F, 0x0024); -+ i2s_codec_write(0x11, 0x0018); //eq on -+ } -+ break; -+ case 48000: -+ speed = 0x0b; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x0082); -+ i2s_codec_write(0x17, 0x000c); -+ i2s_codec_write(0x18, 0x004b); -+ i2s_codec_write(0x19, 0x0036); -+ i2s_codec_write(0x1A, 0x0082); -+ i2s_codec_write(0x1B, 0x000c); -+ i2s_codec_write(0x1C, 0x0068); -+ i2s_codec_write(0x1D, 0x001e); -+ i2s_codec_write(0x1E, 0x0030); -+ i2s_codec_write(0x1F, 0x0023); -+ i2s_codec_write(0x11, 0x0018); //eq on -+ } -+ break; -+ case 29400: -+ speed = 0x0e; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x003d); -+ i2s_codec_write(0x17, 0x0012); -+ i2s_codec_write(0x18, 0x0083); -+ i2s_codec_write(0x19, 0x0000); -+ i2s_codec_write(0x1A, 0x003d); -+ i2s_codec_write(0x1B, 0x0012); -+ i2s_codec_write(0x1C, 0x0079); -+ i2s_codec_write(0x1D, 0x001d); -+ i2s_codec_write(0x1E, 0x000d); -+ i2s_codec_write(0x1F, 0x0025); -+ i2s_codec_write(0x11, 0x0018); //eq on -+ } -+ break; -+ case 44100: -+ speed = 0x0f; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x0059); -+ i2s_codec_write(0x17, 0x000d); -+ i2s_codec_write(0x18, 0x00cb); -+ i2s_codec_write(0x19, 0x0037); -+ i2s_codec_write(0x1A, 0x0059); -+ i2s_codec_write(0x1B, 0x000d); -+ i2s_codec_write(0x1C, 0x0046); -+ i2s_codec_write(0x1D, 0x001e); -+ i2s_codec_write(0x1E, 0x0074); -+ i2s_codec_write(0x1F, 0x0023); -+ i2s_codec_write(0x11, 0x0018); //eq on -+ } -+ break; -+ default: -+ break; -+ } -+ val = speed & 0x08; -+ val = val << 2; -+ speed = speed & 0x07; -+ val = val | speed; -+ i2s_codec_write(0x05, val); -+} -+ -+void ak4642en_mixer_old_info_id_name(void) -+{ -+ strncpy(info.id, "AK4642EN", sizeof(info.id)); -+ strncpy(info.name,"AKM AK4642en codec", sizeof(info.name)); -+} -+ -+void ak4642en_mixer_info_id_name(void) -+{ -+ strncpy(old_info.id, "AK4642EN", sizeof(old_info.id)); -+ strncpy(old_info.name,"AKM AK4642en codec", sizeof(old_info.name)); -+} -+ -+void set_ak4642en_volume(int val) -+{ -+ if ( val == 0 ) -+ codec_volume = 255; -+ else if ( val > 1 && val <= 10) -+ codec_volume = 92; -+ else if ( val > 10 && val <= 20 ) -+ codec_volume = 67; -+ else if ( val > 20 && val <= 30 ) -+ codec_volume = 50; -+ else if ( val > 30 && val <= 40 ) -+ codec_volume = 40; -+ else if ( val > 40 && val <= 50 ) -+ codec_volume = 30; -+ else if ( val > 50 && val <= 60 ) -+ codec_volume = 22; -+ else if ( val > 60&& val <= 70 ) -+ codec_volume = 15; -+ else if ( val > 70 && val <= 80 ) -+ codec_volume = 8; -+ else if ( val > 80 && val <= 90 ) -+ codec_volume = 4; -+ else if ( val > 90 && val <= 100 ) -+ codec_volume = 2; -+ -+ i2s_codec_write(0x0a, codec_volume); -+ i2s_codec_write(0x0d, codec_volume); -+} -+ -+void set_ak4642en_mic(int val) -+{ -+ int mic_gain; -+ mic_gain = 241 * val /100; -+ i2s_codec_write(0x09, mic_gain); -+ i2s_codec_write(0x0c, mic_gain); -+} -+ -+void resume_ak4642en(void) -+{ -+ __gpio_as_output(17); -+ __gpio_set_pin(17); //enable ak4642 -+ __gpio_as_output(68); -+ __gpio_clear_pin(68); -+ __gpio_as_output(69); -+ __gpio_clear_pin(69); -+ __gpio_as_output(70); -+ __gpio_clear_pin(70); -+ __gpio_as_input(71); -+ __gpio_clear_pin(71); -+ __gpio_as_input(77); -+ __gpio_clear_pin(77); -+ __gpio_as_input(78); -+ __gpio_clear_pin(78); -+ REG_GPIO_GPALR(2) &= 0xC3FF0CFF; -+ REG_GPIO_GPALR(2) |= 0x14005000; -+ //set SCC clock initialization -+ REG_SCC1_CR(SCC1_BASE) = 0x00000000; -+ udelay(2); -+ REG_SCC1_CR(SCC1_BASE) |= 1 << 31; -+ udelay(2); -+ __gpio_as_output(I2S_PDN); -+ __gpio_set_pin(I2S_PDN); -+ udelay(5); -+ __gpio_clear_pin(I2S_PDN); -+ ndelay(300);//>150ns -+ __gpio_set_pin(I2S_PDN); -+ mdelay(1); -+ //set PLL Master mode -+ i2s_codec_write(0x01, 0x0008);//master -+ i2s_codec_write(0x04, 0x006b);//ref:12MHz;BITCLK:64fs;I2S compli -+ i2s_codec_write(0x05, 0x000b);//sync:48KHz; -+ i2s_codec_write(0x00, 0x0040);//PMVCM -+ i2s_codec_write(0x01, 0x0009);//master,PLL enable -+ jack_plug_level = 10; -+ old_level = 100; -+ spk_hp = 0; -+ __gpio_as_input(JACK_PLUG_PIN); -+ jack_plug_level = __gpio_get_pin(JACK_PLUG_PIN); -+ //i suppose jack_plug_lvel is 1 indicate with HPO -+ if(jack_plug_level > 1 || jack_plug_level <0) -+ printk("Audio ak4642en codec Jack plug level is wrong!\n"); -+ if(jack_plug_level) -+ __gpio_as_irq_fall_edge(JACK_PLUG_PIN); -+ else -+ __gpio_as_irq_rise_edge(JACK_PLUG_PIN); -+ -+ i2s_codec_write(0x00, 0x0065); //for resume power -+ i2s_codec_write(0x01, 0x0039); //for open pop noise -+ i2s_codec_write(0x01, 0x0079); -+ i2s_codec_write(0x0a, codec_volume); -+ i2s_codec_write(0x0d, codec_volume); -+} -+ -+void suspend_ak4642en(int wr,int rd) -+{ -+ if(wr) //playing -+ { -+ if(jack_plug_level == 0) -+ { -+ i2s_codec_write(0x01, 0x0039); // for close pop noise -+ mdelay(500); -+ i2s_codec_write(0x01, 0x0009); //PLL on I2S -+ i2s_codec_write(0x07, 0x0001); -+ i2s_codec_write(0x11, 0x0000); -+ i2s_codec_write(0x00, 0x0040); -+ i2s_codec_write(0x0f, 0x0008); // for open pop noise -+ -+ } -+ else -+ { -+ //for Speaker output -+ i2s_codec_write(0x02, 0x0020); -+ i2s_codec_write(0x07, 0x0001); -+ i2s_codec_write(0x11, 0x0000); -+ i2s_codec_write(0x02, 0x0000); -+ i2s_codec_write(0x00, 0x0040); // for close pop noise -+ } -+ } -+ -+ if(rd) // recording -+ { -+ i2s_codec_write(0x02, 0x0001); // 5-11 a1 -+ i2s_codec_write(0x07, 0x0001); -+ i2s_codec_write(0x11, 0x0000); -+ mdelay(300); -+ } -+ __gpio_as_output(17); -+ __gpio_clear_pin(17);//disable ak4642 -+ __i2s_disable(); -+} -+ -+static int __init init_ak4642en(void) -+{ -+ set_codec_gpio_pin = set_ak4642en_gpio_pin; -+ each_time_init_codec = each_time_init_ak4642en; -+ clear_codec_mode = clear_ak4642en_mode; -+ -+ set_codec_record = set_ak4642en_record; -+ set_codec_replay = set_ak4642en_replay; -+ set_replay_hp_or_speaker = set_ak4642en_replay; -+ -+ set_codec_speed = set_ak4642en_speed; -+ clear_codec_record = clear_ak4642en_record; -+ clear_codec_replay = clear_ak4642en_replay; -+ -+ codec_mixer_old_info_id_name = ak4642en_mixer_old_info_id_name; -+ codec_mixer_info_id_name = ak4642en_mixer_info_id_name; -+ -+ set_codec_volume = set_ak4642en_volume; -+ -+ set_codec_mic = set_ak4642en_mic; -+ -+ i2s_resume_codec = resume_ak4642en; -+ i2s_suspend_codec = suspend_ak4642en; -+ printk("---> ak4642en initialization!\n"); -+ return 0; -+} -+ -+static void __exit cleanup_ak4642en(void) -+{ -+ spk_hp = 0; -+ i2s_codec_write(0x01, 0x0008);//master,PLL disable -+ //free_irq(JACK_PLUG_IRQ, i2s_controller); -+ __gpio_clear_pin(I2S_PDN); -+ udelay(2); -+ REG_SCC1_CR(SCC1_BASE) &= 0 << 31; -+ udelay(2); -+} -+ -+module_init(init_ak4642en); -+module_exit(cleanup_ak4642en); ++/* ++ * linux/sound/oss/ak4642en.c ++ * ++ * AKM ak4642en codec chip driver to I2S interface ++ * ++ * Copyright (c) 2005-2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Because the normal application of AUDIO devices are focused on Little_endian, ++ * then we only perform the little endian data format in driver. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "sound_config.h" ++ ++extern mixer_info info; ++extern _old_mixer_info old_info; ++extern int abnormal_data_count; ++ ++extern void (*clear_codec_mode)(void); ++extern void (*set_codec_gpio_pin)(void); ++extern void (*each_time_init_codec)(void); ++extern void (*set_codec_record)(void); ++extern void (*set_codec_replay)(void); ++extern void (*clear_codec_record)(void); ++extern void (*clear_codec_replay)(void); ++extern void (*set_codec_speed)(int range); ++extern void (*codec_mixer_old_info_id_name)(void); ++extern void (*codec_mixer_info_id_name)(void); ++extern void (*set_codec_volume)(int val); ++extern void (*set_codec_mic)(int val); ++extern void (*i2s_resume_codec)(void); ++extern void (*i2s_suspend_codec)(int wr,int rd); ++extern void (*set_replay_hp_or_speaker)(void); ++ ++#define I2S_PDN 68 ++#define JACK_PLUG_PIN 83 ++#define JACK_PLUG_IRQ (IRQ_GPIO_0 + JACK_PLUG_PIN) ++ ++static int jack_plug_level, old_level; ++static unsigned int i2c_addr = 0x26; //AK4642EN device address at I2C bus ++static unsigned int i2c_clk = 100000;//AK4642EN 400kHz max,but 100kHz here ++static unsigned int spk_hp = 0; ++static int codec_volume; ++ ++void set_ak4642en_gpio_pin(void); ++void each_time_init_ak4642en(void); ++void set_ak4642en_replay(void); ++void set_ak4642en_record(void); ++void turn_on_ak4642en(void); ++void turn_off_ak4642en(void); ++void set_ak4642en_speed(int rate); ++void reset_ak4642en(void); ++void ak4642en_mixer_old_info_id_name(void); ++void ak4642en_mixer_info_id_name(void); ++void set_ak4642en_bass(int val); ++void set_ak4642en_volume(int val); ++void set_ak4642en_mic(int val); ++void resume_ak4642en(void); ++void suspend_ak4642en(int wr,int rd); ++ ++static void write_reg(u8 reg, u8 val) ++{ ++ i2c_open(); ++ i2c_setclk(i2c_clk); ++ i2c_write((i2c_addr >> 1), &val, reg, 1); ++ i2c_close(); ++} ++ ++#if 0 ++static u8 read_reg(u8 reg) ++{ ++ u8 val; ++ i2c_open(); ++ i2c_setclk(i2c_clk); ++ i2c_read((i2c_addr >> 1), &val, reg, 1); ++ i2c_close(); ++ return val; ++} ++ ++static u16 i2s_codec_read(u8 reg) ++{ ++ u16 value; ++ value = read_reg(reg); ++ return value; ++} ++#endif ++ ++static void i2s_codec_write(u8 reg, u16 data) ++{ ++ u8 val = data & 0xff; ++ write_reg(reg, val); ++} ++ ++void set_ak4642en_gpio_pin(void) ++{ ++ //set AIC pin to I2S slave mode,only GPIO70,71,77,78 ++ __gpio_as_output(68); ++ __gpio_clear_pin(68); ++ __gpio_as_output(69); ++ __gpio_clear_pin(69); ++ __gpio_as_output(70); ++ __gpio_clear_pin(70); ++ __gpio_as_input(71); ++ __gpio_clear_pin(71); ++ __gpio_as_input(77); ++ __gpio_clear_pin(77); ++ __gpio_as_input(78); ++ __gpio_clear_pin(78); ++ REG_GPIO_GPALR(2) &= 0xC3FF0CFF; ++ REG_GPIO_GPALR(2) |= 0x14005000; ++ //set SCC clock initialization ++ REG_SCC1_CR(SCC1_BASE) = 0x00000000; ++ udelay(2); ++ REG_SCC1_CR(SCC1_BASE) |= 1 << 31; ++ udelay(2); ++ ++ __gpio_as_output(I2S_PDN); ++ __gpio_set_pin(I2S_PDN); ++ udelay(5); ++ __gpio_clear_pin(I2S_PDN); ++ ndelay(300);//>150ns ++ __gpio_set_pin(I2S_PDN); ++ mdelay(1); ++ //set PLL Master mode ++ i2s_codec_write(0x01, 0x0008);//master ++ i2s_codec_write(0x04, 0x006b);//ref:12MHz;BITCLK:64fs;I2S compli ++ i2s_codec_write(0x05, 0x000b);//sync:48KHz; ++ i2s_codec_write(0x00, 0x0040);//PMVCM ++ i2s_codec_write(0x01, 0x0009);//master,PLL enable ++ mdelay(40); ++ jack_plug_level = 10; ++ old_level = 100; ++ spk_hp = 0; ++ __gpio_disable_pull(JACK_PLUG_PIN); ++ udelay(10); ++ __gpio_as_input(JACK_PLUG_PIN); ++ jack_plug_level = __gpio_get_pin(JACK_PLUG_PIN); ++ //i suppose jack_plug_lvel is 1 indicate with HPO ++ if (jack_plug_level > 1 || jack_plug_level <0) ++ printk("Audio ak4642en codec Jack plug level is wrong!\n"); ++ if (jack_plug_level) ++ __gpio_as_irq_fall_edge(JACK_PLUG_PIN); ++ else ++ __gpio_as_irq_rise_edge(JACK_PLUG_PIN); ++} ++ ++void clear_ak4642en_mode(void) ++{ ++ spk_hp = 0; ++ i2s_codec_write(0x01, 0x0008);//master,PLL disable ++ //free_irq(JACK_PLUG_IRQ, i2s_controller); ++ __gpio_clear_pin(I2S_PDN); ++ udelay(2); ++ REG_SCC1_CR(SCC1_BASE) &= 0 << 31; ++ udelay(2); ++} ++ ++void set_ak4642en_replay(void) ++{ ++ //for poll ++ /*jack_plug_level is H for SPK,is L for HP*/ ++ jack_plug_level = __gpio_get_pin(JACK_PLUG_PIN); ++ if(old_level == jack_plug_level) ++ return; ++ old_level = jack_plug_level; ++ if(spk_hp == 1) ++ { ++ if(jack_plug_level == 1) ++ { ++ //now HeadPhone output,so clear SPK ++ i2s_codec_write(0x02, 0x0020); ++ i2s_codec_write(0x02, 0x0000); ++ i2s_codec_write(0x00, 0x0040); ++ } ++ else ++ { ++ //now Speaker output,so clear HP ++ i2s_codec_write(0x01, 0x0039); ++ i2s_codec_write(0x01, 0x0009); ++ i2s_codec_write(0x00, 0x0040); ++ i2s_codec_write(0x0e, 0x0000); ++ i2s_codec_write(0x0f, 0x0008); ++ } ++ } ++ spk_hp = 1; ++ if(jack_plug_level == 1) ++ { ++ //for HeadPhone output ++ i2s_codec_write(0x00, 0x0060); // ++ i2s_codec_write(0x0f, 0x0009); //5-10 ++ ++ i2s_codec_write(0x00, 0x0064); // ++ i2s_codec_write(0x09, 0x0091);// volume control 0dB ++ i2s_codec_write(0x0c, 0x0091);// 0dB(right) ++ //eq off ++ i2s_codec_write(0x11, 0x0000);//5-10 ++ i2s_codec_write(0x01, 0x0039); // ++ ++ i2s_codec_write(0x01, 0x0079); // ++ } ++ else ++ { ++ //for Speaker output ++ i2s_codec_write(0x00, 0x0040); ++ i2s_codec_write(0x02, 0x0020); ++ ++ i2s_codec_write(0x03, 0x0018);//5-10 ++ i2s_codec_write(0x06, 0x003c); ++ ++ i2s_codec_write(0x08, 0x00A1);//5-10 ++ ++ i2s_codec_write(0x0b, 0x0040); //5-10 ++ ++ i2s_codec_write(0x07, 0x002d); //5-10 ++ i2s_codec_write(0x09, 0x0091); ++ i2s_codec_write(0x0c, 0x0091); ++ //HP volume output value ++ ++ i2s_codec_write(0x0a, codec_volume);//5-10 ++ i2s_codec_write(0x0d, codec_volume);//5-10 ++ ++ i2s_codec_write(0x00, 0x0074); ++ i2s_codec_write(0x02, 0x00a0); ++ } ++} ++ ++void set_ak4642en_record(void) ++{ ++ abnormal_data_count = 0; ++ i2s_codec_write(0x02, 0x0004); ++ i2s_codec_write(0x03, 0x0038);// recording volume add ++ i2s_codec_write(0x06, 0x0000);//for ALC short waiting time ++ i2s_codec_write(0x08, 0x00e1); ++ i2s_codec_write(0x0b, 0x0000); ++ i2s_codec_write(0x07, 0x0021); // ALC on ++ ++ i2s_codec_write(0x10, 0x0000);//0x0001 ++ //i2s_codec_write(0x10, 0x0001);//0x0001 ++ i2s_codec_write(0x01, 0x0039); //for open pop noise ++ i2s_codec_write(0x01, 0x0079); ++ i2s_codec_write(0x00, 0x0065); ++ mdelay(300); ++} ++ ++void clear_ak4642en_replay(void) ++{ ++ //for poll ++ old_level = 100; ++ spk_hp = 0; ++ if(jack_plug_level == 1) ++ { ++ //for HeadPhone output ++ i2s_codec_write(0x01, 0x0039); // for close pop noise ++ mdelay(300); ++ i2s_codec_write(0x01, 0x0009); //PLL on I2S ++ i2s_codec_write(0x07, 0x0001); ++ i2s_codec_write(0x11, 0x0000); ++ i2s_codec_write(0x00, 0x0040); ++ i2s_codec_write(0x0f, 0x0008); // for open pop noise ++ } ++ else ++ { ++ //for Speaker output ++ i2s_codec_write(0x02, 0x0020); ++ i2s_codec_write(0x07, 0x0001); ++ i2s_codec_write(0x11, 0x0000); ++ i2s_codec_write(0x02, 0x0000); ++ i2s_codec_write(0x00, 0x0040); // for close pop noise ++ } ++} ++ ++void clear_ak4642en_record(void) ++{ ++ //for Mic input(Stereo) ++ i2s_codec_write(0x02, 0x0001); ++ i2s_codec_write(0x07, 0x0001); ++ i2s_codec_write(0x11, 0x0000); ++} ++ ++void each_time_init_ak4642en(void) ++{ ++ __i2s_disable(); ++ __i2s_as_slave(); ++ __i2s_set_sample_size(16); ++} ++ ++void set_ak4642en_speed(int rate) ++{ ++ //codec work at frequency ++ unsigned short speed = 0; ++ unsigned short val = 0; ++ switch (rate) ++ { ++ case 8000: ++ speed = 0x00; ++ if(jack_plug_level == 1) //speaker ++ { ++ i2s_codec_write(0x16, 0x0000); ++ i2s_codec_write(0x17, 0x0000); ++ i2s_codec_write(0x18, 0x0000); ++ i2s_codec_write(0x19, 0x0000); ++ i2s_codec_write(0x1A, 0x0000); ++ i2s_codec_write(0x1B, 0x0000); ++ i2s_codec_write(0x1C, 0x0027);//800hz ++ i2s_codec_write(0x1D, 0x0018); ++ i2s_codec_write(0x1E, 0x00b2); ++ i2s_codec_write(0x1F, 0x002f); ++ i2s_codec_write(0x11, 0x0010); //eq on ++ } ++ break; ++ case 12000: ++ speed = 0x01; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x0000); ++ i2s_codec_write(0x17, 0x0000); ++ i2s_codec_write(0x18, 0x0000); ++ i2s_codec_write(0x19, 0x0000); ++ i2s_codec_write(0x1A, 0x0000); ++ i2s_codec_write(0x1B, 0x0000); ++ i2s_codec_write(0x1C, 0x0064); ++ i2s_codec_write(0x1D, 0x001a); ++ i2s_codec_write(0x1E, 0x0038); ++ i2s_codec_write(0x1F, 0x002b); ++ i2s_codec_write(0x11, 0x0010); //eq on ++ } ++ break; ++ case 16000: ++ speed = 0x02; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x00af); ++ i2s_codec_write(0x17, 0x0020); ++ i2s_codec_write(0x18, 0x0043); ++ i2s_codec_write(0x19, 0x001a); ++ i2s_codec_write(0x1A, 0x00af); ++ i2s_codec_write(0x1B, 0x0020); ++ i2s_codec_write(0x1C, 0x00a0); ++ i2s_codec_write(0x1D, 0x001b); ++ i2s_codec_write(0x1E, 0x00c0); ++ i2s_codec_write(0x1F, 0x0028); ++ i2s_codec_write(0x11, 0x0018); //eq on ++ } ++ break; ++ case 24000: ++ speed = 0x03; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x0086); ++ i2s_codec_write(0x17, 0x0015); ++ i2s_codec_write(0x18, 0x005d); ++ i2s_codec_write(0x19, 0x0006); ++ i2s_codec_write(0x1A, 0x0086); ++ i2s_codec_write(0x1B, 0x0015); ++ i2s_codec_write(0x1C, 0x00f5); ++ i2s_codec_write(0x1D, 0x001c); ++ i2s_codec_write(0x1E, 0x0016); ++ i2s_codec_write(0x1F, 0x0026); ++ i2s_codec_write(0x11, 0x0018); //eq on ++ } ++ break; ++ case 7350: ++ speed = 0x04; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x0000); ++ i2s_codec_write(0x17, 0x0000); ++ i2s_codec_write(0x18, 0x0000); ++ i2s_codec_write(0x19, 0x0000); ++ i2s_codec_write(0x1A, 0x0000); ++ i2s_codec_write(0x1B, 0x0000); ++ i2s_codec_write(0x1C, 0x0027); ++ i2s_codec_write(0x1D, 0x0018); ++ i2s_codec_write(0x1E, 0x00b2); ++ i2s_codec_write(0x1F, 0x002f); ++ i2s_codec_write(0x11, 0x0010); //eq on ++ } ++ break; ++ case 11025: ++ speed = 0x05; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x0059); ++ i2s_codec_write(0x17, 0x000d); ++ i2s_codec_write(0x18, 0x00cb); ++ i2s_codec_write(0x19, 0x0037); ++ i2s_codec_write(0x1A, 0x0059); ++ i2s_codec_write(0x1B, 0x000d); ++ i2s_codec_write(0x1C, 0x0046); ++ i2s_codec_write(0x1D, 0x001e); ++ i2s_codec_write(0x1E, 0x0074); ++ i2s_codec_write(0x1F, 0x0023); ++ i2s_codec_write(0x11, 0x0018); //eq on ++ } ++ break; ++ case 14700: ++ speed = 0x06; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x0000); ++ i2s_codec_write(0x17, 0x0000); ++ i2s_codec_write(0x18, 0x0000); ++ i2s_codec_write(0x19, 0x0000); ++ i2s_codec_write(0x1A, 0x0000); ++ i2s_codec_write(0x1B, 0x0000); ++ i2s_codec_write(0x1C, 0x004a); ++ i2s_codec_write(0x1D, 0x001b); ++ i2s_codec_write(0x1E, 0x006c); ++ i2s_codec_write(0x1F, 0x0029); ++ i2s_codec_write(0x11, 0x0010); //eq on ++ } ++ break; ++ case 22050: ++ speed = 0x07; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x002d); ++ i2s_codec_write(0x17, 0x0017); ++ i2s_codec_write(0x18, 0x0050); ++ i2s_codec_write(0x19, 0x0009); ++ i2s_codec_write(0x1A, 0x002d); ++ i2s_codec_write(0x1B, 0x0017); ++ i2s_codec_write(0x1C, 0x00d7); ++ i2s_codec_write(0x1D, 0x001c); ++ i2s_codec_write(0x1E, 0x0093); ++ i2s_codec_write(0x1F, 0x0026); ++ i2s_codec_write(0x11, 0x0018); //eq on ++ } ++ break; ++ case 32000: ++ speed = 0x0a; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x0012); ++ i2s_codec_write(0x17, 0x0011); ++ i2s_codec_write(0x18, 0x006e); ++ i2s_codec_write(0x19, 0x003e); ++ i2s_codec_write(0x1A, 0x0012); ++ i2s_codec_write(0x1B, 0x0011); ++ i2s_codec_write(0x1C, 0x00aa); ++ i2s_codec_write(0x1D, 0x001d); ++ i2s_codec_write(0x1E, 0x00ab); ++ i2s_codec_write(0x1F, 0x0024); ++ i2s_codec_write(0x11, 0x0018); //eq on ++ } ++ break; ++ case 48000: ++ speed = 0x0b; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x0082); ++ i2s_codec_write(0x17, 0x000c); ++ i2s_codec_write(0x18, 0x004b); ++ i2s_codec_write(0x19, 0x0036); ++ i2s_codec_write(0x1A, 0x0082); ++ i2s_codec_write(0x1B, 0x000c); ++ i2s_codec_write(0x1C, 0x0068); ++ i2s_codec_write(0x1D, 0x001e); ++ i2s_codec_write(0x1E, 0x0030); ++ i2s_codec_write(0x1F, 0x0023); ++ i2s_codec_write(0x11, 0x0018); //eq on ++ } ++ break; ++ case 29400: ++ speed = 0x0e; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x003d); ++ i2s_codec_write(0x17, 0x0012); ++ i2s_codec_write(0x18, 0x0083); ++ i2s_codec_write(0x19, 0x0000); ++ i2s_codec_write(0x1A, 0x003d); ++ i2s_codec_write(0x1B, 0x0012); ++ i2s_codec_write(0x1C, 0x0079); ++ i2s_codec_write(0x1D, 0x001d); ++ i2s_codec_write(0x1E, 0x000d); ++ i2s_codec_write(0x1F, 0x0025); ++ i2s_codec_write(0x11, 0x0018); //eq on ++ } ++ break; ++ case 44100: ++ speed = 0x0f; ++ if(jack_plug_level == 1) ++ { ++ i2s_codec_write(0x16, 0x0059); ++ i2s_codec_write(0x17, 0x000d); ++ i2s_codec_write(0x18, 0x00cb); ++ i2s_codec_write(0x19, 0x0037); ++ i2s_codec_write(0x1A, 0x0059); ++ i2s_codec_write(0x1B, 0x000d); ++ i2s_codec_write(0x1C, 0x0046); ++ i2s_codec_write(0x1D, 0x001e); ++ i2s_codec_write(0x1E, 0x0074); ++ i2s_codec_write(0x1F, 0x0023); ++ i2s_codec_write(0x11, 0x0018); //eq on ++ } ++ break; ++ default: ++ break; ++ } ++ val = speed & 0x08; ++ val = val << 2; ++ speed = speed & 0x07; ++ val = val | speed; ++ i2s_codec_write(0x05, val); ++} ++ ++void ak4642en_mixer_old_info_id_name(void) ++{ ++ strncpy(info.id, "AK4642EN", sizeof(info.id)); ++ strncpy(info.name,"AKM AK4642en codec", sizeof(info.name)); ++} ++ ++void ak4642en_mixer_info_id_name(void) ++{ ++ strncpy(old_info.id, "AK4642EN", sizeof(old_info.id)); ++ strncpy(old_info.name,"AKM AK4642en codec", sizeof(old_info.name)); ++} ++ ++void set_ak4642en_volume(int val) ++{ ++ if ( val == 0 ) ++ codec_volume = 255; ++ else if ( val > 1 && val <= 10) ++ codec_volume = 92; ++ else if ( val > 10 && val <= 20 ) ++ codec_volume = 67; ++ else if ( val > 20 && val <= 30 ) ++ codec_volume = 50; ++ else if ( val > 30 && val <= 40 ) ++ codec_volume = 40; ++ else if ( val > 40 && val <= 50 ) ++ codec_volume = 30; ++ else if ( val > 50 && val <= 60 ) ++ codec_volume = 22; ++ else if ( val > 60&& val <= 70 ) ++ codec_volume = 15; ++ else if ( val > 70 && val <= 80 ) ++ codec_volume = 8; ++ else if ( val > 80 && val <= 90 ) ++ codec_volume = 4; ++ else if ( val > 90 && val <= 100 ) ++ codec_volume = 2; ++ ++ i2s_codec_write(0x0a, codec_volume); ++ i2s_codec_write(0x0d, codec_volume); ++} ++ ++void set_ak4642en_mic(int val) ++{ ++ int mic_gain; ++ mic_gain = 241 * val /100; ++ i2s_codec_write(0x09, mic_gain); ++ i2s_codec_write(0x0c, mic_gain); ++} ++ ++void resume_ak4642en(void) ++{ ++ __gpio_as_output(17); ++ __gpio_set_pin(17); //enable ak4642 ++ __gpio_as_output(68); ++ __gpio_clear_pin(68); ++ __gpio_as_output(69); ++ __gpio_clear_pin(69); ++ __gpio_as_output(70); ++ __gpio_clear_pin(70); ++ __gpio_as_input(71); ++ __gpio_clear_pin(71); ++ __gpio_as_input(77); ++ __gpio_clear_pin(77); ++ __gpio_as_input(78); ++ __gpio_clear_pin(78); ++ REG_GPIO_GPALR(2) &= 0xC3FF0CFF; ++ REG_GPIO_GPALR(2) |= 0x14005000; ++ //set SCC clock initialization ++ REG_SCC1_CR(SCC1_BASE) = 0x00000000; ++ udelay(2); ++ REG_SCC1_CR(SCC1_BASE) |= 1 << 31; ++ udelay(2); ++ __gpio_as_output(I2S_PDN); ++ __gpio_set_pin(I2S_PDN); ++ udelay(5); ++ __gpio_clear_pin(I2S_PDN); ++ ndelay(300);//>150ns ++ __gpio_set_pin(I2S_PDN); ++ mdelay(1); ++ //set PLL Master mode ++ i2s_codec_write(0x01, 0x0008);//master ++ i2s_codec_write(0x04, 0x006b);//ref:12MHz;BITCLK:64fs;I2S compli ++ i2s_codec_write(0x05, 0x000b);//sync:48KHz; ++ i2s_codec_write(0x00, 0x0040);//PMVCM ++ i2s_codec_write(0x01, 0x0009);//master,PLL enable ++ jack_plug_level = 10; ++ old_level = 100; ++ spk_hp = 0; ++ __gpio_as_input(JACK_PLUG_PIN); ++ jack_plug_level = __gpio_get_pin(JACK_PLUG_PIN); ++ //i suppose jack_plug_lvel is 1 indicate with HPO ++ if(jack_plug_level > 1 || jack_plug_level <0) ++ printk("Audio ak4642en codec Jack plug level is wrong!\n"); ++ if(jack_plug_level) ++ __gpio_as_irq_fall_edge(JACK_PLUG_PIN); ++ else ++ __gpio_as_irq_rise_edge(JACK_PLUG_PIN); ++ ++ i2s_codec_write(0x00, 0x0065); //for resume power ++ i2s_codec_write(0x01, 0x0039); //for open pop noise ++ i2s_codec_write(0x01, 0x0079); ++ i2s_codec_write(0x0a, codec_volume); ++ i2s_codec_write(0x0d, codec_volume); ++} ++ ++void suspend_ak4642en(int wr,int rd) ++{ ++ if(wr) //playing ++ { ++ if(jack_plug_level == 0) ++ { ++ i2s_codec_write(0x01, 0x0039); // for close pop noise ++ mdelay(500); ++ i2s_codec_write(0x01, 0x0009); //PLL on I2S ++ i2s_codec_write(0x07, 0x0001); ++ i2s_codec_write(0x11, 0x0000); ++ i2s_codec_write(0x00, 0x0040); ++ i2s_codec_write(0x0f, 0x0008); // for open pop noise ++ ++ } ++ else ++ { ++ //for Speaker output ++ i2s_codec_write(0x02, 0x0020); ++ i2s_codec_write(0x07, 0x0001); ++ i2s_codec_write(0x11, 0x0000); ++ i2s_codec_write(0x02, 0x0000); ++ i2s_codec_write(0x00, 0x0040); // for close pop noise ++ } ++ } ++ ++ if(rd) // recording ++ { ++ i2s_codec_write(0x02, 0x0001); // 5-11 a1 ++ i2s_codec_write(0x07, 0x0001); ++ i2s_codec_write(0x11, 0x0000); ++ mdelay(300); ++ } ++ __gpio_as_output(17); ++ __gpio_clear_pin(17);//disable ak4642 ++ __i2s_disable(); ++} ++ ++static int __init init_ak4642en(void) ++{ ++ set_codec_gpio_pin = set_ak4642en_gpio_pin; ++ each_time_init_codec = each_time_init_ak4642en; ++ clear_codec_mode = clear_ak4642en_mode; ++ ++ set_codec_record = set_ak4642en_record; ++ set_codec_replay = set_ak4642en_replay; ++ set_replay_hp_or_speaker = set_ak4642en_replay; ++ ++ set_codec_speed = set_ak4642en_speed; ++ clear_codec_record = clear_ak4642en_record; ++ clear_codec_replay = clear_ak4642en_replay; ++ ++ codec_mixer_old_info_id_name = ak4642en_mixer_old_info_id_name; ++ codec_mixer_info_id_name = ak4642en_mixer_info_id_name; ++ ++ set_codec_volume = set_ak4642en_volume; ++ ++ set_codec_mic = set_ak4642en_mic; ++ ++ i2s_resume_codec = resume_ak4642en; ++ i2s_suspend_codec = suspend_ak4642en; ++ printk("---> ak4642en initialization!\n"); ++ return 0; ++} ++ ++static void __exit cleanup_ak4642en(void) ++{ ++ spk_hp = 0; ++ i2s_codec_write(0x01, 0x0008);//master,PLL disable ++ //free_irq(JACK_PLUG_IRQ, i2s_controller); ++ __gpio_clear_pin(I2S_PDN); ++ udelay(2); ++ REG_SCC1_CR(SCC1_BASE) &= 0 << 31; ++ udelay(2); ++} ++ ++module_init(init_ak4642en); ++module_exit(cleanup_ak4642en); --- linux-2.6.24.7.old/sound/oss/jz_ac97.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7/sound/oss/jz_ac97.c 2009-04-12 18:13:57.000000000 +0200 @@ -0,0 +1,2252 @@ @@ -4477,83 +991,83 @@ +#define MAX_RETRY 100 + +static unsigned int k_8000[] = { -+ 0, 42, 85, 128, 170, 213, ++ 0, 42, 85, 128, 170, 213, +}; + +static unsigned int reload_8000[] = { -+ 1, 0, 0, 0, 0, 0, ++ 1, 0, 0, 0, 0, 0, +}; + +static unsigned int k_11025[] = { -+ 0, 58, 117, 176, 234, 37, 96, 154, -+ 213, 16, 74, 133, 192, 250, 53, 112, -+ 170, 229, 32, 90, 149, 208, 10, 69, -+ 128, 186, 245, 48, 106, 165, 224, 26, -+ 85, 144, 202, 5, 64, 122, 181, 240, -+ 42, 101, 160, 218, 21, 80, 138, 197, ++ 0, 58, 117, 176, 234, 37, 96, 154, ++ 213, 16, 74, 133, 192, 250, 53, 112, ++ 170, 229, 32, 90, 149, 208, 10, 69, ++ 128, 186, 245, 48, 106, 165, 224, 26, ++ 85, 144, 202, 5, 64, 122, 181, 240, ++ 42, 101, 160, 218, 21, 80, 138, 197, +}; + +static unsigned int reload_11025[] = { -+ 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -+ 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, -+ 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, ++ 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, ++ 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, ++ 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, +}; + +static unsigned int k_16000[] = { -+ 0, 85, 170, ++ 0, 85, 170, +}; + +static unsigned int reload_16000[] = { -+ 1, 0, 0, ++ 1, 0, 0, +}; + +static unsigned int k_22050[] = { -+ 0, 117, 234, 96, 213, 74, 192, 53, -+ 170, 32, 149, 10, 128, 245, 106, 224, -+ 85, 202, 64, 181, 42, 160, 21, 138, ++ 0, 117, 234, 96, 213, 74, 192, 53, ++ 170, 32, 149, 10, 128, 245, 106, 224, ++ 85, 202, 64, 181, 42, 160, 21, 138, +}; + +static unsigned int reload_22050[] = { -+ 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, -+ 1, 0, 1, 0, 1, 0, 1, 0, ++ 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, ++ 1, 0, 1, 0, 1, 0, 1, 0, +}; + +static unsigned int k_24000[] = { -+ 0, 128, ++ 0, 128, +}; + +static unsigned int reload_24000[] = { -+ 1, 0, ++ 1, 0, +}; + +static unsigned int k_32000[] = { -+ 0, 170, 85, ++ 0, 170, 85, +}; + +static unsigned int reload_32000[] = { -+ 1, 0, 1, ++ 1, 0, 1, +}; + +static unsigned int k_44100[] = { -+ 0, 234, 213, 192, 170, 149, 128, 106, -+ 85, 64, 42, 21, ++ 0, 234, 213, 192, 170, 149, 128, 106, ++ 85, 64, 42, 21, +}; + +static unsigned int reload_44100[] = { -+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +}; + +static unsigned int k_48000[] = { -+ 0, ++ 0, +}; + +static unsigned int reload_48000[] = { -+ 1, ++ 1, +}; + + +static unsigned int f_scale_counts[8] = { -+ 6, 48, 3, 24, 2, 3, 12, 1, ++ 6, 48, 3, 24, 2, 3, 12, 1, +}; + +static int jz_audio_rate; @@ -4607,7 +1121,7 @@ + int dma2; /* record */ + + char *name; -+ ++ + int dev_audio; + struct ac97_codec *ac97_codec[NR_AC97]; + @@ -4627,7 +1141,7 @@ + int nextIn; // byte index to next-in to DMA buffer + int nextOut; // byte index to next-out from DMA buffer + int count; // current byte count in DMA buffer -+ int finish; // current transfered byte count in DMA buffer ++ int finish; // current transfered byte count in DMA buffer + unsigned total_bytes; // total bytes written or read + unsigned blocks; + unsigned error; // over/underrun @@ -4936,7 +1450,7 @@ + } + *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); + } -+ ++ + for (i = 0; i < jz_audio_fragstotal; i++) { + *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); + if (*(in_dma_buf + i) == 0) { @@ -4948,13 +1462,13 @@ + *(in_dma_buf + i) = KSEG1ADDR(*(in_dma_buf + i)); + } + return ; -+ ++ + all_mem_err: + printk("error:allocate memory occur error!\n"); + return ; + +mem_failed_out: -+ ++ + for (i = 0; i < jz_audio_fragstotal; i++) { + if(*(out_dma_buf + i)) + free_pages(*(out_dma_buf + i), get_order(fragsize)); @@ -4962,7 +1476,7 @@ + return ; + +mem_failed_in: -+ ++ + for (i = 0; i < jz_audio_fragstotal; i++) { + if(*(in_dma_buf + i)) + free_pages(*(in_dma_buf + i), get_order(fragsize)); @@ -4972,11 +1486,11 @@ +} +static void Free_In_Out_queue(int fragstotal,int fragsize) +{ -+ int i; ++ int i; + if(out_dma_buf != NULL) + { + for (i = 0; i < jz_audio_fragstotal; i++) -+ { ++ { + if(*(out_dma_buf + i)) + free_pages(*(out_dma_buf + i), get_order(fragsize)); + *(out_dma_buf + i) = 0; @@ -4997,7 +1511,7 @@ + if(in_dma_buf) + { + for (i = 0; i < jz_audio_fragstotal; i++) -+ { ++ { + if(*(in_dma_buf + i)) + free_pages(*(in_dma_buf + i), get_order(fragsize)); + *(in_dma_buf + i) = 0; @@ -5097,7 +1611,7 @@ + + jz_audio_rate = rate; + jz_audio_k = STANDARD_SPEED / rate; -+ if (rate * jz_audio_k != STANDARD_SPEED) ++ if (rate * jz_audio_k != STANDARD_SPEED) + jz_audio_q = rate / ((STANDARD_SPEED / jz_audio_k) - rate ); + else + jz_audio_q = 0x1fffffff; /* a very big value, don't compensate */ @@ -5454,7 +1968,7 @@ + } + return done; +} -+ ++ +static inline int jz_in_status_ready(void) +{ + int t2 = 1000; @@ -5486,7 +2000,7 @@ + if (reg < 128) { + u8 ret_reg; + __ac97_out_rcmd_addr(reg);//output read addr -+ if (jz_out_command_ready())//judge if send completely? ++ if (jz_out_command_ready())//judge if send completely? + while (jz_in_status_ready()) {//judge if receive completely? + ret_reg = __ac97_in_status_addr();//slot1:send addr + value = __ac97_in_data(); @@ -5549,7 +2063,7 @@ + udelay(2000); + done = jz_writeAC97Reg(codec, reg, data); + if ( count > MAX_RETRY ){ -+ printk (KERN_DEBUG " After try %d when write AC97 codec (0x%x), can't sucess, give up!! \n", ++ printk (KERN_DEBUG " After try %d when write AC97 codec (0x%x), can't sucess, give up!! \n", + MAX_RETRY, reg); + break; + } @@ -5680,7 +2194,7 @@ + controller->ac97_features &= ~1; + } + } -+ ++ + if ((codec->dev_mixer = + register_sound_mixer(&jz_ac97_mixer_fops, -1)) < 0) { + printk(KERN_ERR "Jz AC97: couldn't register mixer!\n"); @@ -5704,7 +2218,7 @@ + + switch (TYPE(format, channels)) { + default: -+ ++ + case TYPE(AFMT_U8, 1): + if ((ac97_controller->patched) && + (ac97_controller->ac97_features & 1)) { @@ -5794,7 +2308,7 @@ + +static int jz_ac97_init_proc(struct jz_ac97_controller_info *controller) +{ -+ if (!create_proc_read_entry ("ac97", 0, proc_jz_root, ++ if (!create_proc_read_entry ("ac97", 0, proc_jz_root, + ac97_read_proc, controller->ac97_codec[0])) + return -EIO; + @@ -5882,7 +2396,7 @@ + audio_failed: + return; +} -+ ++ +static int __init probe_jz_ac97(struct jz_ac97_controller_info **controller) +{ + if ((*controller = kmalloc(sizeof(struct jz_ac97_controller_info), @@ -5939,7 +2453,7 @@ +static int reserve_power5, reserve_power6; + +static int jz_ac97_suspend(struct jz_ac97_controller_info *controller, int state) -+{ ++{ + struct ac97_codec *codec = controller->ac97_codec[0]; + + /* save codec states */ @@ -6017,7 +2531,7 @@ + return ret; +} +#endif /* CONFIG_PM */ -+ ++ +static int __init init_jz_ac97(void) +{ + int errno; @@ -6035,7 +2549,7 @@ + in_busy_queue.id = NULL; + +#ifdef CONFIG_PM -+ ac97_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ++ ac97_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, + jz_ac97_pm_callback); + if (ac97_controller->pm) + ac97_controller->pm->data = ac97_controller; @@ -6228,7 +2742,7 @@ + unsigned int flags; + count_info cinfo; + -+ switch (cmd) ++ switch (cmd) + { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, (int *)arg); @@ -6260,14 +2774,14 @@ + case SNDCTL_DSP_GETBLKSIZE: + //return put_user(4*PAGE_SIZE, (int *)arg); + return put_user(jz_audio_fragsize , (int *)arg); -+ ++ + case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/ + return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); + + case SNDCTL_DSP_SETFMT: /* Select sample format */ + if (get_user(val, (int *)arg)) + return -EFAULT; -+ ++ + if (val != AFMT_QUERY) { + jz_audio_set_format(controller->dev_audio,val); + } else { @@ -6298,7 +2812,7 @@ + return -EBUSY; + get_user(val, (long *) arg); + jz_audio_fragsize = 1 << (val & 0xFFFF);//16 least bits -+ ++ + if (jz_audio_fragsize < 4 * PAGE_SIZE) + jz_audio_fragsize = 4 * PAGE_SIZE; + if (jz_audio_fragsize > (16 * PAGE_SIZE)) //16 PAGE_SIZE @@ -6308,8 +2822,8 @@ + jz_audio_fragstotal = 2; + if (jz_audio_fragstotal > 32) + jz_audio_fragstotal = 32; -+ -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); + return 0; + + case SNDCTL_DSP_GETCAPS: @@ -6323,7 +2837,7 @@ + return -EINVAL; + + case SNDCTL_DSP_GETOSPACE: -+ { ++ { + audio_buf_info abinfo; + int i, bytes = 0; + @@ -6350,12 +2864,12 @@ + int i, bytes = 0; + + if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; ++ return -EINVAL; + //unused fragment amount + jz_audio_fragments = elements_in_queue(&in_empty_queue); + for (i = 0; i < jz_audio_fragments; i++) + bytes += jz_audio_fragsize; -+ ++ + abinfo.fragments = jz_audio_fragments; + abinfo.fragstotal = jz_audio_fragstotal; + abinfo.fragsize = jz_audio_fragsize; @@ -6427,11 +2941,11 @@ + unfinish = 0; + fullc = elements_in_queue(&out_full_queue); + busyc = elements_in_queue(&out_busy_queue); -+ ++ + for(i = 0;i < fullc ;i ++) + { + id = *(out_full_queue.id + i); -+ unfinish += *(out_dma_buf_data_count + id); ++ unfinish += *(out_dma_buf_data_count + id); + } + for(i = 0;i < busyc ;i ++) + { @@ -6591,10 +3105,10 @@ + Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); + + /* The data buffer size of the user space is always a PAGE_SIZE -+ * scale, so the process can be simplified. ++ * scale, so the process can be simplified. + */ + -+ if ((ac97_controller->patched) && (ac97_controller->ac97_features & 1)) ++ if ((ac97_controller->patched) && (ac97_controller->ac97_features & 1)) + copy_count = count; + else { + if (count < 2*PAGE_SIZE / jz_audio_k) @@ -6645,7 +3159,7 @@ + } else {//when 0,i need refill in empty queue + put_buffer_id(&out_empty_queue, id); + } -+ } else ++ } else + BUG(); + left_count = left_count - copy_count; + ret += copy_count; @@ -6682,5919 +3196,5919 @@ + if ( ac97_controller ) + return ac97_controller->ac97_codec[0]; + return 0; -+ ++ +} + --- linux-2.6.24.7.old/sound/oss/jz_i2s.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7/sound/oss/jz_i2s.c 2009-04-12 18:13:57.000000000 +0200 @@ -0,0 +1,2894 @@ -+/* -+ * linux/drivers/sound/Jz_i2s.c -+ * -+ * JzSOC On-Chip I2S audio driver. -+ * -+ * Copyright (C) 2005 by Junzheng Corp. -+ * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using -+ * dma channel 4&3,noah is tested. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Because the normal application of AUDIO devices are focused on Little_endian, -+ * then we only perform the little endian data format in driver. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "sound_config.h" -+ -+#if defined(CONFIG_I2S_DLV) -+#include "jzdlv.h" -+#endif -+ -+#define DPRINTK(args...) printk(args) -+#define DMA_ID_I2S_TX DMA_ID_AIC_TX -+#define DMA_ID_I2S_RX DMA_ID_AIC_RX -+#define NR_I2S 2 -+#define JZCODEC_RW_BUFFER_SIZE 5 -+#define JZCODEC_RW_BUFFER_TOTAL 4 -+ -+#define USE_NONE 1 -+#define USE_MIC 2 -+#define USE_LINEIN 3 -+ -+typedef struct hpvol_shift_s -+{ -+ int hpvol; -+ int shift; -+} hpvol_shift_t; -+ -+mixer_info info; -+_old_mixer_info old_info; -+int codec_volue_shift; -+hpvol_shift_t hpvol_shift_table[72]; -+int abnormal_data_count; -+unsigned long i2s_clk; -+ -+void (*set_codec_mode)(void) = NULL; -+void (*clear_codec_mode)(void) = NULL; -+void (*set_codec_gpio_pin)(void) = NULL; -+void (*each_time_init_codec)(void) = NULL; -+int (*set_codec_startup_param)(void) = NULL; -+void (*set_codec_volume_table)(void) = NULL; -+void (*set_codec_record)(int mode) = NULL; -+void (*set_codec_replay)(void) = NULL; -+void (*set_codec_replay_record)(int mode) = NULL; -+void (*turn_on_codec)(void) = NULL; -+void (*turn_off_codec)(void) = NULL; -+void (*set_codec_speed)(int rate) = NULL; -+void (*reset_codec)(void) = NULL; -+void (*codec_mixer_old_info_id_name)(void) = NULL; -+void (*codec_mixer_info_id_name)(void) = NULL; -+void (*set_codec_bass)(int val) = NULL; -+void (*set_codec_volume)(int val) = NULL; -+void (*set_codec_mic)(int val) = NULL; -+void (*set_codec_line)(int val) = NULL; -+void (*i2s_resume_codec)(void) = NULL; -+void (*i2s_suspend_codec)(int wr,int rd) = NULL; -+void (*init_codec_pin)(void) = NULL; -+void (*set_codec_some_func)(void) = NULL; -+void (*clear_codec_record)(void) = NULL; -+void (*clear_codec_replay)(void) = NULL; -+void (*set_replay_hp_or_speaker)(void) = NULL; -+void (*set_codec_direct_mode)(void) = NULL; -+void (*clear_codec_direct_mode)(void) = NULL; -+void (*set_codec_linein2hp)(void) = NULL; -+void (*clear_codec_linein2hp)(void) = NULL; -+ -+static int jz_audio_rate; -+static int jz_audio_format; -+static int jz_audio_volume; -+static int jz_audio_channels; -+static int jz_audio_b; /* bits expand multiple */ -+static int jz_audio_fragments; /* unused fragment amount */ -+static int jz_audio_fragstotal; -+static int jz_audio_fragsize; -+static int jz_audio_speed; -+ -+static int codec_bass_gain; -+static int audio_mix_modcnt; -+static int jz_audio_dma_tran_count; /* bytes count of one DMA transfer */ -+#if defined(CONFIG_I2S_DLV) -+int jz_mic_only = 1; -+static int jz_codec_config = 0; -+static unsigned long ramp_up_start; -+static unsigned long ramp_up_end; -+static unsigned long gain_up_start; -+static unsigned long gain_up_end; -+static unsigned long ramp_down_start; -+static unsigned long ramp_down_end; -+static unsigned long gain_down_start; -+static unsigned long gain_down_end; -+#endif -+ -+static int codec_mic_gain; -+static int pop_dma_flag; -+static int last_dma_buffer_id; -+static int drain_flag; -+static int use_mic_line_flag; -+ -+static void (*old_mksound)(unsigned int hz, unsigned int ticks); -+extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); -+static void jz_update_filler(int bits, int channels); -+ -+static int Init_In_Out_queue(int fragstotal,int fragsize); -+static int Free_In_Out_queue(int fragstotal,int fragsize); -+static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref); -+static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref); -+static void (*replay_filler)(signed long src_start, int count, int id); -+static int (*record_filler)(unsigned long dst_start, int count, int id); -+#if defined(CONFIG_I2S_ICODEC) -+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample); -+#endif -+static void jz_audio_reset(void); -+static struct file_operations jz_i2s_audio_fops; -+ -+static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (drain_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue); -+ -+struct jz_i2s_controller_info -+{ -+ int io_base; -+ int dma1; /* for play */ -+ int dma2; /* for record */ -+ char *name; -+ int dev_audio; -+ struct i2s_codec *i2s_codec[NR_I2S]; -+ int opened1; -+ int opened2; -+ unsigned char *tmp1; /* tmp buffer for sample conversions */ -+ unsigned char *tmp2; -+ spinlock_t lock; -+ spinlock_t ioctllock; -+ -+ wait_queue_head_t dac_wait; -+ wait_queue_head_t adc_wait; -+ int nextIn; /* byte index to next-in to DMA buffer */ -+ int nextOut; /* byte index to next-out from DMA buffer */ -+ int count; /* current byte count in DMA buffer */ -+ int finish; /* current transfered byte count in DMA buffer */ -+ unsigned total_bytes; /* total bytes written or read */ -+ unsigned blocks; -+ unsigned error; /* over/underrun */ -+#ifdef CONFIG_PM -+ struct pm_dev *pm; -+#endif -+}; -+ -+ -+static struct jz_i2s_controller_info *i2s_controller = NULL; -+struct i2s_codec -+{ -+ /* I2S controller connected with */ -+ void *private_data; -+ char *name; -+ int id; -+ int dev_mixer; -+ /* controller specific lower leverl i2s accessing routines */ -+ u16 (*codec_read) (u8 reg); /* the function accessing Codec REGs */ -+ void (*codec_write) (u8 reg, u16 val); -+ /* Wait for codec-ready */ -+ void (*codec_wait) (struct i2s_codec *codec); -+ /* OSS mixer masks */ -+ int modcnt; -+ int supported_mixers; -+ int stereo_mixers; -+ int record_sources; -+ int bit_resolution; -+ /* OSS mixer interface */ -+ int (*read_mixer) (struct i2s_codec *codec, int oss_channel); -+ void (*write_mixer)(struct i2s_codec *codec, int oss_channel, -+ unsigned int left, unsigned int right); -+ int (*recmask_io) (struct i2s_codec *codec, int rw, int mask); -+ int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg); -+ /* saved OSS mixer states */ -+ unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; -+}; -+ -+ -+typedef struct buffer_queue_s -+{ -+ int count; -+ int *id; -+ int lock; -+} buffer_queue_t; -+ -+typedef struct left_right_sample_s -+{ -+ signed long left; -+ signed long right; -+} left_right_sample_t; -+ -+static unsigned long pop_turn_onoff_buf; -+static unsigned long pop_turn_onoff_pbuf; -+ -+static unsigned long *out_dma_buf = NULL; -+static unsigned long *out_dma_pbuf = NULL; -+static unsigned long *out_dma_buf_data_count = NULL; -+static unsigned long *in_dma_buf = NULL; -+static unsigned long *in_dma_pbuf = NULL; -+static unsigned long *in_dma_buf_data_count = NULL; -+ -+static buffer_queue_t out_empty_queue; -+static buffer_queue_t out_full_queue; -+static buffer_queue_t out_busy_queue; -+static buffer_queue_t in_empty_queue; -+static buffer_queue_t in_full_queue; -+static buffer_queue_t in_busy_queue; -+static int first_record_call = 0; -+ -+static left_right_sample_t save_last_samples[64]; -+ -+static inline int get_buffer_id(struct buffer_queue_s *q) -+{ -+ int r; -+ unsigned long flags; -+ int i; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ if (q->count == 0) { -+ spin_unlock_irqrestore(&q->lock, flags); -+ return -1; -+ } -+ r = *(q->id + 0); -+ for (i=0;i < q->count-1;i++) -+ *(q->id + i) = *(q->id + (i+1)); -+ q->count --; -+ spin_unlock_irqrestore(&q->lock, flags); -+ -+ return r; -+} -+ -+static inline void put_buffer_id(struct buffer_queue_s *q, int id) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ *(q->id + q->count) = id; -+ q->count ++; -+ spin_unlock_irqrestore(&q->lock, flags); -+} -+ -+static inline int elements_in_queue(struct buffer_queue_s *q) -+{ -+ int r; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ r = q->count; -+ spin_unlock_irqrestore(&q->lock, flags); -+ -+ return r; -+} -+ -+static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode) -+{ -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ jz_audio_dma_tran_count = count / jz_audio_b; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ flags = claim_dma_lock(); -+ disable_dma(chan); -+ clear_dma_ff(chan); -+#if 1 -+ jz_set_oss_dma(chan, mode, jz_audio_format); -+#else -+ set_dma_mode(chan, mode); -+#endif -+ set_dma_addr(chan, phyaddr); -+ if (count == 0) { -+ count++; -+ printk("JzSOC DMA controller can't set dma 0 count!\n"); -+ } -+ set_dma_count(chan, count); -+ enable_dma(chan); -+ release_dma_lock(flags); -+} -+ -+static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id) -+{ -+ int id1, id2; -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ int dma = controller->dma2; -+ -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ -+ if(drain_flag == 1) -+ wake_up(&drain_wait_queue); -+ /* for DSP_GETIPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ id1 = get_buffer_id(&in_busy_queue); -+ put_buffer_id(&in_full_queue, id1); -+ -+ wake_up(&rx_wait_queue); -+ wake_up(&controller->adc_wait); -+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id2); -+ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1); -+ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2)); -+ audio_start_dma(dma,dev_id, -+ *(in_dma_pbuf + id2), -+ *(in_dma_buf_data_count + id2), -+ DMA_MODE_READ); -+ } else -+ in_busy_queue.count = 0; -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id) -+{ -+ int id; -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ int dma = controller->dma1; -+ -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ -+ if(pop_dma_flag == 1) { -+ pop_dma_flag = 0; -+ wake_up(&pop_wait_queue); -+ } else { -+ if(drain_flag == 1) { -+ /* Is replay dma buffer over ? */ -+ if(elements_in_queue(&out_full_queue) <= 0) { -+ drain_flag = 0; -+ wake_up(&drain_wait_queue); -+ } -+ } -+ -+ /* for DSP_GETOPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ if ((id = get_buffer_id(&out_busy_queue)) < 0) -+ printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n"); -+ put_buffer_id(&out_empty_queue, id); -+ if ((id = get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_busy_queue, id); -+ if(*(out_dma_buf_data_count + id) > 0) { -+ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id), -+ *(out_dma_buf_data_count + id), -+ DMA_MODE_WRITE); -+ last_dma_buffer_id = id; -+ } -+ } else -+ out_busy_queue.count = 0; -+ -+ if (elements_in_queue(&out_empty_queue) > 0) { -+ wake_up(&tx_wait_queue); -+ wake_up(&controller->dac_wait); -+ } -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static void jz_i2s_initHw(int set) -+{ -+#if defined(CONFIG_MIPS_JZ_URANUS) -+ i2s_clk = 48000000; -+#else -+ i2s_clk = __cpm_get_i2sclk(); -+#endif -+ __i2s_disable(); -+ if(set) -+ __i2s_reset(); -+ schedule_timeout(5); -+ if(each_time_init_codec) -+ each_time_init_codec(); -+ __i2s_disable_record(); -+ __i2s_disable_replay(); -+ __i2s_disable_loopback(); -+ __i2s_set_transmit_trigger(4); -+ __i2s_set_receive_trigger(3); -+} -+ -+static int Init_In_Out_queue(int fragstotal,int fragsize) -+{ -+ int i; -+ -+ /* recording */ -+ in_empty_queue.count = fragstotal; -+ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_buf) -+ goto all_mem_err; -+ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_pbuf) -+ goto all_mem_err; -+ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_buf_data_count) -+ goto all_mem_err; -+ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_empty_queue.id) -+ goto all_mem_err; -+ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_full_queue.id) -+ goto all_mem_err; -+ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_busy_queue.id) -+ goto all_mem_err; -+ -+ for (i=0;i < fragstotal;i++) -+ *(in_empty_queue.id + i) = i; -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ -+ for (i = 0; i < fragstotal; i++) { -+ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); -+ if (*(in_dma_buf + i) == 0) -+ goto mem_failed_in; -+ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i))); -+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); -+ } -+ -+ /* playing */ -+ out_empty_queue.count = fragstotal; -+ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!out_dma_buf) -+ goto all_mem_err; -+ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!out_dma_pbuf) -+ goto all_mem_err; -+ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ -+ if (!out_dma_buf_data_count) -+ goto all_mem_err; -+ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_empty_queue.id) -+ goto all_mem_err; -+ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_full_queue.id) -+ goto all_mem_err; -+ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_busy_queue.id) -+ goto all_mem_err; -+ for (i=0;i < fragstotal;i++) -+ *(out_empty_queue.id + i) = i; -+ -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ /* alloc DMA buffer */ -+ for (i = 0; i < fragstotal; i++) { -+ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); -+ if (*(out_dma_buf + i) == 0) { -+ printk(" can't allocate required DMA(OUT) buffers.\n"); -+ goto mem_failed_out; -+ } -+ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); -+ } -+ -+ return 1; -+all_mem_err: -+ printk("error:allocate memory occur error 1!\n"); -+ return 0; -+mem_failed_out: -+ printk("error:allocate memory occur error 2!\n"); -+ for (i = 0; i < fragstotal; i++) { -+ if(*(out_dma_buf + i)) -+ free_pages(*(out_dma_buf + i), get_order(fragsize)); -+ } -+ -+ return 0; -+mem_failed_in: -+ printk("error:allocate memory occur error 3!\n"); -+ for (i = 0; i < fragstotal; i++) { -+ if(*(in_dma_buf + i)) -+ free_pages(*(in_dma_buf + i), get_order(fragsize)); -+ } -+ return 0; -+} -+ -+static int Free_In_Out_queue(int fragstotal,int fragsize) -+{ -+ int i; -+ /* playing */ -+ if(out_dma_buf != NULL) { -+ for (i = 0; i < fragstotal; i++) { -+ if(*(out_dma_buf + i)) -+ free_pages(*(out_dma_buf + i), get_order(fragsize)); -+ *(out_dma_buf + i) = 0; -+ } -+ kfree(out_dma_buf); -+ out_dma_buf = NULL; -+ } -+ if(out_dma_pbuf) { -+ kfree(out_dma_pbuf); -+ out_dma_pbuf = NULL; -+ } -+ if(out_dma_buf_data_count) { -+ kfree(out_dma_buf_data_count); -+ out_dma_buf_data_count = NULL; -+ } -+ if(out_empty_queue.id) { -+ kfree(out_empty_queue.id); -+ out_empty_queue.id = NULL; -+ } -+ if(out_full_queue.id) { -+ kfree(out_full_queue.id); -+ out_full_queue.id = NULL; -+ } -+ if(out_busy_queue.id) { -+ kfree(out_busy_queue.id); -+ out_busy_queue.id = NULL; -+ } -+ out_empty_queue.count = fragstotal; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ -+ /* recording */ -+ if(in_dma_buf) { -+ for (i = 0; i < fragstotal; i++) { -+ if(*(in_dma_buf + i)) { -+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); -+ free_pages(*(in_dma_buf + i), get_order(fragsize)); -+ } -+ *(in_dma_buf + i) = 0; -+ } -+ kfree(in_dma_buf); -+ in_dma_buf = NULL; -+ } -+ if(in_dma_pbuf) { -+ kfree(in_dma_pbuf); -+ in_dma_pbuf = NULL; -+ } -+ if(in_dma_buf_data_count) { -+ kfree(in_dma_buf_data_count); -+ in_dma_buf_data_count = NULL; -+ } -+ if(in_empty_queue.id) { -+ kfree(in_empty_queue.id); -+ in_empty_queue.id = NULL; -+ } -+ if(in_full_queue.id) { -+ kfree(in_full_queue.id); -+ in_full_queue.id = NULL; -+ } -+ if(in_busy_queue.id) { -+ kfree(in_busy_queue.id); -+ in_busy_queue.id = NULL; -+ } -+ -+ in_empty_queue.count = fragstotal; -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ -+ return 1; -+} -+ -+static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller) -+{ -+ jz_i2s_initHw(0); -+} -+ -+static int jz_audio_set_speed(int dev, int rate) -+{ -+ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */ -+ jz_audio_speed = rate; -+#if defined(CONFIG_I2S_DLV) -+ if (rate > 96000) -+ rate = 96000; -+#else -+ if (rate > 48000) -+ rate = 48000; -+#endif -+ if (rate < 8000) -+ rate = 8000; -+ jz_audio_rate = rate; -+ -+ if(set_codec_speed) -+ set_codec_speed(rate); -+ -+ return jz_audio_rate; -+} -+ -+ -+static int record_fill_1x8_u(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long data; -+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ volatile unsigned char *dp = (unsigned char*)dst_start; -+ -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt++; -+ data = *(s++); -+ *(dp ++) = ((data << 16) >> 24) + 0x80; -+ s++; /* skip the other channel */ -+ } -+ -+ return cnt; -+} -+ -+ -+static int record_fill_2x8_u(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1, d2; -+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ volatile unsigned char *dp = (unsigned char*)dst_start; -+ -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ *(dp ++) = ((d1 << 16) >> 24) + 0x80; -+ d2 = *(s++); -+ *(dp ++) = ((d2 << 16) >> 24) + 0x80; -+ } -+ -+ return cnt; -+} -+ -+ -+static int record_fill_1x16_s(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1; -+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ unsigned short *dp = (unsigned short *)dst_start; -+ -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt += 2; /* count in byte */ -+ d1 = *(s++); -+ *(dp ++) = (d1 << 16) >> 16; -+ s++; /* skip the other channel */ -+ } -+ -+ return cnt; -+} -+ -+ -+static int record_fill_2x16_s(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1, d2; -+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ unsigned short *dp = (unsigned short *)dst_start; -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt += 4; /* count in byte */ -+ d1 = *(s++); -+ d2 = *(s++); -+ if(abnormal_data_count > 0) { -+ d1 = d2 = 0; -+ abnormal_data_count --; -+ } -+ *(dp ++) = (d1 << 16) >> 16; -+ *(dp ++) = (d2 << 16) >> 16; -+ } -+ -+ return cnt; -+} -+ -+static void replay_fill_1x8_u(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned char data; -+ unsigned long ddata; -+ volatile unsigned char *s = (unsigned char *)src_start; -+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count--; -+ cnt += 1; -+ data = *(s++) - 0x80; -+ ddata = (unsigned long) data << 8; -+ *(dp ++) = ddata; -+ *(dp ++) = ddata; -+ -+ /* save last left and right */ -+ if(count == 1) { -+ save_last_samples[id].left = ddata; -+ save_last_samples[id].right = ddata; -+ } -+ } -+ cnt = cnt * 2 * jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+ -+static void replay_fill_2x8_u(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned char d1; -+ unsigned long dd1; -+ volatile unsigned char *s = (unsigned char *)src_start; -+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count -= 1; -+ cnt += 1 ; -+ d1 = *(s++) - 0x80; -+ dd1 = (unsigned long) d1 << 8; -+ *(dp ++) = dd1; -+ /* save last left */ -+ if(count == 2) -+ save_last_samples[id].left = dd1; -+ /* save last right */ -+ if(count == 1) -+ save_last_samples[id].right = dd1; -+ } -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+ -+static void replay_fill_1x16_s(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed short d1; -+ signed long l1; -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count -= 2; -+ cnt += 2 ; -+ d1 = *(s++); -+ l1 = (signed long)d1; -+#if defined(CONFIG_I2S_ICODEC) -+ l1 >>= codec_volue_shift; -+#endif -+ *(dp ++) = l1; -+ *(dp ++) = l1; -+ -+ /* save last left and right */ -+ if(count == 1) { -+ save_last_samples[id].left = l1; -+ save_last_samples[id].right = l1; -+ } -+ } -+ cnt = cnt * 2 * jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+static void replay_fill_2x16_s(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed short d1; -+ signed long l1; -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+#if defined(CONFIG_I2S_ICODEC) -+ int mute_cnt = 0; -+ signed long tmp1,tmp2; -+ volatile signed long *before_dp; -+ int sam_rate = jz_audio_rate / 20; -+ -+ tmp1 = tmp2 = 0; -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ -+ l1 = (signed long)d1; -+ l1 >>= codec_volue_shift; -+ -+ if(l1 == 0) { -+ mute_cnt ++; -+ if(mute_cnt >= sam_rate) { -+ before_dp = dp - 10; -+ *(before_dp) = (signed long)1; -+ before_dp = dp - 11; -+ *(before_dp) = (signed long)1; -+ mute_cnt = 0; -+ } -+ } else -+ mute_cnt = 0; -+ -+ *(dp ++) = l1; -+ -+ tmp1 = tmp2; -+ tmp2 = l1; -+ } -+ -+ /* save last left */ -+ save_last_samples[id].left = tmp1; -+ /* save last right */ -+ save_last_samples[id].right = tmp2; -+#endif -+#if defined(CONFIG_I2S_DLV) -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ -+ l1 = (signed long)d1; -+ -+ *(dp ++) = l1; -+ } -+#endif -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+static void replay_fill_2x18_s(unsigned long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed long d1; -+ signed long l1; -+ volatile signed long *s = (signed long *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+ while (count > 0) { -+ count -= 4; -+ cnt += 4; -+ d1 = *(s++); -+ l1 = (signed long)d1; -+ *(dp ++) = l1; -+ } -+ -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+static unsigned int jz_audio_set_format(int dev, unsigned int fmt) -+{ -+ switch (fmt) { -+ case AFMT_U8: -+ __i2s_set_oss_sample_size(8); -+ __i2s_set_iss_sample_size(8); -+ jz_audio_format = fmt; -+ jz_update_filler(jz_audio_format,jz_audio_channels); -+ break; -+ case AFMT_S16_LE: -+#if defined(CONFIG_I2S_DLV) -+ /* DAC path and ADC path */ -+ write_codec_file(2, 0x00); -+ //write_codec_file(2, 0x60); -+#endif -+ jz_audio_format = fmt; -+ jz_update_filler(jz_audio_format,jz_audio_channels); -+ __i2s_set_oss_sample_size(16); -+ __i2s_set_iss_sample_size(16); -+ break; -+ case 18: -+ __i2s_set_oss_sample_size(18); -+ jz_audio_format = fmt; -+ jz_update_filler(jz_audio_format,jz_audio_channels); -+ break; -+ case AFMT_QUERY: -+ break; -+ } -+ -+ return jz_audio_format; -+} -+ -+ -+static short jz_audio_set_channels(int dev, short channels) -+{ -+ switch (channels) { -+ case 1: -+ if(set_codec_some_func) -+ set_codec_some_func(); -+ jz_audio_channels = channels; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono -+#endif -+ break; -+ case 2: -+ jz_audio_channels = channels; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo -+#endif -+ break; -+ case 0: -+ break; -+ } -+ -+ return jz_audio_channels; -+} -+ -+static void init_codec(void) -+{ -+ /* inititalize internal I2S codec */ -+ if(init_codec_pin) -+ init_codec_pin(); -+ -+#if defined(CONFIG_I2S_ICDC) -+ /* initialize AIC but not reset it */ -+ jz_i2s_initHw(0); -+#endif -+ if(reset_codec) -+ reset_codec(); -+} -+ -+static void jz_audio_reset(void) -+{ -+ __i2s_disable_replay(); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+ __i2s_disable_transmit_dma(); -+#if defined(CONFIG_I2S_DLV) -+ REG_AIC_I2SCR = 0x10; -+#endif -+ init_codec(); -+} -+ -+static int jz_audio_release(struct inode *inode, struct file *file); -+static int jz_audio_open(struct inode *inode, struct file *file); -+static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg); -+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait); -+static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos); -+static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos); -+ -+/* static struct file_operations jz_i2s_audio_fops */ -+static struct file_operations jz_i2s_audio_fops = -+{ -+ owner: THIS_MODULE, -+ open: jz_audio_open, -+ release: jz_audio_release, -+ write: jz_audio_write, -+ read: jz_audio_read, -+ poll: jz_audio_poll, -+ ioctl: jz_audio_ioctl -+}; -+ -+static int jz_i2s_open_mixdev(struct inode *inode, struct file *file) -+{ -+ int i; -+ int minor = MINOR(inode->i_rdev); -+ struct jz_i2s_controller_info *controller = i2s_controller; -+ -+ for (i = 0; i < NR_I2S; i++) -+ if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor) -+ goto match; -+ -+ if (!controller) -+ return -ENODEV; -+match: -+ file->private_data = controller->i2s_codec[i]; -+ -+ return 0; -+} -+ -+static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ struct i2s_codec *codec = (struct i2s_codec *)file->private_data; -+ return codec->mixer_ioctl(codec, cmd, arg); -+} -+ -+static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin) -+{ -+ return -ESPIPE; -+} -+ -+static struct file_operations jz_i2s_mixer_fops = -+{ -+ owner: THIS_MODULE, -+ llseek: jz_i2s_llseek, -+ ioctl: jz_i2s_ioctl_mixdev, -+ open: jz_i2s_open_mixdev, -+}; -+ -+static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg) -+{ -+ int ret; -+ long val = 0; -+ switch (cmd) { -+ case SOUND_MIXER_INFO: -+ -+ if(codec_mixer_info_id_name) -+ codec_mixer_info_id_name(); -+ info.modify_counter = audio_mix_modcnt; -+ -+ return copy_to_user((void *)arg, &info, sizeof(info)); -+ case SOUND_OLD_MIXER_INFO: -+ -+ if(codec_mixer_old_info_id_name) -+ codec_mixer_old_info_id_name(); -+ -+ return copy_to_user((void *)arg, &old_info, sizeof(info)); -+ case SOUND_MIXER_READ_STEREODEVS: -+ -+ return put_user(0, (long *) arg); -+ case SOUND_MIXER_READ_CAPS: -+ -+ val = SOUND_CAP_EXCL_INPUT; -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_READ_DEVMASK: -+ break; -+ case SOUND_MIXER_READ_RECMASK: -+ break; -+ case SOUND_MIXER_READ_RECSRC: -+ break; -+ case SOUND_MIXER_WRITE_SPEAKER: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ switch(val) { -+ case 100: -+ if(set_codec_direct_mode) -+ set_codec_direct_mode(); -+ break; -+ case 0: -+ if(clear_codec_direct_mode) -+ clear_codec_direct_mode(); -+ break; -+ } -+ break; -+ case SOUND_MIXER_WRITE_BASS: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ codec_bass_gain = val; -+ if(set_codec_bass) -+ set_codec_bass(val); -+ -+ return 0; -+ case SOUND_MIXER_READ_BASS: -+ -+ val = codec_bass_gain; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_WRITE_VOLUME: -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ -+ jz_audio_volume = val; -+ if(set_codec_volume) -+ set_codec_volume(val); -+ -+ return 0; -+ case SOUND_MIXER_READ_VOLUME: -+ -+ val = jz_audio_volume; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ -+ case SOUND_MIXER_WRITE_MIC: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ codec_mic_gain = val; -+ use_mic_line_flag = USE_MIC; -+ if(set_codec_mic) -+ set_codec_mic(val); -+ -+ return 0; -+ case SOUND_MIXER_READ_MIC: -+ -+ val = codec_mic_gain; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ -+ case SOUND_MIXER_WRITE_LINE: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ use_mic_line_flag = USE_LINEIN; -+ codec_mic_gain = val; -+ if(set_codec_line) -+ set_codec_line(val); -+ -+ return 0; -+ case SOUND_MIXER_READ_LINE: -+ -+ val = codec_mic_gain; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ default: -+ return -ENOSYS; -+ } -+ audio_mix_modcnt ++; -+ return 0; -+} -+ -+ -+int i2s_probe_codec(struct i2s_codec *codec) -+{ -+ /* generic OSS to I2S wrapper */ -+ codec->mixer_ioctl = i2s_mixer_ioctl; -+ return 1; -+} -+ -+ -+/* I2S codec initialisation. */ -+static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller) -+{ -+ int num_i2s = 0; -+ struct i2s_codec *codec; -+ -+ for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) { -+ if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL) -+ return -ENOMEM; -+ memset(codec, 0, sizeof(struct i2s_codec)); -+ codec->private_data = controller; -+ codec->id = num_i2s; -+ -+ if (i2s_probe_codec(codec) == 0) -+ break; -+ if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) { -+ printk(KERN_ERR "Jz I2S: couldn't register mixer!\n"); -+ kfree(codec); -+ break; -+ } -+ controller->i2s_codec[num_i2s] = codec; -+ } -+ return num_i2s; -+} -+ -+ -+static void jz_update_filler(int format, int channels) -+{ -+#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) -+ -+ switch (TYPE(format, channels)) -+ { -+ -+ case TYPE(AFMT_U8, 1): -+ jz_audio_b = 4; /* 4bytes * 8bits =32bits */ -+ replay_filler = replay_fill_1x8_u; -+ record_filler = record_fill_1x8_u; -+ break; -+ case TYPE(AFMT_U8, 2): -+ jz_audio_b = 4; -+ replay_filler = replay_fill_2x8_u; -+ record_filler = record_fill_2x8_u; -+ break; -+ case TYPE(AFMT_S16_LE, 1): -+ jz_audio_b = 2; /* 2bytes * 16bits =32bits */ -+ replay_filler = replay_fill_1x16_s; -+ record_filler = record_fill_1x16_s; -+ break; -+ case TYPE(AFMT_S16_LE, 2): -+ jz_audio_b = 2; -+ replay_filler = replay_fill_2x16_s; -+ record_filler = record_fill_2x16_s; -+ break; -+ case TYPE(18, 2): -+ jz_audio_b = 1; -+ replay_filler = replay_fill_2x18_s; -+ record_filler = record_fill_2x16_s; -+ break; -+ default: -+ ; -+ } -+} -+ -+ -+#ifdef CONFIG_PROC_FS -+extern struct proc_dir_entry *proc_jz_root; -+int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) -+{ -+ return 0; -+} -+ -+static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller) -+{ -+ if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0])) -+ return -EIO; -+ return 0; -+} -+ -+static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller) -+{ -+} -+#endif -+ -+static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller) -+{ -+ char *name; -+ int adev; /* No of Audio device. */ -+ -+ name = controller->name; -+ /* initialize AIC controller and reset it */ -+ jz_i2s_initHw(1); -+ adev = register_sound_dsp(&jz_i2s_audio_fops, -1); -+ if (adev < 0) -+ goto audio_failed; -+ /* initialize I2S codec and register /dev/mixer */ -+ if (jz_i2s_codec_init(controller) <= 0) -+ goto mixer_failed; -+ -+#ifdef CONFIG_PROC_FS -+ if (jz_i2s_init_proc(controller) < 0) { -+ printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name); -+ goto proc_failed; -+ } -+#endif -+ -+ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8); -+ if (!controller->tmp1) { -+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); -+ goto tmp1_failed; -+ } -+ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8); -+ if (!controller->tmp2) { -+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); -+ goto tmp2_failed; -+ } -+ if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) { -+ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name); -+ goto dma2_failed; -+ } -+ if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) { -+ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name); -+ goto dma1_failed; -+ } -+ printk("JzSOC On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2)); -+ -+ controller->dev_audio = adev; -+ pop_turn_onoff_buf = __get_free_pages(GFP_KERNEL | GFP_DMA, 8); -+ if(!pop_turn_onoff_buf) -+ printk("pop_turn_onoff_buf alloc is wrong!\n"); -+ pop_turn_onoff_pbuf = virt_to_phys((void *)pop_turn_onoff_buf); -+ -+ return; -+dma2_failed: -+ jz_free_dma(controller->dma1); -+dma1_failed: -+ free_pages((unsigned long)controller->tmp2, 8); -+tmp2_failed: -+ free_pages((unsigned long)controller->tmp1, 8); -+tmp1_failed: -+ -+#ifdef CONFIG_PROC_FS -+ jz_i2s_cleanup_proc(controller); -+#endif -+proc_failed: -+ /* unregister mixer dev */ -+mixer_failed: -+ unregister_sound_dsp(adev); -+audio_failed: -+ return; -+} -+ -+static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller) -+{ -+ if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info), -+ GFP_KERNEL)) == NULL) { -+ printk(KERN_ERR "Jz I2S Controller: out of memory.\n"); -+ return -ENOMEM; -+ } -+ (*controller)->name = "Jz I2S controller"; -+ (*controller)->opened1 = 0; -+ (*controller)->opened2 = 0; -+ init_waitqueue_head(&(*controller)->adc_wait); -+ init_waitqueue_head(&(*controller)->dac_wait); -+ spin_lock_init(&(*controller)->lock); -+ init_waitqueue_head(&rx_wait_queue); -+ init_waitqueue_head(&tx_wait_queue); -+ init_waitqueue_head(&pop_wait_queue); -+ init_waitqueue_head(&drain_wait_queue); -+ -+ return 0; -+} -+ -+static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller) -+{ -+ int adev = controller->dev_audio; -+ -+ jz_i2s_full_reset(controller); -+ controller->dev_audio = -1; -+ if (old_mksound) -+ kd_mksound = old_mksound;/* Our driver support bell for kb, see vt.c */ -+ -+#ifdef CONFIG_PROC_FS -+ jz_i2s_cleanup_proc(controller); -+#endif -+ -+ jz_free_dma(controller->dma1); -+ jz_free_dma(controller->dma2); -+ free_pages((unsigned long)controller->tmp1, 8); -+ free_pages((unsigned long)controller->tmp2, 8); -+ free_pages((unsigned long)pop_turn_onoff_buf, 8); -+ -+ if (adev >= 0) { -+ /* unregister_sound_mixer(audio_devs[adev]->mixer_dev); */ -+ unregister_sound_dsp(controller->dev_audio); -+ } -+} -+ -+#ifdef CONFIG_PM -+static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state) -+{ -+ if(i2s_suspend_codec) -+ i2s_suspend_codec(controller->opened1,controller->opened2); -+ printk("Aic and codec are suspended!\n"); -+ return 0; -+} -+ -+static int jz_i2s_resume(struct jz_i2s_controller_info *controller) -+{ -+ if(i2s_resume_codec) -+ i2s_resume_codec(); -+ -+#if defined(CONFIG_I2S_AK4642EN) -+ jz_i2s_initHw(0); -+ jz_audio_reset(); -+ __i2s_enable(); -+ jz_audio_set_speed(controller->dev_audio,jz_audio_speed); -+ /* playing */ -+ if(controller->opened1) { -+ if(set_codec_replay) -+ set_codec_replay(); -+ int dma = controller->dma1; -+ int id; -+ unsigned long flags; -+ disable_dma(dma); -+ if(__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if(__dmac_channel_transmit_end_detected(dma)) -+ __dmac_channel_clear_transmit_end(dma); -+ -+ /* for DSP_GETOPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ while((id = get_buffer_id(&out_busy_queue)) >= 0) -+ put_buffer_id(&out_empty_queue, id); -+ -+ out_busy_queue.count=0; -+ if((id = get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_empty_queue, id); -+ } -+ if (elements_in_queue(&out_empty_queue) > 0) { -+ wake_up(&tx_wait_queue); -+ wake_up(&controller->dac_wait); -+ } else -+ printk("pm out_empty_queue empty"); -+ } -+ -+ /* recording */ -+ if(controller->opened2) { -+ if(set_codec_record) -+ set_codec_record(use_mic_line_flag); -+ int dma = controller->dma2; -+ int id1, id2; -+ unsigned long flags; -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ } -+ /* for DSP_GETIPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ id1 = get_buffer_id(&in_busy_queue); -+ put_buffer_id(&in_full_queue, id1); -+ wake_up(&rx_wait_queue); -+ wake_up(&controller->adc_wait); -+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_full_queue, id2); -+ } -+ in_busy_queue.count = 0; -+ } -+#endif -+ -+ return 0; -+} -+ -+static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) -+{ -+ int ret; -+ struct jz_i2s_controller_info *controller = pm_dev->data; -+ -+ if (!controller) return -EINVAL; -+ -+ switch (req) { -+ case PM_SUSPEND: -+ ret = jz_i2s_suspend(controller, (int)data); -+ break; -+ case PM_RESUME: -+ ret = jz_i2s_resume(controller); -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+#endif /* CONFIG_PM */ -+ -+#if defined(CONFIG_I2S_DLV) -+static irqreturn_t aic_codec_irq(int irq, void *dev_id) -+{ -+ u8 file_9 = read_codec_file(9); -+ u8 file_8 = read_codec_file(8); -+ -+ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9); -+ if ((file_9 & 0x1f) == 0x10) { -+ -+ write_codec_file(8, 0x3f); -+ write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ mdelay(300); -+ while ((read_codec_file(9) & 0x4) != 0x4); -+ while ((read_codec_file(9) & 0x10) == 0x10) { -+ write_codec_file(9, 0x10); -+ } -+ write_codec_file_bit(5, 0, 6);//SB_OUT->0 -+ mdelay(300); -+ while ((read_codec_file(9) & 0x8) != 0x8); -+ write_codec_file(9, file_9); -+ write_codec_file(8, file_8); -+ -+ return IRQ_HANDLED; -+ } -+ -+ if (file_9 & 0x8) -+ ramp_up_end = jiffies; -+ else if (file_9 & 0x4) -+ ramp_down_end = jiffies; -+ else if (file_9 & 0x2) -+ gain_up_end = jiffies; -+ else if (file_9 & 0x1) -+ gain_down_end = jiffies; -+ -+ write_codec_file(9, file_9); -+ if (file_9 & 0xf) -+ wake_up(&pop_wait_queue); -+ while (REG_ICDC_RGDATA & 0x100); -+ -+ return IRQ_HANDLED; -+} -+#endif -+ -+static int __init init_jz_i2s(void) -+{ -+ int errno; -+#if defined(CONFIG_I2S_DLV) -+ int retval; -+ ramp_up_start = 0; -+ ramp_up_end = 0; -+ gain_up_start = 0; -+ gain_up_end = 0; -+ ramp_down_start = 0; -+ ramp_down_end = 0; -+ gain_down_start = 0; -+ gain_down_end = 0; -+#endif -+ use_mic_line_flag = USE_NONE; -+ abnormal_data_count = 0; -+ if(set_codec_mode) -+ set_codec_mode(); -+ -+ drain_flag = 0; -+ if ((errno = probe_jz_i2s(&i2s_controller)) < 0) -+ return errno; -+ if(set_codec_gpio_pin) -+ set_codec_gpio_pin(); -+ -+ attach_jz_i2s(i2s_controller); -+ if(set_codec_startup_param) -+ set_codec_startup_param(); -+ if(set_codec_volume_table) -+ set_codec_volume_table(); -+ -+#if defined(CONFIG_I2S_DLV) -+ jz_codec_config = 0; -+ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL); -+ if (retval) { -+ printk("Could not get aic codec irq %d\n", IRQ_AIC); -+ return retval; -+ } -+#endif -+ -+ out_empty_queue.id = NULL; -+ out_full_queue.id = NULL; -+ out_busy_queue.id = NULL; -+ in_empty_queue.id = NULL; -+ in_full_queue.id = NULL; -+ in_busy_queue.id = NULL; -+ -+ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE; -+ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ; -+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ -+#ifdef CONFIG_PM -+ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, -+ jz_i2s_pm_callback); -+ if (i2s_controller->pm) -+ i2s_controller->pm->data = i2s_controller; -+#endif -+#if defined(CONFIG_I2S_DLV) -+ __cpm_start_idct(); -+ __cpm_start_db(); -+ __cpm_start_me(); -+ __cpm_start_mc(); -+ __cpm_start_ipu(); -+#endif -+ printk("JZ I2S OSS audio driver initialized\n"); -+ -+ return 0; -+} -+ -+static void __exit cleanup_jz_i2s(void) -+{ -+#ifdef CONFIG_PM -+ /* pm_unregister(i2s_controller->pm); */ -+#endif -+#if defined(CONFIG_I2S_DLV) -+ free_irq(IRQ_AIC, NULL); -+#endif -+ unload_jz_i2s(i2s_controller); -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ if(clear_codec_mode) -+ clear_codec_mode(); -+} -+ -+module_init(init_jz_i2s); -+module_exit(cleanup_jz_i2s); -+ -+#if defined(CONFIG_SOC_JZ4730) -+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count,con; -+ -+ if(elements_in_queue(&in_busy_queue) > 0) { -+ if (nonblock) -+ return -EBUSY; -+ drain_flag = 1; -+ sleep_on(&drain_wait_queue); -+ drain_flag = 0; -+ } else { -+ add_wait_queue(&ctrl->adc_wait, &wait); -+ for (con = 0; con < 1000; con ++) { -+ udelay(1); -+ set_current_state(TASK_INTERRUPTIBLE); -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ if (nonblock) { -+ remove_wait_queue(&ctrl->adc_wait, &wait); -+ current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ } -+ remove_wait_queue(&ctrl->adc_wait, &wait); -+ current->state = TASK_RUNNING; -+ } -+ return 0; -+} -+ -+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count; -+ -+ if(elements_in_queue(&out_full_queue) > 0) { -+ if (nonblock) -+ return -EBUSY; -+ -+ drain_flag = 1; -+ sleep_on(&drain_wait_queue); -+ drain_flag = 0; -+ } else { -+ add_wait_queue(&(ctrl->dac_wait), &wait); -+ for (;;) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ if(elements_in_queue(&out_full_queue) <= 0) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if(count <= 0) -+ break; -+ } -+ if (nonblock) { -+ remove_wait_queue(&ctrl->dac_wait, &wait); -+ current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ } -+ remove_wait_queue(&ctrl->dac_wait, &wait); -+ current->state = TASK_RUNNING; -+ } -+ -+ return 0; -+} -+#endif -+ -+#if defined(CONFIG_SOC_JZ4740) -+#define MAXDELAY 50000 -+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ int count,ele,i=0; -+ int tfl; -+ -+ for (;;) { -+ if(!nonblock) {//blocked -+ if ( i < MAXDELAY ) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ -+ ele = elements_in_queue(&out_full_queue); -+ if(ele <= 0) { -+ udelay(10); -+ spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ } -+ } else {//non-blocked -+ mdelay(100); -+ ele = elements_in_queue(&out_full_queue); -+ -+ if(ele <= 0) { -+ mdelay(100); -+ -+ spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ } -+ } -+ } -+ -+ /* wait for TX fifo */ -+ while (1) { -+ tfl = __aic_get_transmit_resident(); -+ if (tfl == 0) -+ break; -+ udelay(2); -+ } -+ -+ return 0; -+} -+ -+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ int count,i=0; -+ -+ for (;;) { -+ if ( i < MAXDELAY ) -+ { -+ udelay(10); -+ i++; -+ } -+ else -+ break; -+ spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ -+ if (nonblock) { -+ return -EBUSY; -+ } -+ } -+ -+ return 0; -+} -+#endif -+ -+#if defined(CONFIG_SOC_JZ4750) -+#define MAXDELAY 50000 -+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ //DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count,i=0; -+ -+ //add_wait_queue(&ctrl->adc_wait, &wait); -+ for (;;) { -+ if (i < MAXDELAY) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ //set_current_state(TASK_INTERRUPTIBLE); -+ spin_lock_irqsave(&ctrl->lock, flags); -+ //spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ //spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ -+ /*if (signal_pending(current)) -+ break;*/ -+ if (nonblock) { -+ //remove_wait_queue(&ctrl->adc_wait, &wait); -+ //current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ } -+ //remove_wait_queue(&ctrl->adc_wait, &wait); -+ //current->state = TASK_RUNNING; -+ /*if (signal_pending(current)) -+ return -ERESTARTSYS;*/ -+ return 0; -+} -+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ unsigned long flags; -+ int count,ele,busyele,emptyele,i=0; -+ -+ for (;;) { -+ if(!nonblock) {//blocked -+ if (i < MAXDELAY) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ -+ ele = elements_in_queue(&out_full_queue); -+ if(ele <= 0) { -+ udelay(200); -+ -+ busyele = elements_in_queue(&out_busy_queue); -+ emptyele = elements_in_queue(&out_empty_queue); -+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ } -+ } -+ } else {//non-blocked -+ //mdelay(100); -+ ele = elements_in_queue(&out_full_queue); -+ -+ if(ele <= 0) { -+ //mdelay(100); -+ busyele = elements_in_queue(&out_busy_queue); -+ emptyele = elements_in_queue(&out_empty_queue); -+ -+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ } -+ } -+ } -+ } -+ -+ return 0; -+} -+#endif -+ -+static int jz_audio_release(struct inode *inode, struct file *file) -+{ -+ unsigned long flags; -+#if defined(CONFIG_I2S_DLV) -+ unsigned long tfl; -+#endif -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+#if defined(CONFIG_I2S_DLV) -+ jz_codec_config = 0; -+#endif -+ if (controller == NULL) -+ return -ENODEV; -+ -+ pop_dma_flag = 0; -+ -+ if (controller->opened1 == 1 && controller->opened2 == 1) { -+ controller->opened1 = 0; -+ __i2s_enable_transmit_dma(); -+ __i2s_enable_replay(); -+ drain_dac(controller, file->f_flags & O_NONBLOCK); -+#if defined(CONFIG_I2S_DLV) -+ /* wait for fifo empty */ -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ gain_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //gain_down_end = jiffies; -+ /*while (1) { -+ tfl = REG_AIC_SR & 0x00003f00; -+ if (tfl == 0) { -+ udelay(500); -+ break; -+ } -+ mdelay(2); -+ }*/ -+ mdelay(100); -+#endif -+ disable_dma(controller->dma1); -+ set_dma_count(controller->dma1, 0); -+ __i2s_disable_transmit_dma(); -+ __i2s_disable_replay(); -+ -+#if defined(CONFIG_I2S_ICODEC) -+ if(clear_codec_replay) -+ clear_codec_replay(); -+#endif -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ controller->opened2 = 0; -+ first_record_call = 1; -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ drain_adc(controller, file->f_flags & O_NONBLOCK); -+ disable_dma(controller->dma2); -+ set_dma_count(controller->dma2, 0); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+#if defined(CONFIG_I2S_ICODEC) -+ if(clear_codec_record) -+ clear_codec_record(); -+#endif -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ ramp_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //ramp_down_end = jiffies; -+ if (use_mic_line_flag == USE_LINEIN) { -+ unset_record_line_input_audio_with_audio_data_replay(); -+ //printk("3 use_mic_line_flag=%d\n",use_mic_line_flag); -+ } -+ if (use_mic_line_flag == USE_MIC) { -+ unset_record_mic_input_audio_with_audio_data_replay(); -+ //printk("4 use_mic_line_flag=%d\n",use_mic_line_flag); -+ } -+ -+#if 0 -+ unset_record_playing_audio_mixed_with_mic_input_audio(); -+#endif -+#endif -+ __i2s_disable(); -+ if(turn_off_codec) -+ turn_off_codec(); -+ abnormal_data_count = 0; -+ } else if (controller->opened1 == 1) { -+ //controller->opened1 = 0; -+ __i2s_enable_transmit_dma(); -+ __i2s_enable_replay(); -+ drain_dac(controller, file->f_flags & O_NONBLOCK); -+ /* add some mute to anti-pop */ -+#if defined(CONFIG_I2S_ICODEC) -+ //write_mute_to_dma_buffer(save_last_samples[last_dma_buffer_id].left,save_last_samples[last_dma_buffer_id].right); -+#endif -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ gain_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //gain_down_end = jiffies; -+ while (1) { -+ tfl = REG_AIC_SR & 0x00003f00; -+ if (tfl == 0) { -+ udelay(500); -+ break; -+ } -+ mdelay(2); -+ } -+#endif -+ disable_dma(controller->dma1); -+ set_dma_count(controller->dma1, 0); -+ __i2s_disable_transmit_dma(); -+ __i2s_disable_replay(); -+#if defined(CONFIG_I2S_ICODEC) -+ if(clear_codec_replay) -+ clear_codec_replay(); -+#endif -+ __aic_flush_fifo(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ ramp_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //ramp_down_end = jiffies; -+ unset_audio_data_replay(); -+#endif -+ __i2s_disable(); -+#if defined(CONFIG_I2S_ICODEC) -+ if(turn_off_codec) -+ turn_off_codec(); -+#endif -+ } else if (controller->opened2 == 1) { -+ controller->opened2 = 0; -+ first_record_call = 1; -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ drain_adc(controller, file->f_flags & O_NONBLOCK); -+ disable_dma(controller->dma2); -+ set_dma_count(controller->dma2, 0); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+#if defined(CONFIG_I2S_ICODEC) -+ if(clear_codec_record) -+ clear_codec_record(); -+#endif -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+#if defined(CONFIG_I2S_DLV) -+#if 0 -+ /* unset Record MIC input audio with direct playback */ -+ unset_record_mic_input_audio_with_direct_playback(); -+#endif -+#if 1 -+ /* unset Record MIC input audio without playback */ -+ unset_record_mic_input_audio_without_playback(); -+#endif -+#if 0 -+ /* tested */ -+ /* unset Record LINE input audio without playback */ -+ unset_record_line_input_audio_without_playback(); -+#endif -+#endif -+ __i2s_disable(); -+#if defined(CONFIG_I2S_ICODEC) -+ if(turn_off_codec) -+ turn_off_codec(); -+#endif -+ abnormal_data_count = 0; -+ } -+ -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+/* __cpm_stop_idct(); -+ __cpm_stop_db(); -+ __cpm_stop_me(); -+ __cpm_stop_mc(); -+ __cpm_stop_ipu();*/ -+#endif -+ -+ if (controller->opened1 == 1 && controller->opened2 == 1) { -+ controller->opened1 = 0; -+ controller->opened2 = 0; -+ //print_pop_duration(); -+ //__dmac_disable_module(0); -+ } else if ( controller->opened1 == 1 ) { -+ controller->opened1 = 0; -+ //print_pop_duration(); -+ } else if ( controller->opened2 == 1 ) { -+ controller->opened2 = 0; -+ } -+ -+ return 0; -+} -+ -+static int jz_audio_open(struct inode *inode, struct file *file) -+{ -+ int i; -+ struct jz_i2s_controller_info *controller = i2s_controller; -+#if defined(CONFIG_I2S_DLV) -+ jz_codec_config = 0; -+#endif -+ if (controller == NULL) -+ return -ENODEV; -+ -+ mdelay(2); -+#if defined(CONFIG_I2S_DLV) -+ REG_DMAC_DMACKE(0) = 0x3f; -+#endif -+ pop_dma_flag = 0; -+ if (controller->opened1 == 1 || controller->opened2 == 1 ) { -+ printk("\naudio is busy!\n"); -+ return -EBUSY; -+ } -+ -+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { -+ if (controller->opened1 == 1) -+ return -EBUSY; -+ controller->opened1 = 1; -+ /* for ioctl */ -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ -+ for(i=0;i < 64;i++) { -+ save_last_samples[i].left = 0; -+ save_last_samples[i].right = 0; -+ } -+ -+ out_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(out_empty_queue.id + i) = i; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ last_dma_buffer_id = 0; -+ -+ if (controller->opened2 == 1) -+ return -EBUSY; -+ -+ controller->opened2 = 1; -+ first_record_call = 1; -+ /* for ioctl */ -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ -+ in_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(in_empty_queue.id + i) = i; -+ -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ } else if (file->f_mode & FMODE_WRITE) { -+ if (controller->opened1 == 1) -+ return -EBUSY; -+ -+ controller->opened1 = 1; -+ /* for ioctl */ -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ -+ for(i=0;i < 64;i++) { -+ save_last_samples[i].left = 0; -+ save_last_samples[i].right = 0; -+ } -+ -+ out_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(out_empty_queue.id + i) = i; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ last_dma_buffer_id = 0; -+ } else if (file->f_mode & FMODE_READ) { -+ if (controller->opened2 == 1) -+ return -EBUSY; -+ -+ controller->opened2 = 1; -+ first_record_call = 1; -+ /* for ioctl */ -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ -+ in_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(in_empty_queue.id + i) = i; -+ -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ } -+ -+ file->private_data = controller; -+ jz_audio_reset(); -+ REG_AIC_FR |= (1 << 6); -+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { -+#if defined(CONFIG_I2S_ICODEC) -+ if (set_codec_replay_record) -+ set_codec_replay_record(use_mic_line_flag); -+#endif -+#if defined(CONFIG_I2S_DLV) -+ if (use_mic_line_flag == USE_NONE) { -+ printk("you select mic or line recording please.or use mic recording!\n"); -+ use_mic_line_flag = USE_MIC; -+ } -+ if (use_mic_line_flag == USE_LINEIN) { -+ /* Record LINE input audio with Audio data replay (full duplex for linein) */ -+ /* codec_test_line */ -+ set_record_line_input_audio_with_audio_data_replay(); -+ -+ } -+ if (use_mic_line_flag == USE_MIC) { -+ /* Record MIC input audio with Audio data replay (full duplex) */ -+ /* codec_test_mic */ -+ set_record_mic_input_audio_with_audio_data_replay(); -+ } -+#if 0 -+ /* Record playing audio mixed with MIC input audio */ -+ set_record_playing_audio_mixed_with_mic_input_audio(); -+#endif -+ -+#endif -+ } else if (file->f_mode & FMODE_WRITE) { -+#if defined(CONFIG_I2S_ICODEC) -+ if(set_codec_replay) -+ set_codec_replay(); -+#endif -+#if defined(CONFIG_I2S_DLV) -+ //mdelay(10); -+ /* Audio data replay */ -+ set_audio_data_replay(); -+#endif -+ } else if (file->f_mode & FMODE_READ) { -+#if defined(CONFIG_I2S_ICODEC) -+ abnormal_data_count = 0; -+ if(set_codec_record) -+ set_codec_record(use_mic_line_flag); -+#endif -+#if defined(CONFIG_I2S_DLV) -+#if 0 -+ /* Record MIC input audio with direct playback */ -+ set_record_mic_input_audio_with_direct_playback(); -+#endif -+ -+#if 1 -+ /* set Record MIC input audio without playback */ -+ set_record_mic_input_audio_without_playback(); -+#endif -+#if 0 -+ /* tested */ -+ /* set Record LINE input audio without playback */ -+ set_record_line_input_audio_without_playback(); -+#endif -+ mdelay(1); -+#endif -+ } -+ -+#if defined(CONFIG_I2S_DLV) -+ __aic_reset(); -+ -+ mdelay(10); -+ REG_AIC_I2SCR = 0x10; -+ mdelay(20); -+ __aic_flush_fifo(); -+#endif -+ -+ __i2s_enable(); -+ -+#if defined(CONFIG_I2S_DLV) -+ ndelay(100); -+ -+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { -+#if defined(CONFIG_I2S_DLV) -+ //set SB_ADC or SB_DAC -+ __dmac_enable_module(0); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ ramp_up_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //ramp_up_end = jiffies; -+#endif -+ } else if (file->f_mode & FMODE_WRITE) { -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ ramp_up_start = jiffies; -+ /*while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_RCR = 0x1; -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_RGR = 1;*/ -+ sleep_on(&pop_wait_queue); -+ //ramp_up_end = jiffies; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+#endif -+ } else if (file->f_mode & FMODE_READ) { -+#if defined(CONFIG_I2S_DLV) -+ if (jz_mic_only) -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ else -+ write_codec_file_bit(5, 0, 7);//SB_DAC->0 -+ mdelay(500); -+#endif -+ } -+#endif -+ return 0; -+} -+ -+ -+static int jz_audio_ioctl(struct inode *inode, struct file *file, -+unsigned int cmd, unsigned long arg) -+{ -+ int val,fullc,busyc,unfinish,newfragstotal,newfragsize; -+ unsigned int flags; -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ count_info cinfo; -+ audio_buf_info abinfo; -+ int id, i; -+ -+ val = 0; -+ switch (cmd) { -+ case OSS_GETVERSION: -+ return put_user(SOUND_VERSION, (int *)arg); -+ case SNDCTL_DSP_RESET: -+#if 0 -+ jz_audio_reset(); -+ __i2s_disable_replay(); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+ __i2s_disable_transmit_dma(); -+#endif -+ return 0; -+ case SNDCTL_DSP_SYNC: -+ if (file->f_mode & FMODE_WRITE) -+ return drain_dac(controller, file->f_flags & O_NONBLOCK); -+ return 0; -+ case SNDCTL_DSP_SPEED: -+ /* set smaple rate */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ if (val >= 0) -+ jz_audio_set_speed(controller->dev_audio, val); -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_STEREO: -+ /* set stereo or mono channel */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); -+ -+ return 0; -+ case SNDCTL_DSP_GETBLKSIZE: -+ //return put_user(jz_audio_fragsize / jz_audio_b, (int *)arg); -+ return put_user(jz_audio_fragsize, (int *)arg); -+ case SNDCTL_DSP_GETFMTS: -+ /* Returns a mask of supported sample format*/ -+ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); -+ case SNDCTL_DSP_SETFMT: -+ /* Select sample format */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ if (val != AFMT_QUERY) -+ jz_audio_set_format(controller->dev_audio,val); -+ else { -+ if (file->f_mode & FMODE_READ) -+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; -+ else -+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; -+ } -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_CHANNELS: -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ jz_audio_set_channels(controller->dev_audio, val); -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_POST: -+ /* FIXME: the same as RESET ?? */ -+ return 0; -+ case SNDCTL_DSP_SUBDIVIDE: -+ return 0; -+ case SNDCTL_DSP_SETFRAGMENT: -+ get_user(val, (long *) arg); -+ newfragsize = 1 << (val & 0xFFFF); -+ if (newfragsize < 4 * PAGE_SIZE) -+ newfragsize = 4 * PAGE_SIZE; -+ if (newfragsize > (16 * PAGE_SIZE)) -+ newfragsize = 16 * PAGE_SIZE; -+ -+ newfragstotal = (val >> 16) & 0x7FFF; -+ if (newfragstotal < 2) -+ newfragstotal = 2; -+ if (newfragstotal > 32) -+ newfragstotal = 32; -+ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize)) -+ return 0; -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ mdelay(500); -+ jz_audio_fragstotal = newfragstotal; -+ jz_audio_fragsize = newfragsize; -+ -+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ mdelay(10); -+ -+ return 0; -+ case SNDCTL_DSP_GETCAPS: -+ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg); -+ case SNDCTL_DSP_NONBLOCK: -+ file->f_flags |= O_NONBLOCK; -+ return 0; -+ case SNDCTL_DSP_SETDUPLEX: -+ return -EINVAL; -+ case SNDCTL_DSP_GETOSPACE: -+ { -+ int i; -+ unsigned long bytes = 0; -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ jz_audio_fragments = elements_in_queue(&out_empty_queue); -+ for (i = 0; i < jz_audio_fragments; i++) -+ bytes += jz_audio_fragsize; -+ -+ if (jz_audio_channels == 2) -+ bytes /= jz_audio_b; -+ else if (jz_audio_channels == 1) -+ bytes /= 4; -+ else -+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 1!\n"); -+ -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ /* unused fragment amount */ -+ abinfo.fragments = jz_audio_fragments; -+ /* amount of fragments */ -+ abinfo.fragstotal = jz_audio_fragstotal; -+ /* fragment size in bytes */ -+ if (jz_audio_channels == 2) -+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; -+ else if (jz_audio_channels == 1) -+ abinfo.fragsize = jz_audio_fragsize / 4; -+ else -+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 2!\n"); -+ -+ /* write size count without blocking in bytes */ -+ abinfo.bytes = (int)bytes; -+ -+ return copy_to_user((void *)arg, &abinfo, -+ sizeof(abinfo)) ? -EFAULT : 0; -+ } -+ case SNDCTL_DSP_GETISPACE: -+ { -+ int i; -+ unsigned long bytes = 0; -+ if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ jz_audio_fragments = elements_in_queue(&in_empty_queue); -+ for (i = 0; i < jz_audio_fragments; i++) -+ bytes += jz_audio_fragsize; -+ -+ if (jz_audio_channels == 2) -+ bytes /= jz_audio_b; -+ else if (jz_audio_channels == 1) -+ bytes /= 4; -+ else -+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 1!\n"); -+ -+ abinfo.fragments = jz_audio_fragments; -+ abinfo.fragstotal = jz_audio_fragstotal; -+ -+ if (jz_audio_channels == 2) -+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; -+ else if (jz_audio_channels == 1) -+ abinfo.fragsize = jz_audio_fragsize / 4; -+ else -+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 2!\n"); -+ -+ abinfo.bytes = (int)bytes; -+ -+ return copy_to_user((void *)arg, &abinfo, -+ sizeof(abinfo)) ? -EFAULT : 0; -+ } -+ case SNDCTL_DSP_GETTRIGGER: -+ val = 0; -+ if (file->f_mode & FMODE_READ && in_dma_buf) -+ val |= PCM_ENABLE_INPUT; -+ if (file->f_mode & FMODE_WRITE && out_dma_buf) -+ val |= PCM_ENABLE_OUTPUT; -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_SETTRIGGER: -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ return 0; -+ case SNDCTL_DSP_GETIPTR: -+ if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ cinfo.bytes = controller->total_bytes; -+ cinfo.blocks = controller->blocks; -+ cinfo.ptr = controller->nextIn; -+ controller->blocks = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); -+ case SNDCTL_DSP_GETOPTR: -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ cinfo.bytes = controller->total_bytes; -+ cinfo.blocks = controller->blocks; -+ cinfo.ptr = controller->nextOut; -+ controller->blocks = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); -+ case SNDCTL_DSP_GETODELAY: -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ unfinish = 0; -+ fullc = elements_in_queue(&out_full_queue); -+ busyc = elements_in_queue(&out_busy_queue); -+ for(i = 0;i < fullc ;i ++) { -+ id = *(out_full_queue.id + i); -+ unfinish += *(out_dma_buf_data_count + id); -+ } -+ for(i = 0;i < busyc ;i ++) { -+ id = *(out_busy_queue.id + i); -+ unfinish += get_dma_residue(controller->dma1); -+ } -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ if (jz_audio_channels == 2) -+ unfinish /= jz_audio_b; -+ else if (jz_audio_channels == 1) -+ unfinish /= 4; -+ else -+ printk("SNDCTL_DSP_GETODELAY : channels is wrong !\n"); -+ -+ return put_user(unfinish, (int *) arg); -+ case SOUND_PCM_READ_RATE: -+ return put_user(jz_audio_rate, (int *)arg); -+ case SOUND_PCM_READ_CHANNELS: -+ return put_user(jz_audio_channels, (int *)arg); -+ case SOUND_PCM_READ_BITS: -+ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg); -+ case SNDCTL_DSP_MAPINBUF: -+ case SNDCTL_DSP_MAPOUTBUF: -+ case SNDCTL_DSP_SETSYNCRO: -+ case SOUND_PCM_WRITE_FILTER: -+ case SOUND_PCM_READ_FILTER: -+ return -EINVAL; -+ } -+ return -EINVAL; -+} -+ -+ -+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait) -+{ -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ unsigned long flags; -+ unsigned int mask = 0; -+ -+ if (file->f_mode & FMODE_WRITE) { -+ if (elements_in_queue(&out_empty_queue) > 0) -+ return POLLOUT | POLLWRNORM; -+ -+ poll_wait(file, &controller->dac_wait, wait); -+ } -+ -+ if (file->f_mode & FMODE_READ) { -+ if (elements_in_queue(&in_full_queue) > 0) -+ return POLLIN | POLLRDNORM; -+ -+ poll_wait(file, &controller->adc_wait, wait); -+ } -+ -+ spin_lock_irqsave(&controller->lock, flags); -+ if (file->f_mode & FMODE_WRITE) { -+ if (elements_in_queue(&out_empty_queue) > 0) -+ mask |= POLLOUT | POLLWRNORM; -+ } else if (file->f_mode & FMODE_READ) { -+ if (elements_in_queue(&in_full_queue) > 0) -+ mask |= POLLIN | POLLRDNORM; -+ } -+ spin_unlock_irqrestore(&controller->lock, flags); -+ -+ return mask; -+} -+ -+static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) -+{ -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ int id, ret = 0, left_count, copy_count, cnt = 0; -+ unsigned long flags; -+ -+ if (count < 0) -+ return -EINVAL; -+ -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextIn = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ copy_count = jz_audio_fragsize / 4; -+ -+ left_count = count; -+ if (first_record_call) { -+ first_record_call = 0; -+ audio_read_back_first: -+ if ((id = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id); -+ spin_lock(&controller->lock); -+ *(in_dma_buf_data_count + id) = copy_count * 4; -+ -+ spin_unlock(&controller->lock); -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); -+ audio_start_dma(controller->dma2,file->private_data, -+ *(in_dma_pbuf + id), -+ *(in_dma_buf_data_count + id), -+ DMA_MODE_READ); -+ sleep_on(&rx_wait_queue); -+ } else -+ goto audio_read_back_first; -+ } -+ -+ while (left_count > 0) { -+ audio_read_back_second: -+ if (elements_in_queue(&in_full_queue) <= 0) { -+ if (file->f_flags & O_NONBLOCK) -+ return ret ? ret : -EAGAIN; -+ else -+ sleep_on(&rx_wait_queue); -+ } -+ -+ if ((id = get_buffer_id(&in_full_queue)) >= 0) { -+ spin_lock(&controller->lock); -+ cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id); -+ spin_unlock(&controller->lock); -+ put_buffer_id(&in_empty_queue, id); -+ } else -+ goto audio_read_back_second; -+ -+ if (elements_in_queue(&in_busy_queue) == 0) { -+ if ((id=get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id); -+ spin_lock(&controller->lock); -+ *(in_dma_buf_data_count + id) = copy_count * 4; -+ spin_unlock(&controller->lock); -+ -+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); -+ audio_start_dma(controller->dma2,file->private_data, -+ *(in_dma_pbuf + id), -+ *(in_dma_buf_data_count + id), -+ DMA_MODE_READ); -+ } -+ } -+ if (ret + cnt > count) { -+ spin_lock(&controller->lock); -+ cnt = count - ret; -+ spin_unlock(&controller->lock); -+ } -+ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt)) -+ return ret ? ret : -EFAULT; -+ -+ spin_lock(&controller->lock); -+ ret += cnt; -+ spin_unlock(&controller->lock); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextIn += ret; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ spin_lock(&controller->lock); -+ left_count -= cnt; -+ spin_unlock(&controller->lock); -+ } -+ return ret; -+} -+ -+static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) -+{ -+ int id, ret = 0, left_count, copy_count = 0; -+ unsigned int flags; -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ -+ if (count <= 0) -+ return -EINVAL; -+ -+ if(set_replay_hp_or_speaker) -+ set_replay_hp_or_speaker(); -+ -+ __i2s_enable_transmit_dma(); -+ __i2s_enable_replay(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextOut = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ if (jz_audio_channels == 2) -+ copy_count = jz_audio_fragsize / jz_audio_b; -+ else if(jz_audio_channels == 1) -+ copy_count = jz_audio_fragsize / 4; -+ left_count = count; -+ if (copy_from_user(controller->tmp1, buffer, count)) { -+ printk("copy_from_user failed:%d",ret); -+ return ret ? ret : -EFAULT; -+ } -+ -+ while (left_count > 0) { -+ audio_write_back: -+ if (file->f_flags & O_NONBLOCK) -+ udelay(2); -+ if (elements_in_queue(&out_empty_queue) == 0) { -+ if (file->f_flags & O_NONBLOCK) -+ return ret; -+ else -+ sleep_on(&tx_wait_queue); -+ } -+ /* the end fragment size in this write */ -+ if (ret + copy_count > count) -+ copy_count = count - ret; -+ if ((id = get_buffer_id(&out_empty_queue)) >= 0) { -+ replay_filler((signed long)controller->tmp1 + ret, copy_count, id); -+ if(*(out_dma_buf_data_count + id) > 0) { -+ put_buffer_id(&out_full_queue, id); -+ dma_cache_wback_inv(*(out_dma_buf + id), *(out_dma_buf_data_count + id)); -+ } else -+ put_buffer_id(&out_empty_queue, id); -+ } else -+ goto audio_write_back; -+ -+ left_count = left_count - copy_count; -+ ret += copy_count; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextOut += ret; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ if (elements_in_queue(&out_busy_queue) == 0) { -+ if ((id=get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_busy_queue, id); -+ if(*(out_dma_buf_data_count + id) > 0) { -+ audio_start_dma(controller->dma1, -+ file->private_data, -+ *(out_dma_pbuf + id), -+ *(out_dma_buf_data_count + id), -+ DMA_MODE_WRITE); -+ last_dma_buffer_id = id; -+#if defined(CONFIG_I2S_DLV) -+ if (jz_codec_config == 0) { -+ write_codec_file_bit(1, 0, 5); -+ gain_up_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //gain_up_end = jiffies; -+ jz_codec_config = 1; -+ //SB_ADC->1 -+ //write_codec_file_bit(5, 1, 4); -+ //while(1); -+ } -+#endif -+ } -+ } -+ } -+ } -+ -+ return ret; -+} -+ -+#if defined(CONFIG_I2S_ICODEC) -+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample) -+{ -+ int i,step_len; -+ unsigned long *pop_buf = (unsigned long*)pop_turn_onoff_buf; -+ unsigned int sample_oss = (REG_AIC_CR & 0x00380000) >> 19; -+ unsigned long l_sample_count,r_sample_count,sample_count; -+ struct jz_i2s_controller_info *controller = i2s_controller; -+ signed int left_sam=0,right_sam=0,l_val,r_val; -+ -+ switch (sample_oss) { -+ case 0x0: -+ break; -+ case 0x1: -+ left_sam = (signed int)l_sample; -+ right_sam = (signed int)r_sample; -+ break; -+ case 0x2: -+ break; -+ case 0x3: -+ break; -+ case 0x4: -+ break; -+ } -+ -+ if(left_sam == 0 && right_sam == 0) -+ return; -+ -+ switch (sample_oss) { -+ case 0x0: -+ break; -+ case 0x1: -+ step_len = jz_audio_speed / 10 * 3; -+ step_len = step_len / 2; -+ step_len = 0x7fff / step_len + 1; -+ -+ l_sample_count = 0; -+ l_val = left_sam; -+ -+ while(1) { -+ if(l_val > 0) { -+ if(l_val >= step_len) { -+ l_val -= step_len; -+ l_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(l_val < 0) { -+ if(l_val <= -step_len) { -+ l_val += step_len; -+ l_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(l_val == 0) -+ break; -+ } -+ -+ r_sample_count = 0; -+ r_val = right_sam; -+ while(1) { -+ if(r_val > 0) { -+ if(r_val >= step_len) { -+ r_val -= step_len; -+ r_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(r_val < 0) { -+ if(r_val <= -step_len) { -+ r_val += step_len; -+ r_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(r_val == 0) -+ break; -+ } -+ /* fill up */ -+ if(l_sample_count > r_sample_count) -+ sample_count = l_sample_count; -+ else -+ sample_count = r_sample_count; -+ -+ l_val = left_sam; -+ r_val = right_sam; -+ for(i=0;i <= sample_count;i++) { -+ -+ *pop_buf = (unsigned long)l_val; -+ pop_buf ++; -+ -+ if(l_val > step_len) -+ l_val -= step_len; -+ else if(l_val < -step_len) -+ l_val += step_len; -+ else if(l_val >= -step_len && l_val <= step_len) -+ l_val = 0; -+ -+ *pop_buf = (unsigned long)r_val; -+ pop_buf ++; -+ if(r_val > step_len) -+ r_val -= step_len; -+ else if(r_val < -step_len) -+ r_val += step_len; -+ else if(r_val >= -step_len && r_val <= step_len) -+ r_val = 0; -+ } -+ -+ *pop_buf = 0; -+ pop_buf ++; -+ *pop_buf = 0; -+ -+ pop_buf ++; -+ sample_count += 2; -+ dma_cache_wback_inv(pop_turn_onoff_buf, sample_count*8); -+ -+ pop_dma_flag = 1; -+ audio_start_dma(controller->dma1,controller,pop_turn_onoff_pbuf,sample_count*8,DMA_MODE_WRITE); -+ sleep_on(&pop_wait_queue); -+ pop_dma_flag = 0; -+ break; -+ case 0x2: -+ break; -+ case 0x3: -+ break; -+ case 0x4: -+ break; -+ } -+} -+#endif ++/* ++ * linux/drivers/sound/Jz_i2s.c ++ * ++ * JzSOC On-Chip I2S audio driver. ++ * ++ * Copyright (C) 2005 by Junzheng Corp. ++ * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using ++ * dma channel 4&3,noah is tested. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Because the normal application of AUDIO devices are focused on Little_endian, ++ * then we only perform the little endian data format in driver. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "sound_config.h" ++ ++#if defined(CONFIG_I2S_DLV) ++#include "jzdlv.h" ++#endif ++ ++#define DPRINTK(args...) printk(args) ++#define DMA_ID_I2S_TX DMA_ID_AIC_TX ++#define DMA_ID_I2S_RX DMA_ID_AIC_RX ++#define NR_I2S 2 ++#define JZCODEC_RW_BUFFER_SIZE 5 ++#define JZCODEC_RW_BUFFER_TOTAL 4 ++ ++#define USE_NONE 1 ++#define USE_MIC 2 ++#define USE_LINEIN 3 ++ ++typedef struct hpvol_shift_s ++{ ++ int hpvol; ++ int shift; ++} hpvol_shift_t; ++ ++mixer_info info; ++_old_mixer_info old_info; ++int codec_volue_shift; ++hpvol_shift_t hpvol_shift_table[72]; ++int abnormal_data_count; ++unsigned long i2s_clk; ++ ++void (*set_codec_mode)(void) = NULL; ++void (*clear_codec_mode)(void) = NULL; ++void (*set_codec_gpio_pin)(void) = NULL; ++void (*each_time_init_codec)(void) = NULL; ++int (*set_codec_startup_param)(void) = NULL; ++void (*set_codec_volume_table)(void) = NULL; ++void (*set_codec_record)(int mode) = NULL; ++void (*set_codec_replay)(void) = NULL; ++void (*set_codec_replay_record)(int mode) = NULL; ++void (*turn_on_codec)(void) = NULL; ++void (*turn_off_codec)(void) = NULL; ++void (*set_codec_speed)(int rate) = NULL; ++void (*reset_codec)(void) = NULL; ++void (*codec_mixer_old_info_id_name)(void) = NULL; ++void (*codec_mixer_info_id_name)(void) = NULL; ++void (*set_codec_bass)(int val) = NULL; ++void (*set_codec_volume)(int val) = NULL; ++void (*set_codec_mic)(int val) = NULL; ++void (*set_codec_line)(int val) = NULL; ++void (*i2s_resume_codec)(void) = NULL; ++void (*i2s_suspend_codec)(int wr,int rd) = NULL; ++void (*init_codec_pin)(void) = NULL; ++void (*set_codec_some_func)(void) = NULL; ++void (*clear_codec_record)(void) = NULL; ++void (*clear_codec_replay)(void) = NULL; ++void (*set_replay_hp_or_speaker)(void) = NULL; ++void (*set_codec_direct_mode)(void) = NULL; ++void (*clear_codec_direct_mode)(void) = NULL; ++void (*set_codec_linein2hp)(void) = NULL; ++void (*clear_codec_linein2hp)(void) = NULL; ++ ++static int jz_audio_rate; ++static int jz_audio_format; ++static int jz_audio_volume; ++static int jz_audio_channels; ++static int jz_audio_b; /* bits expand multiple */ ++static int jz_audio_fragments; /* unused fragment amount */ ++static int jz_audio_fragstotal; ++static int jz_audio_fragsize; ++static int jz_audio_speed; ++ ++static int codec_bass_gain; ++static int audio_mix_modcnt; ++static int jz_audio_dma_tran_count; /* bytes count of one DMA transfer */ ++#if defined(CONFIG_I2S_DLV) ++int jz_mic_only = 1; ++static int jz_codec_config = 0; ++static unsigned long ramp_up_start; ++static unsigned long ramp_up_end; ++static unsigned long gain_up_start; ++static unsigned long gain_up_end; ++static unsigned long ramp_down_start; ++static unsigned long ramp_down_end; ++static unsigned long gain_down_start; ++static unsigned long gain_down_end; ++#endif ++ ++static int codec_mic_gain; ++static int pop_dma_flag; ++static int last_dma_buffer_id; ++static int drain_flag; ++static int use_mic_line_flag; ++ ++static void (*old_mksound)(unsigned int hz, unsigned int ticks); ++extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); ++static void jz_update_filler(int bits, int channels); ++ ++static int Init_In_Out_queue(int fragstotal,int fragsize); ++static int Free_In_Out_queue(int fragstotal,int fragsize); ++static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref); ++static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref); ++static void (*replay_filler)(signed long src_start, int count, int id); ++static int (*record_filler)(unsigned long dst_start, int count, int id); ++#if defined(CONFIG_I2S_ICODEC) ++static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample); ++#endif ++static void jz_audio_reset(void); ++static struct file_operations jz_i2s_audio_fops; ++ ++static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (drain_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue); ++ ++struct jz_i2s_controller_info ++{ ++ int io_base; ++ int dma1; /* for play */ ++ int dma2; /* for record */ ++ char *name; ++ int dev_audio; ++ struct i2s_codec *i2s_codec[NR_I2S]; ++ int opened1; ++ int opened2; ++ unsigned char *tmp1; /* tmp buffer for sample conversions */ ++ unsigned char *tmp2; ++ spinlock_t lock; ++ spinlock_t ioctllock; ++ ++ wait_queue_head_t dac_wait; ++ wait_queue_head_t adc_wait; ++ int nextIn; /* byte index to next-in to DMA buffer */ ++ int nextOut; /* byte index to next-out from DMA buffer */ ++ int count; /* current byte count in DMA buffer */ ++ int finish; /* current transfered byte count in DMA buffer */ ++ unsigned total_bytes; /* total bytes written or read */ ++ unsigned blocks; ++ unsigned error; /* over/underrun */ ++#ifdef CONFIG_PM ++ struct pm_dev *pm; ++#endif ++}; ++ ++ ++static struct jz_i2s_controller_info *i2s_controller = NULL; ++struct i2s_codec ++{ ++ /* I2S controller connected with */ ++ void *private_data; ++ char *name; ++ int id; ++ int dev_mixer; ++ /* controller specific lower leverl i2s accessing routines */ ++ u16 (*codec_read) (u8 reg); /* the function accessing Codec REGs */ ++ void (*codec_write) (u8 reg, u16 val); ++ /* Wait for codec-ready */ ++ void (*codec_wait) (struct i2s_codec *codec); ++ /* OSS mixer masks */ ++ int modcnt; ++ int supported_mixers; ++ int stereo_mixers; ++ int record_sources; ++ int bit_resolution; ++ /* OSS mixer interface */ ++ int (*read_mixer) (struct i2s_codec *codec, int oss_channel); ++ void (*write_mixer)(struct i2s_codec *codec, int oss_channel, ++ unsigned int left, unsigned int right); ++ int (*recmask_io) (struct i2s_codec *codec, int rw, int mask); ++ int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg); ++ /* saved OSS mixer states */ ++ unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; ++}; ++ ++ ++typedef struct buffer_queue_s ++{ ++ int count; ++ int *id; ++ int lock; ++} buffer_queue_t; ++ ++typedef struct left_right_sample_s ++{ ++ signed long left; ++ signed long right; ++} left_right_sample_t; ++ ++static unsigned long pop_turn_onoff_buf; ++static unsigned long pop_turn_onoff_pbuf; ++ ++static unsigned long *out_dma_buf = NULL; ++static unsigned long *out_dma_pbuf = NULL; ++static unsigned long *out_dma_buf_data_count = NULL; ++static unsigned long *in_dma_buf = NULL; ++static unsigned long *in_dma_pbuf = NULL; ++static unsigned long *in_dma_buf_data_count = NULL; ++ ++static buffer_queue_t out_empty_queue; ++static buffer_queue_t out_full_queue; ++static buffer_queue_t out_busy_queue; ++static buffer_queue_t in_empty_queue; ++static buffer_queue_t in_full_queue; ++static buffer_queue_t in_busy_queue; ++static int first_record_call = 0; ++ ++static left_right_sample_t save_last_samples[64]; ++ ++static inline int get_buffer_id(struct buffer_queue_s *q) ++{ ++ int r; ++ unsigned long flags; ++ int i; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ if (q->count == 0) { ++ spin_unlock_irqrestore(&q->lock, flags); ++ return -1; ++ } ++ r = *(q->id + 0); ++ for (i=0;i < q->count-1;i++) ++ *(q->id + i) = *(q->id + (i+1)); ++ q->count --; ++ spin_unlock_irqrestore(&q->lock, flags); ++ ++ return r; ++} ++ ++static inline void put_buffer_id(struct buffer_queue_s *q, int id) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ *(q->id + q->count) = id; ++ q->count ++; ++ spin_unlock_irqrestore(&q->lock, flags); ++} ++ ++static inline int elements_in_queue(struct buffer_queue_s *q) ++{ ++ int r; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ r = q->count; ++ spin_unlock_irqrestore(&q->lock, flags); ++ ++ return r; ++} ++ ++static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode) ++{ ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ jz_audio_dma_tran_count = count / jz_audio_b; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ flags = claim_dma_lock(); ++ disable_dma(chan); ++ clear_dma_ff(chan); ++#if 1 ++ jz_set_oss_dma(chan, mode, jz_audio_format); ++#else ++ set_dma_mode(chan, mode); ++#endif ++ set_dma_addr(chan, phyaddr); ++ if (count == 0) { ++ count++; ++ printk("JzSOC DMA controller can't set dma 0 count!\n"); ++ } ++ set_dma_count(chan, count); ++ enable_dma(chan); ++ release_dma_lock(flags); ++} ++ ++static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id) ++{ ++ int id1, id2; ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ int dma = controller->dma2; ++ ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ ++ if(drain_flag == 1) ++ wake_up(&drain_wait_queue); ++ /* for DSP_GETIPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ id1 = get_buffer_id(&in_busy_queue); ++ put_buffer_id(&in_full_queue, id1); ++ ++ wake_up(&rx_wait_queue); ++ wake_up(&controller->adc_wait); ++ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id2); ++ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1); ++ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2)); ++ audio_start_dma(dma,dev_id, ++ *(in_dma_pbuf + id2), ++ *(in_dma_buf_data_count + id2), ++ DMA_MODE_READ); ++ } else ++ in_busy_queue.count = 0; ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id) ++{ ++ int id; ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ int dma = controller->dma1; ++ ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ ++ if(pop_dma_flag == 1) { ++ pop_dma_flag = 0; ++ wake_up(&pop_wait_queue); ++ } else { ++ if(drain_flag == 1) { ++ /* Is replay dma buffer over ? */ ++ if(elements_in_queue(&out_full_queue) <= 0) { ++ drain_flag = 0; ++ wake_up(&drain_wait_queue); ++ } ++ } ++ ++ /* for DSP_GETOPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ if ((id = get_buffer_id(&out_busy_queue)) < 0) ++ printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n"); ++ put_buffer_id(&out_empty_queue, id); ++ if ((id = get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_busy_queue, id); ++ if(*(out_dma_buf_data_count + id) > 0) { ++ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id), ++ *(out_dma_buf_data_count + id), ++ DMA_MODE_WRITE); ++ last_dma_buffer_id = id; ++ } ++ } else ++ out_busy_queue.count = 0; ++ ++ if (elements_in_queue(&out_empty_queue) > 0) { ++ wake_up(&tx_wait_queue); ++ wake_up(&controller->dac_wait); ++ } ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static void jz_i2s_initHw(int set) ++{ ++#if defined(CONFIG_MIPS_JZ_URANUS) ++ i2s_clk = 48000000; ++#else ++ i2s_clk = __cpm_get_i2sclk(); ++#endif ++ __i2s_disable(); ++ if(set) ++ __i2s_reset(); ++ schedule_timeout(5); ++ if(each_time_init_codec) ++ each_time_init_codec(); ++ __i2s_disable_record(); ++ __i2s_disable_replay(); ++ __i2s_disable_loopback(); ++ __i2s_set_transmit_trigger(4); ++ __i2s_set_receive_trigger(3); ++} ++ ++static int Init_In_Out_queue(int fragstotal,int fragsize) ++{ ++ int i; ++ ++ /* recording */ ++ in_empty_queue.count = fragstotal; ++ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_buf) ++ goto all_mem_err; ++ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_pbuf) ++ goto all_mem_err; ++ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_buf_data_count) ++ goto all_mem_err; ++ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_empty_queue.id) ++ goto all_mem_err; ++ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_full_queue.id) ++ goto all_mem_err; ++ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_busy_queue.id) ++ goto all_mem_err; ++ ++ for (i=0;i < fragstotal;i++) ++ *(in_empty_queue.id + i) = i; ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ ++ for (i = 0; i < fragstotal; i++) { ++ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); ++ if (*(in_dma_buf + i) == 0) ++ goto mem_failed_in; ++ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i))); ++ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); ++ } ++ ++ /* playing */ ++ out_empty_queue.count = fragstotal; ++ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!out_dma_buf) ++ goto all_mem_err; ++ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!out_dma_pbuf) ++ goto all_mem_err; ++ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ ++ if (!out_dma_buf_data_count) ++ goto all_mem_err; ++ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_empty_queue.id) ++ goto all_mem_err; ++ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_full_queue.id) ++ goto all_mem_err; ++ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_busy_queue.id) ++ goto all_mem_err; ++ for (i=0;i < fragstotal;i++) ++ *(out_empty_queue.id + i) = i; ++ ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ /* alloc DMA buffer */ ++ for (i = 0; i < fragstotal; i++) { ++ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); ++ if (*(out_dma_buf + i) == 0) { ++ printk(" can't allocate required DMA(OUT) buffers.\n"); ++ goto mem_failed_out; ++ } ++ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); ++ } ++ ++ return 1; ++all_mem_err: ++ printk("error:allocate memory occur error 1!\n"); ++ return 0; ++mem_failed_out: ++ printk("error:allocate memory occur error 2!\n"); ++ for (i = 0; i < fragstotal; i++) { ++ if(*(out_dma_buf + i)) ++ free_pages(*(out_dma_buf + i), get_order(fragsize)); ++ } ++ ++ return 0; ++mem_failed_in: ++ printk("error:allocate memory occur error 3!\n"); ++ for (i = 0; i < fragstotal; i++) { ++ if(*(in_dma_buf + i)) ++ free_pages(*(in_dma_buf + i), get_order(fragsize)); ++ } ++ return 0; ++} ++ ++static int Free_In_Out_queue(int fragstotal,int fragsize) ++{ ++ int i; ++ /* playing */ ++ if(out_dma_buf != NULL) { ++ for (i = 0; i < fragstotal; i++) { ++ if(*(out_dma_buf + i)) ++ free_pages(*(out_dma_buf + i), get_order(fragsize)); ++ *(out_dma_buf + i) = 0; ++ } ++ kfree(out_dma_buf); ++ out_dma_buf = NULL; ++ } ++ if(out_dma_pbuf) { ++ kfree(out_dma_pbuf); ++ out_dma_pbuf = NULL; ++ } ++ if(out_dma_buf_data_count) { ++ kfree(out_dma_buf_data_count); ++ out_dma_buf_data_count = NULL; ++ } ++ if(out_empty_queue.id) { ++ kfree(out_empty_queue.id); ++ out_empty_queue.id = NULL; ++ } ++ if(out_full_queue.id) { ++ kfree(out_full_queue.id); ++ out_full_queue.id = NULL; ++ } ++ if(out_busy_queue.id) { ++ kfree(out_busy_queue.id); ++ out_busy_queue.id = NULL; ++ } ++ out_empty_queue.count = fragstotal; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ ++ /* recording */ ++ if(in_dma_buf) { ++ for (i = 0; i < fragstotal; i++) { ++ if(*(in_dma_buf + i)) { ++ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); ++ free_pages(*(in_dma_buf + i), get_order(fragsize)); ++ } ++ *(in_dma_buf + i) = 0; ++ } ++ kfree(in_dma_buf); ++ in_dma_buf = NULL; ++ } ++ if(in_dma_pbuf) { ++ kfree(in_dma_pbuf); ++ in_dma_pbuf = NULL; ++ } ++ if(in_dma_buf_data_count) { ++ kfree(in_dma_buf_data_count); ++ in_dma_buf_data_count = NULL; ++ } ++ if(in_empty_queue.id) { ++ kfree(in_empty_queue.id); ++ in_empty_queue.id = NULL; ++ } ++ if(in_full_queue.id) { ++ kfree(in_full_queue.id); ++ in_full_queue.id = NULL; ++ } ++ if(in_busy_queue.id) { ++ kfree(in_busy_queue.id); ++ in_busy_queue.id = NULL; ++ } ++ ++ in_empty_queue.count = fragstotal; ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ ++ return 1; ++} ++ ++static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller) ++{ ++ jz_i2s_initHw(0); ++} ++ ++static int jz_audio_set_speed(int dev, int rate) ++{ ++ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */ ++ jz_audio_speed = rate; ++#if defined(CONFIG_I2S_DLV) ++ if (rate > 96000) ++ rate = 96000; ++#else ++ if (rate > 48000) ++ rate = 48000; ++#endif ++ if (rate < 8000) ++ rate = 8000; ++ jz_audio_rate = rate; ++ ++ if(set_codec_speed) ++ set_codec_speed(rate); ++ ++ return jz_audio_rate; ++} ++ ++ ++static int record_fill_1x8_u(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long data; ++ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ volatile unsigned char *dp = (unsigned char*)dst_start; ++ ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt++; ++ data = *(s++); ++ *(dp ++) = ((data << 16) >> 24) + 0x80; ++ s++; /* skip the other channel */ ++ } ++ ++ return cnt; ++} ++ ++ ++static int record_fill_2x8_u(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1, d2; ++ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ volatile unsigned char *dp = (unsigned char*)dst_start; ++ ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ *(dp ++) = ((d1 << 16) >> 24) + 0x80; ++ d2 = *(s++); ++ *(dp ++) = ((d2 << 16) >> 24) + 0x80; ++ } ++ ++ return cnt; ++} ++ ++ ++static int record_fill_1x16_s(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1; ++ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ unsigned short *dp = (unsigned short *)dst_start; ++ ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt += 2; /* count in byte */ ++ d1 = *(s++); ++ *(dp ++) = (d1 << 16) >> 16; ++ s++; /* skip the other channel */ ++ } ++ ++ return cnt; ++} ++ ++ ++static int record_fill_2x16_s(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1, d2; ++ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ unsigned short *dp = (unsigned short *)dst_start; ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt += 4; /* count in byte */ ++ d1 = *(s++); ++ d2 = *(s++); ++ if(abnormal_data_count > 0) { ++ d1 = d2 = 0; ++ abnormal_data_count --; ++ } ++ *(dp ++) = (d1 << 16) >> 16; ++ *(dp ++) = (d2 << 16) >> 16; ++ } ++ ++ return cnt; ++} ++ ++static void replay_fill_1x8_u(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned char data; ++ unsigned long ddata; ++ volatile unsigned char *s = (unsigned char *)src_start; ++ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count--; ++ cnt += 1; ++ data = *(s++) - 0x80; ++ ddata = (unsigned long) data << 8; ++ *(dp ++) = ddata; ++ *(dp ++) = ddata; ++ ++ /* save last left and right */ ++ if(count == 1) { ++ save_last_samples[id].left = ddata; ++ save_last_samples[id].right = ddata; ++ } ++ } ++ cnt = cnt * 2 * jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++ ++static void replay_fill_2x8_u(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned char d1; ++ unsigned long dd1; ++ volatile unsigned char *s = (unsigned char *)src_start; ++ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count -= 1; ++ cnt += 1 ; ++ d1 = *(s++) - 0x80; ++ dd1 = (unsigned long) d1 << 8; ++ *(dp ++) = dd1; ++ /* save last left */ ++ if(count == 2) ++ save_last_samples[id].left = dd1; ++ /* save last right */ ++ if(count == 1) ++ save_last_samples[id].right = dd1; ++ } ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++ ++static void replay_fill_1x16_s(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed short d1; ++ signed long l1; ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count -= 2; ++ cnt += 2 ; ++ d1 = *(s++); ++ l1 = (signed long)d1; ++#if defined(CONFIG_I2S_ICODEC) ++ l1 >>= codec_volue_shift; ++#endif ++ *(dp ++) = l1; ++ *(dp ++) = l1; ++ ++ /* save last left and right */ ++ if(count == 1) { ++ save_last_samples[id].left = l1; ++ save_last_samples[id].right = l1; ++ } ++ } ++ cnt = cnt * 2 * jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++static void replay_fill_2x16_s(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed short d1; ++ signed long l1; ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++#if defined(CONFIG_I2S_ICODEC) ++ int mute_cnt = 0; ++ signed long tmp1,tmp2; ++ volatile signed long *before_dp; ++ int sam_rate = jz_audio_rate / 20; ++ ++ tmp1 = tmp2 = 0; ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ ++ l1 = (signed long)d1; ++ l1 >>= codec_volue_shift; ++ ++ if(l1 == 0) { ++ mute_cnt ++; ++ if(mute_cnt >= sam_rate) { ++ before_dp = dp - 10; ++ *(before_dp) = (signed long)1; ++ before_dp = dp - 11; ++ *(before_dp) = (signed long)1; ++ mute_cnt = 0; ++ } ++ } else ++ mute_cnt = 0; ++ ++ *(dp ++) = l1; ++ ++ tmp1 = tmp2; ++ tmp2 = l1; ++ } ++ ++ /* save last left */ ++ save_last_samples[id].left = tmp1; ++ /* save last right */ ++ save_last_samples[id].right = tmp2; ++#endif ++#if defined(CONFIG_I2S_DLV) ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ ++ l1 = (signed long)d1; ++ ++ *(dp ++) = l1; ++ } ++#endif ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++static void replay_fill_2x18_s(unsigned long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed long d1; ++ signed long l1; ++ volatile signed long *s = (signed long *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++ while (count > 0) { ++ count -= 4; ++ cnt += 4; ++ d1 = *(s++); ++ l1 = (signed long)d1; ++ *(dp ++) = l1; ++ } ++ ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++static unsigned int jz_audio_set_format(int dev, unsigned int fmt) ++{ ++ switch (fmt) { ++ case AFMT_U8: ++ __i2s_set_oss_sample_size(8); ++ __i2s_set_iss_sample_size(8); ++ jz_audio_format = fmt; ++ jz_update_filler(jz_audio_format,jz_audio_channels); ++ break; ++ case AFMT_S16_LE: ++#if defined(CONFIG_I2S_DLV) ++ /* DAC path and ADC path */ ++ write_codec_file(2, 0x00); ++ //write_codec_file(2, 0x60); ++#endif ++ jz_audio_format = fmt; ++ jz_update_filler(jz_audio_format,jz_audio_channels); ++ __i2s_set_oss_sample_size(16); ++ __i2s_set_iss_sample_size(16); ++ break; ++ case 18: ++ __i2s_set_oss_sample_size(18); ++ jz_audio_format = fmt; ++ jz_update_filler(jz_audio_format,jz_audio_channels); ++ break; ++ case AFMT_QUERY: ++ break; ++ } ++ ++ return jz_audio_format; ++} ++ ++ ++static short jz_audio_set_channels(int dev, short channels) ++{ ++ switch (channels) { ++ case 1: ++ if(set_codec_some_func) ++ set_codec_some_func(); ++ jz_audio_channels = channels; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono ++#endif ++ break; ++ case 2: ++ jz_audio_channels = channels; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo ++#endif ++ break; ++ case 0: ++ break; ++ } ++ ++ return jz_audio_channels; ++} ++ ++static void init_codec(void) ++{ ++ /* inititalize internal I2S codec */ ++ if(init_codec_pin) ++ init_codec_pin(); ++ ++#if defined(CONFIG_I2S_ICDC) ++ /* initialize AIC but not reset it */ ++ jz_i2s_initHw(0); ++#endif ++ if(reset_codec) ++ reset_codec(); ++} ++ ++static void jz_audio_reset(void) ++{ ++ __i2s_disable_replay(); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++ __i2s_disable_transmit_dma(); ++#if defined(CONFIG_I2S_DLV) ++ REG_AIC_I2SCR = 0x10; ++#endif ++ init_codec(); ++} ++ ++static int jz_audio_release(struct inode *inode, struct file *file); ++static int jz_audio_open(struct inode *inode, struct file *file); ++static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg); ++static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait); ++static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos); ++static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos); ++ ++/* static struct file_operations jz_i2s_audio_fops */ ++static struct file_operations jz_i2s_audio_fops = ++{ ++ owner: THIS_MODULE, ++ open: jz_audio_open, ++ release: jz_audio_release, ++ write: jz_audio_write, ++ read: jz_audio_read, ++ poll: jz_audio_poll, ++ ioctl: jz_audio_ioctl ++}; ++ ++static int jz_i2s_open_mixdev(struct inode *inode, struct file *file) ++{ ++ int i; ++ int minor = MINOR(inode->i_rdev); ++ struct jz_i2s_controller_info *controller = i2s_controller; ++ ++ for (i = 0; i < NR_I2S; i++) ++ if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor) ++ goto match; ++ ++ if (!controller) ++ return -ENODEV; ++match: ++ file->private_data = controller->i2s_codec[i]; ++ ++ return 0; ++} ++ ++static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ struct i2s_codec *codec = (struct i2s_codec *)file->private_data; ++ return codec->mixer_ioctl(codec, cmd, arg); ++} ++ ++static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin) ++{ ++ return -ESPIPE; ++} ++ ++static struct file_operations jz_i2s_mixer_fops = ++{ ++ owner: THIS_MODULE, ++ llseek: jz_i2s_llseek, ++ ioctl: jz_i2s_ioctl_mixdev, ++ open: jz_i2s_open_mixdev, ++}; ++ ++static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg) ++{ ++ int ret; ++ long val = 0; ++ switch (cmd) { ++ case SOUND_MIXER_INFO: ++ ++ if(codec_mixer_info_id_name) ++ codec_mixer_info_id_name(); ++ info.modify_counter = audio_mix_modcnt; ++ ++ return copy_to_user((void *)arg, &info, sizeof(info)); ++ case SOUND_OLD_MIXER_INFO: ++ ++ if(codec_mixer_old_info_id_name) ++ codec_mixer_old_info_id_name(); ++ ++ return copy_to_user((void *)arg, &old_info, sizeof(info)); ++ case SOUND_MIXER_READ_STEREODEVS: ++ ++ return put_user(0, (long *) arg); ++ case SOUND_MIXER_READ_CAPS: ++ ++ val = SOUND_CAP_EXCL_INPUT; ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_READ_DEVMASK: ++ break; ++ case SOUND_MIXER_READ_RECMASK: ++ break; ++ case SOUND_MIXER_READ_RECSRC: ++ break; ++ case SOUND_MIXER_WRITE_SPEAKER: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ switch(val) { ++ case 100: ++ if(set_codec_direct_mode) ++ set_codec_direct_mode(); ++ break; ++ case 0: ++ if(clear_codec_direct_mode) ++ clear_codec_direct_mode(); ++ break; ++ } ++ break; ++ case SOUND_MIXER_WRITE_BASS: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ codec_bass_gain = val; ++ if(set_codec_bass) ++ set_codec_bass(val); ++ ++ return 0; ++ case SOUND_MIXER_READ_BASS: ++ ++ val = codec_bass_gain; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_WRITE_VOLUME: ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ ++ jz_audio_volume = val; ++ if(set_codec_volume) ++ set_codec_volume(val); ++ ++ return 0; ++ case SOUND_MIXER_READ_VOLUME: ++ ++ val = jz_audio_volume; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ ++ case SOUND_MIXER_WRITE_MIC: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ codec_mic_gain = val; ++ use_mic_line_flag = USE_MIC; ++ if(set_codec_mic) ++ set_codec_mic(val); ++ ++ return 0; ++ case SOUND_MIXER_READ_MIC: ++ ++ val = codec_mic_gain; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ ++ case SOUND_MIXER_WRITE_LINE: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ use_mic_line_flag = USE_LINEIN; ++ codec_mic_gain = val; ++ if(set_codec_line) ++ set_codec_line(val); ++ ++ return 0; ++ case SOUND_MIXER_READ_LINE: ++ ++ val = codec_mic_gain; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ default: ++ return -ENOSYS; ++ } ++ audio_mix_modcnt ++; ++ return 0; ++} ++ ++ ++int i2s_probe_codec(struct i2s_codec *codec) ++{ ++ /* generic OSS to I2S wrapper */ ++ codec->mixer_ioctl = i2s_mixer_ioctl; ++ return 1; ++} ++ ++ ++/* I2S codec initialisation. */ ++static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller) ++{ ++ int num_i2s = 0; ++ struct i2s_codec *codec; ++ ++ for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) { ++ if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL) ++ return -ENOMEM; ++ memset(codec, 0, sizeof(struct i2s_codec)); ++ codec->private_data = controller; ++ codec->id = num_i2s; ++ ++ if (i2s_probe_codec(codec) == 0) ++ break; ++ if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) { ++ printk(KERN_ERR "Jz I2S: couldn't register mixer!\n"); ++ kfree(codec); ++ break; ++ } ++ controller->i2s_codec[num_i2s] = codec; ++ } ++ return num_i2s; ++} ++ ++ ++static void jz_update_filler(int format, int channels) ++{ ++#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) ++ ++ switch (TYPE(format, channels)) ++ { ++ ++ case TYPE(AFMT_U8, 1): ++ jz_audio_b = 4; /* 4bytes * 8bits =32bits */ ++ replay_filler = replay_fill_1x8_u; ++ record_filler = record_fill_1x8_u; ++ break; ++ case TYPE(AFMT_U8, 2): ++ jz_audio_b = 4; ++ replay_filler = replay_fill_2x8_u; ++ record_filler = record_fill_2x8_u; ++ break; ++ case TYPE(AFMT_S16_LE, 1): ++ jz_audio_b = 2; /* 2bytes * 16bits =32bits */ ++ replay_filler = replay_fill_1x16_s; ++ record_filler = record_fill_1x16_s; ++ break; ++ case TYPE(AFMT_S16_LE, 2): ++ jz_audio_b = 2; ++ replay_filler = replay_fill_2x16_s; ++ record_filler = record_fill_2x16_s; ++ break; ++ case TYPE(18, 2): ++ jz_audio_b = 1; ++ replay_filler = replay_fill_2x18_s; ++ record_filler = record_fill_2x16_s; ++ break; ++ default: ++ ; ++ } ++} ++ ++ ++#ifdef CONFIG_PROC_FS ++extern struct proc_dir_entry *proc_jz_root; ++int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ return 0; ++} ++ ++static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller) ++{ ++ if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0])) ++ return -EIO; ++ return 0; ++} ++ ++static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller) ++{ ++} ++#endif ++ ++static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller) ++{ ++ char *name; ++ int adev; /* No of Audio device. */ ++ ++ name = controller->name; ++ /* initialize AIC controller and reset it */ ++ jz_i2s_initHw(1); ++ adev = register_sound_dsp(&jz_i2s_audio_fops, -1); ++ if (adev < 0) ++ goto audio_failed; ++ /* initialize I2S codec and register /dev/mixer */ ++ if (jz_i2s_codec_init(controller) <= 0) ++ goto mixer_failed; ++ ++#ifdef CONFIG_PROC_FS ++ if (jz_i2s_init_proc(controller) < 0) { ++ printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name); ++ goto proc_failed; ++ } ++#endif ++ ++ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8); ++ if (!controller->tmp1) { ++ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); ++ goto tmp1_failed; ++ } ++ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8); ++ if (!controller->tmp2) { ++ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); ++ goto tmp2_failed; ++ } ++ if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) { ++ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name); ++ goto dma2_failed; ++ } ++ if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) { ++ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name); ++ goto dma1_failed; ++ } ++ printk("JzSOC On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2)); ++ ++ controller->dev_audio = adev; ++ pop_turn_onoff_buf = __get_free_pages(GFP_KERNEL | GFP_DMA, 8); ++ if(!pop_turn_onoff_buf) ++ printk("pop_turn_onoff_buf alloc is wrong!\n"); ++ pop_turn_onoff_pbuf = virt_to_phys((void *)pop_turn_onoff_buf); ++ ++ return; ++dma2_failed: ++ jz_free_dma(controller->dma1); ++dma1_failed: ++ free_pages((unsigned long)controller->tmp2, 8); ++tmp2_failed: ++ free_pages((unsigned long)controller->tmp1, 8); ++tmp1_failed: ++ ++#ifdef CONFIG_PROC_FS ++ jz_i2s_cleanup_proc(controller); ++#endif ++proc_failed: ++ /* unregister mixer dev */ ++mixer_failed: ++ unregister_sound_dsp(adev); ++audio_failed: ++ return; ++} ++ ++static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller) ++{ ++ if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info), ++ GFP_KERNEL)) == NULL) { ++ printk(KERN_ERR "Jz I2S Controller: out of memory.\n"); ++ return -ENOMEM; ++ } ++ (*controller)->name = "Jz I2S controller"; ++ (*controller)->opened1 = 0; ++ (*controller)->opened2 = 0; ++ init_waitqueue_head(&(*controller)->adc_wait); ++ init_waitqueue_head(&(*controller)->dac_wait); ++ spin_lock_init(&(*controller)->lock); ++ init_waitqueue_head(&rx_wait_queue); ++ init_waitqueue_head(&tx_wait_queue); ++ init_waitqueue_head(&pop_wait_queue); ++ init_waitqueue_head(&drain_wait_queue); ++ ++ return 0; ++} ++ ++static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller) ++{ ++ int adev = controller->dev_audio; ++ ++ jz_i2s_full_reset(controller); ++ controller->dev_audio = -1; ++ if (old_mksound) ++ kd_mksound = old_mksound;/* Our driver support bell for kb, see vt.c */ ++ ++#ifdef CONFIG_PROC_FS ++ jz_i2s_cleanup_proc(controller); ++#endif ++ ++ jz_free_dma(controller->dma1); ++ jz_free_dma(controller->dma2); ++ free_pages((unsigned long)controller->tmp1, 8); ++ free_pages((unsigned long)controller->tmp2, 8); ++ free_pages((unsigned long)pop_turn_onoff_buf, 8); ++ ++ if (adev >= 0) { ++ /* unregister_sound_mixer(audio_devs[adev]->mixer_dev); */ ++ unregister_sound_dsp(controller->dev_audio); ++ } ++} ++ ++#ifdef CONFIG_PM ++static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state) ++{ ++ if(i2s_suspend_codec) ++ i2s_suspend_codec(controller->opened1,controller->opened2); ++ printk("Aic and codec are suspended!\n"); ++ return 0; ++} ++ ++static int jz_i2s_resume(struct jz_i2s_controller_info *controller) ++{ ++ if(i2s_resume_codec) ++ i2s_resume_codec(); ++ ++#if defined(CONFIG_I2S_AK4642EN) ++ jz_i2s_initHw(0); ++ jz_audio_reset(); ++ __i2s_enable(); ++ jz_audio_set_speed(controller->dev_audio,jz_audio_speed); ++ /* playing */ ++ if(controller->opened1) { ++ if(set_codec_replay) ++ set_codec_replay(); ++ int dma = controller->dma1; ++ int id; ++ unsigned long flags; ++ disable_dma(dma); ++ if(__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if(__dmac_channel_transmit_end_detected(dma)) ++ __dmac_channel_clear_transmit_end(dma); ++ ++ /* for DSP_GETOPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ while((id = get_buffer_id(&out_busy_queue)) >= 0) ++ put_buffer_id(&out_empty_queue, id); ++ ++ out_busy_queue.count=0; ++ if((id = get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_empty_queue, id); ++ } ++ if (elements_in_queue(&out_empty_queue) > 0) { ++ wake_up(&tx_wait_queue); ++ wake_up(&controller->dac_wait); ++ } else ++ printk("pm out_empty_queue empty"); ++ } ++ ++ /* recording */ ++ if(controller->opened2) { ++ if(set_codec_record) ++ set_codec_record(use_mic_line_flag); ++ int dma = controller->dma2; ++ int id1, id2; ++ unsigned long flags; ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ } ++ /* for DSP_GETIPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ id1 = get_buffer_id(&in_busy_queue); ++ put_buffer_id(&in_full_queue, id1); ++ wake_up(&rx_wait_queue); ++ wake_up(&controller->adc_wait); ++ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_full_queue, id2); ++ } ++ in_busy_queue.count = 0; ++ } ++#endif ++ ++ return 0; ++} ++ ++static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ int ret; ++ struct jz_i2s_controller_info *controller = pm_dev->data; ++ ++ if (!controller) return -EINVAL; ++ ++ switch (req) { ++ case PM_SUSPEND: ++ ret = jz_i2s_suspend(controller, (int)data); ++ break; ++ case PM_RESUME: ++ ret = jz_i2s_resume(controller); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++#endif /* CONFIG_PM */ ++ ++#if defined(CONFIG_I2S_DLV) ++static irqreturn_t aic_codec_irq(int irq, void *dev_id) ++{ ++ u8 file_9 = read_codec_file(9); ++ u8 file_8 = read_codec_file(8); ++ ++ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9); ++ if ((file_9 & 0x1f) == 0x10) { ++ ++ write_codec_file(8, 0x3f); ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ mdelay(300); ++ while ((read_codec_file(9) & 0x4) != 0x4); ++ while ((read_codec_file(9) & 0x10) == 0x10) { ++ write_codec_file(9, 0x10); ++ } ++ write_codec_file_bit(5, 0, 6);//SB_OUT->0 ++ mdelay(300); ++ while ((read_codec_file(9) & 0x8) != 0x8); ++ write_codec_file(9, file_9); ++ write_codec_file(8, file_8); ++ ++ return IRQ_HANDLED; ++ } ++ ++ if (file_9 & 0x8) ++ ramp_up_end = jiffies; ++ else if (file_9 & 0x4) ++ ramp_down_end = jiffies; ++ else if (file_9 & 0x2) ++ gain_up_end = jiffies; ++ else if (file_9 & 0x1) ++ gain_down_end = jiffies; ++ ++ write_codec_file(9, file_9); ++ if (file_9 & 0xf) ++ wake_up(&pop_wait_queue); ++ while (REG_ICDC_RGDATA & 0x100); ++ ++ return IRQ_HANDLED; ++} ++#endif ++ ++static int __init init_jz_i2s(void) ++{ ++ int errno; ++#if defined(CONFIG_I2S_DLV) ++ int retval; ++ ramp_up_start = 0; ++ ramp_up_end = 0; ++ gain_up_start = 0; ++ gain_up_end = 0; ++ ramp_down_start = 0; ++ ramp_down_end = 0; ++ gain_down_start = 0; ++ gain_down_end = 0; ++#endif ++ use_mic_line_flag = USE_NONE; ++ abnormal_data_count = 0; ++ if(set_codec_mode) ++ set_codec_mode(); ++ ++ drain_flag = 0; ++ if ((errno = probe_jz_i2s(&i2s_controller)) < 0) ++ return errno; ++ if(set_codec_gpio_pin) ++ set_codec_gpio_pin(); ++ ++ attach_jz_i2s(i2s_controller); ++ if(set_codec_startup_param) ++ set_codec_startup_param(); ++ if(set_codec_volume_table) ++ set_codec_volume_table(); ++ ++#if defined(CONFIG_I2S_DLV) ++ jz_codec_config = 0; ++ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL); ++ if (retval) { ++ printk("Could not get aic codec irq %d\n", IRQ_AIC); ++ return retval; ++ } ++#endif ++ ++ out_empty_queue.id = NULL; ++ out_full_queue.id = NULL; ++ out_busy_queue.id = NULL; ++ in_empty_queue.id = NULL; ++ in_full_queue.id = NULL; ++ in_busy_queue.id = NULL; ++ ++ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE; ++ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ; ++ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ ++#ifdef CONFIG_PM ++ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ++ jz_i2s_pm_callback); ++ if (i2s_controller->pm) ++ i2s_controller->pm->data = i2s_controller; ++#endif ++#if defined(CONFIG_I2S_DLV) ++ __cpm_start_idct(); ++ __cpm_start_db(); ++ __cpm_start_me(); ++ __cpm_start_mc(); ++ __cpm_start_ipu(); ++#endif ++ printk("JZ I2S OSS audio driver initialized\n"); ++ ++ return 0; ++} ++ ++static void __exit cleanup_jz_i2s(void) ++{ ++#ifdef CONFIG_PM ++ /* pm_unregister(i2s_controller->pm); */ ++#endif ++#if defined(CONFIG_I2S_DLV) ++ free_irq(IRQ_AIC, NULL); ++#endif ++ unload_jz_i2s(i2s_controller); ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ if(clear_codec_mode) ++ clear_codec_mode(); ++} ++ ++module_init(init_jz_i2s); ++module_exit(cleanup_jz_i2s); ++ ++#if defined(CONFIG_SOC_JZ4730) ++static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count,con; ++ ++ if(elements_in_queue(&in_busy_queue) > 0) { ++ if (nonblock) ++ return -EBUSY; ++ drain_flag = 1; ++ sleep_on(&drain_wait_queue); ++ drain_flag = 0; ++ } else { ++ add_wait_queue(&ctrl->adc_wait, &wait); ++ for (con = 0; con < 1000; con ++) { ++ udelay(1); ++ set_current_state(TASK_INTERRUPTIBLE); ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ if (nonblock) { ++ remove_wait_queue(&ctrl->adc_wait, &wait); ++ current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ } ++ remove_wait_queue(&ctrl->adc_wait, &wait); ++ current->state = TASK_RUNNING; ++ } ++ return 0; ++} ++ ++static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count; ++ ++ if(elements_in_queue(&out_full_queue) > 0) { ++ if (nonblock) ++ return -EBUSY; ++ ++ drain_flag = 1; ++ sleep_on(&drain_wait_queue); ++ drain_flag = 0; ++ } else { ++ add_wait_queue(&(ctrl->dac_wait), &wait); ++ for (;;) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ if(elements_in_queue(&out_full_queue) <= 0) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if(count <= 0) ++ break; ++ } ++ if (nonblock) { ++ remove_wait_queue(&ctrl->dac_wait, &wait); ++ current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ } ++ remove_wait_queue(&ctrl->dac_wait, &wait); ++ current->state = TASK_RUNNING; ++ } ++ ++ return 0; ++} ++#endif ++ ++#if defined(CONFIG_SOC_JZ4740) ++#define MAXDELAY 50000 ++static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ int count,ele,i=0; ++ int tfl; ++ ++ for (;;) { ++ if(!nonblock) {//blocked ++ if ( i < MAXDELAY ) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ ++ ele = elements_in_queue(&out_full_queue); ++ if(ele <= 0) { ++ udelay(10); ++ spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ } ++ } else {//non-blocked ++ mdelay(100); ++ ele = elements_in_queue(&out_full_queue); ++ ++ if(ele <= 0) { ++ mdelay(100); ++ ++ spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ } ++ } ++ } ++ ++ /* wait for TX fifo */ ++ while (1) { ++ tfl = __aic_get_transmit_resident(); ++ if (tfl == 0) ++ break; ++ udelay(2); ++ } ++ ++ return 0; ++} ++ ++static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ int count,i=0; ++ ++ for (;;) { ++ if ( i < MAXDELAY ) ++ { ++ udelay(10); ++ i++; ++ } ++ else ++ break; ++ spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ ++ if (nonblock) { ++ return -EBUSY; ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++#if defined(CONFIG_SOC_JZ4750) ++#define MAXDELAY 50000 ++static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ //DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count,i=0; ++ ++ //add_wait_queue(&ctrl->adc_wait, &wait); ++ for (;;) { ++ if (i < MAXDELAY) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ //set_current_state(TASK_INTERRUPTIBLE); ++ spin_lock_irqsave(&ctrl->lock, flags); ++ //spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ //spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ ++ /*if (signal_pending(current)) ++ break;*/ ++ if (nonblock) { ++ //remove_wait_queue(&ctrl->adc_wait, &wait); ++ //current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ } ++ //remove_wait_queue(&ctrl->adc_wait, &wait); ++ //current->state = TASK_RUNNING; ++ /*if (signal_pending(current)) ++ return -ERESTARTSYS;*/ ++ return 0; ++} ++static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ unsigned long flags; ++ int count,ele,busyele,emptyele,i=0; ++ ++ for (;;) { ++ if(!nonblock) {//blocked ++ if (i < MAXDELAY) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ ++ ele = elements_in_queue(&out_full_queue); ++ if(ele <= 0) { ++ udelay(200); ++ ++ busyele = elements_in_queue(&out_busy_queue); ++ emptyele = elements_in_queue(&out_empty_queue); ++ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ } ++ } ++ } else {//non-blocked ++ //mdelay(100); ++ ele = elements_in_queue(&out_full_queue); ++ ++ if(ele <= 0) { ++ //mdelay(100); ++ busyele = elements_in_queue(&out_busy_queue); ++ emptyele = elements_in_queue(&out_empty_queue); ++ ++ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++static int jz_audio_release(struct inode *inode, struct file *file) ++{ ++ unsigned long flags; ++#if defined(CONFIG_I2S_DLV) ++ unsigned long tfl; ++#endif ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++#if defined(CONFIG_I2S_DLV) ++ jz_codec_config = 0; ++#endif ++ if (controller == NULL) ++ return -ENODEV; ++ ++ pop_dma_flag = 0; ++ ++ if (controller->opened1 == 1 && controller->opened2 == 1) { ++ controller->opened1 = 0; ++ __i2s_enable_transmit_dma(); ++ __i2s_enable_replay(); ++ drain_dac(controller, file->f_flags & O_NONBLOCK); ++#if defined(CONFIG_I2S_DLV) ++ /* wait for fifo empty */ ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ gain_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //gain_down_end = jiffies; ++ /*while (1) { ++ tfl = REG_AIC_SR & 0x00003f00; ++ if (tfl == 0) { ++ udelay(500); ++ break; ++ } ++ mdelay(2); ++ }*/ ++ mdelay(100); ++#endif ++ disable_dma(controller->dma1); ++ set_dma_count(controller->dma1, 0); ++ __i2s_disable_transmit_dma(); ++ __i2s_disable_replay(); ++ ++#if defined(CONFIG_I2S_ICODEC) ++ if(clear_codec_replay) ++ clear_codec_replay(); ++#endif ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ controller->opened2 = 0; ++ first_record_call = 1; ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ drain_adc(controller, file->f_flags & O_NONBLOCK); ++ disable_dma(controller->dma2); ++ set_dma_count(controller->dma2, 0); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++#if defined(CONFIG_I2S_ICODEC) ++ if(clear_codec_record) ++ clear_codec_record(); ++#endif ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ ramp_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //ramp_down_end = jiffies; ++ if (use_mic_line_flag == USE_LINEIN) { ++ unset_record_line_input_audio_with_audio_data_replay(); ++ //printk("3 use_mic_line_flag=%d\n",use_mic_line_flag); ++ } ++ if (use_mic_line_flag == USE_MIC) { ++ unset_record_mic_input_audio_with_audio_data_replay(); ++ //printk("4 use_mic_line_flag=%d\n",use_mic_line_flag); ++ } ++ ++#if 0 ++ unset_record_playing_audio_mixed_with_mic_input_audio(); ++#endif ++#endif ++ __i2s_disable(); ++ if(turn_off_codec) ++ turn_off_codec(); ++ abnormal_data_count = 0; ++ } else if (controller->opened1 == 1) { ++ //controller->opened1 = 0; ++ __i2s_enable_transmit_dma(); ++ __i2s_enable_replay(); ++ drain_dac(controller, file->f_flags & O_NONBLOCK); ++ /* add some mute to anti-pop */ ++#if defined(CONFIG_I2S_ICODEC) ++ //write_mute_to_dma_buffer(save_last_samples[last_dma_buffer_id].left,save_last_samples[last_dma_buffer_id].right); ++#endif ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ gain_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //gain_down_end = jiffies; ++ while (1) { ++ tfl = REG_AIC_SR & 0x00003f00; ++ if (tfl == 0) { ++ udelay(500); ++ break; ++ } ++ mdelay(2); ++ } ++#endif ++ disable_dma(controller->dma1); ++ set_dma_count(controller->dma1, 0); ++ __i2s_disable_transmit_dma(); ++ __i2s_disable_replay(); ++#if defined(CONFIG_I2S_ICODEC) ++ if(clear_codec_replay) ++ clear_codec_replay(); ++#endif ++ __aic_flush_fifo(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ ramp_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //ramp_down_end = jiffies; ++ unset_audio_data_replay(); ++#endif ++ __i2s_disable(); ++#if defined(CONFIG_I2S_ICODEC) ++ if(turn_off_codec) ++ turn_off_codec(); ++#endif ++ } else if (controller->opened2 == 1) { ++ controller->opened2 = 0; ++ first_record_call = 1; ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ drain_adc(controller, file->f_flags & O_NONBLOCK); ++ disable_dma(controller->dma2); ++ set_dma_count(controller->dma2, 0); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++#if defined(CONFIG_I2S_ICODEC) ++ if(clear_codec_record) ++ clear_codec_record(); ++#endif ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++#if defined(CONFIG_I2S_DLV) ++#if 0 ++ /* unset Record MIC input audio with direct playback */ ++ unset_record_mic_input_audio_with_direct_playback(); ++#endif ++#if 1 ++ /* unset Record MIC input audio without playback */ ++ unset_record_mic_input_audio_without_playback(); ++#endif ++#if 0 ++ /* tested */ ++ /* unset Record LINE input audio without playback */ ++ unset_record_line_input_audio_without_playback(); ++#endif ++#endif ++ __i2s_disable(); ++#if defined(CONFIG_I2S_ICODEC) ++ if(turn_off_codec) ++ turn_off_codec(); ++#endif ++ abnormal_data_count = 0; ++ } ++ ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++/* __cpm_stop_idct(); ++ __cpm_stop_db(); ++ __cpm_stop_me(); ++ __cpm_stop_mc(); ++ __cpm_stop_ipu();*/ ++#endif ++ ++ if (controller->opened1 == 1 && controller->opened2 == 1) { ++ controller->opened1 = 0; ++ controller->opened2 = 0; ++ //print_pop_duration(); ++ //__dmac_disable_module(0); ++ } else if ( controller->opened1 == 1 ) { ++ controller->opened1 = 0; ++ //print_pop_duration(); ++ } else if ( controller->opened2 == 1 ) { ++ controller->opened2 = 0; ++ } ++ ++ return 0; ++} ++ ++static int jz_audio_open(struct inode *inode, struct file *file) ++{ ++ int i; ++ struct jz_i2s_controller_info *controller = i2s_controller; ++#if defined(CONFIG_I2S_DLV) ++ jz_codec_config = 0; ++#endif ++ if (controller == NULL) ++ return -ENODEV; ++ ++ mdelay(2); ++#if defined(CONFIG_I2S_DLV) ++ REG_DMAC_DMACKE(0) = 0x3f; ++#endif ++ pop_dma_flag = 0; ++ if (controller->opened1 == 1 || controller->opened2 == 1 ) { ++ printk("\naudio is busy!\n"); ++ return -EBUSY; ++ } ++ ++ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { ++ if (controller->opened1 == 1) ++ return -EBUSY; ++ controller->opened1 = 1; ++ /* for ioctl */ ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ ++ for(i=0;i < 64;i++) { ++ save_last_samples[i].left = 0; ++ save_last_samples[i].right = 0; ++ } ++ ++ out_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(out_empty_queue.id + i) = i; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ last_dma_buffer_id = 0; ++ ++ if (controller->opened2 == 1) ++ return -EBUSY; ++ ++ controller->opened2 = 1; ++ first_record_call = 1; ++ /* for ioctl */ ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ ++ in_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(in_empty_queue.id + i) = i; ++ ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ } else if (file->f_mode & FMODE_WRITE) { ++ if (controller->opened1 == 1) ++ return -EBUSY; ++ ++ controller->opened1 = 1; ++ /* for ioctl */ ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ ++ for(i=0;i < 64;i++) { ++ save_last_samples[i].left = 0; ++ save_last_samples[i].right = 0; ++ } ++ ++ out_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(out_empty_queue.id + i) = i; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ last_dma_buffer_id = 0; ++ } else if (file->f_mode & FMODE_READ) { ++ if (controller->opened2 == 1) ++ return -EBUSY; ++ ++ controller->opened2 = 1; ++ first_record_call = 1; ++ /* for ioctl */ ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ ++ in_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(in_empty_queue.id + i) = i; ++ ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ } ++ ++ file->private_data = controller; ++ jz_audio_reset(); ++ REG_AIC_FR |= (1 << 6); ++ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { ++#if defined(CONFIG_I2S_ICODEC) ++ if (set_codec_replay_record) ++ set_codec_replay_record(use_mic_line_flag); ++#endif ++#if defined(CONFIG_I2S_DLV) ++ if (use_mic_line_flag == USE_NONE) { ++ printk("you select mic or line recording please.or use mic recording!\n"); ++ use_mic_line_flag = USE_MIC; ++ } ++ if (use_mic_line_flag == USE_LINEIN) { ++ /* Record LINE input audio with Audio data replay (full duplex for linein) */ ++ /* codec_test_line */ ++ set_record_line_input_audio_with_audio_data_replay(); ++ ++ } ++ if (use_mic_line_flag == USE_MIC) { ++ /* Record MIC input audio with Audio data replay (full duplex) */ ++ /* codec_test_mic */ ++ set_record_mic_input_audio_with_audio_data_replay(); ++ } ++#if 0 ++ /* Record playing audio mixed with MIC input audio */ ++ set_record_playing_audio_mixed_with_mic_input_audio(); ++#endif ++ ++#endif ++ } else if (file->f_mode & FMODE_WRITE) { ++#if defined(CONFIG_I2S_ICODEC) ++ if(set_codec_replay) ++ set_codec_replay(); ++#endif ++#if defined(CONFIG_I2S_DLV) ++ //mdelay(10); ++ /* Audio data replay */ ++ set_audio_data_replay(); ++#endif ++ } else if (file->f_mode & FMODE_READ) { ++#if defined(CONFIG_I2S_ICODEC) ++ abnormal_data_count = 0; ++ if(set_codec_record) ++ set_codec_record(use_mic_line_flag); ++#endif ++#if defined(CONFIG_I2S_DLV) ++#if 0 ++ /* Record MIC input audio with direct playback */ ++ set_record_mic_input_audio_with_direct_playback(); ++#endif ++ ++#if 1 ++ /* set Record MIC input audio without playback */ ++ set_record_mic_input_audio_without_playback(); ++#endif ++#if 0 ++ /* tested */ ++ /* set Record LINE input audio without playback */ ++ set_record_line_input_audio_without_playback(); ++#endif ++ mdelay(1); ++#endif ++ } ++ ++#if defined(CONFIG_I2S_DLV) ++ __aic_reset(); ++ ++ mdelay(10); ++ REG_AIC_I2SCR = 0x10; ++ mdelay(20); ++ __aic_flush_fifo(); ++#endif ++ ++ __i2s_enable(); ++ ++#if defined(CONFIG_I2S_DLV) ++ ndelay(100); ++ ++ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { ++#if defined(CONFIG_I2S_DLV) ++ //set SB_ADC or SB_DAC ++ __dmac_enable_module(0); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ ramp_up_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //ramp_up_end = jiffies; ++#endif ++ } else if (file->f_mode & FMODE_WRITE) { ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ ramp_up_start = jiffies; ++ /*while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_RCR = 0x1; ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_RGR = 1;*/ ++ sleep_on(&pop_wait_queue); ++ //ramp_up_end = jiffies; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++#endif ++ } else if (file->f_mode & FMODE_READ) { ++#if defined(CONFIG_I2S_DLV) ++ if (jz_mic_only) ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ else ++ write_codec_file_bit(5, 0, 7);//SB_DAC->0 ++ mdelay(500); ++#endif ++ } ++#endif ++ return 0; ++} ++ ++ ++static int jz_audio_ioctl(struct inode *inode, struct file *file, ++unsigned int cmd, unsigned long arg) ++{ ++ int val,fullc,busyc,unfinish,newfragstotal,newfragsize; ++ unsigned int flags; ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ count_info cinfo; ++ audio_buf_info abinfo; ++ int id, i; ++ ++ val = 0; ++ switch (cmd) { ++ case OSS_GETVERSION: ++ return put_user(SOUND_VERSION, (int *)arg); ++ case SNDCTL_DSP_RESET: ++#if 0 ++ jz_audio_reset(); ++ __i2s_disable_replay(); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++ __i2s_disable_transmit_dma(); ++#endif ++ return 0; ++ case SNDCTL_DSP_SYNC: ++ if (file->f_mode & FMODE_WRITE) ++ return drain_dac(controller, file->f_flags & O_NONBLOCK); ++ return 0; ++ case SNDCTL_DSP_SPEED: ++ /* set smaple rate */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ if (val >= 0) ++ jz_audio_set_speed(controller->dev_audio, val); ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_STEREO: ++ /* set stereo or mono channel */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); ++ ++ return 0; ++ case SNDCTL_DSP_GETBLKSIZE: ++ //return put_user(jz_audio_fragsize / jz_audio_b, (int *)arg); ++ return put_user(jz_audio_fragsize, (int *)arg); ++ case SNDCTL_DSP_GETFMTS: ++ /* Returns a mask of supported sample format*/ ++ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); ++ case SNDCTL_DSP_SETFMT: ++ /* Select sample format */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ if (val != AFMT_QUERY) ++ jz_audio_set_format(controller->dev_audio,val); ++ else { ++ if (file->f_mode & FMODE_READ) ++ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; ++ else ++ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; ++ } ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_CHANNELS: ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ jz_audio_set_channels(controller->dev_audio, val); ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_POST: ++ /* FIXME: the same as RESET ?? */ ++ return 0; ++ case SNDCTL_DSP_SUBDIVIDE: ++ return 0; ++ case SNDCTL_DSP_SETFRAGMENT: ++ get_user(val, (long *) arg); ++ newfragsize = 1 << (val & 0xFFFF); ++ if (newfragsize < 4 * PAGE_SIZE) ++ newfragsize = 4 * PAGE_SIZE; ++ if (newfragsize > (16 * PAGE_SIZE)) ++ newfragsize = 16 * PAGE_SIZE; ++ ++ newfragstotal = (val >> 16) & 0x7FFF; ++ if (newfragstotal < 2) ++ newfragstotal = 2; ++ if (newfragstotal > 32) ++ newfragstotal = 32; ++ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize)) ++ return 0; ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ mdelay(500); ++ jz_audio_fragstotal = newfragstotal; ++ jz_audio_fragsize = newfragsize; ++ ++ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ mdelay(10); ++ ++ return 0; ++ case SNDCTL_DSP_GETCAPS: ++ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg); ++ case SNDCTL_DSP_NONBLOCK: ++ file->f_flags |= O_NONBLOCK; ++ return 0; ++ case SNDCTL_DSP_SETDUPLEX: ++ return -EINVAL; ++ case SNDCTL_DSP_GETOSPACE: ++ { ++ int i; ++ unsigned long bytes = 0; ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ jz_audio_fragments = elements_in_queue(&out_empty_queue); ++ for (i = 0; i < jz_audio_fragments; i++) ++ bytes += jz_audio_fragsize; ++ ++ if (jz_audio_channels == 2) ++ bytes /= jz_audio_b; ++ else if (jz_audio_channels == 1) ++ bytes /= 4; ++ else ++ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 1!\n"); ++ ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ /* unused fragment amount */ ++ abinfo.fragments = jz_audio_fragments; ++ /* amount of fragments */ ++ abinfo.fragstotal = jz_audio_fragstotal; ++ /* fragment size in bytes */ ++ if (jz_audio_channels == 2) ++ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; ++ else if (jz_audio_channels == 1) ++ abinfo.fragsize = jz_audio_fragsize / 4; ++ else ++ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 2!\n"); ++ ++ /* write size count without blocking in bytes */ ++ abinfo.bytes = (int)bytes; ++ ++ return copy_to_user((void *)arg, &abinfo, ++ sizeof(abinfo)) ? -EFAULT : 0; ++ } ++ case SNDCTL_DSP_GETISPACE: ++ { ++ int i; ++ unsigned long bytes = 0; ++ if (!(file->f_mode & FMODE_READ)) ++ return -EINVAL; ++ jz_audio_fragments = elements_in_queue(&in_empty_queue); ++ for (i = 0; i < jz_audio_fragments; i++) ++ bytes += jz_audio_fragsize; ++ ++ if (jz_audio_channels == 2) ++ bytes /= jz_audio_b; ++ else if (jz_audio_channels == 1) ++ bytes /= 4; ++ else ++ printk("SNDCTL_DSP_GETISPACE : channels is wrong 1!\n"); ++ ++ abinfo.fragments = jz_audio_fragments; ++ abinfo.fragstotal = jz_audio_fragstotal; ++ ++ if (jz_audio_channels == 2) ++ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; ++ else if (jz_audio_channels == 1) ++ abinfo.fragsize = jz_audio_fragsize / 4; ++ else ++ printk("SNDCTL_DSP_GETISPACE : channels is wrong 2!\n"); ++ ++ abinfo.bytes = (int)bytes; ++ ++ return copy_to_user((void *)arg, &abinfo, ++ sizeof(abinfo)) ? -EFAULT : 0; ++ } ++ case SNDCTL_DSP_GETTRIGGER: ++ val = 0; ++ if (file->f_mode & FMODE_READ && in_dma_buf) ++ val |= PCM_ENABLE_INPUT; ++ if (file->f_mode & FMODE_WRITE && out_dma_buf) ++ val |= PCM_ENABLE_OUTPUT; ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_SETTRIGGER: ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ return 0; ++ case SNDCTL_DSP_GETIPTR: ++ if (!(file->f_mode & FMODE_READ)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ cinfo.bytes = controller->total_bytes; ++ cinfo.blocks = controller->blocks; ++ cinfo.ptr = controller->nextIn; ++ controller->blocks = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); ++ case SNDCTL_DSP_GETOPTR: ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ cinfo.bytes = controller->total_bytes; ++ cinfo.blocks = controller->blocks; ++ cinfo.ptr = controller->nextOut; ++ controller->blocks = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); ++ case SNDCTL_DSP_GETODELAY: ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ unfinish = 0; ++ fullc = elements_in_queue(&out_full_queue); ++ busyc = elements_in_queue(&out_busy_queue); ++ for(i = 0;i < fullc ;i ++) { ++ id = *(out_full_queue.id + i); ++ unfinish += *(out_dma_buf_data_count + id); ++ } ++ for(i = 0;i < busyc ;i ++) { ++ id = *(out_busy_queue.id + i); ++ unfinish += get_dma_residue(controller->dma1); ++ } ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ if (jz_audio_channels == 2) ++ unfinish /= jz_audio_b; ++ else if (jz_audio_channels == 1) ++ unfinish /= 4; ++ else ++ printk("SNDCTL_DSP_GETODELAY : channels is wrong !\n"); ++ ++ return put_user(unfinish, (int *) arg); ++ case SOUND_PCM_READ_RATE: ++ return put_user(jz_audio_rate, (int *)arg); ++ case SOUND_PCM_READ_CHANNELS: ++ return put_user(jz_audio_channels, (int *)arg); ++ case SOUND_PCM_READ_BITS: ++ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg); ++ case SNDCTL_DSP_MAPINBUF: ++ case SNDCTL_DSP_MAPOUTBUF: ++ case SNDCTL_DSP_SETSYNCRO: ++ case SOUND_PCM_WRITE_FILTER: ++ case SOUND_PCM_READ_FILTER: ++ return -EINVAL; ++ } ++ return -EINVAL; ++} ++ ++ ++static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait) ++{ ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ unsigned long flags; ++ unsigned int mask = 0; ++ ++ if (file->f_mode & FMODE_WRITE) { ++ if (elements_in_queue(&out_empty_queue) > 0) ++ return POLLOUT | POLLWRNORM; ++ ++ poll_wait(file, &controller->dac_wait, wait); ++ } ++ ++ if (file->f_mode & FMODE_READ) { ++ if (elements_in_queue(&in_full_queue) > 0) ++ return POLLIN | POLLRDNORM; ++ ++ poll_wait(file, &controller->adc_wait, wait); ++ } ++ ++ spin_lock_irqsave(&controller->lock, flags); ++ if (file->f_mode & FMODE_WRITE) { ++ if (elements_in_queue(&out_empty_queue) > 0) ++ mask |= POLLOUT | POLLWRNORM; ++ } else if (file->f_mode & FMODE_READ) { ++ if (elements_in_queue(&in_full_queue) > 0) ++ mask |= POLLIN | POLLRDNORM; ++ } ++ spin_unlock_irqrestore(&controller->lock, flags); ++ ++ return mask; ++} ++ ++static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) ++{ ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ int id, ret = 0, left_count, copy_count, cnt = 0; ++ unsigned long flags; ++ ++ if (count < 0) ++ return -EINVAL; ++ ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextIn = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ copy_count = jz_audio_fragsize / 4; ++ ++ left_count = count; ++ if (first_record_call) { ++ first_record_call = 0; ++ audio_read_back_first: ++ if ((id = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id); ++ spin_lock(&controller->lock); ++ *(in_dma_buf_data_count + id) = copy_count * 4; ++ ++ spin_unlock(&controller->lock); ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); ++ audio_start_dma(controller->dma2,file->private_data, ++ *(in_dma_pbuf + id), ++ *(in_dma_buf_data_count + id), ++ DMA_MODE_READ); ++ sleep_on(&rx_wait_queue); ++ } else ++ goto audio_read_back_first; ++ } ++ ++ while (left_count > 0) { ++ audio_read_back_second: ++ if (elements_in_queue(&in_full_queue) <= 0) { ++ if (file->f_flags & O_NONBLOCK) ++ return ret ? ret : -EAGAIN; ++ else ++ sleep_on(&rx_wait_queue); ++ } ++ ++ if ((id = get_buffer_id(&in_full_queue)) >= 0) { ++ spin_lock(&controller->lock); ++ cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id); ++ spin_unlock(&controller->lock); ++ put_buffer_id(&in_empty_queue, id); ++ } else ++ goto audio_read_back_second; ++ ++ if (elements_in_queue(&in_busy_queue) == 0) { ++ if ((id=get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id); ++ spin_lock(&controller->lock); ++ *(in_dma_buf_data_count + id) = copy_count * 4; ++ spin_unlock(&controller->lock); ++ ++ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); ++ audio_start_dma(controller->dma2,file->private_data, ++ *(in_dma_pbuf + id), ++ *(in_dma_buf_data_count + id), ++ DMA_MODE_READ); ++ } ++ } ++ if (ret + cnt > count) { ++ spin_lock(&controller->lock); ++ cnt = count - ret; ++ spin_unlock(&controller->lock); ++ } ++ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt)) ++ return ret ? ret : -EFAULT; ++ ++ spin_lock(&controller->lock); ++ ret += cnt; ++ spin_unlock(&controller->lock); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextIn += ret; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ spin_lock(&controller->lock); ++ left_count -= cnt; ++ spin_unlock(&controller->lock); ++ } ++ return ret; ++} ++ ++static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) ++{ ++ int id, ret = 0, left_count, copy_count = 0; ++ unsigned int flags; ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ ++ if (count <= 0) ++ return -EINVAL; ++ ++ if(set_replay_hp_or_speaker) ++ set_replay_hp_or_speaker(); ++ ++ __i2s_enable_transmit_dma(); ++ __i2s_enable_replay(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextOut = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ if (jz_audio_channels == 2) ++ copy_count = jz_audio_fragsize / jz_audio_b; ++ else if(jz_audio_channels == 1) ++ copy_count = jz_audio_fragsize / 4; ++ left_count = count; ++ if (copy_from_user(controller->tmp1, buffer, count)) { ++ printk("copy_from_user failed:%d",ret); ++ return ret ? ret : -EFAULT; ++ } ++ ++ while (left_count > 0) { ++ audio_write_back: ++ if (file->f_flags & O_NONBLOCK) ++ udelay(2); ++ if (elements_in_queue(&out_empty_queue) == 0) { ++ if (file->f_flags & O_NONBLOCK) ++ return ret; ++ else ++ sleep_on(&tx_wait_queue); ++ } ++ /* the end fragment size in this write */ ++ if (ret + copy_count > count) ++ copy_count = count - ret; ++ if ((id = get_buffer_id(&out_empty_queue)) >= 0) { ++ replay_filler((signed long)controller->tmp1 + ret, copy_count, id); ++ if(*(out_dma_buf_data_count + id) > 0) { ++ put_buffer_id(&out_full_queue, id); ++ dma_cache_wback_inv(*(out_dma_buf + id), *(out_dma_buf_data_count + id)); ++ } else ++ put_buffer_id(&out_empty_queue, id); ++ } else ++ goto audio_write_back; ++ ++ left_count = left_count - copy_count; ++ ret += copy_count; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextOut += ret; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ if (elements_in_queue(&out_busy_queue) == 0) { ++ if ((id=get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_busy_queue, id); ++ if(*(out_dma_buf_data_count + id) > 0) { ++ audio_start_dma(controller->dma1, ++ file->private_data, ++ *(out_dma_pbuf + id), ++ *(out_dma_buf_data_count + id), ++ DMA_MODE_WRITE); ++ last_dma_buffer_id = id; ++#if defined(CONFIG_I2S_DLV) ++ if (jz_codec_config == 0) { ++ write_codec_file_bit(1, 0, 5); ++ gain_up_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //gain_up_end = jiffies; ++ jz_codec_config = 1; ++ //SB_ADC->1 ++ //write_codec_file_bit(5, 1, 4); ++ //while(1); ++ } ++#endif ++ } ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++#if defined(CONFIG_I2S_ICODEC) ++static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample) ++{ ++ int i,step_len; ++ unsigned long *pop_buf = (unsigned long*)pop_turn_onoff_buf; ++ unsigned int sample_oss = (REG_AIC_CR & 0x00380000) >> 19; ++ unsigned long l_sample_count,r_sample_count,sample_count; ++ struct jz_i2s_controller_info *controller = i2s_controller; ++ signed int left_sam=0,right_sam=0,l_val,r_val; ++ ++ switch (sample_oss) { ++ case 0x0: ++ break; ++ case 0x1: ++ left_sam = (signed int)l_sample; ++ right_sam = (signed int)r_sample; ++ break; ++ case 0x2: ++ break; ++ case 0x3: ++ break; ++ case 0x4: ++ break; ++ } ++ ++ if(left_sam == 0 && right_sam == 0) ++ return; ++ ++ switch (sample_oss) { ++ case 0x0: ++ break; ++ case 0x1: ++ step_len = jz_audio_speed / 10 * 3; ++ step_len = step_len / 2; ++ step_len = 0x7fff / step_len + 1; ++ ++ l_sample_count = 0; ++ l_val = left_sam; ++ ++ while(1) { ++ if(l_val > 0) { ++ if(l_val >= step_len) { ++ l_val -= step_len; ++ l_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(l_val < 0) { ++ if(l_val <= -step_len) { ++ l_val += step_len; ++ l_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(l_val == 0) ++ break; ++ } ++ ++ r_sample_count = 0; ++ r_val = right_sam; ++ while(1) { ++ if(r_val > 0) { ++ if(r_val >= step_len) { ++ r_val -= step_len; ++ r_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(r_val < 0) { ++ if(r_val <= -step_len) { ++ r_val += step_len; ++ r_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(r_val == 0) ++ break; ++ } ++ /* fill up */ ++ if(l_sample_count > r_sample_count) ++ sample_count = l_sample_count; ++ else ++ sample_count = r_sample_count; ++ ++ l_val = left_sam; ++ r_val = right_sam; ++ for(i=0;i <= sample_count;i++) { ++ ++ *pop_buf = (unsigned long)l_val; ++ pop_buf ++; ++ ++ if(l_val > step_len) ++ l_val -= step_len; ++ else if(l_val < -step_len) ++ l_val += step_len; ++ else if(l_val >= -step_len && l_val <= step_len) ++ l_val = 0; ++ ++ *pop_buf = (unsigned long)r_val; ++ pop_buf ++; ++ if(r_val > step_len) ++ r_val -= step_len; ++ else if(r_val < -step_len) ++ r_val += step_len; ++ else if(r_val >= -step_len && r_val <= step_len) ++ r_val = 0; ++ } ++ ++ *pop_buf = 0; ++ pop_buf ++; ++ *pop_buf = 0; ++ ++ pop_buf ++; ++ sample_count += 2; ++ dma_cache_wback_inv(pop_turn_onoff_buf, sample_count*8); ++ ++ pop_dma_flag = 1; ++ audio_start_dma(controller->dma1,controller,pop_turn_onoff_pbuf,sample_count*8,DMA_MODE_WRITE); ++ sleep_on(&pop_wait_queue); ++ pop_dma_flag = 0; ++ break; ++ case 0x2: ++ break; ++ case 0x3: ++ break; ++ case 0x4: ++ break; ++ } ++} ++#endif --- linux-2.6.24.7.old/sound/oss/jz_i2s_4750.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7/sound/oss/jz_i2s_4750.c 2009-04-12 18:13:57.000000000 +0200 @@ -0,0 +1,3010 @@ -+/* -+ * linux/drivers/sound/Jz_i2s.c -+ * -+ * JzSOC On-Chip I2S audio driver. -+ * -+ * Copyright (C) 2005 by Junzheng Corp. -+ * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using -+ * dma channel 4&3,noah is tested. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Because the normal application of AUDIO devices are focused on Little_endian, -+ * then we only perform the little endian data format in driver. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "sound_config.h" -+ -+#define DPRINTK(args...) printk(args) -+#define DMA_ID_I2S_TX DMA_ID_AIC_TX -+#define DMA_ID_I2S_RX DMA_ID_AIC_RX -+#define NR_I2S 2 -+#define MAXDELAY 50000 -+#define JZCODEC_RW_BUFFER_SIZE 2 -+#define JZCODEC_RW_BUFFER_TOTAL 6 -+ -+typedef struct hpvol_shift_s -+{ -+ int hpvol; -+ int shift; -+} hpvol_shift_t; -+ -+mixer_info info; -+_old_mixer_info old_info; -+int codec_volue_shift; -+hpvol_shift_t hpvol_shift_table[72]; -+int abnormal_data_count; -+unsigned long i2s_clk; -+ -+void (*set_codec_mode)(void) = NULL; -+void (*clear_codec_mode)(void) = NULL; -+void (*set_codec_gpio_pin)(void) = NULL; -+void (*each_time_init_codec)(void) = NULL; -+int (*set_codec_startup_param)(void) = NULL; -+void (*set_codec_volume_table)(void) = NULL; -+void (*set_codec_record)(void) = NULL; -+void (*set_codec_replay)(void) = NULL; -+void (*set_codec_replay_record)(void); -+void (*turn_on_codec)(void) = NULL; -+void (*turn_off_codec)(void) = NULL; -+void (*set_codec_speed)(int rate) = NULL; -+void (*reset_codec)(void) = NULL; -+void (*codec_mixer_old_info_id_name)(void) = NULL; -+void (*codec_mixer_info_id_name)(void) = NULL; -+void (*set_codec_bass)(int val) = NULL; -+void (*set_codec_volume)(int val) = NULL; -+void (*set_codec_mic)(int val) = NULL; -+void (*i2s_resume_codec)(void) = NULL; -+void (*i2s_suspend_codec)(int wr,int rd) = NULL; -+void (*init_codec_pin)(void) = NULL; -+void (*set_codec_some_func)(void) = NULL; -+void (*clear_codec_record)(void) = NULL; -+void (*clear_codec_replay)(void) = NULL; -+void (*set_replay_hp_or_speaker)(void) = NULL; -+void (*set_codec_direct_mode)(void) = NULL; -+void (*clear_codec_direct_mode)(void) = NULL; -+ -+static int jz_audio_rate; -+static int jz_audio_format; -+static int jz_audio_volume; -+static int jz_audio_channels; -+static int jz_audio_b; /* bits expand multiple */ -+static int jz_audio_fragments; /* unused fragment amount */ -+static int jz_audio_fragstotal; -+static int jz_audio_fragsize; -+static int jz_audio_speed; -+ -+static int codec_bass_gain; -+static int audio_mix_modcnt; -+static int jz_audio_dma_tran_count; /* bytes count of one DMA transfer */ -+static int jz_mic_only = 1; -+static int jz_codec_config = 0; -+static unsigned long ramp_up_start; -+static unsigned long ramp_up_end; -+static unsigned long gain_up_start; -+static unsigned long gain_up_end; -+static unsigned long ramp_down_start; -+static unsigned long ramp_down_end; -+static unsigned long gain_down_start; -+static unsigned long gain_down_end; -+ -+static int codec_mic_gain; -+static int pop_dma_flag; -+static int last_dma_buffer_id; -+static int drain_flag; -+ -+static void (*old_mksound)(unsigned int hz, unsigned int ticks); -+extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); -+static void jz_update_filler(int bits, int channels); -+ -+static int Init_In_Out_queue(int fragstotal,int fragsize); -+static int Free_In_Out_queue(int fragstotal,int fragsize); -+static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref); -+static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref); -+static void (*replay_filler)(signed long src_start, int count, int id); -+static int (*record_filler)(unsigned long dst_start, int count, int id); -+#if defined(CONFIG_I2S_ICODEC) -+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample); -+#endif -+static void jz_audio_reset(void); -+static struct file_operations jz_i2s_audio_fops; -+ -+static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (drain_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue); -+ -+struct jz_i2s_controller_info -+{ -+ int io_base; -+ int dma1; /* for play */ -+ int dma2; /* for record */ -+ char *name; -+ int dev_audio; -+ struct i2s_codec *i2s_codec[NR_I2S]; -+ int opened1; -+ int opened2; -+ unsigned char *tmp1; /* tmp buffer for sample conversions */ -+ unsigned char *tmp2; -+ spinlock_t lock; -+ spinlock_t ioctllock; -+ -+ wait_queue_head_t dac_wait; -+ wait_queue_head_t adc_wait; -+ int nextIn; /* byte index to next-in to DMA buffer */ -+ int nextOut; /* byte index to next-out from DMA buffer */ -+ int count; /* current byte count in DMA buffer */ -+ int finish; /* current transfered byte count in DMA buffer */ -+ unsigned total_bytes; /* total bytes written or read */ -+ unsigned blocks; -+ unsigned error; /* over/underrun */ -+#ifdef CONFIG_PM -+ struct pm_dev *pm; -+#endif -+}; -+ -+ -+static struct jz_i2s_controller_info *i2s_controller = NULL; -+struct i2s_codec -+{ -+ /* I2S controller connected with */ -+ void *private_data; -+ char *name; -+ int id; -+ int dev_mixer; -+ /* controller specific lower leverl i2s accessing routines */ -+ u16 (*codec_read) (u8 reg); /* the function accessing Codec REGs */ -+ void (*codec_write) (u8 reg, u16 val); -+ /* Wait for codec-ready */ -+ void (*codec_wait) (struct i2s_codec *codec); -+ /* OSS mixer masks */ -+ int modcnt; -+ int supported_mixers; -+ int stereo_mixers; -+ int record_sources; -+ int bit_resolution; -+ /* OSS mixer interface */ -+ int (*read_mixer) (struct i2s_codec *codec, int oss_channel); -+ void (*write_mixer)(struct i2s_codec *codec, int oss_channel, -+ unsigned int left, unsigned int right); -+ int (*recmask_io) (struct i2s_codec *codec, int rw, int mask); -+ int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg); -+ /* saved OSS mixer states */ -+ unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; -+}; -+ -+ -+typedef struct buffer_queue_s -+{ -+ int count; -+ int *id; -+ int lock; -+} buffer_queue_t; -+ -+typedef struct left_right_sample_s -+{ -+ signed long left; -+ signed long right; -+} left_right_sample_t; -+ -+static unsigned long pop_turn_onoff_buf; -+static unsigned long pop_turn_onoff_pbuf; -+ -+static unsigned long *out_dma_buf = NULL; -+static unsigned long *out_dma_pbuf = NULL; -+static unsigned long *out_dma_buf_data_count = NULL; -+static unsigned long *in_dma_buf = NULL; -+static unsigned long *in_dma_pbuf = NULL; -+static unsigned long *in_dma_buf_data_count = NULL; -+ -+static buffer_queue_t out_empty_queue; -+static buffer_queue_t out_full_queue; -+static buffer_queue_t out_busy_queue; -+static buffer_queue_t in_empty_queue; -+static buffer_queue_t in_full_queue; -+static buffer_queue_t in_busy_queue; -+static int first_record_call = 0; -+ -+static left_right_sample_t save_last_samples[64]; -+static int read_codec_file(int addr) -+{ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ mdelay(1); -+ return(__icdc_get_value()); -+} -+ -+#if 0 /* mask warning */ -+static void printk_codec_files(void) -+{ -+ int cnt; -+ -+ printk("\n"); -+ -+ printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR); -+ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR); -+ printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR); -+ printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR); -+ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR); -+ printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR); -+ printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR); -+ printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA); -+ -+ for (cnt = 0; cnt <= 27 ; cnt++) { -+ printk(" ( %d : 0x%x ) ",cnt ,read_codec_file(cnt)); -+ } -+ printk("\n"); -+} -+#endif -+ -+static void write_codec_file(int addr, int val) -+{ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ __icdc_set_cmd(val); /* write */ -+ mdelay(1); -+ __icdc_set_rgwr(); -+ mdelay(1); -+} -+ -+static int write_codec_file_bit(int addr, int bitval, int mask_bit) -+{ -+ int val; -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ mdelay(1); -+ val = __icdc_get_value(); /* read */ -+ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ val &= ~(1 << mask_bit); -+ if (bitval == 1) -+ val |= 1 << mask_bit; -+ -+ __icdc_set_cmd(val); /* write */ -+ mdelay(1); -+ __icdc_set_rgwr(); -+ mdelay(1); -+ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ val = __icdc_get_value(); /* read */ -+ -+ if (((val >> mask_bit) & bitval) == bitval) -+ return 1; -+ else -+ return 0; -+} -+ -+#if 0 /* mask warning */ -+/* set Audio data replay */ -+static void set_audio_data_replay(void) -+{ -+ /* DAC path */ -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ mdelay(10); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ //mdelay(100); -+ //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //mdelay(300); -+} -+#endif -+ -+/* unset Audio data replay */ -+static void unset_audio_data_replay(void) -+{ -+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ //mdelay(800); -+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ //mdelay(800); -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 4);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+#if 0 /* mask warning */ -+/* set Record MIC input audio without playback */ -+static void set_record_mic_input_audio_without_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 1; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ mdelay(10); -+ write_codec_file_bit(1, 1, 2); -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ -+ write_codec_file(22, 0x40);//mic 1 -+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ //write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file(1, 0x4); -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Record MIC input audio without playback */ -+static void unset_record_mic_input_audio_without_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 0; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Record LINE input audio without playback */ -+static void set_record_line_input_audio_without_playback(void) -+{ -+ /* ADC path for LINE IN */ -+ jz_mic_only = 1; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ write_codec_file(22, 0xf6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ mdelay(10); -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file(1, 0x4); -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Record LINE input audio without playback */ -+static void unset_record_line_input_audio_without_playback(void) -+{ -+ /* ADC path for LINE IN */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1 -+ -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Playback LINE input audio direct only */ -+static void set_playback_line_input_audio_direct_only(void) -+{ -+ jz_audio_reset();//or init_codec() -+ REG_AIC_I2SCR = 0x10; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ write_codec_file(22, 0xf6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ mdelay(10); -+ write_codec_file_bit(1, 1, 2);//CR1.HP_BYPASS->1 -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ //write_codec_file_bit(5, 1, 7);//PMR1.SB_DAC->1 -+ //write_codec_file_bit(5, 1, 4);//PMR1.SB_ADC->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Playback LINE input audio direct only */ -+static void unset_playback_line_input_audio_direct_only(void) -+{ -+ write_codec_file_bit(6, 0, 3);//GIM->0 -+ write_codec_file_bit(1, 0, 2);//PMR1.BYPASS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LINE->1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ mdelay(100); -+ write_codec_file_bit(5, 1, 5);//PMR1.SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Record MIC input audio with direct playback */ -+static void set_record_mic_input_audio_with_direct_playback(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ jz_mic_only = 0; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ -+ write_codec_file(22, 0x60);//mic 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ //write_codec_file(1, 0x4); -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Record MIC input audio with direct playback */ -+static void unset_record_mic_input_audio_with_direct_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 0; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Record playing audio mixed with MIC input audio */ -+static void set_record_playing_audio_mixed_with_mic_input_audio(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ mdelay(10); -+ -+ write_codec_file(22, 0x63);//mic 1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ write_codec_file_bit(5, 0, 4);//PMR1.SB_MIX->0 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Record playing audio mixed with MIC input audio */ -+static void unset_record_playing_audio_mixed_with_mic_input_audio(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Record MIC input audio with Audio data replay (full duplex) */ -+static void set_record_mic_input_audio_with_audio_data_replay(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Record MIC input audio with Audio data replay (full duplex) */ -+static void unset_record_mic_input_audio_with_audio_data_replay(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Record LINE input audio with Audio data replay (full duplex for linein) */ -+static void set_record_line_input_audio_with_audio_data_replay(void) -+{ -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ -+ -+ //jz_mic_only = 1; -+ write_codec_file(22, 0xc6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Record LINE input audio with Audio data replay (full duplex for linein) */ -+static void unset_record_line_input_audio_with_audio_data_replay(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+static inline int get_buffer_id(struct buffer_queue_s *q) -+{ -+ int r; -+ unsigned long flags; -+ int i; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ if (q->count == 0) { -+ spin_unlock_irqrestore(&q->lock, flags); -+ return -1; -+ } -+ r = *(q->id + 0); -+ for (i=0;i < q->count-1;i++) -+ *(q->id + i) = *(q->id + (i+1)); -+ q->count --; -+ spin_unlock_irqrestore(&q->lock, flags); -+ -+ return r; -+} -+ -+static inline void put_buffer_id(struct buffer_queue_s *q, int id) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ *(q->id + q->count) = id; -+ q->count ++; -+ spin_unlock_irqrestore(&q->lock, flags); -+} -+ -+static inline int elements_in_queue(struct buffer_queue_s *q) -+{ -+ int r; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ r = q->count; -+ spin_unlock_irqrestore(&q->lock, flags); -+ -+ return r; -+} -+ -+static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode) -+{ -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ jz_audio_dma_tran_count = count / jz_audio_b; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ flags = claim_dma_lock(); -+ disable_dma(chan); -+ clear_dma_ff(chan); -+ //set_dma_mode(chan, mode); -+ jz_set_oss_dma(chan, mode, jz_audio_format); -+ set_dma_addr(chan, phyaddr); -+ if (count == 0) { -+ count++; -+ printk("JzSOC DMA controller can't set dma 0 count!\n"); -+ } -+ set_dma_count(chan, count); -+ enable_dma(chan); -+ release_dma_lock(flags); -+} -+ -+static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id) -+{ -+ int id1, id2; -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ int dma = controller->dma2; -+ -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ -+ if(drain_flag == 1) -+ wake_up(&drain_wait_queue); -+ /* for DSP_GETIPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ id1 = get_buffer_id(&in_busy_queue); -+ put_buffer_id(&in_full_queue, id1); -+ -+ wake_up(&rx_wait_queue); -+ wake_up(&controller->adc_wait); -+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id2); -+ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1); -+ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2)); -+ audio_start_dma(dma,dev_id, -+ *(in_dma_pbuf + id2), -+ *(in_dma_buf_data_count + id2), -+ DMA_MODE_READ); -+ } else -+ in_busy_queue.count = 0; -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id) -+{ -+ int id; -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ int dma = controller->dma1; -+ -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ -+ if(pop_dma_flag == 1) { -+ pop_dma_flag = 0; -+ wake_up(&pop_wait_queue); -+ } else { -+ if(drain_flag == 1) { -+ /* Is replay dma buffer over ? */ -+ if(elements_in_queue(&out_full_queue) <= 0) { -+ drain_flag = 0; -+ wake_up(&drain_wait_queue); -+ } -+ } -+ -+ /* for DSP_GETOPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ if ((id = get_buffer_id(&out_busy_queue)) < 0) -+ printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n"); -+ put_buffer_id(&out_empty_queue, id); -+ if ((id = get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_busy_queue, id); -+ if(*(out_dma_buf_data_count + id) > 0) { -+ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id), -+ *(out_dma_buf_data_count + id), -+ DMA_MODE_WRITE); -+ last_dma_buffer_id = id; -+ } -+ } else -+ out_busy_queue.count = 0; -+ -+ if (elements_in_queue(&out_empty_queue) > 0) { -+ wake_up(&tx_wait_queue); -+ wake_up(&controller->dac_wait); -+ } -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static void jz_i2s_initHw(int set) -+{ -+#if defined(CONFIG_MIPS_JZ_URANUS) -+ i2s_clk = 48000000; -+#else -+ i2s_clk = __cpm_get_i2sclk(); -+#endif -+ __i2s_disable(); -+ if(set) -+ __i2s_reset(); -+ schedule_timeout(5); -+ if(each_time_init_codec) -+ each_time_init_codec(); -+ __i2s_disable_record(); -+ __i2s_disable_replay(); -+ __i2s_disable_loopback(); -+ __i2s_set_transmit_trigger(4); -+ __i2s_set_receive_trigger(3); -+} -+ -+static int Init_In_Out_queue(int fragstotal,int fragsize) -+{ -+ int i; -+ -+ /* recording */ -+ in_empty_queue.count = fragstotal; -+ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_buf) -+ goto all_mem_err; -+ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_pbuf) -+ goto all_mem_err; -+ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_buf_data_count) -+ goto all_mem_err; -+ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_empty_queue.id) -+ goto all_mem_err; -+ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_full_queue.id) -+ goto all_mem_err; -+ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_busy_queue.id) -+ goto all_mem_err; -+ -+ for (i=0;i < fragstotal;i++) -+ *(in_empty_queue.id + i) = i; -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ -+ for (i = 0; i < fragstotal; i++) { -+ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); -+ if (*(in_dma_buf + i) == 0) -+ goto mem_failed_in; -+ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i))); -+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); -+ } -+ -+ /* playing */ -+ out_empty_queue.count = fragstotal; -+ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!out_dma_buf) -+ goto all_mem_err; -+ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!out_dma_pbuf) -+ goto all_mem_err; -+ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ -+ if (!out_dma_buf_data_count) -+ goto all_mem_err; -+ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_empty_queue.id) -+ goto all_mem_err; -+ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_full_queue.id) -+ goto all_mem_err; -+ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_busy_queue.id) -+ goto all_mem_err; -+ for (i=0;i < fragstotal;i++) -+ *(out_empty_queue.id + i) = i; -+ -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ /* alloc DMA buffer */ -+ for (i = 0; i < fragstotal; i++) { -+ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); -+ if (*(out_dma_buf + i) == 0) { -+ printk(" can't allocate required DMA(OUT) buffers.\n"); -+ goto mem_failed_out; -+ } -+ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); -+ } -+ -+ return 1; -+all_mem_err: -+ printk("error:allocate memory occur error 1!\n"); -+ return 0; -+mem_failed_out: -+ printk("error:allocate memory occur error 2!\n"); -+ for (i = 0; i < fragstotal; i++) { -+ if(*(out_dma_buf + i)) -+ free_pages(*(out_dma_buf + i), get_order(fragsize)); -+ } -+ -+ return 0; -+mem_failed_in: -+ printk("error:allocate memory occur error 3!\n"); -+ for (i = 0; i < fragstotal; i++) { -+ if(*(in_dma_buf + i)) -+ free_pages(*(in_dma_buf + i), get_order(fragsize)); -+ } -+ return 0; -+} -+ -+static int Free_In_Out_queue(int fragstotal,int fragsize) -+{ -+ int i; -+ /* playing */ -+ if(out_dma_buf != NULL) { -+ for (i = 0; i < fragstotal; i++) { -+ if(*(out_dma_buf + i)) -+ free_pages(*(out_dma_buf + i), get_order(fragsize)); -+ *(out_dma_buf + i) = 0; -+ } -+ kfree(out_dma_buf); -+ out_dma_buf = NULL; -+ } -+ if(out_dma_pbuf) { -+ kfree(out_dma_pbuf); -+ out_dma_pbuf = NULL; -+ } -+ if(out_dma_buf_data_count) { -+ kfree(out_dma_buf_data_count); -+ out_dma_buf_data_count = NULL; -+ } -+ if(out_empty_queue.id) { -+ kfree(out_empty_queue.id); -+ out_empty_queue.id = NULL; -+ } -+ if(out_full_queue.id) { -+ kfree(out_full_queue.id); -+ out_full_queue.id = NULL; -+ } -+ if(out_busy_queue.id) { -+ kfree(out_busy_queue.id); -+ out_busy_queue.id = NULL; -+ } -+ out_empty_queue.count = fragstotal; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ -+ /* recording */ -+ if(in_dma_buf) { -+ for (i = 0; i < fragstotal; i++) { -+ if(*(in_dma_buf + i)) { -+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); -+ free_pages(*(in_dma_buf + i), get_order(fragsize)); -+ } -+ *(in_dma_buf + i) = 0; -+ } -+ kfree(in_dma_buf); -+ in_dma_buf = NULL; -+ } -+ if(in_dma_pbuf) { -+ kfree(in_dma_pbuf); -+ in_dma_pbuf = NULL; -+ } -+ if(in_dma_buf_data_count) { -+ kfree(in_dma_buf_data_count); -+ in_dma_buf_data_count = NULL; -+ } -+ if(in_empty_queue.id) { -+ kfree(in_empty_queue.id); -+ in_empty_queue.id = NULL; -+ } -+ if(in_full_queue.id) { -+ kfree(in_full_queue.id); -+ in_full_queue.id = NULL; -+ } -+ if(in_busy_queue.id) { -+ kfree(in_busy_queue.id); -+ in_busy_queue.id = NULL; -+ } -+ -+ in_empty_queue.count = fragstotal; -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ -+ return 1; -+} -+ -+static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller) -+{ -+ jz_i2s_initHw(0); -+} -+ -+static int jz_audio_set_speed(int dev, int rate) -+{ -+ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */ -+ jz_audio_speed = rate; -+ if (rate > 48000) -+ rate = 48000; -+ if (rate < 8000) -+ rate = 8000; -+ jz_audio_rate = rate; -+ -+ if(set_codec_speed) -+ set_codec_speed(rate); -+ -+ return jz_audio_rate; -+} -+ -+ -+static int record_fill_1x8_u(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long data; -+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ volatile unsigned char *dp = (unsigned char*)dst_start; -+ -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt++; -+ data = *(s++); -+ *(dp ++) = ((data << 16) >> 24) + 0x80; -+ s++; /* skip the other channel */ -+ } -+ -+ return cnt; -+} -+ -+ -+static int record_fill_2x8_u(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1, d2; -+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ volatile unsigned char *dp = (unsigned char*)dst_start; -+ -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ *(dp ++) = ((d1 << 16) >> 24) + 0x80; -+ d2 = *(s++); -+ *(dp ++) = ((d2 << 16) >> 24) + 0x80; -+ } -+ -+ return cnt; -+} -+ -+ -+static int record_fill_1x16_s(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1; -+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ unsigned short *dp = (unsigned short *)dst_start; -+ -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt += 2; /* count in byte */ -+ d1 = *(s++); -+ *(dp ++) = (d1 << 16) >> 16; -+ s++; /* skip the other channel */ -+ } -+ -+ return cnt; -+} -+ -+ -+static int record_fill_2x16_s(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1, d2; -+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ unsigned short *dp = (unsigned short *)dst_start; -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt += 4; /* count in byte */ -+ d1 = *(s++); -+ d2 = *(s++); -+ if(abnormal_data_count > 0) { -+ d1 = d2 = 0; -+ abnormal_data_count --; -+ } -+ *(dp ++) = (d1 << 16) >> 16; -+ *(dp ++) = (d2 << 16) >> 16; -+ } -+ -+ return cnt; -+} -+ -+static void replay_fill_1x8_u(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned char data; -+ unsigned long ddata; -+ volatile unsigned char *s = (unsigned char *)src_start; -+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count--; -+ cnt += 1; -+ data = *(s++) - 0x80; -+ ddata = (unsigned long) data << 8; -+ *(dp ++) = ddata; -+ *(dp ++) = ddata; -+ -+ /* save last left and right */ -+ if(count == 1) { -+ save_last_samples[id].left = ddata; -+ save_last_samples[id].right = ddata; -+ } -+ } -+ cnt = cnt * 2 * jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+ -+static void replay_fill_2x8_u(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned char d1; -+ unsigned long dd1; -+ volatile unsigned char *s = (unsigned char *)src_start; -+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count -= 1; -+ cnt += 1 ; -+ d1 = *(s++) - 0x80; -+ dd1 = (unsigned long) d1 << 8; -+ *(dp ++) = dd1; -+ /* save last left */ -+ if(count == 2) -+ save_last_samples[id].left = dd1; -+ /* save last right */ -+ if(count == 1) -+ save_last_samples[id].right = dd1; -+ } -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+ -+static void replay_fill_1x16_s(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed short d1; -+ signed long l1; -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count -= 2; -+ cnt += 2 ; -+ d1 = *(s++); -+ l1 = (signed long)d1; -+ *(dp ++) = l1; -+ *(dp ++) = l1; -+ -+ /* save last left and right */ -+ if(count == 1) { -+ save_last_samples[id].left = l1; -+ save_last_samples[id].right = l1; -+ } -+ } -+ cnt = cnt * 2 * jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+#if 0 -+static void replay_fill_2x16_s(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed short d1; -+ signed long l1; -+ int mute_cnt = 0; -+ signed long tmp1,tmp2; -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+#if defined(CONFIG_I2S_ICDC) -+ volatile signed long *before_dp; -+ int sam_rate = jz_audio_rate / 20; -+ -+ tmp1 = tmp2 = 0; -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ -+ l1 = (signed long)d1; -+ l1 >>= codec_volue_shift; -+ -+ if(l1 == 0) { -+ mute_cnt ++; -+ if(mute_cnt >= sam_rate) { -+ before_dp = dp - 10; -+ *(before_dp) = (signed long)1; -+ before_dp = dp - 11; -+ *(before_dp) = (signed long)1; -+ mute_cnt = 0; -+ } -+ } else -+ mute_cnt = 0; -+ -+ *(dp ++) = l1; -+ -+ tmp1 = tmp2; -+ tmp2 = l1; -+ } -+ -+ /* save last left */ -+ save_last_samples[id].left = tmp1; -+ /* save last right */ -+ save_last_samples[id].right = tmp2; -+#endif -+#if defined(CONFIG_I2S_DLV) -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ -+ l1 = (signed long)d1; -+ -+ *(dp ++) = l1; -+ } -+#endif -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+#else -+static void replay_fill_2x16_s(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed short d1; -+ signed long l1; -+ -+#if 0 -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed short *dp = (signed short*)(*(out_dma_buf + id)); -+ memcpy((char*)dp, (char*)s, count); -+ *(out_dma_buf_data_count + id) = count; -+#else -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ -+ l1 = (signed long)d1; -+ -+ *(dp ++) = l1; -+ } -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+#endif -+} -+#endif -+ -+ -+static unsigned int jz_audio_set_format(int dev, unsigned int fmt) -+{ -+ switch (fmt) { -+ case AFMT_U8: -+ __i2s_set_oss_sample_size(8); -+ __i2s_set_iss_sample_size(8); -+ jz_audio_format = fmt; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+ break; -+ case AFMT_S16_LE: -+#if defined(CONFIG_I2S_DLV) -+ /* DAC path and ADC path */ -+ write_codec_file(2, 0x00); -+ //write_codec_file(2, 0x60); -+#endif -+ jz_audio_format = fmt; -+ jz_update_filler(jz_audio_format,jz_audio_channels); -+ /* print all files */ -+ __i2s_set_oss_sample_size(16); -+ __i2s_set_iss_sample_size(16); -+ break; -+ -+ case AFMT_QUERY: -+ break; -+ } -+ -+ return jz_audio_format; -+} -+ -+ -+static short jz_audio_set_channels(int dev, short channels) -+{ -+ switch (channels) { -+ case 1: -+ if(set_codec_some_func) -+ set_codec_some_func(); -+ jz_audio_channels = channels; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono -+#endif -+ break; -+ case 2: -+ jz_audio_channels = channels; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo -+#endif -+ break; -+ case 0: -+ break; -+ } -+ -+ return jz_audio_channels; -+} -+ -+static void init_codec(void) -+{ -+ /* inititalize internal I2S codec */ -+ if(init_codec_pin) -+ init_codec_pin(); -+ -+#if defined(CONFIG_I2S_ICDC) -+ /* initialize AIC but not reset it */ -+ jz_i2s_initHw(0); -+#endif -+ if(reset_codec) -+ reset_codec(); -+} -+ -+static void jz_audio_reset(void) -+{ -+ __i2s_disable_replay(); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+ __i2s_disable_transmit_dma(); -+#if defined(CONFIG_I2S_DLV) -+ REG_AIC_I2SCR = 0x10; -+#endif -+ init_codec(); -+} -+ -+static int jz_audio_release(struct inode *inode, struct file *file); -+static int jz_audio_open(struct inode *inode, struct file *file); -+static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg); -+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait); -+static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos); -+static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos); -+ -+/* static struct file_operations jz_i2s_audio_fops */ -+static struct file_operations jz_i2s_audio_fops = -+{ -+ owner: THIS_MODULE, -+ open: jz_audio_open, -+ release: jz_audio_release, -+ write: jz_audio_write, -+ read: jz_audio_read, -+ poll: jz_audio_poll, -+ ioctl: jz_audio_ioctl -+}; -+ -+static int jz_i2s_open_mixdev(struct inode *inode, struct file *file) -+{ -+ int i; -+ int minor = MINOR(inode->i_rdev); -+ struct jz_i2s_controller_info *controller = i2s_controller; -+ -+ for (i = 0; i < NR_I2S; i++) -+ if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor) -+ goto match; -+ -+ if (!controller) -+ return -ENODEV; -+match: -+ file->private_data = controller->i2s_codec[i]; -+ -+ return 0; -+} -+ -+static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ struct i2s_codec *codec = (struct i2s_codec *)file->private_data; -+ return codec->mixer_ioctl(codec, cmd, arg); -+} -+ -+static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin) -+{ -+ return -ESPIPE; -+} -+ -+static struct file_operations jz_i2s_mixer_fops = -+{ -+ owner: THIS_MODULE, -+ llseek: jz_i2s_llseek, -+ ioctl: jz_i2s_ioctl_mixdev, -+ open: jz_i2s_open_mixdev, -+}; -+ -+static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg) -+{ -+ int ret; -+ long val = 0; -+ switch (cmd) { -+ case SOUND_MIXER_INFO: -+ -+ if(codec_mixer_info_id_name) -+ codec_mixer_info_id_name(); -+ info.modify_counter = audio_mix_modcnt; -+ -+ return copy_to_user((void *)arg, &info, sizeof(info)); -+ case SOUND_OLD_MIXER_INFO: -+ -+ if(codec_mixer_old_info_id_name) -+ codec_mixer_old_info_id_name(); -+ -+ return copy_to_user((void *)arg, &old_info, sizeof(info)); -+ case SOUND_MIXER_READ_STEREODEVS: -+ -+ return put_user(0, (long *) arg); -+ case SOUND_MIXER_READ_CAPS: -+ -+ val = SOUND_CAP_EXCL_INPUT; -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_READ_DEVMASK: -+ break; -+ case SOUND_MIXER_READ_RECMASK: -+ break; -+ case SOUND_MIXER_READ_RECSRC: -+ break; -+ case SOUND_MIXER_WRITE_SPEAKER: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ switch(val) { -+ case 100: -+ if(set_codec_direct_mode) -+ set_codec_direct_mode(); -+ break; -+ case 0: -+ if(clear_codec_direct_mode) -+ clear_codec_direct_mode(); -+ break; -+ } -+ break; -+ case SOUND_MIXER_WRITE_BASS: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ codec_bass_gain = val; -+ if(set_codec_bass) -+ set_codec_bass(val); -+ -+ return 0; -+ case SOUND_MIXER_READ_BASS: -+ -+ val = codec_bass_gain; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_WRITE_VOLUME: -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ if (val > 31) -+ val = 31; -+ jz_audio_volume = val; -+ -+ if(set_codec_volume) -+ set_codec_volume(val); -+ return 0; -+ case SOUND_MIXER_READ_VOLUME: -+ -+ val = jz_audio_volume; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_WRITE_MIC: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ codec_mic_gain = val; -+ if(set_codec_mic) -+ set_codec_mic(val); -+ -+ return 0; -+ case SOUND_MIXER_READ_MIC: -+ -+ val = codec_mic_gain; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ default: -+ return -ENOSYS; -+ } -+ audio_mix_modcnt ++; -+ return 0; -+} -+ -+ -+int i2s_probe_codec(struct i2s_codec *codec) -+{ -+ /* generic OSS to I2S wrapper */ -+ codec->mixer_ioctl = i2s_mixer_ioctl; -+ return 1; -+} -+ -+ -+/* I2S codec initialisation. */ -+static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller) -+{ -+ int num_i2s = 0; -+ struct i2s_codec *codec; -+ -+ for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) { -+ if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL) -+ return -ENOMEM; -+ memset(codec, 0, sizeof(struct i2s_codec)); -+ codec->private_data = controller; -+ codec->id = num_i2s; -+ -+ if (i2s_probe_codec(codec) == 0) -+ break; -+ if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) { -+ printk(KERN_ERR "Jz I2S: couldn't register mixer!\n"); -+ kfree(codec); -+ break; -+ } -+ controller->i2s_codec[num_i2s] = codec; -+ } -+ return num_i2s; -+} -+ -+ -+static void jz_update_filler(int format, int channels) -+{ -+#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) -+ -+ switch (TYPE(format, channels)) -+ { -+ -+ case TYPE(AFMT_U8, 1): -+ jz_audio_b = 4; /* 4bytes * 8bits =32bits */ -+ replay_filler = replay_fill_1x8_u; -+ record_filler = record_fill_1x8_u; -+ break; -+ case TYPE(AFMT_U8, 2): -+ jz_audio_b = 4; -+ replay_filler = replay_fill_2x8_u; -+ record_filler = record_fill_2x8_u; -+ break; -+ case TYPE(AFMT_S16_LE, 1): -+ jz_audio_b = 2; /* 2bytes * 16bits =32bits */ -+ replay_filler = replay_fill_1x16_s; -+ record_filler = record_fill_1x16_s; -+ break; -+ case TYPE(AFMT_S16_LE, 2): -+ jz_audio_b = 2; -+ replay_filler = replay_fill_2x16_s; -+ record_filler = record_fill_2x16_s; -+ break; -+ default: -+ ; -+ } -+} -+ -+ -+#ifdef CONFIG_PROC_FS -+extern struct proc_dir_entry *proc_jz_root; -+int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) -+{ -+ return 0; -+} -+ -+static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller) -+{ -+ if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0])) -+ return -EIO; -+ return 0; -+} -+ -+static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller) -+{ -+} -+#endif -+ -+static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller) -+{ -+ char *name; -+ int adev; /* No of Audio device. */ -+ -+ name = controller->name; -+ /* initialize AIC controller and reset it */ -+ jz_i2s_initHw(1); -+ adev = register_sound_dsp(&jz_i2s_audio_fops, -1); -+ if (adev < 0) -+ goto audio_failed; -+ /* initialize I2S codec and register /dev/mixer */ -+ if (jz_i2s_codec_init(controller) <= 0) -+ goto mixer_failed; -+ -+#ifdef CONFIG_PROC_FS -+ if (jz_i2s_init_proc(controller) < 0) { -+ printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name); -+ goto proc_failed; -+ } -+#endif -+ -+ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8); -+ if (!controller->tmp1) { -+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); -+ goto tmp1_failed; -+ } -+ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8); -+ if (!controller->tmp2) { -+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); -+ goto tmp2_failed; -+ } -+ if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) { -+ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name); -+ goto dma2_failed; -+ } -+ if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) { -+ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name); -+ goto dma1_failed; -+ } -+ printk("JzSOC On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2)); -+ -+ controller->dev_audio = adev; -+ pop_turn_onoff_buf = __get_free_pages(GFP_KERNEL | GFP_DMA, 8); -+ if(!pop_turn_onoff_buf) -+ printk("pop_turn_onoff_buf alloc is wrong!\n"); -+ pop_turn_onoff_pbuf = virt_to_phys((void *)pop_turn_onoff_buf); -+ -+ return; -+dma2_failed: -+ jz_free_dma(controller->dma1); -+dma1_failed: -+ free_pages((unsigned long)controller->tmp2, 8); -+tmp2_failed: -+ free_pages((unsigned long)controller->tmp1, 8); -+tmp1_failed: -+ -+#ifdef CONFIG_PROC_FS -+ jz_i2s_cleanup_proc(controller); -+#endif -+proc_failed: -+ /* unregister mixer dev */ -+mixer_failed: -+ unregister_sound_dsp(adev); -+audio_failed: -+ return; -+} -+ -+static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller) -+{ -+ if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info), -+ GFP_KERNEL)) == NULL) { -+ printk(KERN_ERR "Jz I2S Controller: out of memory.\n"); -+ return -ENOMEM; -+ } -+ (*controller)->name = "Jz I2S controller"; -+ (*controller)->opened1 = 0; -+ (*controller)->opened2 = 0; -+ init_waitqueue_head(&(*controller)->adc_wait); -+ init_waitqueue_head(&(*controller)->dac_wait); -+ spin_lock_init(&(*controller)->lock); -+ init_waitqueue_head(&rx_wait_queue); -+ init_waitqueue_head(&tx_wait_queue); -+ init_waitqueue_head(&pop_wait_queue); -+ init_waitqueue_head(&drain_wait_queue); -+ -+ return 0; -+} -+ -+static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller) -+{ -+ int adev = controller->dev_audio; -+ -+ jz_i2s_full_reset(controller); -+ controller->dev_audio = -1; -+ if (old_mksound) -+ kd_mksound = old_mksound;/* Our driver support bell for kb, see vt.c */ -+ -+#ifdef CONFIG_PROC_FS -+ jz_i2s_cleanup_proc(controller); -+#endif -+ -+ jz_free_dma(controller->dma1); -+ jz_free_dma(controller->dma2); -+ free_pages((unsigned long)controller->tmp1, 8); -+ free_pages((unsigned long)controller->tmp2, 8); -+ free_pages((unsigned long)pop_turn_onoff_buf, 8); -+ -+ if (adev >= 0) { -+ /* unregister_sound_mixer(audio_devs[adev]->mixer_dev); */ -+ unregister_sound_dsp(controller->dev_audio); -+ } -+} -+ -+#ifdef CONFIG_PM -+static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state) -+{ -+ if(i2s_suspend_codec) -+ i2s_suspend_codec(controller->opened1,controller->opened2); -+ printk("Aic and codec are suspended!\n"); -+ return 0; -+} -+ -+static int jz_i2s_resume(struct jz_i2s_controller_info *controller) -+{ -+ if(i2s_resume_codec) -+ i2s_resume_codec(); -+ -+#if defined(CONFIG_I2S_AK4642EN) -+ jz_i2s_initHw(0); -+ jz_audio_reset(); -+ __i2s_enable(); -+ jz_audio_set_speed(controller->dev_audio,jz_audio_speed); -+ /* playing */ -+ if(controller->opened1) { -+ if(set_codec_replay) -+ set_codec_replay(); -+ int dma = controller->dma1; -+ int id; -+ unsigned long flags; -+ disable_dma(dma); -+ if(__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if(__dmac_channel_transmit_end_detected(dma)) -+ __dmac_channel_clear_transmit_end(dma); -+ -+ /* for DSP_GETOPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ while((id = get_buffer_id(&out_busy_queue)) >= 0) -+ put_buffer_id(&out_empty_queue, id); -+ -+ out_busy_queue.count=0; -+ if((id = get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_empty_queue, id); -+ } -+ if (elements_in_queue(&out_empty_queue) > 0) { -+ wake_up(&tx_wait_queue); -+ wake_up(&controller->dac_wait); -+ } else -+ printk("pm out_empty_queue empty"); -+ } -+ -+ /* recording */ -+ if(controller->opened2) { -+ if(set_codec_record) -+ set_codec_record(); -+ int dma = controller->dma2; -+ int id1, id2; -+ unsigned long flags; -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ } -+ /* for DSP_GETIPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ id1 = get_buffer_id(&in_busy_queue); -+ put_buffer_id(&in_full_queue, id1); -+ wake_up(&rx_wait_queue); -+ wake_up(&controller->adc_wait); -+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_full_queue, id2); -+ } -+ in_busy_queue.count = 0; -+ } -+#endif -+ -+ return 0; -+} -+ -+static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) -+{ -+ int ret; -+ struct jz_i2s_controller_info *controller = pm_dev->data; -+ -+ if (!controller) return -EINVAL; -+ -+ switch (req) { -+ case PM_SUSPEND: -+ ret = jz_i2s_suspend(controller, (int)data); -+ break; -+ case PM_RESUME: -+ ret = jz_i2s_resume(controller); -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+#endif /* CONFIG_PM */ -+static irqreturn_t aic_codec_irq(int irq, void *dev_id) -+{ -+ u8 file_9 = read_codec_file(9); -+ u8 file_8 = read_codec_file(8); -+ -+ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9); -+ if ((file_9 & 0x1f) == 0x10) { -+ -+ write_codec_file(8, 0x3f); -+ write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ mdelay(300); -+ while ((read_codec_file(9) & 0x4) != 0x4); -+ while ((read_codec_file(9) & 0x10) == 0x10) { -+ write_codec_file(9, 0x10); -+ } -+ write_codec_file_bit(5, 0, 6);//SB_OUT->0 -+ mdelay(300); -+ while ((read_codec_file(9) & 0x8) != 0x8); -+ write_codec_file(9, file_9); -+ write_codec_file(8, file_8); -+ -+ return IRQ_HANDLED; -+ } -+ -+ if (file_9 & 0x8) -+ ramp_up_end = jiffies; -+ else if (file_9 & 0x4) -+ ramp_down_end = jiffies; -+ else if (file_9 & 0x2) -+ gain_up_end = jiffies; -+ else if (file_9 & 0x1) -+ gain_down_end = jiffies; -+ -+ write_codec_file(9, file_9); -+ if (file_9 & 0xf) -+ wake_up(&pop_wait_queue); -+ while (REG_ICDC_RGDATA & 0x100); -+ -+ return IRQ_HANDLED; -+} -+ -+static int __init init_jz_i2s(void) -+{ -+ int errno, retval; -+#if defined(CONFIG_I2S_DLV) -+ -+ ramp_up_start = 0; -+ ramp_up_end = 0; -+ gain_up_start = 0; -+ gain_up_end = 0; -+ ramp_down_start = 0; -+ ramp_down_end = 0; -+ gain_down_start = 0; -+ gain_down_end = 0; -+#endif -+ -+ abnormal_data_count = 0; -+ if(set_codec_mode) -+ set_codec_mode(); -+ -+ drain_flag = 0; -+ if ((errno = probe_jz_i2s(&i2s_controller)) < 0) -+ return errno; -+ if(set_codec_gpio_pin) -+ set_codec_gpio_pin(); -+ -+ attach_jz_i2s(i2s_controller); -+ if(set_codec_startup_param) -+ set_codec_startup_param(); -+#if defined(CONFIG_I2S_DLV) -+ jz_codec_config = 0; -+ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL); -+ if (retval) { -+ printk("Could not get aic codec irq %d\n", IRQ_AIC); -+ return retval; -+ } -+#endif -+ if(set_codec_volume_table) -+ set_codec_volume_table(); -+ -+ out_empty_queue.id = NULL; -+ out_full_queue.id = NULL; -+ out_busy_queue.id = NULL; -+ in_empty_queue.id = NULL; -+ in_full_queue.id = NULL; -+ in_busy_queue.id = NULL; -+ -+ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE; -+ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ; -+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ -+#ifdef CONFIG_PM -+ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, -+ jz_i2s_pm_callback); -+ if (i2s_controller->pm) -+ i2s_controller->pm->data = i2s_controller; -+#endif -+ -+#if defined(CONFIG_I2S_DLV) -+ __cpm_start_idct(); -+ __cpm_start_db(); -+ __cpm_start_me(); -+ __cpm_start_mc(); -+ __cpm_start_ipu(); -+#endif -+ -+ printk("JZ I2S OSS audio driver initialized\n"); -+ -+ return 0; -+} -+ -+static void __exit cleanup_jz_i2s(void) -+{ -+#ifdef CONFIG_PM -+ /* pm_unregister(i2s_controller->pm); */ -+#endif -+#if defined(CONFIG_I2S_DLV) -+ free_irq(IRQ_AIC, NULL); -+#endif -+ unload_jz_i2s(i2s_controller); -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ if(clear_codec_mode) -+ clear_codec_mode(); -+} -+ -+module_init(init_jz_i2s); -+module_exit(cleanup_jz_i2s); -+ -+#if defined(CONFIG_SOC_JZ4730) -+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count,con; -+ -+ if(elements_in_queue(&in_busy_queue) > 0) { -+ if (nonblock) -+ return -EBUSY; -+ drain_flag = 1; -+ sleep_on(&drain_wait_queue); -+ drain_flag = 0; -+ } else { -+ add_wait_queue(&ctrl->adc_wait, &wait); -+ for (con = 0; con < 1000; con ++) { -+ udelay(1); -+ set_current_state(TASK_INTERRUPTIBLE); -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ if (nonblock) { -+ remove_wait_queue(&ctrl->adc_wait, &wait); -+ current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ } -+ remove_wait_queue(&ctrl->adc_wait, &wait); -+ current->state = TASK_RUNNING; -+ } -+ return 0; -+} -+ -+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count; -+ -+ if(elements_in_queue(&out_full_queue) > 0) { -+ if (nonblock) -+ return -EBUSY; -+ -+ drain_flag = 1; -+ sleep_on(&drain_wait_queue); -+ drain_flag = 0; -+ } else { -+ add_wait_queue(&(ctrl->dac_wait), &wait); -+ for (;;) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ if(elements_in_queue(&out_full_queue) <= 0) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if(count <= 0) -+ break; -+ } -+ if (nonblock) { -+ remove_wait_queue(&ctrl->dac_wait, &wait); -+ current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ } -+ remove_wait_queue(&ctrl->dac_wait, &wait); -+ current->state = TASK_RUNNING; -+ } -+ -+ return 0; -+} -+#endif -+ -+#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) -+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ //DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count,i=0; -+ -+ //add_wait_queue(&ctrl->adc_wait, &wait); -+ for (;;) { -+ if (i < MAXDELAY) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ //set_current_state(TASK_INTERRUPTIBLE); -+ spin_lock_irqsave(&ctrl->lock, flags); -+ //spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ //spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ -+ /*if (signal_pending(current)) -+ break;*/ -+ if (nonblock) { -+ //remove_wait_queue(&ctrl->adc_wait, &wait); -+ //current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ } -+ //remove_wait_queue(&ctrl->adc_wait, &wait); -+ //current->state = TASK_RUNNING; -+ /*if (signal_pending(current)) -+ return -ERESTARTSYS;*/ -+ return 0; -+} -+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ unsigned long flags; -+ int count,ele,busyele,emptyele,i=0; -+ -+ for (;;) { -+ if(!nonblock) {//blocked -+ if (i < MAXDELAY) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ -+ ele = elements_in_queue(&out_full_queue); -+ if(ele <= 0) { -+ udelay(200); -+ -+ busyele = elements_in_queue(&out_busy_queue); -+ emptyele = elements_in_queue(&out_empty_queue); -+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ } -+ } -+ } else {//non-blocked -+ //mdelay(100); -+ ele = elements_in_queue(&out_full_queue); -+ -+ if(ele <= 0) { -+ //mdelay(100); -+ busyele = elements_in_queue(&out_busy_queue); -+ emptyele = elements_in_queue(&out_empty_queue); -+ -+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ } -+ } -+ } -+ } -+ -+ return 0; -+} -+#endif -+ -+#if defined(CONFIG_SOC_JZ4740) -+#define MAXDELAY 50000 -+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ int count,ele,i=0; -+ -+ for (;;) { -+ if(!nonblock) {//blocked -+ if ( i < MAXDELAY ) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ -+ ele = elements_in_queue(&out_full_queue); -+ if(ele <= 0) { -+ udelay(10); -+ spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ } -+ } else {//non-blocked -+ mdelay(100); -+ ele = elements_in_queue(&out_full_queue); -+ -+ if(ele <= 0) { -+ mdelay(100); -+ -+ spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ int count,i=0; -+ -+ for (;;) { -+ if ( i < MAXDELAY ) -+ { -+ udelay(10); -+ i++; -+ } -+ else -+ break; -+ spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ -+ if (nonblock) { -+ return -EBUSY; -+ } -+ } -+ -+ return 0; -+} -+#endif -+ -+static int jz_audio_release(struct inode *inode, struct file *file) -+{ -+ unsigned long flags; -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ unsigned long tfl; -+ -+ if (controller == NULL) -+ return -ENODEV; -+ -+ pop_dma_flag = 0; -+ if (controller->opened1 == 1) { -+ controller->opened1 = 0; -+ __i2s_enable_transmit_dma(); -+ __i2s_enable_replay(); -+ drain_dac(controller, file->f_flags & O_NONBLOCK); -+ /* add some mute to anti-pop */ -+#if defined(CONFIG_I2S_DLV) -+ /* wait for fifo empty */ -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ gain_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //gain_down_end = jiffies; -+ while (1) { -+ tfl = REG_AIC_SR & 0x00003f00; -+ if (tfl == 0) { -+ udelay(500); -+ break; -+ } -+ mdelay(2); -+ } -+#endif -+ disable_dma(controller->dma1); -+ set_dma_count(controller->dma1, 0); -+ __i2s_disable_transmit_dma(); -+ __i2s_disable_replay(); -+ __aic_flush_fifo(); -+ if(clear_codec_replay) -+ clear_codec_replay(); -+ __aic_flush_fifo(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ ramp_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //ramp_down_end = jiffies; -+ unset_audio_data_replay(); -+#endif -+ __i2s_disable(); -+ if(turn_off_codec) -+ turn_off_codec(); -+ } -+ -+ if (controller->opened2 == 1) { -+ controller->opened2 = 0; -+ first_record_call = 1; -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ drain_adc(controller, file->f_flags & O_NONBLOCK); -+ disable_dma(controller->dma2); -+ set_dma_count(controller->dma2, 0); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+ -+ if(clear_codec_record) -+ clear_codec_record(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ __i2s_disable(); -+ if(turn_off_codec) -+ turn_off_codec(); -+ abnormal_data_count = 0; -+ } -+ -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+#endif -+ return 0; -+} -+ -+static int jz_audio_open(struct inode *inode, struct file *file) -+{ -+ int i; -+ struct jz_i2s_controller_info *controller = i2s_controller; -+ -+ if (controller == NULL) -+ return -ENODEV; -+ -+ mdelay(2); -+ REG_DMAC_DMACKE(0) = 0x3f; -+ pop_dma_flag = 0; -+ if (controller->opened1 == 1 || controller->opened2 == 1 ) { -+ printk("\naudio is busy!\n"); -+ return -EBUSY; -+ } -+ jz_codec_config = 0; -+ -+ ramp_up_start = 0; -+ ramp_up_end = 0; -+ gain_up_start = 0; -+ gain_up_end = 0; -+ ramp_down_start = 0; -+ ramp_down_end = 0; -+ gain_down_start = 0; -+ gain_down_end = 0; -+ if (file->f_mode & FMODE_WRITE) { -+ if (controller->opened1 == 1) -+ return -EBUSY; -+ -+ controller->opened1 = 1; -+ /* for ioctl */ -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ -+ for(i=0;i < 64;i++) { -+ save_last_samples[i].left = 0; -+ save_last_samples[i].right = 0; -+ } -+ -+ out_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(out_empty_queue.id + i) = i; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ last_dma_buffer_id = 0; -+ } -+ -+ if (file->f_mode & FMODE_READ) { -+ if (controller->opened2 == 1) -+ return -EBUSY; -+ -+ controller->opened2 = 1; -+ first_record_call = 1; -+ /* for ioctl */ -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ -+ in_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(in_empty_queue.id + i) = i; -+ -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ } -+ -+ file->private_data = controller; -+ jz_audio_reset(); -+ REG_AIC_FR |= (1 << 6); -+ -+ if (file->f_mode & FMODE_WRITE) { -+ if(set_codec_replay) -+ set_codec_replay(); -+ } -+ -+ if (file->f_mode & FMODE_READ) { -+ abnormal_data_count = 0; -+ if(set_codec_record) -+ set_codec_record(); -+ } -+ -+#if defined(CONFIG_I2S_DLV) -+ __aic_reset(); -+ -+ mdelay(10); -+ REG_AIC_I2SCR = 0x10; -+ mdelay(20); -+ __aic_flush_fifo(); -+#endif -+ -+ __i2s_enable(); -+ -+#if defined(CONFIG_I2S_DLV) -+ if (file->f_mode & FMODE_WRITE) { -+ -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ ramp_up_start = jiffies; -+ /*while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_RCR = 0x1; -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_RGR = 1;*/ -+ sleep_on(&pop_wait_queue); -+ //ramp_up_end = jiffies; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ } else if (file->f_mode & FMODE_READ) { -+ if (jz_mic_only) -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ else -+ write_codec_file_bit(5, 0, 7);//SB_DAC->0 -+ mdelay(500); -+ } -+ -+#endif -+ -+ return 0; -+} -+ -+ -+static int jz_audio_ioctl(struct inode *inode, struct file *file, -+unsigned int cmd, unsigned long arg) -+{ -+ int val,fullc,busyc,unfinish,newfragstotal,newfragsize; -+ unsigned int flags; -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ count_info cinfo; -+ audio_buf_info abinfo; -+ int id, i; -+ -+ val = 0; -+ switch (cmd) { -+ case OSS_GETVERSION: -+ return put_user(SOUND_VERSION, (int *)arg); -+ case SNDCTL_DSP_RESET: -+#if 0 -+ jz_audio_reset(); -+ __i2s_disable_replay(); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+ __i2s_disable_transmit_dma(); -+#endif -+ return 0; -+ case SNDCTL_DSP_SYNC: -+ if (file->f_mode & FMODE_WRITE) -+ return drain_dac(controller, file->f_flags & O_NONBLOCK); -+ return 0; -+ case SNDCTL_DSP_SPEED: -+ /* set smaple rate */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ if (val >= 0) -+ jz_audio_set_speed(controller->dev_audio, val); -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_STEREO: -+ /* set stereo or mono channel */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); -+ -+ return 0; -+ case SNDCTL_DSP_GETBLKSIZE: -+ //return put_user(jz_audio_fragsize / jz_audio_b, (int *)arg); -+ return put_user(jz_audio_fragsize, (int *)arg); -+ case SNDCTL_DSP_GETFMTS: -+ /* Returns a mask of supported sample format*/ -+ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); -+ case SNDCTL_DSP_SETFMT: -+ /* Select sample format */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ if (val != AFMT_QUERY) -+ jz_audio_set_format(controller->dev_audio,val); -+ else { -+ if (file->f_mode & FMODE_READ) -+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; -+ else -+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; -+ } -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_CHANNELS: -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ jz_audio_set_channels(controller->dev_audio, val); -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_POST: -+ /* FIXME: the same as RESET ?? */ -+ return 0; -+ case SNDCTL_DSP_SUBDIVIDE: -+ return 0; -+ case SNDCTL_DSP_SETFRAGMENT: -+ get_user(val, (long *) arg); -+ newfragsize = 1 << (val & 0xFFFF); -+ if (newfragsize < 4 * PAGE_SIZE) -+ newfragsize = 4 * PAGE_SIZE; -+ if (newfragsize > (16 * PAGE_SIZE)) -+ newfragsize = 16 * PAGE_SIZE; -+ -+ newfragstotal = (val >> 16) & 0x7FFF; -+ if (newfragstotal < 2) -+ newfragstotal = 2; -+ if (newfragstotal > 32) -+ newfragstotal = 32; -+ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize)) -+ return 0; -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ mdelay(500); -+ jz_audio_fragstotal = newfragstotal; -+ jz_audio_fragsize = newfragsize; -+ -+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ mdelay(10); -+ -+ return 0; -+ case SNDCTL_DSP_GETCAPS: -+ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg); -+ case SNDCTL_DSP_NONBLOCK: -+ file->f_flags |= O_NONBLOCK; -+ return 0; -+ case SNDCTL_DSP_SETDUPLEX: -+ return -EINVAL; -+ case SNDCTL_DSP_GETOSPACE: -+ { -+ int i, bytes = 0; -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ jz_audio_fragments = elements_in_queue(&out_empty_queue); -+ for (i = 0; i < jz_audio_fragments; i++) -+ bytes += jz_audio_fragsize; -+ -+ if (jz_audio_channels == 2) -+ bytes /= jz_audio_b; -+ else if (jz_audio_channels == 1) -+ bytes /= 4; -+ else -+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 1!\n"); -+ -+ -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ /* unused fragment amount */ -+ abinfo.fragments = jz_audio_fragments; -+ /* amount of fragments */ -+ abinfo.fragstotal = jz_audio_fragstotal; -+ /* fragment size in bytes */ -+ if (jz_audio_channels == 2) -+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; -+ else if (jz_audio_channels == 1) -+ abinfo.fragsize = jz_audio_fragsize / 4; -+ else -+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 2!\n"); -+ -+ /* write size count without blocking in bytes */ -+ abinfo.bytes = bytes; -+ -+ return copy_to_user((void *)arg, &abinfo, -+ sizeof(abinfo)) ? -EFAULT : 0; -+ } -+ case SNDCTL_DSP_GETISPACE: -+ { -+ int i, bytes = 0; -+ if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ jz_audio_fragments = elements_in_queue(&in_empty_queue); -+ for (i = 0; i < jz_audio_fragments; i++) -+ bytes += jz_audio_fragsize; -+ -+ if (jz_audio_channels == 2) -+ bytes /= jz_audio_b; -+ else if (jz_audio_channels == 1) -+ bytes /= 4; -+ else -+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 1!\n"); -+ -+ abinfo.fragments = jz_audio_fragments; -+ abinfo.fragstotal = jz_audio_fragstotal; -+ -+ if (jz_audio_channels == 2) -+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; -+ else if (jz_audio_channels == 1) -+ abinfo.fragsize = jz_audio_fragsize / 4; -+ else -+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 2!\n"); -+ -+ abinfo.bytes = bytes; -+ -+ return copy_to_user((void *)arg, &abinfo, -+ sizeof(abinfo)) ? -EFAULT : 0; -+ } -+ case SNDCTL_DSP_GETTRIGGER: -+ val = 0; -+ if (file->f_mode & FMODE_READ && in_dma_buf) -+ val |= PCM_ENABLE_INPUT; -+ if (file->f_mode & FMODE_WRITE && out_dma_buf) -+ val |= PCM_ENABLE_OUTPUT; -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_SETTRIGGER: -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ return 0; -+ case SNDCTL_DSP_GETIPTR: -+ if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ cinfo.bytes = controller->total_bytes; -+ cinfo.blocks = controller->blocks; -+ cinfo.ptr = controller->nextIn; -+ controller->blocks = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); -+ case SNDCTL_DSP_GETOPTR: -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ cinfo.bytes = controller->total_bytes; -+ cinfo.blocks = controller->blocks; -+ cinfo.ptr = controller->nextOut; -+ controller->blocks = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); -+ case SNDCTL_DSP_GETODELAY: -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ unfinish = 0; -+ fullc = elements_in_queue(&out_full_queue); -+ busyc = elements_in_queue(&out_busy_queue); -+ for(i = 0;i < fullc ;i ++) { -+ id = *(out_full_queue.id + i); -+ unfinish += *(out_dma_buf_data_count + id); -+ } -+ for(i = 0;i < busyc ;i ++) { -+ id = *(out_busy_queue.id + i); -+ unfinish += get_dma_residue(controller->dma1); -+ } -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ if (jz_audio_channels == 2) -+ unfinish /= jz_audio_b; -+ else if (jz_audio_channels == 1) -+ unfinish /= 4; -+ else -+ printk("SNDCTL_DSP_GETODELAY : channels is wrong !\n"); -+ -+ return put_user(unfinish, (int *) arg); -+ case SOUND_PCM_READ_RATE: -+ return put_user(jz_audio_rate, (int *)arg); -+ case SOUND_PCM_READ_CHANNELS: -+ return put_user(jz_audio_channels, (int *)arg); -+ case SOUND_PCM_READ_BITS: -+ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg); -+ case SNDCTL_DSP_MAPINBUF: -+ case SNDCTL_DSP_MAPOUTBUF: -+ case SNDCTL_DSP_SETSYNCRO: -+ case SOUND_PCM_WRITE_FILTER: -+ case SOUND_PCM_READ_FILTER: -+ return -EINVAL; -+ } -+ return -EINVAL; -+} -+ -+ -+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait) -+{ -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ unsigned long flags; -+ unsigned int mask = 0; -+ -+ if (file->f_mode & FMODE_WRITE) { -+ if (elements_in_queue(&out_empty_queue) > 0) -+ return POLLOUT | POLLWRNORM; -+ -+ poll_wait(file, &controller->dac_wait, wait); -+ } -+ -+ if (file->f_mode & FMODE_READ) { -+ if (elements_in_queue(&in_full_queue) > 0) -+ return POLLIN | POLLRDNORM; -+ -+ poll_wait(file, &controller->adc_wait, wait); -+ } -+ -+ spin_lock_irqsave(&controller->lock, flags); -+ if (file->f_mode & FMODE_WRITE) { -+ if (elements_in_queue(&out_empty_queue) > 0) -+ mask |= POLLOUT | POLLWRNORM; -+ } else if (file->f_mode & FMODE_READ) { -+ if (elements_in_queue(&in_full_queue) > 0) -+ mask |= POLLIN | POLLRDNORM; -+ } -+ spin_unlock_irqrestore(&controller->lock, flags); -+ -+ return mask; -+} -+ -+static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) -+{ -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ int id, ret = 0, left_count, copy_count, cnt = 0; -+ unsigned long flags; -+ -+ if (count < 0) -+ return -EINVAL; -+ -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextIn = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ copy_count = jz_audio_fragsize / 4; -+ -+ left_count = count; -+ if (first_record_call) { -+ first_record_call = 0; -+ audio_read_back_first: -+ if ((id = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id); -+ spin_lock(&controller->lock); -+ *(in_dma_buf_data_count + id) = copy_count * 4; -+ -+ spin_unlock(&controller->lock); -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); -+ audio_start_dma(controller->dma2,file->private_data, -+ *(in_dma_pbuf + id), -+ *(in_dma_buf_data_count + id), -+ DMA_MODE_READ); -+ sleep_on(&rx_wait_queue); -+ } else -+ goto audio_read_back_first; -+ } -+ -+ while (left_count > 0) { -+ audio_read_back_second: -+ if (elements_in_queue(&in_full_queue) <= 0) { -+ if (file->f_flags & O_NONBLOCK) -+ return ret ? ret : -EAGAIN; -+ else -+ sleep_on(&rx_wait_queue); -+ } -+ -+ if ((id = get_buffer_id(&in_full_queue)) >= 0) { -+ spin_lock(&controller->lock); -+ cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id); -+ spin_unlock(&controller->lock); -+ put_buffer_id(&in_empty_queue, id); -+ } else -+ goto audio_read_back_second; -+ -+ if (elements_in_queue(&in_busy_queue) == 0) { -+ if ((id=get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id); -+ spin_lock(&controller->lock); -+ *(in_dma_buf_data_count + id) = copy_count * 4; -+ spin_unlock(&controller->lock); -+ -+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); -+ audio_start_dma(controller->dma2,file->private_data, -+ *(in_dma_pbuf + id), -+ *(in_dma_buf_data_count + id), -+ DMA_MODE_READ); -+ } -+ } -+ if (ret + cnt > count) { -+ spin_lock(&controller->lock); -+ cnt = count - ret; -+ spin_unlock(&controller->lock); -+ } -+ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt)) -+ return ret ? ret : -EFAULT; -+ -+ spin_lock(&controller->lock); -+ ret += cnt; -+ spin_unlock(&controller->lock); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextIn += ret; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ spin_lock(&controller->lock); -+ left_count -= cnt; -+ spin_unlock(&controller->lock); -+ } -+ return ret; -+} -+ -+static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) -+{ -+ int id, ret = 0, left_count, copy_count = 0; -+ unsigned int flags; -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ -+ if (count <= 0) -+ return -EINVAL; -+ -+ if(set_replay_hp_or_speaker) -+ set_replay_hp_or_speaker(); -+ -+ __i2s_enable_transmit_dma(); -+ __i2s_enable_replay(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextOut = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ if (jz_audio_channels == 2) -+ copy_count = jz_audio_fragsize / jz_audio_b; -+ else if(jz_audio_channels == 1) -+ copy_count = jz_audio_fragsize / 4; -+ left_count = count; -+ if (copy_from_user(controller->tmp1, buffer, count)) { -+ printk("copy_from_user failed:%d",ret); -+ return ret ? ret : -EFAULT; -+ } -+ -+ while (left_count > 0) { -+ audio_write_back: -+ /*if (file->f_flags & O_NONBLOCK) -+ udelay(2);*/ -+ if (elements_in_queue(&out_empty_queue) == 0) { -+ if (file->f_flags & O_NONBLOCK) -+ return ret; -+ else -+ sleep_on(&tx_wait_queue); -+ } -+ /* the end fragment size in this write */ -+ if (ret + copy_count > count) -+ copy_count = count - ret; -+ if ((id = get_buffer_id(&out_empty_queue)) >= 0) { -+ replay_filler((signed long)controller->tmp1 + ret, copy_count, id); -+ if(*(out_dma_buf_data_count + id) > 0) { -+ put_buffer_id(&out_full_queue, id); -+ dma_cache_wback_inv(*(out_dma_buf + id), -+ *(out_dma_buf_data_count + id)); -+ } else -+ put_buffer_id(&out_empty_queue, id); -+ } else -+ goto audio_write_back; -+ -+ left_count = left_count - copy_count; -+ ret += copy_count; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextOut += ret; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ if (elements_in_queue(&out_busy_queue) == 0) { -+ if ((id=get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_busy_queue, id); -+ -+ if(*(out_dma_buf_data_count + id) > 0) { -+ audio_start_dma(controller->dma1, -+ file->private_data, -+ *(out_dma_pbuf + id), -+ *(out_dma_buf_data_count + id), -+ DMA_MODE_WRITE); -+ last_dma_buffer_id = id; -+ if (jz_codec_config == 0) { -+ write_codec_file_bit(1, 0, 5); -+ gain_up_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //gain_up_end = jiffies; -+ jz_codec_config = 1; -+ //SB_ADC->1 -+ //write_codec_file_bit(5, 1, 4); -+ //while(1); -+ } -+ } -+ } -+ } -+ } -+ -+ return ret; -+} -+ -+#if defined(CONFIG_I2S_ICODEC) -+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample) -+{ -+ int i,step_len; -+ unsigned long *pop_buf = (unsigned long*)pop_turn_onoff_buf; -+ unsigned int sample_oss = (REG_AIC_CR & 0x00380000) >> 19; -+ unsigned long l_sample_count,r_sample_count,sample_count; -+ struct jz_i2s_controller_info *controller = i2s_controller; -+ signed int left_sam=0,right_sam=0,l_val,r_val; -+ -+ switch (sample_oss) { -+ case 0x0: -+ break; -+ case 0x1: -+ left_sam = (signed int)l_sample; -+ right_sam = (signed int)r_sample; -+ break; -+ case 0x2: -+ break; -+ case 0x3: -+ break; -+ case 0x4: -+ break; -+ } -+ -+ if(left_sam == 0 && right_sam == 0) -+ return; -+ -+ switch (sample_oss) { -+ case 0x0: -+ break; -+ case 0x1: -+ step_len = jz_audio_speed / 10 * 3; -+ step_len = step_len / 2; -+ step_len = 0x7fff / step_len + 1; -+ -+ l_sample_count = 0; -+ l_val = left_sam; -+ -+ while(1) { -+ if(l_val > 0) { -+ if(l_val >= step_len) { -+ l_val -= step_len; -+ l_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(l_val < 0) { -+ if(l_val <= -step_len) { -+ l_val += step_len; -+ l_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(l_val == 0) -+ break; -+ } -+ -+ r_sample_count = 0; -+ r_val = right_sam; -+ while(1) { -+ if(r_val > 0) { -+ if(r_val >= step_len) { -+ r_val -= step_len; -+ r_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(r_val < 0) { -+ if(r_val <= -step_len) { -+ r_val += step_len; -+ r_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(r_val == 0) -+ break; -+ } -+ /* fill up */ -+ if(l_sample_count > r_sample_count) -+ sample_count = l_sample_count; -+ else -+ sample_count = r_sample_count; -+ -+ l_val = left_sam; -+ r_val = right_sam; -+ for(i=0;i <= sample_count;i++) { -+ -+ *pop_buf = (unsigned long)l_val; -+ pop_buf ++; -+ -+ if(l_val > step_len) -+ l_val -= step_len; -+ else if(l_val < -step_len) -+ l_val += step_len; -+ else if(l_val >= -step_len && l_val <= step_len) -+ l_val = 0; -+ -+ *pop_buf = (unsigned long)r_val; -+ pop_buf ++; -+ if(r_val > step_len) -+ r_val -= step_len; -+ else if(r_val < -step_len) -+ r_val += step_len; -+ else if(r_val >= -step_len && r_val <= step_len) -+ r_val = 0; -+ } -+ -+ *pop_buf = 0; -+ pop_buf ++; -+ *pop_buf = 0; -+ -+ pop_buf ++; -+ sample_count += 2; -+ dma_cache_wback_inv(pop_turn_onoff_buf, sample_count*8); -+ -+ pop_dma_flag = 1; -+ audio_start_dma(controller->dma1,controller,pop_turn_onoff_pbuf,sample_count*8,DMA_MODE_WRITE); -+ sleep_on(&pop_wait_queue); -+ pop_dma_flag = 0; -+ break; -+ case 0x2: -+ break; -+ case 0x3: -+ break; -+ case 0x4: -+ break; -+ } -+} -+#endif ++/* ++ * linux/drivers/sound/Jz_i2s.c ++ * ++ * JzSOC On-Chip I2S audio driver. ++ * ++ * Copyright (C) 2005 by Junzheng Corp. ++ * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using ++ * dma channel 4&3,noah is tested. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Because the normal application of AUDIO devices are focused on Little_endian, ++ * then we only perform the little endian data format in driver. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "sound_config.h" ++ ++#define DPRINTK(args...) printk(args) ++#define DMA_ID_I2S_TX DMA_ID_AIC_TX ++#define DMA_ID_I2S_RX DMA_ID_AIC_RX ++#define NR_I2S 2 ++#define MAXDELAY 50000 ++#define JZCODEC_RW_BUFFER_SIZE 2 ++#define JZCODEC_RW_BUFFER_TOTAL 6 ++ ++typedef struct hpvol_shift_s ++{ ++ int hpvol; ++ int shift; ++} hpvol_shift_t; ++ ++mixer_info info; ++_old_mixer_info old_info; ++int codec_volue_shift; ++hpvol_shift_t hpvol_shift_table[72]; ++int abnormal_data_count; ++unsigned long i2s_clk; ++ ++void (*set_codec_mode)(void) = NULL; ++void (*clear_codec_mode)(void) = NULL; ++void (*set_codec_gpio_pin)(void) = NULL; ++void (*each_time_init_codec)(void) = NULL; ++int (*set_codec_startup_param)(void) = NULL; ++void (*set_codec_volume_table)(void) = NULL; ++void (*set_codec_record)(void) = NULL; ++void (*set_codec_replay)(void) = NULL; ++void (*set_codec_replay_record)(void); ++void (*turn_on_codec)(void) = NULL; ++void (*turn_off_codec)(void) = NULL; ++void (*set_codec_speed)(int rate) = NULL; ++void (*reset_codec)(void) = NULL; ++void (*codec_mixer_old_info_id_name)(void) = NULL; ++void (*codec_mixer_info_id_name)(void) = NULL; ++void (*set_codec_bass)(int val) = NULL; ++void (*set_codec_volume)(int val) = NULL; ++void (*set_codec_mic)(int val) = NULL; ++void (*i2s_resume_codec)(void) = NULL; ++void (*i2s_suspend_codec)(int wr,int rd) = NULL; ++void (*init_codec_pin)(void) = NULL; ++void (*set_codec_some_func)(void) = NULL; ++void (*clear_codec_record)(void) = NULL; ++void (*clear_codec_replay)(void) = NULL; ++void (*set_replay_hp_or_speaker)(void) = NULL; ++void (*set_codec_direct_mode)(void) = NULL; ++void (*clear_codec_direct_mode)(void) = NULL; ++ ++static int jz_audio_rate; ++static int jz_audio_format; ++static int jz_audio_volume; ++static int jz_audio_channels; ++static int jz_audio_b; /* bits expand multiple */ ++static int jz_audio_fragments; /* unused fragment amount */ ++static int jz_audio_fragstotal; ++static int jz_audio_fragsize; ++static int jz_audio_speed; ++ ++static int codec_bass_gain; ++static int audio_mix_modcnt; ++static int jz_audio_dma_tran_count; /* bytes count of one DMA transfer */ ++static int jz_mic_only = 1; ++static int jz_codec_config = 0; ++static unsigned long ramp_up_start; ++static unsigned long ramp_up_end; ++static unsigned long gain_up_start; ++static unsigned long gain_up_end; ++static unsigned long ramp_down_start; ++static unsigned long ramp_down_end; ++static unsigned long gain_down_start; ++static unsigned long gain_down_end; ++ ++static int codec_mic_gain; ++static int pop_dma_flag; ++static int last_dma_buffer_id; ++static int drain_flag; ++ ++static void (*old_mksound)(unsigned int hz, unsigned int ticks); ++extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); ++static void jz_update_filler(int bits, int channels); ++ ++static int Init_In_Out_queue(int fragstotal,int fragsize); ++static int Free_In_Out_queue(int fragstotal,int fragsize); ++static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref); ++static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref); ++static void (*replay_filler)(signed long src_start, int count, int id); ++static int (*record_filler)(unsigned long dst_start, int count, int id); ++#if defined(CONFIG_I2S_ICODEC) ++static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample); ++#endif ++static void jz_audio_reset(void); ++static struct file_operations jz_i2s_audio_fops; ++ ++static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (drain_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue); ++ ++struct jz_i2s_controller_info ++{ ++ int io_base; ++ int dma1; /* for play */ ++ int dma2; /* for record */ ++ char *name; ++ int dev_audio; ++ struct i2s_codec *i2s_codec[NR_I2S]; ++ int opened1; ++ int opened2; ++ unsigned char *tmp1; /* tmp buffer for sample conversions */ ++ unsigned char *tmp2; ++ spinlock_t lock; ++ spinlock_t ioctllock; ++ ++ wait_queue_head_t dac_wait; ++ wait_queue_head_t adc_wait; ++ int nextIn; /* byte index to next-in to DMA buffer */ ++ int nextOut; /* byte index to next-out from DMA buffer */ ++ int count; /* current byte count in DMA buffer */ ++ int finish; /* current transfered byte count in DMA buffer */ ++ unsigned total_bytes; /* total bytes written or read */ ++ unsigned blocks; ++ unsigned error; /* over/underrun */ ++#ifdef CONFIG_PM ++ struct pm_dev *pm; ++#endif ++}; ++ ++ ++static struct jz_i2s_controller_info *i2s_controller = NULL; ++struct i2s_codec ++{ ++ /* I2S controller connected with */ ++ void *private_data; ++ char *name; ++ int id; ++ int dev_mixer; ++ /* controller specific lower leverl i2s accessing routines */ ++ u16 (*codec_read) (u8 reg); /* the function accessing Codec REGs */ ++ void (*codec_write) (u8 reg, u16 val); ++ /* Wait for codec-ready */ ++ void (*codec_wait) (struct i2s_codec *codec); ++ /* OSS mixer masks */ ++ int modcnt; ++ int supported_mixers; ++ int stereo_mixers; ++ int record_sources; ++ int bit_resolution; ++ /* OSS mixer interface */ ++ int (*read_mixer) (struct i2s_codec *codec, int oss_channel); ++ void (*write_mixer)(struct i2s_codec *codec, int oss_channel, ++ unsigned int left, unsigned int right); ++ int (*recmask_io) (struct i2s_codec *codec, int rw, int mask); ++ int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg); ++ /* saved OSS mixer states */ ++ unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; ++}; ++ ++ ++typedef struct buffer_queue_s ++{ ++ int count; ++ int *id; ++ int lock; ++} buffer_queue_t; ++ ++typedef struct left_right_sample_s ++{ ++ signed long left; ++ signed long right; ++} left_right_sample_t; ++ ++static unsigned long pop_turn_onoff_buf; ++static unsigned long pop_turn_onoff_pbuf; ++ ++static unsigned long *out_dma_buf = NULL; ++static unsigned long *out_dma_pbuf = NULL; ++static unsigned long *out_dma_buf_data_count = NULL; ++static unsigned long *in_dma_buf = NULL; ++static unsigned long *in_dma_pbuf = NULL; ++static unsigned long *in_dma_buf_data_count = NULL; ++ ++static buffer_queue_t out_empty_queue; ++static buffer_queue_t out_full_queue; ++static buffer_queue_t out_busy_queue; ++static buffer_queue_t in_empty_queue; ++static buffer_queue_t in_full_queue; ++static buffer_queue_t in_busy_queue; ++static int first_record_call = 0; ++ ++static left_right_sample_t save_last_samples[64]; ++static int read_codec_file(int addr) ++{ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ mdelay(1); ++ return(__icdc_get_value()); ++} ++ ++#if 0 /* mask warning */ ++static void printk_codec_files(void) ++{ ++ int cnt; ++ ++ printk("\n"); ++ ++ printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR); ++ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR); ++ printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR); ++ printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR); ++ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR); ++ printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR); ++ printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR); ++ printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA); ++ ++ for (cnt = 0; cnt <= 27 ; cnt++) { ++ printk(" ( %d : 0x%x ) ",cnt ,read_codec_file(cnt)); ++ } ++ printk("\n"); ++} ++#endif ++ ++static void write_codec_file(int addr, int val) ++{ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ __icdc_set_cmd(val); /* write */ ++ mdelay(1); ++ __icdc_set_rgwr(); ++ mdelay(1); ++} ++ ++static int write_codec_file_bit(int addr, int bitval, int mask_bit) ++{ ++ int val; ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ mdelay(1); ++ val = __icdc_get_value(); /* read */ ++ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ val &= ~(1 << mask_bit); ++ if (bitval == 1) ++ val |= 1 << mask_bit; ++ ++ __icdc_set_cmd(val); /* write */ ++ mdelay(1); ++ __icdc_set_rgwr(); ++ mdelay(1); ++ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ val = __icdc_get_value(); /* read */ ++ ++ if (((val >> mask_bit) & bitval) == bitval) ++ return 1; ++ else ++ return 0; ++} ++ ++#if 0 /* mask warning */ ++/* set Audio data replay */ ++static void set_audio_data_replay(void) ++{ ++ /* DAC path */ ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ mdelay(10); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ //mdelay(100); ++ //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //mdelay(300); ++} ++#endif ++ ++/* unset Audio data replay */ ++static void unset_audio_data_replay(void) ++{ ++ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ //mdelay(800); ++ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ //mdelay(800); ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 4);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++#if 0 /* mask warning */ ++/* set Record MIC input audio without playback */ ++static void set_record_mic_input_audio_without_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 1; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ mdelay(10); ++ write_codec_file_bit(1, 1, 2); ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ ++ write_codec_file(22, 0x40);//mic 1 ++ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ //write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file(1, 0x4); ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Record MIC input audio without playback */ ++static void unset_record_mic_input_audio_without_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 0; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Record LINE input audio without playback */ ++static void set_record_line_input_audio_without_playback(void) ++{ ++ /* ADC path for LINE IN */ ++ jz_mic_only = 1; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ write_codec_file(22, 0xf6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ mdelay(10); ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file(1, 0x4); ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Record LINE input audio without playback */ ++static void unset_record_line_input_audio_without_playback(void) ++{ ++ /* ADC path for LINE IN */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1 ++ ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Playback LINE input audio direct only */ ++static void set_playback_line_input_audio_direct_only(void) ++{ ++ jz_audio_reset();//or init_codec() ++ REG_AIC_I2SCR = 0x10; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ write_codec_file(22, 0xf6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ mdelay(10); ++ write_codec_file_bit(1, 1, 2);//CR1.HP_BYPASS->1 ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ //write_codec_file_bit(5, 1, 7);//PMR1.SB_DAC->1 ++ //write_codec_file_bit(5, 1, 4);//PMR1.SB_ADC->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Playback LINE input audio direct only */ ++static void unset_playback_line_input_audio_direct_only(void) ++{ ++ write_codec_file_bit(6, 0, 3);//GIM->0 ++ write_codec_file_bit(1, 0, 2);//PMR1.BYPASS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LINE->1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ mdelay(100); ++ write_codec_file_bit(5, 1, 5);//PMR1.SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Record MIC input audio with direct playback */ ++static void set_record_mic_input_audio_with_direct_playback(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ jz_mic_only = 0; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ ++ write_codec_file(22, 0x60);//mic 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ //write_codec_file(1, 0x4); ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Record MIC input audio with direct playback */ ++static void unset_record_mic_input_audio_with_direct_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 0; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Record playing audio mixed with MIC input audio */ ++static void set_record_playing_audio_mixed_with_mic_input_audio(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ mdelay(10); ++ ++ write_codec_file(22, 0x63);//mic 1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ write_codec_file_bit(5, 0, 4);//PMR1.SB_MIX->0 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Record playing audio mixed with MIC input audio */ ++static void unset_record_playing_audio_mixed_with_mic_input_audio(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Record MIC input audio with Audio data replay (full duplex) */ ++static void set_record_mic_input_audio_with_audio_data_replay(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Record MIC input audio with Audio data replay (full duplex) */ ++static void unset_record_mic_input_audio_with_audio_data_replay(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Record LINE input audio with Audio data replay (full duplex for linein) */ ++static void set_record_line_input_audio_with_audio_data_replay(void) ++{ ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ ++ ++ //jz_mic_only = 1; ++ write_codec_file(22, 0xc6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Record LINE input audio with Audio data replay (full duplex for linein) */ ++static void unset_record_line_input_audio_with_audio_data_replay(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++static inline int get_buffer_id(struct buffer_queue_s *q) ++{ ++ int r; ++ unsigned long flags; ++ int i; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ if (q->count == 0) { ++ spin_unlock_irqrestore(&q->lock, flags); ++ return -1; ++ } ++ r = *(q->id + 0); ++ for (i=0;i < q->count-1;i++) ++ *(q->id + i) = *(q->id + (i+1)); ++ q->count --; ++ spin_unlock_irqrestore(&q->lock, flags); ++ ++ return r; ++} ++ ++static inline void put_buffer_id(struct buffer_queue_s *q, int id) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ *(q->id + q->count) = id; ++ q->count ++; ++ spin_unlock_irqrestore(&q->lock, flags); ++} ++ ++static inline int elements_in_queue(struct buffer_queue_s *q) ++{ ++ int r; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ r = q->count; ++ spin_unlock_irqrestore(&q->lock, flags); ++ ++ return r; ++} ++ ++static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode) ++{ ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ jz_audio_dma_tran_count = count / jz_audio_b; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ flags = claim_dma_lock(); ++ disable_dma(chan); ++ clear_dma_ff(chan); ++ //set_dma_mode(chan, mode); ++ jz_set_oss_dma(chan, mode, jz_audio_format); ++ set_dma_addr(chan, phyaddr); ++ if (count == 0) { ++ count++; ++ printk("JzSOC DMA controller can't set dma 0 count!\n"); ++ } ++ set_dma_count(chan, count); ++ enable_dma(chan); ++ release_dma_lock(flags); ++} ++ ++static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id) ++{ ++ int id1, id2; ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ int dma = controller->dma2; ++ ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ ++ if(drain_flag == 1) ++ wake_up(&drain_wait_queue); ++ /* for DSP_GETIPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ id1 = get_buffer_id(&in_busy_queue); ++ put_buffer_id(&in_full_queue, id1); ++ ++ wake_up(&rx_wait_queue); ++ wake_up(&controller->adc_wait); ++ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id2); ++ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1); ++ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2)); ++ audio_start_dma(dma,dev_id, ++ *(in_dma_pbuf + id2), ++ *(in_dma_buf_data_count + id2), ++ DMA_MODE_READ); ++ } else ++ in_busy_queue.count = 0; ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id) ++{ ++ int id; ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ int dma = controller->dma1; ++ ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ ++ if(pop_dma_flag == 1) { ++ pop_dma_flag = 0; ++ wake_up(&pop_wait_queue); ++ } else { ++ if(drain_flag == 1) { ++ /* Is replay dma buffer over ? */ ++ if(elements_in_queue(&out_full_queue) <= 0) { ++ drain_flag = 0; ++ wake_up(&drain_wait_queue); ++ } ++ } ++ ++ /* for DSP_GETOPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ if ((id = get_buffer_id(&out_busy_queue)) < 0) ++ printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n"); ++ put_buffer_id(&out_empty_queue, id); ++ if ((id = get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_busy_queue, id); ++ if(*(out_dma_buf_data_count + id) > 0) { ++ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id), ++ *(out_dma_buf_data_count + id), ++ DMA_MODE_WRITE); ++ last_dma_buffer_id = id; ++ } ++ } else ++ out_busy_queue.count = 0; ++ ++ if (elements_in_queue(&out_empty_queue) > 0) { ++ wake_up(&tx_wait_queue); ++ wake_up(&controller->dac_wait); ++ } ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static void jz_i2s_initHw(int set) ++{ ++#if defined(CONFIG_MIPS_JZ_URANUS) ++ i2s_clk = 48000000; ++#else ++ i2s_clk = __cpm_get_i2sclk(); ++#endif ++ __i2s_disable(); ++ if(set) ++ __i2s_reset(); ++ schedule_timeout(5); ++ if(each_time_init_codec) ++ each_time_init_codec(); ++ __i2s_disable_record(); ++ __i2s_disable_replay(); ++ __i2s_disable_loopback(); ++ __i2s_set_transmit_trigger(4); ++ __i2s_set_receive_trigger(3); ++} ++ ++static int Init_In_Out_queue(int fragstotal,int fragsize) ++{ ++ int i; ++ ++ /* recording */ ++ in_empty_queue.count = fragstotal; ++ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_buf) ++ goto all_mem_err; ++ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_pbuf) ++ goto all_mem_err; ++ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_buf_data_count) ++ goto all_mem_err; ++ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_empty_queue.id) ++ goto all_mem_err; ++ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_full_queue.id) ++ goto all_mem_err; ++ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_busy_queue.id) ++ goto all_mem_err; ++ ++ for (i=0;i < fragstotal;i++) ++ *(in_empty_queue.id + i) = i; ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ ++ for (i = 0; i < fragstotal; i++) { ++ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); ++ if (*(in_dma_buf + i) == 0) ++ goto mem_failed_in; ++ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i))); ++ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); ++ } ++ ++ /* playing */ ++ out_empty_queue.count = fragstotal; ++ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!out_dma_buf) ++ goto all_mem_err; ++ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!out_dma_pbuf) ++ goto all_mem_err; ++ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ ++ if (!out_dma_buf_data_count) ++ goto all_mem_err; ++ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_empty_queue.id) ++ goto all_mem_err; ++ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_full_queue.id) ++ goto all_mem_err; ++ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_busy_queue.id) ++ goto all_mem_err; ++ for (i=0;i < fragstotal;i++) ++ *(out_empty_queue.id + i) = i; ++ ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ /* alloc DMA buffer */ ++ for (i = 0; i < fragstotal; i++) { ++ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); ++ if (*(out_dma_buf + i) == 0) { ++ printk(" can't allocate required DMA(OUT) buffers.\n"); ++ goto mem_failed_out; ++ } ++ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); ++ } ++ ++ return 1; ++all_mem_err: ++ printk("error:allocate memory occur error 1!\n"); ++ return 0; ++mem_failed_out: ++ printk("error:allocate memory occur error 2!\n"); ++ for (i = 0; i < fragstotal; i++) { ++ if(*(out_dma_buf + i)) ++ free_pages(*(out_dma_buf + i), get_order(fragsize)); ++ } ++ ++ return 0; ++mem_failed_in: ++ printk("error:allocate memory occur error 3!\n"); ++ for (i = 0; i < fragstotal; i++) { ++ if(*(in_dma_buf + i)) ++ free_pages(*(in_dma_buf + i), get_order(fragsize)); ++ } ++ return 0; ++} ++ ++static int Free_In_Out_queue(int fragstotal,int fragsize) ++{ ++ int i; ++ /* playing */ ++ if(out_dma_buf != NULL) { ++ for (i = 0; i < fragstotal; i++) { ++ if(*(out_dma_buf + i)) ++ free_pages(*(out_dma_buf + i), get_order(fragsize)); ++ *(out_dma_buf + i) = 0; ++ } ++ kfree(out_dma_buf); ++ out_dma_buf = NULL; ++ } ++ if(out_dma_pbuf) { ++ kfree(out_dma_pbuf); ++ out_dma_pbuf = NULL; ++ } ++ if(out_dma_buf_data_count) { ++ kfree(out_dma_buf_data_count); ++ out_dma_buf_data_count = NULL; ++ } ++ if(out_empty_queue.id) { ++ kfree(out_empty_queue.id); ++ out_empty_queue.id = NULL; ++ } ++ if(out_full_queue.id) { ++ kfree(out_full_queue.id); ++ out_full_queue.id = NULL; ++ } ++ if(out_busy_queue.id) { ++ kfree(out_busy_queue.id); ++ out_busy_queue.id = NULL; ++ } ++ out_empty_queue.count = fragstotal; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ ++ /* recording */ ++ if(in_dma_buf) { ++ for (i = 0; i < fragstotal; i++) { ++ if(*(in_dma_buf + i)) { ++ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); ++ free_pages(*(in_dma_buf + i), get_order(fragsize)); ++ } ++ *(in_dma_buf + i) = 0; ++ } ++ kfree(in_dma_buf); ++ in_dma_buf = NULL; ++ } ++ if(in_dma_pbuf) { ++ kfree(in_dma_pbuf); ++ in_dma_pbuf = NULL; ++ } ++ if(in_dma_buf_data_count) { ++ kfree(in_dma_buf_data_count); ++ in_dma_buf_data_count = NULL; ++ } ++ if(in_empty_queue.id) { ++ kfree(in_empty_queue.id); ++ in_empty_queue.id = NULL; ++ } ++ if(in_full_queue.id) { ++ kfree(in_full_queue.id); ++ in_full_queue.id = NULL; ++ } ++ if(in_busy_queue.id) { ++ kfree(in_busy_queue.id); ++ in_busy_queue.id = NULL; ++ } ++ ++ in_empty_queue.count = fragstotal; ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ ++ return 1; ++} ++ ++static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller) ++{ ++ jz_i2s_initHw(0); ++} ++ ++static int jz_audio_set_speed(int dev, int rate) ++{ ++ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */ ++ jz_audio_speed = rate; ++ if (rate > 48000) ++ rate = 48000; ++ if (rate < 8000) ++ rate = 8000; ++ jz_audio_rate = rate; ++ ++ if(set_codec_speed) ++ set_codec_speed(rate); ++ ++ return jz_audio_rate; ++} ++ ++ ++static int record_fill_1x8_u(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long data; ++ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ volatile unsigned char *dp = (unsigned char*)dst_start; ++ ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt++; ++ data = *(s++); ++ *(dp ++) = ((data << 16) >> 24) + 0x80; ++ s++; /* skip the other channel */ ++ } ++ ++ return cnt; ++} ++ ++ ++static int record_fill_2x8_u(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1, d2; ++ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ volatile unsigned char *dp = (unsigned char*)dst_start; ++ ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ *(dp ++) = ((d1 << 16) >> 24) + 0x80; ++ d2 = *(s++); ++ *(dp ++) = ((d2 << 16) >> 24) + 0x80; ++ } ++ ++ return cnt; ++} ++ ++ ++static int record_fill_1x16_s(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1; ++ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ unsigned short *dp = (unsigned short *)dst_start; ++ ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt += 2; /* count in byte */ ++ d1 = *(s++); ++ *(dp ++) = (d1 << 16) >> 16; ++ s++; /* skip the other channel */ ++ } ++ ++ return cnt; ++} ++ ++ ++static int record_fill_2x16_s(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1, d2; ++ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ unsigned short *dp = (unsigned short *)dst_start; ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt += 4; /* count in byte */ ++ d1 = *(s++); ++ d2 = *(s++); ++ if(abnormal_data_count > 0) { ++ d1 = d2 = 0; ++ abnormal_data_count --; ++ } ++ *(dp ++) = (d1 << 16) >> 16; ++ *(dp ++) = (d2 << 16) >> 16; ++ } ++ ++ return cnt; ++} ++ ++static void replay_fill_1x8_u(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned char data; ++ unsigned long ddata; ++ volatile unsigned char *s = (unsigned char *)src_start; ++ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count--; ++ cnt += 1; ++ data = *(s++) - 0x80; ++ ddata = (unsigned long) data << 8; ++ *(dp ++) = ddata; ++ *(dp ++) = ddata; ++ ++ /* save last left and right */ ++ if(count == 1) { ++ save_last_samples[id].left = ddata; ++ save_last_samples[id].right = ddata; ++ } ++ } ++ cnt = cnt * 2 * jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++ ++static void replay_fill_2x8_u(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned char d1; ++ unsigned long dd1; ++ volatile unsigned char *s = (unsigned char *)src_start; ++ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count -= 1; ++ cnt += 1 ; ++ d1 = *(s++) - 0x80; ++ dd1 = (unsigned long) d1 << 8; ++ *(dp ++) = dd1; ++ /* save last left */ ++ if(count == 2) ++ save_last_samples[id].left = dd1; ++ /* save last right */ ++ if(count == 1) ++ save_last_samples[id].right = dd1; ++ } ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++ ++static void replay_fill_1x16_s(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed short d1; ++ signed long l1; ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count -= 2; ++ cnt += 2 ; ++ d1 = *(s++); ++ l1 = (signed long)d1; ++ *(dp ++) = l1; ++ *(dp ++) = l1; ++ ++ /* save last left and right */ ++ if(count == 1) { ++ save_last_samples[id].left = l1; ++ save_last_samples[id].right = l1; ++ } ++ } ++ cnt = cnt * 2 * jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++#if 0 ++static void replay_fill_2x16_s(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed short d1; ++ signed long l1; ++ int mute_cnt = 0; ++ signed long tmp1,tmp2; ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++#if defined(CONFIG_I2S_ICDC) ++ volatile signed long *before_dp; ++ int sam_rate = jz_audio_rate / 20; ++ ++ tmp1 = tmp2 = 0; ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ ++ l1 = (signed long)d1; ++ l1 >>= codec_volue_shift; ++ ++ if(l1 == 0) { ++ mute_cnt ++; ++ if(mute_cnt >= sam_rate) { ++ before_dp = dp - 10; ++ *(before_dp) = (signed long)1; ++ before_dp = dp - 11; ++ *(before_dp) = (signed long)1; ++ mute_cnt = 0; ++ } ++ } else ++ mute_cnt = 0; ++ ++ *(dp ++) = l1; ++ ++ tmp1 = tmp2; ++ tmp2 = l1; ++ } ++ ++ /* save last left */ ++ save_last_samples[id].left = tmp1; ++ /* save last right */ ++ save_last_samples[id].right = tmp2; ++#endif ++#if defined(CONFIG_I2S_DLV) ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ ++ l1 = (signed long)d1; ++ ++ *(dp ++) = l1; ++ } ++#endif ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++#else ++static void replay_fill_2x16_s(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed short d1; ++ signed long l1; ++ ++#if 0 ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed short *dp = (signed short*)(*(out_dma_buf + id)); ++ memcpy((char*)dp, (char*)s, count); ++ *(out_dma_buf_data_count + id) = count; ++#else ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ ++ l1 = (signed long)d1; ++ ++ *(dp ++) = l1; ++ } ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++#endif ++} ++#endif ++ ++ ++static unsigned int jz_audio_set_format(int dev, unsigned int fmt) ++{ ++ switch (fmt) { ++ case AFMT_U8: ++ __i2s_set_oss_sample_size(8); ++ __i2s_set_iss_sample_size(8); ++ jz_audio_format = fmt; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++ break; ++ case AFMT_S16_LE: ++#if defined(CONFIG_I2S_DLV) ++ /* DAC path and ADC path */ ++ write_codec_file(2, 0x00); ++ //write_codec_file(2, 0x60); ++#endif ++ jz_audio_format = fmt; ++ jz_update_filler(jz_audio_format,jz_audio_channels); ++ /* print all files */ ++ __i2s_set_oss_sample_size(16); ++ __i2s_set_iss_sample_size(16); ++ break; ++ ++ case AFMT_QUERY: ++ break; ++ } ++ ++ return jz_audio_format; ++} ++ ++ ++static short jz_audio_set_channels(int dev, short channels) ++{ ++ switch (channels) { ++ case 1: ++ if(set_codec_some_func) ++ set_codec_some_func(); ++ jz_audio_channels = channels; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono ++#endif ++ break; ++ case 2: ++ jz_audio_channels = channels; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo ++#endif ++ break; ++ case 0: ++ break; ++ } ++ ++ return jz_audio_channels; ++} ++ ++static void init_codec(void) ++{ ++ /* inititalize internal I2S codec */ ++ if(init_codec_pin) ++ init_codec_pin(); ++ ++#if defined(CONFIG_I2S_ICDC) ++ /* initialize AIC but not reset it */ ++ jz_i2s_initHw(0); ++#endif ++ if(reset_codec) ++ reset_codec(); ++} ++ ++static void jz_audio_reset(void) ++{ ++ __i2s_disable_replay(); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++ __i2s_disable_transmit_dma(); ++#if defined(CONFIG_I2S_DLV) ++ REG_AIC_I2SCR = 0x10; ++#endif ++ init_codec(); ++} ++ ++static int jz_audio_release(struct inode *inode, struct file *file); ++static int jz_audio_open(struct inode *inode, struct file *file); ++static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg); ++static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait); ++static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos); ++static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos); ++ ++/* static struct file_operations jz_i2s_audio_fops */ ++static struct file_operations jz_i2s_audio_fops = ++{ ++ owner: THIS_MODULE, ++ open: jz_audio_open, ++ release: jz_audio_release, ++ write: jz_audio_write, ++ read: jz_audio_read, ++ poll: jz_audio_poll, ++ ioctl: jz_audio_ioctl ++}; ++ ++static int jz_i2s_open_mixdev(struct inode *inode, struct file *file) ++{ ++ int i; ++ int minor = MINOR(inode->i_rdev); ++ struct jz_i2s_controller_info *controller = i2s_controller; ++ ++ for (i = 0; i < NR_I2S; i++) ++ if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor) ++ goto match; ++ ++ if (!controller) ++ return -ENODEV; ++match: ++ file->private_data = controller->i2s_codec[i]; ++ ++ return 0; ++} ++ ++static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ struct i2s_codec *codec = (struct i2s_codec *)file->private_data; ++ return codec->mixer_ioctl(codec, cmd, arg); ++} ++ ++static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin) ++{ ++ return -ESPIPE; ++} ++ ++static struct file_operations jz_i2s_mixer_fops = ++{ ++ owner: THIS_MODULE, ++ llseek: jz_i2s_llseek, ++ ioctl: jz_i2s_ioctl_mixdev, ++ open: jz_i2s_open_mixdev, ++}; ++ ++static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg) ++{ ++ int ret; ++ long val = 0; ++ switch (cmd) { ++ case SOUND_MIXER_INFO: ++ ++ if(codec_mixer_info_id_name) ++ codec_mixer_info_id_name(); ++ info.modify_counter = audio_mix_modcnt; ++ ++ return copy_to_user((void *)arg, &info, sizeof(info)); ++ case SOUND_OLD_MIXER_INFO: ++ ++ if(codec_mixer_old_info_id_name) ++ codec_mixer_old_info_id_name(); ++ ++ return copy_to_user((void *)arg, &old_info, sizeof(info)); ++ case SOUND_MIXER_READ_STEREODEVS: ++ ++ return put_user(0, (long *) arg); ++ case SOUND_MIXER_READ_CAPS: ++ ++ val = SOUND_CAP_EXCL_INPUT; ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_READ_DEVMASK: ++ break; ++ case SOUND_MIXER_READ_RECMASK: ++ break; ++ case SOUND_MIXER_READ_RECSRC: ++ break; ++ case SOUND_MIXER_WRITE_SPEAKER: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ switch(val) { ++ case 100: ++ if(set_codec_direct_mode) ++ set_codec_direct_mode(); ++ break; ++ case 0: ++ if(clear_codec_direct_mode) ++ clear_codec_direct_mode(); ++ break; ++ } ++ break; ++ case SOUND_MIXER_WRITE_BASS: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ codec_bass_gain = val; ++ if(set_codec_bass) ++ set_codec_bass(val); ++ ++ return 0; ++ case SOUND_MIXER_READ_BASS: ++ ++ val = codec_bass_gain; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_WRITE_VOLUME: ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ if (val > 31) ++ val = 31; ++ jz_audio_volume = val; ++ ++ if(set_codec_volume) ++ set_codec_volume(val); ++ return 0; ++ case SOUND_MIXER_READ_VOLUME: ++ ++ val = jz_audio_volume; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_WRITE_MIC: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ codec_mic_gain = val; ++ if(set_codec_mic) ++ set_codec_mic(val); ++ ++ return 0; ++ case SOUND_MIXER_READ_MIC: ++ ++ val = codec_mic_gain; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ default: ++ return -ENOSYS; ++ } ++ audio_mix_modcnt ++; ++ return 0; ++} ++ ++ ++int i2s_probe_codec(struct i2s_codec *codec) ++{ ++ /* generic OSS to I2S wrapper */ ++ codec->mixer_ioctl = i2s_mixer_ioctl; ++ return 1; ++} ++ ++ ++/* I2S codec initialisation. */ ++static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller) ++{ ++ int num_i2s = 0; ++ struct i2s_codec *codec; ++ ++ for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) { ++ if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL) ++ return -ENOMEM; ++ memset(codec, 0, sizeof(struct i2s_codec)); ++ codec->private_data = controller; ++ codec->id = num_i2s; ++ ++ if (i2s_probe_codec(codec) == 0) ++ break; ++ if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) { ++ printk(KERN_ERR "Jz I2S: couldn't register mixer!\n"); ++ kfree(codec); ++ break; ++ } ++ controller->i2s_codec[num_i2s] = codec; ++ } ++ return num_i2s; ++} ++ ++ ++static void jz_update_filler(int format, int channels) ++{ ++#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) ++ ++ switch (TYPE(format, channels)) ++ { ++ ++ case TYPE(AFMT_U8, 1): ++ jz_audio_b = 4; /* 4bytes * 8bits =32bits */ ++ replay_filler = replay_fill_1x8_u; ++ record_filler = record_fill_1x8_u; ++ break; ++ case TYPE(AFMT_U8, 2): ++ jz_audio_b = 4; ++ replay_filler = replay_fill_2x8_u; ++ record_filler = record_fill_2x8_u; ++ break; ++ case TYPE(AFMT_S16_LE, 1): ++ jz_audio_b = 2; /* 2bytes * 16bits =32bits */ ++ replay_filler = replay_fill_1x16_s; ++ record_filler = record_fill_1x16_s; ++ break; ++ case TYPE(AFMT_S16_LE, 2): ++ jz_audio_b = 2; ++ replay_filler = replay_fill_2x16_s; ++ record_filler = record_fill_2x16_s; ++ break; ++ default: ++ ; ++ } ++} ++ ++ ++#ifdef CONFIG_PROC_FS ++extern struct proc_dir_entry *proc_jz_root; ++int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ return 0; ++} ++ ++static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller) ++{ ++ if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0])) ++ return -EIO; ++ return 0; ++} ++ ++static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller) ++{ ++} ++#endif ++ ++static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller) ++{ ++ char *name; ++ int adev; /* No of Audio device. */ ++ ++ name = controller->name; ++ /* initialize AIC controller and reset it */ ++ jz_i2s_initHw(1); ++ adev = register_sound_dsp(&jz_i2s_audio_fops, -1); ++ if (adev < 0) ++ goto audio_failed; ++ /* initialize I2S codec and register /dev/mixer */ ++ if (jz_i2s_codec_init(controller) <= 0) ++ goto mixer_failed; ++ ++#ifdef CONFIG_PROC_FS ++ if (jz_i2s_init_proc(controller) < 0) { ++ printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name); ++ goto proc_failed; ++ } ++#endif ++ ++ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8); ++ if (!controller->tmp1) { ++ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); ++ goto tmp1_failed; ++ } ++ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8); ++ if (!controller->tmp2) { ++ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); ++ goto tmp2_failed; ++ } ++ if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) { ++ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name); ++ goto dma2_failed; ++ } ++ if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) { ++ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name); ++ goto dma1_failed; ++ } ++ printk("JzSOC On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2)); ++ ++ controller->dev_audio = adev; ++ pop_turn_onoff_buf = __get_free_pages(GFP_KERNEL | GFP_DMA, 8); ++ if(!pop_turn_onoff_buf) ++ printk("pop_turn_onoff_buf alloc is wrong!\n"); ++ pop_turn_onoff_pbuf = virt_to_phys((void *)pop_turn_onoff_buf); ++ ++ return; ++dma2_failed: ++ jz_free_dma(controller->dma1); ++dma1_failed: ++ free_pages((unsigned long)controller->tmp2, 8); ++tmp2_failed: ++ free_pages((unsigned long)controller->tmp1, 8); ++tmp1_failed: ++ ++#ifdef CONFIG_PROC_FS ++ jz_i2s_cleanup_proc(controller); ++#endif ++proc_failed: ++ /* unregister mixer dev */ ++mixer_failed: ++ unregister_sound_dsp(adev); ++audio_failed: ++ return; ++} ++ ++static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller) ++{ ++ if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info), ++ GFP_KERNEL)) == NULL) { ++ printk(KERN_ERR "Jz I2S Controller: out of memory.\n"); ++ return -ENOMEM; ++ } ++ (*controller)->name = "Jz I2S controller"; ++ (*controller)->opened1 = 0; ++ (*controller)->opened2 = 0; ++ init_waitqueue_head(&(*controller)->adc_wait); ++ init_waitqueue_head(&(*controller)->dac_wait); ++ spin_lock_init(&(*controller)->lock); ++ init_waitqueue_head(&rx_wait_queue); ++ init_waitqueue_head(&tx_wait_queue); ++ init_waitqueue_head(&pop_wait_queue); ++ init_waitqueue_head(&drain_wait_queue); ++ ++ return 0; ++} ++ ++static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller) ++{ ++ int adev = controller->dev_audio; ++ ++ jz_i2s_full_reset(controller); ++ controller->dev_audio = -1; ++ if (old_mksound) ++ kd_mksound = old_mksound;/* Our driver support bell for kb, see vt.c */ ++ ++#ifdef CONFIG_PROC_FS ++ jz_i2s_cleanup_proc(controller); ++#endif ++ ++ jz_free_dma(controller->dma1); ++ jz_free_dma(controller->dma2); ++ free_pages((unsigned long)controller->tmp1, 8); ++ free_pages((unsigned long)controller->tmp2, 8); ++ free_pages((unsigned long)pop_turn_onoff_buf, 8); ++ ++ if (adev >= 0) { ++ /* unregister_sound_mixer(audio_devs[adev]->mixer_dev); */ ++ unregister_sound_dsp(controller->dev_audio); ++ } ++} ++ ++#ifdef CONFIG_PM ++static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state) ++{ ++ if(i2s_suspend_codec) ++ i2s_suspend_codec(controller->opened1,controller->opened2); ++ printk("Aic and codec are suspended!\n"); ++ return 0; ++} ++ ++static int jz_i2s_resume(struct jz_i2s_controller_info *controller) ++{ ++ if(i2s_resume_codec) ++ i2s_resume_codec(); ++ ++#if defined(CONFIG_I2S_AK4642EN) ++ jz_i2s_initHw(0); ++ jz_audio_reset(); ++ __i2s_enable(); ++ jz_audio_set_speed(controller->dev_audio,jz_audio_speed); ++ /* playing */ ++ if(controller->opened1) { ++ if(set_codec_replay) ++ set_codec_replay(); ++ int dma = controller->dma1; ++ int id; ++ unsigned long flags; ++ disable_dma(dma); ++ if(__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if(__dmac_channel_transmit_end_detected(dma)) ++ __dmac_channel_clear_transmit_end(dma); ++ ++ /* for DSP_GETOPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ while((id = get_buffer_id(&out_busy_queue)) >= 0) ++ put_buffer_id(&out_empty_queue, id); ++ ++ out_busy_queue.count=0; ++ if((id = get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_empty_queue, id); ++ } ++ if (elements_in_queue(&out_empty_queue) > 0) { ++ wake_up(&tx_wait_queue); ++ wake_up(&controller->dac_wait); ++ } else ++ printk("pm out_empty_queue empty"); ++ } ++ ++ /* recording */ ++ if(controller->opened2) { ++ if(set_codec_record) ++ set_codec_record(); ++ int dma = controller->dma2; ++ int id1, id2; ++ unsigned long flags; ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ } ++ /* for DSP_GETIPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ id1 = get_buffer_id(&in_busy_queue); ++ put_buffer_id(&in_full_queue, id1); ++ wake_up(&rx_wait_queue); ++ wake_up(&controller->adc_wait); ++ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_full_queue, id2); ++ } ++ in_busy_queue.count = 0; ++ } ++#endif ++ ++ return 0; ++} ++ ++static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ int ret; ++ struct jz_i2s_controller_info *controller = pm_dev->data; ++ ++ if (!controller) return -EINVAL; ++ ++ switch (req) { ++ case PM_SUSPEND: ++ ret = jz_i2s_suspend(controller, (int)data); ++ break; ++ case PM_RESUME: ++ ret = jz_i2s_resume(controller); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++#endif /* CONFIG_PM */ ++static irqreturn_t aic_codec_irq(int irq, void *dev_id) ++{ ++ u8 file_9 = read_codec_file(9); ++ u8 file_8 = read_codec_file(8); ++ ++ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9); ++ if ((file_9 & 0x1f) == 0x10) { ++ ++ write_codec_file(8, 0x3f); ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ mdelay(300); ++ while ((read_codec_file(9) & 0x4) != 0x4); ++ while ((read_codec_file(9) & 0x10) == 0x10) { ++ write_codec_file(9, 0x10); ++ } ++ write_codec_file_bit(5, 0, 6);//SB_OUT->0 ++ mdelay(300); ++ while ((read_codec_file(9) & 0x8) != 0x8); ++ write_codec_file(9, file_9); ++ write_codec_file(8, file_8); ++ ++ return IRQ_HANDLED; ++ } ++ ++ if (file_9 & 0x8) ++ ramp_up_end = jiffies; ++ else if (file_9 & 0x4) ++ ramp_down_end = jiffies; ++ else if (file_9 & 0x2) ++ gain_up_end = jiffies; ++ else if (file_9 & 0x1) ++ gain_down_end = jiffies; ++ ++ write_codec_file(9, file_9); ++ if (file_9 & 0xf) ++ wake_up(&pop_wait_queue); ++ while (REG_ICDC_RGDATA & 0x100); ++ ++ return IRQ_HANDLED; ++} ++ ++static int __init init_jz_i2s(void) ++{ ++ int errno, retval; ++#if defined(CONFIG_I2S_DLV) ++ ++ ramp_up_start = 0; ++ ramp_up_end = 0; ++ gain_up_start = 0; ++ gain_up_end = 0; ++ ramp_down_start = 0; ++ ramp_down_end = 0; ++ gain_down_start = 0; ++ gain_down_end = 0; ++#endif ++ ++ abnormal_data_count = 0; ++ if(set_codec_mode) ++ set_codec_mode(); ++ ++ drain_flag = 0; ++ if ((errno = probe_jz_i2s(&i2s_controller)) < 0) ++ return errno; ++ if(set_codec_gpio_pin) ++ set_codec_gpio_pin(); ++ ++ attach_jz_i2s(i2s_controller); ++ if(set_codec_startup_param) ++ set_codec_startup_param(); ++#if defined(CONFIG_I2S_DLV) ++ jz_codec_config = 0; ++ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL); ++ if (retval) { ++ printk("Could not get aic codec irq %d\n", IRQ_AIC); ++ return retval; ++ } ++#endif ++ if(set_codec_volume_table) ++ set_codec_volume_table(); ++ ++ out_empty_queue.id = NULL; ++ out_full_queue.id = NULL; ++ out_busy_queue.id = NULL; ++ in_empty_queue.id = NULL; ++ in_full_queue.id = NULL; ++ in_busy_queue.id = NULL; ++ ++ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE; ++ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ; ++ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ ++#ifdef CONFIG_PM ++ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ++ jz_i2s_pm_callback); ++ if (i2s_controller->pm) ++ i2s_controller->pm->data = i2s_controller; ++#endif ++ ++#if defined(CONFIG_I2S_DLV) ++ __cpm_start_idct(); ++ __cpm_start_db(); ++ __cpm_start_me(); ++ __cpm_start_mc(); ++ __cpm_start_ipu(); ++#endif ++ ++ printk("JZ I2S OSS audio driver initialized\n"); ++ ++ return 0; ++} ++ ++static void __exit cleanup_jz_i2s(void) ++{ ++#ifdef CONFIG_PM ++ /* pm_unregister(i2s_controller->pm); */ ++#endif ++#if defined(CONFIG_I2S_DLV) ++ free_irq(IRQ_AIC, NULL); ++#endif ++ unload_jz_i2s(i2s_controller); ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ if(clear_codec_mode) ++ clear_codec_mode(); ++} ++ ++module_init(init_jz_i2s); ++module_exit(cleanup_jz_i2s); ++ ++#if defined(CONFIG_SOC_JZ4730) ++static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count,con; ++ ++ if(elements_in_queue(&in_busy_queue) > 0) { ++ if (nonblock) ++ return -EBUSY; ++ drain_flag = 1; ++ sleep_on(&drain_wait_queue); ++ drain_flag = 0; ++ } else { ++ add_wait_queue(&ctrl->adc_wait, &wait); ++ for (con = 0; con < 1000; con ++) { ++ udelay(1); ++ set_current_state(TASK_INTERRUPTIBLE); ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ if (nonblock) { ++ remove_wait_queue(&ctrl->adc_wait, &wait); ++ current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ } ++ remove_wait_queue(&ctrl->adc_wait, &wait); ++ current->state = TASK_RUNNING; ++ } ++ return 0; ++} ++ ++static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count; ++ ++ if(elements_in_queue(&out_full_queue) > 0) { ++ if (nonblock) ++ return -EBUSY; ++ ++ drain_flag = 1; ++ sleep_on(&drain_wait_queue); ++ drain_flag = 0; ++ } else { ++ add_wait_queue(&(ctrl->dac_wait), &wait); ++ for (;;) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ if(elements_in_queue(&out_full_queue) <= 0) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if(count <= 0) ++ break; ++ } ++ if (nonblock) { ++ remove_wait_queue(&ctrl->dac_wait, &wait); ++ current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ } ++ remove_wait_queue(&ctrl->dac_wait, &wait); ++ current->state = TASK_RUNNING; ++ } ++ ++ return 0; ++} ++#endif ++ ++#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) ++static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ //DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count,i=0; ++ ++ //add_wait_queue(&ctrl->adc_wait, &wait); ++ for (;;) { ++ if (i < MAXDELAY) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ //set_current_state(TASK_INTERRUPTIBLE); ++ spin_lock_irqsave(&ctrl->lock, flags); ++ //spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ //spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ ++ /*if (signal_pending(current)) ++ break;*/ ++ if (nonblock) { ++ //remove_wait_queue(&ctrl->adc_wait, &wait); ++ //current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ } ++ //remove_wait_queue(&ctrl->adc_wait, &wait); ++ //current->state = TASK_RUNNING; ++ /*if (signal_pending(current)) ++ return -ERESTARTSYS;*/ ++ return 0; ++} ++static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ unsigned long flags; ++ int count,ele,busyele,emptyele,i=0; ++ ++ for (;;) { ++ if(!nonblock) {//blocked ++ if (i < MAXDELAY) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ ++ ele = elements_in_queue(&out_full_queue); ++ if(ele <= 0) { ++ udelay(200); ++ ++ busyele = elements_in_queue(&out_busy_queue); ++ emptyele = elements_in_queue(&out_empty_queue); ++ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ } ++ } ++ } else {//non-blocked ++ //mdelay(100); ++ ele = elements_in_queue(&out_full_queue); ++ ++ if(ele <= 0) { ++ //mdelay(100); ++ busyele = elements_in_queue(&out_busy_queue); ++ emptyele = elements_in_queue(&out_empty_queue); ++ ++ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++#if defined(CONFIG_SOC_JZ4740) ++#define MAXDELAY 50000 ++static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ int count,ele,i=0; ++ ++ for (;;) { ++ if(!nonblock) {//blocked ++ if ( i < MAXDELAY ) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ ++ ele = elements_in_queue(&out_full_queue); ++ if(ele <= 0) { ++ udelay(10); ++ spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ } ++ } else {//non-blocked ++ mdelay(100); ++ ele = elements_in_queue(&out_full_queue); ++ ++ if(ele <= 0) { ++ mdelay(100); ++ ++ spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ int count,i=0; ++ ++ for (;;) { ++ if ( i < MAXDELAY ) ++ { ++ udelay(10); ++ i++; ++ } ++ else ++ break; ++ spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ ++ if (nonblock) { ++ return -EBUSY; ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++static int jz_audio_release(struct inode *inode, struct file *file) ++{ ++ unsigned long flags; ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ unsigned long tfl; ++ ++ if (controller == NULL) ++ return -ENODEV; ++ ++ pop_dma_flag = 0; ++ if (controller->opened1 == 1) { ++ controller->opened1 = 0; ++ __i2s_enable_transmit_dma(); ++ __i2s_enable_replay(); ++ drain_dac(controller, file->f_flags & O_NONBLOCK); ++ /* add some mute to anti-pop */ ++#if defined(CONFIG_I2S_DLV) ++ /* wait for fifo empty */ ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ gain_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //gain_down_end = jiffies; ++ while (1) { ++ tfl = REG_AIC_SR & 0x00003f00; ++ if (tfl == 0) { ++ udelay(500); ++ break; ++ } ++ mdelay(2); ++ } ++#endif ++ disable_dma(controller->dma1); ++ set_dma_count(controller->dma1, 0); ++ __i2s_disable_transmit_dma(); ++ __i2s_disable_replay(); ++ __aic_flush_fifo(); ++ if(clear_codec_replay) ++ clear_codec_replay(); ++ __aic_flush_fifo(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ ramp_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //ramp_down_end = jiffies; ++ unset_audio_data_replay(); ++#endif ++ __i2s_disable(); ++ if(turn_off_codec) ++ turn_off_codec(); ++ } ++ ++ if (controller->opened2 == 1) { ++ controller->opened2 = 0; ++ first_record_call = 1; ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ drain_adc(controller, file->f_flags & O_NONBLOCK); ++ disable_dma(controller->dma2); ++ set_dma_count(controller->dma2, 0); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++ ++ if(clear_codec_record) ++ clear_codec_record(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ __i2s_disable(); ++ if(turn_off_codec) ++ turn_off_codec(); ++ abnormal_data_count = 0; ++ } ++ ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++#endif ++ return 0; ++} ++ ++static int jz_audio_open(struct inode *inode, struct file *file) ++{ ++ int i; ++ struct jz_i2s_controller_info *controller = i2s_controller; ++ ++ if (controller == NULL) ++ return -ENODEV; ++ ++ mdelay(2); ++ REG_DMAC_DMACKE(0) = 0x3f; ++ pop_dma_flag = 0; ++ if (controller->opened1 == 1 || controller->opened2 == 1 ) { ++ printk("\naudio is busy!\n"); ++ return -EBUSY; ++ } ++ jz_codec_config = 0; ++ ++ ramp_up_start = 0; ++ ramp_up_end = 0; ++ gain_up_start = 0; ++ gain_up_end = 0; ++ ramp_down_start = 0; ++ ramp_down_end = 0; ++ gain_down_start = 0; ++ gain_down_end = 0; ++ if (file->f_mode & FMODE_WRITE) { ++ if (controller->opened1 == 1) ++ return -EBUSY; ++ ++ controller->opened1 = 1; ++ /* for ioctl */ ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ ++ for(i=0;i < 64;i++) { ++ save_last_samples[i].left = 0; ++ save_last_samples[i].right = 0; ++ } ++ ++ out_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(out_empty_queue.id + i) = i; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ last_dma_buffer_id = 0; ++ } ++ ++ if (file->f_mode & FMODE_READ) { ++ if (controller->opened2 == 1) ++ return -EBUSY; ++ ++ controller->opened2 = 1; ++ first_record_call = 1; ++ /* for ioctl */ ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ ++ in_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(in_empty_queue.id + i) = i; ++ ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ } ++ ++ file->private_data = controller; ++ jz_audio_reset(); ++ REG_AIC_FR |= (1 << 6); ++ ++ if (file->f_mode & FMODE_WRITE) { ++ if(set_codec_replay) ++ set_codec_replay(); ++ } ++ ++ if (file->f_mode & FMODE_READ) { ++ abnormal_data_count = 0; ++ if(set_codec_record) ++ set_codec_record(); ++ } ++ ++#if defined(CONFIG_I2S_DLV) ++ __aic_reset(); ++ ++ mdelay(10); ++ REG_AIC_I2SCR = 0x10; ++ mdelay(20); ++ __aic_flush_fifo(); ++#endif ++ ++ __i2s_enable(); ++ ++#if defined(CONFIG_I2S_DLV) ++ if (file->f_mode & FMODE_WRITE) { ++ ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ ramp_up_start = jiffies; ++ /*while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_RCR = 0x1; ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_RGR = 1;*/ ++ sleep_on(&pop_wait_queue); ++ //ramp_up_end = jiffies; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ } else if (file->f_mode & FMODE_READ) { ++ if (jz_mic_only) ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ else ++ write_codec_file_bit(5, 0, 7);//SB_DAC->0 ++ mdelay(500); ++ } ++ ++#endif ++ ++ return 0; ++} ++ ++ ++static int jz_audio_ioctl(struct inode *inode, struct file *file, ++unsigned int cmd, unsigned long arg) ++{ ++ int val,fullc,busyc,unfinish,newfragstotal,newfragsize; ++ unsigned int flags; ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ count_info cinfo; ++ audio_buf_info abinfo; ++ int id, i; ++ ++ val = 0; ++ switch (cmd) { ++ case OSS_GETVERSION: ++ return put_user(SOUND_VERSION, (int *)arg); ++ case SNDCTL_DSP_RESET: ++#if 0 ++ jz_audio_reset(); ++ __i2s_disable_replay(); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++ __i2s_disable_transmit_dma(); ++#endif ++ return 0; ++ case SNDCTL_DSP_SYNC: ++ if (file->f_mode & FMODE_WRITE) ++ return drain_dac(controller, file->f_flags & O_NONBLOCK); ++ return 0; ++ case SNDCTL_DSP_SPEED: ++ /* set smaple rate */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ if (val >= 0) ++ jz_audio_set_speed(controller->dev_audio, val); ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_STEREO: ++ /* set stereo or mono channel */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); ++ ++ return 0; ++ case SNDCTL_DSP_GETBLKSIZE: ++ //return put_user(jz_audio_fragsize / jz_audio_b, (int *)arg); ++ return put_user(jz_audio_fragsize, (int *)arg); ++ case SNDCTL_DSP_GETFMTS: ++ /* Returns a mask of supported sample format*/ ++ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); ++ case SNDCTL_DSP_SETFMT: ++ /* Select sample format */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ if (val != AFMT_QUERY) ++ jz_audio_set_format(controller->dev_audio,val); ++ else { ++ if (file->f_mode & FMODE_READ) ++ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; ++ else ++ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; ++ } ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_CHANNELS: ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ jz_audio_set_channels(controller->dev_audio, val); ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_POST: ++ /* FIXME: the same as RESET ?? */ ++ return 0; ++ case SNDCTL_DSP_SUBDIVIDE: ++ return 0; ++ case SNDCTL_DSP_SETFRAGMENT: ++ get_user(val, (long *) arg); ++ newfragsize = 1 << (val & 0xFFFF); ++ if (newfragsize < 4 * PAGE_SIZE) ++ newfragsize = 4 * PAGE_SIZE; ++ if (newfragsize > (16 * PAGE_SIZE)) ++ newfragsize = 16 * PAGE_SIZE; ++ ++ newfragstotal = (val >> 16) & 0x7FFF; ++ if (newfragstotal < 2) ++ newfragstotal = 2; ++ if (newfragstotal > 32) ++ newfragstotal = 32; ++ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize)) ++ return 0; ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ mdelay(500); ++ jz_audio_fragstotal = newfragstotal; ++ jz_audio_fragsize = newfragsize; ++ ++ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ mdelay(10); ++ ++ return 0; ++ case SNDCTL_DSP_GETCAPS: ++ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg); ++ case SNDCTL_DSP_NONBLOCK: ++ file->f_flags |= O_NONBLOCK; ++ return 0; ++ case SNDCTL_DSP_SETDUPLEX: ++ return -EINVAL; ++ case SNDCTL_DSP_GETOSPACE: ++ { ++ int i, bytes = 0; ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ jz_audio_fragments = elements_in_queue(&out_empty_queue); ++ for (i = 0; i < jz_audio_fragments; i++) ++ bytes += jz_audio_fragsize; ++ ++ if (jz_audio_channels == 2) ++ bytes /= jz_audio_b; ++ else if (jz_audio_channels == 1) ++ bytes /= 4; ++ else ++ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 1!\n"); ++ ++ ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ /* unused fragment amount */ ++ abinfo.fragments = jz_audio_fragments; ++ /* amount of fragments */ ++ abinfo.fragstotal = jz_audio_fragstotal; ++ /* fragment size in bytes */ ++ if (jz_audio_channels == 2) ++ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; ++ else if (jz_audio_channels == 1) ++ abinfo.fragsize = jz_audio_fragsize / 4; ++ else ++ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 2!\n"); ++ ++ /* write size count without blocking in bytes */ ++ abinfo.bytes = bytes; ++ ++ return copy_to_user((void *)arg, &abinfo, ++ sizeof(abinfo)) ? -EFAULT : 0; ++ } ++ case SNDCTL_DSP_GETISPACE: ++ { ++ int i, bytes = 0; ++ if (!(file->f_mode & FMODE_READ)) ++ return -EINVAL; ++ jz_audio_fragments = elements_in_queue(&in_empty_queue); ++ for (i = 0; i < jz_audio_fragments; i++) ++ bytes += jz_audio_fragsize; ++ ++ if (jz_audio_channels == 2) ++ bytes /= jz_audio_b; ++ else if (jz_audio_channels == 1) ++ bytes /= 4; ++ else ++ printk("SNDCTL_DSP_GETISPACE : channels is wrong 1!\n"); ++ ++ abinfo.fragments = jz_audio_fragments; ++ abinfo.fragstotal = jz_audio_fragstotal; ++ ++ if (jz_audio_channels == 2) ++ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; ++ else if (jz_audio_channels == 1) ++ abinfo.fragsize = jz_audio_fragsize / 4; ++ else ++ printk("SNDCTL_DSP_GETISPACE : channels is wrong 2!\n"); ++ ++ abinfo.bytes = bytes; ++ ++ return copy_to_user((void *)arg, &abinfo, ++ sizeof(abinfo)) ? -EFAULT : 0; ++ } ++ case SNDCTL_DSP_GETTRIGGER: ++ val = 0; ++ if (file->f_mode & FMODE_READ && in_dma_buf) ++ val |= PCM_ENABLE_INPUT; ++ if (file->f_mode & FMODE_WRITE && out_dma_buf) ++ val |= PCM_ENABLE_OUTPUT; ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_SETTRIGGER: ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ return 0; ++ case SNDCTL_DSP_GETIPTR: ++ if (!(file->f_mode & FMODE_READ)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ cinfo.bytes = controller->total_bytes; ++ cinfo.blocks = controller->blocks; ++ cinfo.ptr = controller->nextIn; ++ controller->blocks = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); ++ case SNDCTL_DSP_GETOPTR: ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ cinfo.bytes = controller->total_bytes; ++ cinfo.blocks = controller->blocks; ++ cinfo.ptr = controller->nextOut; ++ controller->blocks = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); ++ case SNDCTL_DSP_GETODELAY: ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ unfinish = 0; ++ fullc = elements_in_queue(&out_full_queue); ++ busyc = elements_in_queue(&out_busy_queue); ++ for(i = 0;i < fullc ;i ++) { ++ id = *(out_full_queue.id + i); ++ unfinish += *(out_dma_buf_data_count + id); ++ } ++ for(i = 0;i < busyc ;i ++) { ++ id = *(out_busy_queue.id + i); ++ unfinish += get_dma_residue(controller->dma1); ++ } ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ if (jz_audio_channels == 2) ++ unfinish /= jz_audio_b; ++ else if (jz_audio_channels == 1) ++ unfinish /= 4; ++ else ++ printk("SNDCTL_DSP_GETODELAY : channels is wrong !\n"); ++ ++ return put_user(unfinish, (int *) arg); ++ case SOUND_PCM_READ_RATE: ++ return put_user(jz_audio_rate, (int *)arg); ++ case SOUND_PCM_READ_CHANNELS: ++ return put_user(jz_audio_channels, (int *)arg); ++ case SOUND_PCM_READ_BITS: ++ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg); ++ case SNDCTL_DSP_MAPINBUF: ++ case SNDCTL_DSP_MAPOUTBUF: ++ case SNDCTL_DSP_SETSYNCRO: ++ case SOUND_PCM_WRITE_FILTER: ++ case SOUND_PCM_READ_FILTER: ++ return -EINVAL; ++ } ++ return -EINVAL; ++} ++ ++ ++static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait) ++{ ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ unsigned long flags; ++ unsigned int mask = 0; ++ ++ if (file->f_mode & FMODE_WRITE) { ++ if (elements_in_queue(&out_empty_queue) > 0) ++ return POLLOUT | POLLWRNORM; ++ ++ poll_wait(file, &controller->dac_wait, wait); ++ } ++ ++ if (file->f_mode & FMODE_READ) { ++ if (elements_in_queue(&in_full_queue) > 0) ++ return POLLIN | POLLRDNORM; ++ ++ poll_wait(file, &controller->adc_wait, wait); ++ } ++ ++ spin_lock_irqsave(&controller->lock, flags); ++ if (file->f_mode & FMODE_WRITE) { ++ if (elements_in_queue(&out_empty_queue) > 0) ++ mask |= POLLOUT | POLLWRNORM; ++ } else if (file->f_mode & FMODE_READ) { ++ if (elements_in_queue(&in_full_queue) > 0) ++ mask |= POLLIN | POLLRDNORM; ++ } ++ spin_unlock_irqrestore(&controller->lock, flags); ++ ++ return mask; ++} ++ ++static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) ++{ ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ int id, ret = 0, left_count, copy_count, cnt = 0; ++ unsigned long flags; ++ ++ if (count < 0) ++ return -EINVAL; ++ ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextIn = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ copy_count = jz_audio_fragsize / 4; ++ ++ left_count = count; ++ if (first_record_call) { ++ first_record_call = 0; ++ audio_read_back_first: ++ if ((id = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id); ++ spin_lock(&controller->lock); ++ *(in_dma_buf_data_count + id) = copy_count * 4; ++ ++ spin_unlock(&controller->lock); ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); ++ audio_start_dma(controller->dma2,file->private_data, ++ *(in_dma_pbuf + id), ++ *(in_dma_buf_data_count + id), ++ DMA_MODE_READ); ++ sleep_on(&rx_wait_queue); ++ } else ++ goto audio_read_back_first; ++ } ++ ++ while (left_count > 0) { ++ audio_read_back_second: ++ if (elements_in_queue(&in_full_queue) <= 0) { ++ if (file->f_flags & O_NONBLOCK) ++ return ret ? ret : -EAGAIN; ++ else ++ sleep_on(&rx_wait_queue); ++ } ++ ++ if ((id = get_buffer_id(&in_full_queue)) >= 0) { ++ spin_lock(&controller->lock); ++ cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id); ++ spin_unlock(&controller->lock); ++ put_buffer_id(&in_empty_queue, id); ++ } else ++ goto audio_read_back_second; ++ ++ if (elements_in_queue(&in_busy_queue) == 0) { ++ if ((id=get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id); ++ spin_lock(&controller->lock); ++ *(in_dma_buf_data_count + id) = copy_count * 4; ++ spin_unlock(&controller->lock); ++ ++ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); ++ audio_start_dma(controller->dma2,file->private_data, ++ *(in_dma_pbuf + id), ++ *(in_dma_buf_data_count + id), ++ DMA_MODE_READ); ++ } ++ } ++ if (ret + cnt > count) { ++ spin_lock(&controller->lock); ++ cnt = count - ret; ++ spin_unlock(&controller->lock); ++ } ++ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt)) ++ return ret ? ret : -EFAULT; ++ ++ spin_lock(&controller->lock); ++ ret += cnt; ++ spin_unlock(&controller->lock); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextIn += ret; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ spin_lock(&controller->lock); ++ left_count -= cnt; ++ spin_unlock(&controller->lock); ++ } ++ return ret; ++} ++ ++static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) ++{ ++ int id, ret = 0, left_count, copy_count = 0; ++ unsigned int flags; ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ ++ if (count <= 0) ++ return -EINVAL; ++ ++ if(set_replay_hp_or_speaker) ++ set_replay_hp_or_speaker(); ++ ++ __i2s_enable_transmit_dma(); ++ __i2s_enable_replay(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextOut = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ if (jz_audio_channels == 2) ++ copy_count = jz_audio_fragsize / jz_audio_b; ++ else if(jz_audio_channels == 1) ++ copy_count = jz_audio_fragsize / 4; ++ left_count = count; ++ if (copy_from_user(controller->tmp1, buffer, count)) { ++ printk("copy_from_user failed:%d",ret); ++ return ret ? ret : -EFAULT; ++ } ++ ++ while (left_count > 0) { ++ audio_write_back: ++ /*if (file->f_flags & O_NONBLOCK) ++ udelay(2);*/ ++ if (elements_in_queue(&out_empty_queue) == 0) { ++ if (file->f_flags & O_NONBLOCK) ++ return ret; ++ else ++ sleep_on(&tx_wait_queue); ++ } ++ /* the end fragment size in this write */ ++ if (ret + copy_count > count) ++ copy_count = count - ret; ++ if ((id = get_buffer_id(&out_empty_queue)) >= 0) { ++ replay_filler((signed long)controller->tmp1 + ret, copy_count, id); ++ if(*(out_dma_buf_data_count + id) > 0) { ++ put_buffer_id(&out_full_queue, id); ++ dma_cache_wback_inv(*(out_dma_buf + id), ++ *(out_dma_buf_data_count + id)); ++ } else ++ put_buffer_id(&out_empty_queue, id); ++ } else ++ goto audio_write_back; ++ ++ left_count = left_count - copy_count; ++ ret += copy_count; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextOut += ret; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ if (elements_in_queue(&out_busy_queue) == 0) { ++ if ((id=get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_busy_queue, id); ++ ++ if(*(out_dma_buf_data_count + id) > 0) { ++ audio_start_dma(controller->dma1, ++ file->private_data, ++ *(out_dma_pbuf + id), ++ *(out_dma_buf_data_count + id), ++ DMA_MODE_WRITE); ++ last_dma_buffer_id = id; ++ if (jz_codec_config == 0) { ++ write_codec_file_bit(1, 0, 5); ++ gain_up_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //gain_up_end = jiffies; ++ jz_codec_config = 1; ++ //SB_ADC->1 ++ //write_codec_file_bit(5, 1, 4); ++ //while(1); ++ } ++ } ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++#if defined(CONFIG_I2S_ICODEC) ++static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample) ++{ ++ int i,step_len; ++ unsigned long *pop_buf = (unsigned long*)pop_turn_onoff_buf; ++ unsigned int sample_oss = (REG_AIC_CR & 0x00380000) >> 19; ++ unsigned long l_sample_count,r_sample_count,sample_count; ++ struct jz_i2s_controller_info *controller = i2s_controller; ++ signed int left_sam=0,right_sam=0,l_val,r_val; ++ ++ switch (sample_oss) { ++ case 0x0: ++ break; ++ case 0x1: ++ left_sam = (signed int)l_sample; ++ right_sam = (signed int)r_sample; ++ break; ++ case 0x2: ++ break; ++ case 0x3: ++ break; ++ case 0x4: ++ break; ++ } ++ ++ if(left_sam == 0 && right_sam == 0) ++ return; ++ ++ switch (sample_oss) { ++ case 0x0: ++ break; ++ case 0x1: ++ step_len = jz_audio_speed / 10 * 3; ++ step_len = step_len / 2; ++ step_len = 0x7fff / step_len + 1; ++ ++ l_sample_count = 0; ++ l_val = left_sam; ++ ++ while(1) { ++ if(l_val > 0) { ++ if(l_val >= step_len) { ++ l_val -= step_len; ++ l_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(l_val < 0) { ++ if(l_val <= -step_len) { ++ l_val += step_len; ++ l_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(l_val == 0) ++ break; ++ } ++ ++ r_sample_count = 0; ++ r_val = right_sam; ++ while(1) { ++ if(r_val > 0) { ++ if(r_val >= step_len) { ++ r_val -= step_len; ++ r_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(r_val < 0) { ++ if(r_val <= -step_len) { ++ r_val += step_len; ++ r_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(r_val == 0) ++ break; ++ } ++ /* fill up */ ++ if(l_sample_count > r_sample_count) ++ sample_count = l_sample_count; ++ else ++ sample_count = r_sample_count; ++ ++ l_val = left_sam; ++ r_val = right_sam; ++ for(i=0;i <= sample_count;i++) { ++ ++ *pop_buf = (unsigned long)l_val; ++ pop_buf ++; ++ ++ if(l_val > step_len) ++ l_val -= step_len; ++ else if(l_val < -step_len) ++ l_val += step_len; ++ else if(l_val >= -step_len && l_val <= step_len) ++ l_val = 0; ++ ++ *pop_buf = (unsigned long)r_val; ++ pop_buf ++; ++ if(r_val > step_len) ++ r_val -= step_len; ++ else if(r_val < -step_len) ++ r_val += step_len; ++ else if(r_val >= -step_len && r_val <= step_len) ++ r_val = 0; ++ } ++ ++ *pop_buf = 0; ++ pop_buf ++; ++ *pop_buf = 0; ++ ++ pop_buf ++; ++ sample_count += 2; ++ dma_cache_wback_inv(pop_turn_onoff_buf, sample_count*8); ++ ++ pop_dma_flag = 1; ++ audio_start_dma(controller->dma1,controller,pop_turn_onoff_pbuf,sample_count*8,DMA_MODE_WRITE); ++ sleep_on(&pop_wait_queue); ++ pop_dma_flag = 0; ++ break; ++ case 0x2: ++ break; ++ case 0x3: ++ break; ++ case 0x4: ++ break; ++ } ++} ++#endif --- linux-2.6.24.7.old/sound/oss/jz_i2s_dlv_dma_test.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7/sound/oss/jz_i2s_dlv_dma_test.c 2009-04-12 18:13:57.000000000 +0200 @@ -0,0 +1,2808 @@ @@ -12711,7 +9225,7 @@ + int nextIn; // byte index to next-in to DMA buffer + int nextOut; // byte index to next-out from DMA buffer + int count; // current byte count in DMA buffer -+ int finish; // current transfered byte count in DMA buffer ++ int finish; // current transfered byte count in DMA buffer + unsigned total_bytes; // total bytes written or read + unsigned blocks; + unsigned error; // over/underrun @@ -12722,13 +9236,13 @@ + + +static struct jz_i2s_controller_info *i2s_controller = NULL; -+struct i2s_codec ++struct i2s_codec +{ + /* I2S controller connected with */ + void *private_data; + char *name; + int id; -+ int dev_mixer; ++ int dev_mixer; + /* controller specific lower leverl i2s accessing routines */ + u16 (*codec_read) (u8 reg);//the function accessing Codec REGs fcj add + void (*codec_write) (u8 reg, u16 val);//to AK4642EN,val is 8bit @@ -12751,7 +9265,7 @@ +}; + + -+typedef struct buffer_queue_s ++typedef struct buffer_queue_s +{ + int count; + int *id; @@ -12798,12 +9312,12 @@ + int cnt; + + printk("\n"); -+ ++ + printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR); + printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR); + printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR); + printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR); -+ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR); ++ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR); + printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR); + printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR); + printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA); @@ -12845,11 +9359,11 @@ + + while (__icdc_rgwr_ready()); + __icdc_set_addr(addr); -+ val = __icdc_get_value(); /* read */ -+ ++ val = __icdc_get_value(); /* read */ ++ + if (((val >> mask_bit) & bitval) == bitval) + return 1; -+ else ++ else + return 0; +} + @@ -12864,10 +9378,10 @@ + write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 + write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 + write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ ++ + write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 + write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ ++ + write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 + //mdelay(100); + //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 @@ -12899,16 +9413,16 @@ + mdelay(10); + write_codec_file_bit(1, 1, 2); + //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ ++ + write_codec_file(22, 0x40);//mic 1 + write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 + write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 + write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ ++ + write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 + write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 + //write_codec_file_bit(6, 1, 3);// gain set -+ ++ + write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 + mdelay(100); + write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 @@ -12932,7 +9446,7 @@ +/* set Record LINE input audio without playback */ +static void set_record_line_input_audio_without_playback(void) +{ -+ /* ADC path for LINE IN */ ++ /* ADC path for LINE IN */ + jz_mic_only = 1; + write_codec_file(9, 0xff); + write_codec_file(8, 0x3f); @@ -12942,7 +9456,7 @@ + write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 + write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 + write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ ++ + write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 + write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 + mdelay(10); @@ -12958,7 +9472,7 @@ + /* ADC path for LINE IN */ + write_codec_file_bit(5, 1, 4);//SB_ADC->1 + write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1 -+ ++ + write_codec_file(22, 0xc0);//CR3.SB_MIC1 + write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 + write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 @@ -13005,24 +9519,24 @@ + +/* set Record MIC input audio with direct playback */ +static void set_record_mic_input_audio_with_direct_playback(void) -+{ ++{ + write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 + jz_mic_only = 0; + write_codec_file(9, 0xff); + write_codec_file(8, 0x3f); + mdelay(10); -+ ++ + write_codec_file(22, 0x60);//mic 1 + write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 + write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 + write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 + write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 + write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ ++ + write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 + write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 + write_codec_file_bit(6, 1, 3);// gain set -+ ++ + write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 + mdelay(100); + write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 @@ -13051,13 +9565,13 @@ + //write_codec_file(8, 0x30); + write_codec_file(8, 0x20); + mdelay(10); -+ ++ + write_codec_file(22, 0x63);//mic 1 -+ ++ + write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 + write_codec_file_bit(6, 1, 3);// gain set + -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 + write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 + write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 + write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 @@ -13085,12 +9599,12 @@ + +/* set Record MIC input audio with Audio data replay (full duplex) */ +static void set_record_mic_input_audio_with_audio_data_replay(void) -+{ ++{ + write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 + write_codec_file(9, 0xff); + //write_codec_file(8, 0x30); + write_codec_file(8, 0x20); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 + write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 + write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 + @@ -13118,18 +9632,18 @@ +///////// +/* set Record LINE input audio with Audio data replay (full duplex for linein) */ +static void set_record_line_input_audio_with_audio_data_replay(void) -+{ ++{ + write_codec_file(9, 0xff); + //write_codec_file(8, 0x30); + write_codec_file(8, 0x20); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 + write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 + write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 + write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 + //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1 + write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 + write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ ++ + + //jz_mic_only = 1; + write_codec_file(22, 0xc6);//line in 1 @@ -13160,7 +9674,7 @@ + int i; + spin_lock_irqsave(&q->lock, flags); + //spin_lock(&q->lock); -+ if (q->count == 0) { ++ if (q->count == 0) { + spin_unlock_irqrestore(&q->lock, flags); + //spin_unlock(&q->lock); + return -1; @@ -13211,10 +9725,10 @@ + //__dmac_disable_module(0); + disable_dma(chan); + clear_dma_ff(chan); -+ ++ + set_dma_mode(chan, mode); + set_dma_addr(chan, phyaddr); -+ if (count == 0) ++ if (count == 0) + { + count++; + printk("JzSOC DMA controller can't set dma 0 count!\n"); @@ -13225,17 +9739,17 @@ + //__dmac_enable_module(0); + release_dma_lock(flags); + //dump_jz_dma_channel(chan); -+ ++ + //printk_codec_files(); +} + +static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id) +{ + int id1, id2; -+ ++ + struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; + int dma = controller->dma2; -+ ++ + disable_dma(dma); + if (__dmac_channel_address_error_detected(dma)) { + printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); @@ -13252,7 +9766,7 @@ + spin_unlock(&controller->ioctllock); + id1 = get_buffer_id(&in_busy_queue); + put_buffer_id(&in_full_queue, id1); -+ ++ + wake_up(&rx_wait_queue); + wake_up(&controller->adc_wait); + if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { @@ -13264,12 +9778,12 @@ + *(in_dma_pbuf + id2), + *(in_dma_buf_data_count + id2), + DMA_MODE_READ); -+ } -+ else ++ } ++ else + in_busy_queue.count = 0; + } + return IRQ_HANDLED; -+ ++ +} + +static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id) @@ -13279,7 +9793,7 @@ + struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; + int dma = controller->dma1; + disable_dma(dma); -+ ++ + if (__dmac_channel_address_error_detected(dma)) { + printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); + __dmac_channel_clear_address_error(dma); @@ -13320,7 +9834,7 @@ +{ + __i2s_disable(); + //schedule_timeout(5); -+ ++ +#if defined(CONFIG_I2S_DLV) + __i2s_disable(); + __i2s_as_slave(); @@ -13394,7 +9908,7 @@ + out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); + if (!out_busy_queue.id) + goto all_mem_err; -+ for (i=0;i < fragstotal;i++) ++ for (i=0;i < fragstotal;i++) + *(out_empty_queue.id + i) = i; + + out_busy_queue.count = 0; @@ -13408,7 +9922,7 @@ + } + *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); + } -+ ++ + return 1; +all_mem_err: + printk("error:allocate memory occur error 1!\n"); @@ -13474,7 +9988,7 @@ + dma_cache_wback_inv(*(in_dma_buf + i), fragsize); + free_pages(*(in_dma_buf + i), get_order(fragsize)); + } -+ *(in_dma_buf + i) = 0; //release page error ++ *(in_dma_buf + i) = 0; //release page error + } + kfree(in_dma_buf); + in_dma_buf = NULL; @@ -13503,7 +10017,7 @@ + in_empty_queue.count = fragstotal; + in_full_queue.count = 0; + in_busy_queue.count = 0; -+ ++ + return 1; +} + @@ -13523,7 +10037,7 @@ + if (rate < 8000) + rate = 8000; + jz_audio_rate = rate; -+ ++ +#if defined(CONFIG_I2S_DLV) + speed = 0; + switch (rate) { @@ -13567,7 +10081,7 @@ + val = read_codec_file(4); + val = (speed << 4) | speed; + write_codec_file(4, val); -+ ++ +#if 0 + for (i = 0; i <= 27 ; i++) { + printk(" ( CCC %d : 0x%x ) ",i ,read_codec_file(i)); @@ -13710,12 +10224,12 @@ + signed long l1; + volatile signed short *s = (signed short *)src_start; + volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+ ++ + while (count > 0) { + count -= 2; + cnt += 2 ; + d1 = *(s++); -+ l1 = (unsigned long)d1; ++ l1 = (unsigned long)d1; + *(dp ++) = l1; + *(dp ++) = l1; + } @@ -13730,17 +10244,17 @@ + signed long l1; + volatile signed short *s = (signed short *)src_start; + volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+ ++ + while (count > 0) { + count -= 2; + cnt += 2; + d1 = *(s++); -+ ++ + l1 = (signed long)d1; -+ ++ + *(dp ++) = l1; + } -+ ++ + cnt *= jz_audio_b; + *(out_dma_buf_data_count + id) = cnt; +} @@ -13761,7 +10275,7 @@ + + jz_audio_format = fmt; + jz_update_filler(jz_audio_format, jz_audio_channels); -+ ++ + /* print all files */ + __i2s_set_oss_sample_size(16); + __i2s_set_iss_sample_size(16); @@ -13859,11 +10373,11 @@ + int i; + int minor = MINOR(inode->i_rdev); + struct jz_i2s_controller_info *controller = i2s_controller; -+ ++ + for (i = 0; i < NR_I2S; i++) + if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor) + goto match; -+ ++ + if (!controller) + return -ENODEV; +match: @@ -13882,7 +10396,7 @@ + return -ESPIPE; +} + -+static struct file_operations jz_i2s_mixer_fops = ++static struct file_operations jz_i2s_mixer_fops = +{ + owner: THIS_MODULE, + llseek: jz_i2s_llseek, @@ -13895,7 +10409,7 @@ + int ret; + u8 cur_vol; + long val = 0; -+ ++ + switch (cmd) { + case SOUND_MIXER_INFO: + { @@ -13914,8 +10428,8 @@ +#if defined(CONFIG_I2S_DLV) + strncpy(info.id, "DLV", sizeof(info.id)); + strncpy(info.name,"Jz4750 internal codec", sizeof(info.name)); -+#endif -+ ++#endif ++ + return copy_to_user((void *)arg, &info, sizeof(info)); + } + case SOUND_MIXER_READ_STEREODEVS: @@ -13938,7 +10452,7 @@ + val = 0; + if(val > 100) + val = 100; -+ ++ + REG_CPM_I2SCDR = val; + printk_codec_files(); + break; @@ -13946,7 +10460,7 @@ + ret = get_user(val, (long *) arg); + if (ret) + return ret; -+ ++ + val = val & 0xff; + if(val < 0) + val = 0; @@ -13955,12 +10469,12 @@ +#if defined(CONFIG_I2S_DLV) +#endif + return 0; -+ -+ case SOUND_MIXER_READ_BASS: ++ ++ case SOUND_MIXER_READ_BASS: +#if defined(CONFIG_I2S_DLV) +#endif + return put_user(val, (long *) arg); -+ ++ + case SOUND_MIXER_WRITE_VOLUME: + ret = get_user(val, (long *) arg); + if (ret) @@ -13988,11 +10502,11 @@ + } + if(val > 31) + val = 31; -+ ++ + jz_audio_volume = val; + //printk("\njz_audio_volume=%d\n",jz_audio_volume); +#if defined(CONFIG_I2S_DLV) -+ cur_vol = val; ++ cur_vol = val; + write_codec_file(17, cur_vol | 0xc0); + write_codec_file(18, cur_vol); +#endif @@ -14000,13 +10514,13 @@ + case SOUND_MIXER_READ_VOLUME: +#if defined(CONFIG_I2S_DLV) + val = jz_audio_volume | jz_audio_volume << 8; -+#endif ++#endif + return put_user(val, (long *) arg); + case SOUND_MIXER_WRITE_LINE: + ret = get_user(val, (long *) arg); + if (ret) + return ret; -+ ++ + val = val & 0xff; + if(val < 0) + val = 0; @@ -14023,13 +10537,13 @@ + printk_codec_files(); + return 99; + } -+ ++ + if(val > 31) + val = 31; +#if defined(CONFIG_I2S_DLV) + use_mic_line_flag = USE_LINEIN; + /* set gain */ -+ cur_vol = val; ++ cur_vol = val; + cur_vol &= 0x1f; + write_codec_file(11, cur_vol);//GO1L + write_codec_file(12, cur_vol);//GO1R @@ -14040,7 +10554,7 @@ + ret = get_user(val, (long *) arg); + if (ret) + return ret; -+ ++ + val = val & 0xff; + if(val < 0) + val = 0; @@ -14051,13 +10565,13 @@ + use_mic_line_flag = USE_MIC; + /* set gain */ + //write_codec_file_bit(6, 1, 3);//GIM -+ cur_vol = val; ++ cur_vol = val; + cur_vol |= cur_vol << 4; + write_codec_file(19, cur_vol);//GIL,GIR +#endif + return 0; -+ -+ case SOUND_MIXER_READ_MIC: ++ ++ case SOUND_MIXER_READ_MIC: +#if defined(CONFIG_I2S_DLV) +#endif + @@ -14066,7 +10580,7 @@ + return -ENOSYS; + } + audio_mix_modcnt ++; -+ ++ + return 0; +} + @@ -14083,14 +10597,14 @@ +{ + int num_i2s = 0; + struct i2s_codec *codec; -+ ++ + for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) { + if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL) + return -ENOMEM; + memset(codec, 0, sizeof(struct i2s_codec)); + codec->private_data = controller; + codec->id = num_i2s; -+ ++ + if (i2s_probe_codec(codec) == 0) + break; + if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) { @@ -14117,7 +10631,7 @@ + l1 = (signed long)d1; + *(dp ++) = l1; + } -+ ++ + cnt *= jz_audio_b; + *(out_dma_buf_data_count + id) = cnt; +} @@ -14136,9 +10650,9 @@ + l1 = (signed long)d1; + *(dp ++) = l1; + } -+ ++ + cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; ++ *(out_dma_buf_data_count + id) = cnt; + //printk("--- play 24 ---\n"); +} + @@ -14146,7 +10660,7 @@ +{ + #define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) + -+ switch (TYPE(format, channels)) ++ switch (TYPE(format, channels)) + { + default: + case TYPE(AFMT_U8, 1): @@ -14209,7 +10723,7 @@ +static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller) +{ + char *name; -+ int adev;//No of Audio device. ++ int adev;//No of Audio device. + name = controller->name; + jz_i2s_initHw(1);//initialize AIC controller and reset it + /* register /dev/audio */ @@ -14219,14 +10733,14 @@ + /* initialize I2S codec and register /dev/mixer */ + if (jz_i2s_codec_init(controller) <= 0) + goto mixer_failed; -+ ++ +#ifdef CONFIG_PROC_FS + if (jz_i2s_init_proc(controller) < 0) { + printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name); + goto proc_failed; + } +#endif -+ ++ + controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, JZCODEC_USER_BUFFER); + if (!controller->tmp1) { + printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); @@ -14248,7 +10762,7 @@ + goto dma2_failed; + } + printk("JzSOC On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2)); -+ ++ + controller->dev_audio = adev; + + return; @@ -14260,7 +10774,7 @@ +tmp2_failed: +tmp1_failed: + free_pages((unsigned long)controller->tmp1, JZCODEC_USER_BUFFER); -+ ++ +#ifdef CONFIG_PROC_FS + jz_i2s_cleanup_proc(controller); +#endif @@ -14298,15 +10812,15 @@ + int adev = controller->dev_audio; + jz_i2s_full_reset (controller); + controller->dev_audio = -1; -+ ++ +#ifdef CONFIG_PROC_FS + jz_i2s_cleanup_proc(controller); +#endif -+ ++ + jz_free_dma(controller->dma1); + jz_free_dma(controller->dma2); + free_pages((unsigned long)controller->tmp1, JZCODEC_USER_BUFFER); -+ free_pages((unsigned long)controller->tmp2, JZCODEC_USER_BUFFER); ++ free_pages((unsigned long)controller->tmp2, JZCODEC_USER_BUFFER); + if (adev >= 0) { + //unregister_sound_mixer(audio_devs[adev]->mixer_dev); + unregister_sound_dsp(controller->dev_audio); @@ -14316,7 +10830,7 @@ + +#ifdef CONFIG_PM +static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state) -+{ ++{ + return 0; +} + @@ -14353,7 +10867,7 @@ +{ + u8 file_9 = read_codec_file(9); + u8 file_8 = read_codec_file(8); -+ ++ + //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9); + if ((file_9 & 0x1f) == 0x10) { + @@ -14386,14 +10900,14 @@ + if (file_9 & 0xf) + wake_up(&pop_wait_queue); + while (REG_ICDC_RGDATA & 0x100); -+ ++ + return IRQ_HANDLED; +} + +static int __init init_jz_i2s(void) +{ + int errno, retval; -+ ++ +#if defined(CONFIG_I2S_DLV) + ramp_up_start = 0; + ramp_up_end = 0; @@ -14445,13 +10959,13 @@ + in_empty_queue.id = NULL; + in_full_queue.id = NULL; + in_busy_queue.id = NULL; -+ ++ + jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE; + jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ; + Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ ++ +#ifdef CONFIG_PM -+ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ++ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, + jz_i2s_pm_callback); + if (i2s_controller->pm) + i2s_controller->pm->data = i2s_controller; @@ -14472,8 +10986,8 @@ + unload_jz_i2s(i2s_controller); +#if defined(CONFIG_I2S_DLV) + free_irq(IRQ_AIC, NULL); -+#endif -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++#endif ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); +} + +module_init(init_jz_i2s); @@ -14491,7 +11005,7 @@ + udelay(10); + i++; + } else -+ break; ++ break; + //set_current_state(TASK_INTERRUPTIBLE); + spin_lock_irqsave(&ctrl->lock, flags); + //spin_lock(&ctrl->lock); @@ -14500,7 +11014,7 @@ + //spin_unlock(&ctrl->lock); + if (count <= 0) + break; -+ ++ + /*if (signal_pending(current)) + break;*/ + if (nonblock) { @@ -14519,19 +11033,19 @@ +{ + unsigned long flags; + int count,ele,busyele,emptyele,i=0; -+ ++ + for (;;) { + if(!nonblock) {//blocked + if (i < MAXDELAY) { + udelay(10); + i++; + } else -+ break; -+ ++ break; ++ + ele = elements_in_queue(&out_full_queue); + if(ele <= 0) { + udelay(200); -+ ++ + busyele = elements_in_queue(&out_busy_queue); + emptyele = elements_in_queue(&out_empty_queue); + if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { @@ -14545,12 +11059,12 @@ + } else {//non-blocked + mdelay(100); + ele = elements_in_queue(&out_full_queue); -+ ++ + if(ele <= 0) { + mdelay(100); + busyele = elements_in_queue(&out_busy_queue); + emptyele = elements_in_queue(&out_empty_queue); -+ ++ + if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { + spin_lock_irqsave(&ctrl->lock, flags); + count = get_dma_residue(ctrl->dma1); @@ -14561,7 +11075,7 @@ + } + } + } -+ ++ + return 0; +} + @@ -14578,11 +11092,11 @@ + printk("ramp_down_end =0x%x\n",ramp_down_end); + printk("gain_down_start=0x%x\n",gain_down_start); + printk("gain_down_end =0x%x\n",gain_down_end); -+#endif ++#endif + -+ diff = (long)ramp_up_end - (long)ramp_up_start; ++ diff = (long)ramp_up_end - (long)ramp_up_start; + printk("ramp up duration: %d ms\n",diff * 1000 / HZ); -+ diff = (long)gain_up_end - (long)gain_up_start; ++ diff = (long)gain_up_end - (long)gain_up_start; + printk("gain up duration: %d ms\n",diff * 1000 / HZ); + diff = (long)gain_down_end - (long)gain_down_start; + printk("gain down duration: %d ms\n",diff); @@ -14591,7 +11105,7 @@ +} + +static int jz_audio_release(struct inode *inode, struct file *file) -+{ ++{ + struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; + unsigned long tfl; + @@ -14616,14 +11130,14 @@ + break; + } + mdelay(2); -+ }*/ ++ }*/ + mdelay(100); + disable_dma(controller->dma1); + set_dma_count(controller->dma1, 0); + + __i2s_disable_transmit_dma(); + __i2s_disable_replay(); -+ ++ + //spin_lock_irqsave(&controller->ioctllock, flags); + spin_lock(&controller->ioctllock); + controller->total_bytes = 0; @@ -14693,12 +11207,12 @@ + } + disable_dma(controller->dma1); + set_dma_count(controller->dma1, 0); -+ ++ + __i2s_disable_transmit_dma(); + __i2s_disable_replay(); -+ ++ + __aic_flush_fifo(); -+ ++ + //spin_lock_irqsave(&controller->ioctllock, flags); + spin_lock(&controller->ioctllock); + controller->total_bytes = 0; @@ -14727,7 +11241,7 @@ + set_dma_count(controller->dma2, 0); + __i2s_disable_receive_dma(); + __i2s_disable_record(); -+ ++ + //spin_lock_irqsave(&controller->ioctllock, flags); + spin_lock(&controller->ioctllock); + controller->total_bytes = 0; @@ -14755,7 +11269,7 @@ +#endif + __i2s_disable(); + } -+ ++ + if (controller->opened1 == 1 && controller->opened2 == 1) { + controller->opened1 = 0; + controller->opened2 = 0; @@ -14769,7 +11283,7 @@ + } + write_codec_file(9, 0xff); + write_codec_file(8, 0x3f); -+ ++ +/* __cpm_stop_idct(); + __cpm_stop_db(); + __cpm_stop_me(); @@ -14814,7 +11328,7 @@ + controller->blocks = 0; + controller->nextOut = 0; + -+ out_empty_queue.count = jz_audio_fragstotal; ++ out_empty_queue.count = jz_audio_fragstotal; + for (i=0;i < jz_audio_fragstotal;i++) + *(out_empty_queue.id + i) = i; + out_busy_queue.count = 0; @@ -14822,7 +11336,7 @@ + + if (controller->opened2 == 1) + return -EBUSY; -+ ++ + controller->opened2 = 1; + first_record_call = 1; + /* for ioctl */ @@ -14832,11 +11346,11 @@ + controller->finish = 0; + controller->blocks = 0; + controller->nextIn = 0; -+ ++ + in_empty_queue.count = jz_audio_fragstotal; + for (i=0;i < jz_audio_fragstotal;i++) + *(in_empty_queue.id + i) = i; -+ ++ + in_full_queue.count = 0; + in_busy_queue.count = 0; + } else if (file->f_mode & FMODE_WRITE) { @@ -14851,15 +11365,15 @@ + controller->blocks = 0; + controller->nextOut = 0; + -+ out_empty_queue.count = jz_audio_fragstotal; ++ out_empty_queue.count = jz_audio_fragstotal; + for (i=0;i < jz_audio_fragstotal;i++) + *(out_empty_queue.id + i) = i; + out_busy_queue.count = 0; -+ out_full_queue.count = 0; ++ out_full_queue.count = 0; + } else if (file->f_mode & FMODE_READ) { + if (controller->opened2 == 1) + return -EBUSY; -+ ++ + controller->opened2 = 1; + first_record_call = 1; + //for ioctl @@ -14869,11 +11383,11 @@ + controller->finish = 0; + controller->blocks = 0; + controller->nextIn = 0; -+ ++ + in_empty_queue.count = jz_audio_fragstotal; + for (i=0;i < jz_audio_fragstotal;i++) + *(in_empty_queue.id + i) = i; -+ ++ + in_full_queue.count = 0; + in_busy_queue.count = 0; + } @@ -14883,33 +11397,33 @@ + + if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { +#if defined(CONFIG_I2S_DLV) -+ ++ + if (use_mic_line_flag == USE_LINEIN) { + /* Record LINE input audio with Audio data replay (full duplex for linein) */ + /* codec_test_line */ + set_record_line_input_audio_with_audio_data_replay(); -+ ++ + } + if (use_mic_line_flag == USE_MIC) { + /* Record MIC input audio with Audio data replay (full duplex) */ + /* codec_test_mic */ + set_record_mic_input_audio_with_audio_data_replay(); + } -+#if 0 ++#if 0 + /* Record playing audio mixed with MIC input audio */ + set_record_playing_audio_mixed_with_mic_input_audio(); +#endif + +#endif + } else if (file->f_mode & FMODE_WRITE) { -+#if defined(CONFIG_I2S_DLV) ++#if defined(CONFIG_I2S_DLV) + //mdelay(10); + /* Audio data replay */ + set_audio_data_replay(); +#endif + } else if (file->f_mode & FMODE_READ) { +#if defined(CONFIG_I2S_DLV) -+#if 0 ++#if 0 + /* Record MIC input audio with direct playback */ + set_record_mic_input_audio_with_direct_playback(); +#endif @@ -14928,14 +11442,14 @@ + } + + __aic_reset(); -+ ++ + mdelay(10); + REG_AIC_I2SCR = 0x10; + mdelay(20); + __aic_flush_fifo(); + __i2s_enable(); + ndelay(100); -+ ++ + if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { +#if defined(CONFIG_I2S_DLV) + //set SB_ADC or SB_DAC @@ -14979,9 +11493,9 @@ + int val,fullc,busyc,unfinish,newfragstotal,newfragsize; + unsigned int flags; + struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ ++ + audio_buf_info abinfo; -+ int i, bytes, id; ++ int i, bytes, id; + count_info cinfo; + val = 0; + bytes = 0; @@ -15009,14 +11523,14 @@ + return -EFAULT; + jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); + return 0; -+ ++ + case SNDCTL_DSP_GETBLKSIZE: + //return put_user(4*PAGE_SIZE, (int *)arg); + return put_user(jz_audio_fragsize , (int *)arg); + case SNDCTL_DSP_GETFMTS: + /* Returns a mask of supported sample format*/ + return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); -+ ++ + case SNDCTL_DSP_SETFMT: + /* Select sample format */ + { @@ -15029,33 +11543,33 @@ + val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; + else + val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; -+ ++ + } + return put_user(val, (int *)arg); + } -+ ++ + case SNDCTL_DSP_CHANNELS: + if (get_user(val, (int *)arg)) + return -EFAULT; + jz_audio_set_channels(controller->dev_audio, val); + return put_user(val, (int *)arg); -+ ++ + case SNDCTL_DSP_POST: + /* FIXME: the same as RESET ?? */ + return 0; -+ ++ + case SNDCTL_DSP_SUBDIVIDE: + return 0; -+ ++ + case SNDCTL_DSP_SETFRAGMENT: + get_user(val, (long *) arg); + newfragsize = 1 << (val & 0xFFFF);//16 least bits -+ ++ + if (newfragsize < 4 * PAGE_SIZE) + newfragsize = 4 * PAGE_SIZE; + if (newfragsize > (16 * PAGE_SIZE)) //16 PAGE_SIZE + newfragsize = 16 * PAGE_SIZE; -+ ++ + newfragstotal = (val >> 16) & 0x7FFF; + if (newfragstotal < 2) + newfragstotal = 2; @@ -15067,10 +11581,10 @@ + mdelay(500); + jz_audio_fragstotal = newfragstotal; + jz_audio_fragsize = newfragsize; -+ ++ + Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); + mdelay(10); -+ ++ + return 0; + case SNDCTL_DSP_GETCAPS: + return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg); @@ -15083,7 +11597,7 @@ + { + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; -+ ++ + //unused fragment amount + spin_lock_irqsave(&controller->ioctllock, flags); + jz_audio_fragments = elements_in_queue(&out_empty_queue); @@ -15099,8 +11613,8 @@ + } + case SNDCTL_DSP_GETISPACE: + if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ ++ return -EINVAL; ++ + bytes = 0; + //unused fragment amount + jz_audio_fragments = elements_in_queue(&in_empty_queue); @@ -15111,7 +11625,7 @@ + abinfo.fragstotal = jz_audio_fragstotal; + abinfo.fragsize = jz_audio_fragsize; + abinfo.bytes = bytes; -+ return copy_to_user((void *)arg, &abinfo, ++ return copy_to_user((void *)arg, &abinfo, + sizeof(abinfo)) ? -EFAULT : 0; + case SNDCTL_DSP_GETTRIGGER: + val = 0; @@ -15120,7 +11634,7 @@ + if (file->f_mode & FMODE_WRITE && out_dma_buf) + val |= PCM_ENABLE_OUTPUT; + return put_user(val, (int *)arg); -+ ++ + case SNDCTL_DSP_SETTRIGGER: + if (get_user(val, (int *)arg)) + return -EFAULT; @@ -15135,7 +11649,7 @@ + cinfo.ptr = controller->nextIn; + controller->blocks = 0; + spin_unlock_irqrestore(&controller->ioctllock, flags); -+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); ++ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + case SNDCTL_DSP_GETOPTR: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; @@ -15150,14 +11664,14 @@ + case SNDCTL_DSP_GETODELAY: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; -+ ++ + spin_lock_irqsave(&controller->ioctllock, flags); + unfinish = 0; + fullc = elements_in_queue(&out_full_queue); + busyc = elements_in_queue(&out_busy_queue); + for(i = 0;i < fullc ;i ++) { + id = *(out_full_queue.id + i); -+ unfinish += *(out_dma_buf_data_count + id); ++ unfinish += *(out_dma_buf_data_count + id); + } + for(i = 0;i < busyc ;i ++) { + id = *(out_busy_queue.id + i); @@ -15171,7 +11685,7 @@ + case SOUND_PCM_READ_CHANNELS: + return put_user(jz_audio_channels, (int *)arg); + case SOUND_PCM_READ_BITS: -+ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, ++ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, + (int *)arg); + case SNDCTL_DSP_MAPINBUF: + case SNDCTL_DSP_MAPOUTBUF: @@ -15189,13 +11703,13 @@ + struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; + unsigned long flags; + unsigned int mask = 0; -+ ++ + if (file->f_mode & FMODE_WRITE) { + if (elements_in_queue(&out_empty_queue) > 0) + return POLLOUT | POLLWRNORM; + poll_wait(file, &controller->dac_wait, wait); + } -+ ++ + if (file->f_mode & FMODE_READ) { + if (elements_in_queue(&in_full_queue) > 0) + return POLLIN | POLLRDNORM; @@ -15217,10 +11731,10 @@ +{ + struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; + int id, ret = 0, left_count, copy_count, cnt = 0; -+ ++ + if (count < 0) + return -EINVAL; -+ ++ + __i2s_enable_receive_dma(); + __i2s_enable_record(); + //spin_lock_irqsave(&controller->ioctllock, flags); @@ -15228,27 +11742,27 @@ + controller->nextIn = 0; + //spin_unlock_irqrestore(&controller->ioctllock, flags); + spin_unlock(&controller->ioctllock); -+ ++ + spin_lock(&controller->lock); + + copy_count = jz_audio_fragsize / 4; -+ ++ + left_count = count; + spin_unlock(&controller->lock); -+ ++ + if (first_record_call) { + first_record_call = 0; + audio_read_back_first: + if ((id = get_buffer_id(&in_empty_queue)) >= 0) { + put_buffer_id(&in_busy_queue, id); -+ spin_lock(&controller->lock); ++ spin_lock(&controller->lock); + *(in_dma_buf_data_count + id) = copy_count * 4; + spin_unlock(&controller->lock); + __i2s_enable_receive_dma(); + __i2s_enable_record(); -+ ++ + //write back -+ dma_cache_wback_inv(*(in_dma_buf + id), ++ dma_cache_wback_inv(*(in_dma_buf + id), + *(in_dma_buf_data_count + id)); + audio_start_dma(controller->dma2,file->private_data, + *(in_dma_pbuf + id), @@ -15272,13 +11786,13 @@ + return ret ? ret: -ERESTARTSYS; */ + if ((id = get_buffer_id(&in_full_queue)) >= 0) { + spin_lock(&controller->lock); -+ cnt = record_filler((unsigned long)controller->tmp2+ret, ++ cnt = record_filler((unsigned long)controller->tmp2+ret, + copy_count, id); + spin_unlock(&controller->lock); + put_buffer_id(&in_empty_queue, id); + } else + goto audio_read_back_second; -+ ++ + if (elements_in_queue(&in_busy_queue) == 0) { + if ((id=get_buffer_id(&in_empty_queue)) >= 0) { + put_buffer_id(&in_busy_queue, id); @@ -15286,7 +11800,7 @@ + *(in_dma_buf_data_count + id) = copy_count * 4; + spin_unlock(&controller->lock); + //write back -+ dma_cache_wback_inv(*(in_dma_buf + id), ++ dma_cache_wback_inv(*(in_dma_buf + id), + *(in_dma_buf_data_count + id)); + audio_start_dma(controller->dma2,file->private_data, + *(in_dma_pbuf + id), @@ -15327,7 +11841,7 @@ + + __i2s_enable_transmit_dma(); + __i2s_enable_replay(); -+ ++ + spin_lock_irqsave(&controller->ioctllock, flags); + //spin_lock(&controller->ioctllock); + controller->nextOut = 0; @@ -15337,7 +11851,7 @@ + copy_count = jz_audio_fragsize / jz_audio_b; + else if(jz_audio_channels == 1) + copy_count = jz_audio_fragsize / 4; -+ ++ + left_count = count; + if (copy_from_user(controller->tmp1, buffer, count)) { + printk("copy_from_user failed:%d",ret); @@ -15366,13 +11880,13 @@ + replay_filler((signed long)controller->tmp1 + ret, copy_count, id); + if(*(out_dma_buf_data_count + id) > 0) { + put_buffer_id(&out_full_queue, id); //busy in -+ dma_cache_wback_inv(*(out_dma_buf + id), ++ dma_cache_wback_inv(*(out_dma_buf + id), + *(out_dma_buf_data_count + id)); + } else + put_buffer_id(&out_empty_queue, id); //spare + } else + goto audio_write_back; -+ ++ + left_count = left_count - copy_count; + ret += copy_count; + //spin_lock_irqsave(&controller->ioctllock, flags); @@ -15383,7 +11897,7 @@ + if (elements_in_queue(&out_busy_queue) == 0) { + if ((id = get_buffer_id(&out_full_queue)) >= 0) { + put_buffer_id(&out_busy_queue, id); //first once,next spare -+ ++ + if(*(out_dma_buf_data_count + id) > 0) { + audio_start_dma(controller->dma1, + file->private_data, @@ -15409,2987 +11923,2987 @@ --- linux-2.6.24.7.old/sound/oss/jz_i2s_for_4750.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7/sound/oss/jz_i2s_for_4750.c 2009-04-12 18:13:57.000000000 +0200 @@ -0,0 +1,2981 @@ -+/* -+ * linux/drivers/sound/Jz_i2s.c -+ * -+ * JzSOC On-Chip I2S audio driver. -+ * -+ * Copyright (C) 2005 by Junzheng Corp. -+ * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using -+ * dma channel 4&3,noah is tested. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Because the normal application of AUDIO devices are focused on Little_endian, -+ * then we only perform the little endian data format in driver. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "sound_config.h" -+ -+#define DPRINTK(args...) printk(args) -+#define DMA_ID_I2S_TX DMA_ID_AIC_TX -+#define DMA_ID_I2S_RX DMA_ID_AIC_RX -+#define NR_I2S 2 -+#define MAXDELAY 50000 -+#define JZCODEC_RW_BUFFER_SIZE 2 -+#define JZCODEC_RW_BUFFER_TOTAL 6 -+ -+typedef struct hpvol_shift_s -+{ -+ int hpvol; -+ int shift; -+} hpvol_shift_t; -+ -+mixer_info info; -+_old_mixer_info old_info; -+int codec_volue_shift; -+hpvol_shift_t hpvol_shift_table[72]; -+int abnormal_data_count; -+unsigned long i2s_clk; -+ -+void (*set_codec_mode)(void) = NULL; -+void (*clear_codec_mode)(void) = NULL; -+void (*set_codec_gpio_pin)(void) = NULL; -+void (*each_time_init_codec)(void) = NULL; -+int (*set_codec_startup_param)(void) = NULL; -+void (*set_codec_volume_table)(void) = NULL; -+void (*set_codec_record)(void) = NULL; -+void (*set_codec_replay)(void) = NULL; -+void (*set_codec_replay_record)(void); -+void (*turn_on_codec)(void) = NULL; -+void (*turn_off_codec)(void) = NULL; -+void (*set_codec_speed)(int rate) = NULL; -+void (*reset_codec)(void) = NULL; -+void (*codec_mixer_old_info_id_name)(void) = NULL; -+void (*codec_mixer_info_id_name)(void) = NULL; -+void (*set_codec_bass)(int val) = NULL; -+void (*set_codec_volume)(int val) = NULL; -+void (*set_codec_mic)(int val) = NULL; -+void (*i2s_resume_codec)(void) = NULL; -+void (*i2s_suspend_codec)(int wr,int rd) = NULL; -+void (*init_codec_pin)(void) = NULL; -+void (*set_codec_some_func)(void) = NULL; -+void (*clear_codec_record)(void) = NULL; -+void (*clear_codec_replay)(void) = NULL; -+void (*set_replay_hp_or_speaker)(void) = NULL; -+void (*set_codec_direct_mode)(void) = NULL; -+void (*clear_codec_direct_mode)(void) = NULL; -+ -+static int jz_audio_rate; -+static int jz_audio_format; -+static int jz_audio_volume; -+static int jz_audio_channels; -+static int jz_audio_b; /* bits expand multiple */ -+static int jz_audio_fragments; /* unused fragment amount */ -+static int jz_audio_fragstotal; -+static int jz_audio_fragsize; -+static int jz_audio_speed; -+ -+static int codec_bass_gain; -+static int audio_mix_modcnt; -+static int jz_audio_dma_tran_count; /* bytes count of one DMA transfer */ -+static int jz_mic_only = 1; -+static int jz_codec_config = 0; -+static unsigned long ramp_up_start; -+static unsigned long ramp_up_end; -+static unsigned long gain_up_start; -+static unsigned long gain_up_end; -+static unsigned long ramp_down_start; -+static unsigned long ramp_down_end; -+static unsigned long gain_down_start; -+static unsigned long gain_down_end; -+ -+static int codec_mic_gain; -+static int pop_dma_flag; -+static int last_dma_buffer_id; -+static int drain_flag; -+ -+static void (*old_mksound)(unsigned int hz, unsigned int ticks); -+extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); -+static void jz_update_filler(int bits, int channels); -+ -+static int Init_In_Out_queue(int fragstotal,int fragsize); -+static int Free_In_Out_queue(int fragstotal,int fragsize); -+static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref); -+static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref); -+static void (*replay_filler)(signed long src_start, int count, int id); -+static int (*record_filler)(unsigned long dst_start, int count, int id); -+#if defined(CONFIG_I2S_ICODEC) -+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample); -+#endif -+static void jz_audio_reset(void); -+static struct file_operations jz_i2s_audio_fops; -+ -+static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (drain_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue); -+ -+struct jz_i2s_controller_info -+{ -+ int io_base; -+ int dma1; /* for play */ -+ int dma2; /* for record */ -+ char *name; -+ int dev_audio; -+ struct i2s_codec *i2s_codec[NR_I2S]; -+ int opened1; -+ int opened2; -+ unsigned char *tmp1; /* tmp buffer for sample conversions */ -+ unsigned char *tmp2; -+ spinlock_t lock; -+ spinlock_t ioctllock; -+ -+ wait_queue_head_t dac_wait; -+ wait_queue_head_t adc_wait; -+ int nextIn; /* byte index to next-in to DMA buffer */ -+ int nextOut; /* byte index to next-out from DMA buffer */ -+ int count; /* current byte count in DMA buffer */ -+ int finish; /* current transfered byte count in DMA buffer */ -+ unsigned total_bytes; /* total bytes written or read */ -+ unsigned blocks; -+ unsigned error; /* over/underrun */ -+#ifdef CONFIG_PM -+ struct pm_dev *pm; -+#endif -+}; -+ -+ -+static struct jz_i2s_controller_info *i2s_controller = NULL; -+struct i2s_codec -+{ -+ /* I2S controller connected with */ -+ void *private_data; -+ char *name; -+ int id; -+ int dev_mixer; -+ /* controller specific lower leverl i2s accessing routines */ -+ u16 (*codec_read) (u8 reg); /* the function accessing Codec REGs */ -+ void (*codec_write) (u8 reg, u16 val); -+ /* Wait for codec-ready */ -+ void (*codec_wait) (struct i2s_codec *codec); -+ /* OSS mixer masks */ -+ int modcnt; -+ int supported_mixers; -+ int stereo_mixers; -+ int record_sources; -+ int bit_resolution; -+ /* OSS mixer interface */ -+ int (*read_mixer) (struct i2s_codec *codec, int oss_channel); -+ void (*write_mixer)(struct i2s_codec *codec, int oss_channel, -+ unsigned int left, unsigned int right); -+ int (*recmask_io) (struct i2s_codec *codec, int rw, int mask); -+ int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg); -+ /* saved OSS mixer states */ -+ unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; -+}; -+ -+ -+typedef struct buffer_queue_s -+{ -+ int count; -+ int *id; -+ int lock; -+} buffer_queue_t; -+ -+typedef struct left_right_sample_s -+{ -+ signed long left; -+ signed long right; -+} left_right_sample_t; -+ -+static unsigned long pop_turn_onoff_buf; -+static unsigned long pop_turn_onoff_pbuf; -+ -+static unsigned long *out_dma_buf = NULL; -+static unsigned long *out_dma_pbuf = NULL; -+static unsigned long *out_dma_buf_data_count = NULL; -+static unsigned long *in_dma_buf = NULL; -+static unsigned long *in_dma_pbuf = NULL; -+static unsigned long *in_dma_buf_data_count = NULL; -+ -+static buffer_queue_t out_empty_queue; -+static buffer_queue_t out_full_queue; -+static buffer_queue_t out_busy_queue; -+static buffer_queue_t in_empty_queue; -+static buffer_queue_t in_full_queue; -+static buffer_queue_t in_busy_queue; -+static int first_record_call = 0; -+ -+static left_right_sample_t save_last_samples[64]; -+static int read_codec_file(int addr) -+{ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ mdelay(1); -+ return(__icdc_get_value()); -+} -+ -+static void printk_codec_files(void) -+{ -+ int cnt; -+ -+ printk("\n"); -+ -+ printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR); -+ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR); -+ printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR); -+ printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR); -+ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR); -+ printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR); -+ printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR); -+ printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA); -+ -+ for (cnt = 0; cnt <= 27 ; cnt++) { -+ printk(" ( %d : 0x%x ) ",cnt ,read_codec_file(cnt)); -+ } -+ printk("\n"); -+} -+ -+static void write_codec_file(int addr, int val) -+{ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ __icdc_set_cmd(val); /* write */ -+ mdelay(1); -+ __icdc_set_rgwr(); -+ mdelay(1); -+} -+ -+static int write_codec_file_bit(int addr, int bitval, int mask_bit) -+{ -+ int val; -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ mdelay(1); -+ val = __icdc_get_value(); /* read */ -+ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ val &= ~(1 << mask_bit); -+ if (bitval == 1) -+ val |= 1 << mask_bit; -+ -+ __icdc_set_cmd(val); /* write */ -+ mdelay(1); -+ __icdc_set_rgwr(); -+ mdelay(1); -+ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ val = __icdc_get_value(); /* read */ -+ -+ if (((val >> mask_bit) & bitval) == bitval) -+ return 1; -+ else -+ return 0; -+} -+ -+/* set Audio data replay */ -+static void set_audio_data_replay() -+{ -+ /* DAC path */ -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ mdelay(10); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ //mdelay(100); -+ //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //mdelay(300); -+} -+ -+/* unset Audio data replay */ -+static void unset_audio_data_replay(void) -+{ -+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ //mdelay(800); -+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ //mdelay(800); -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 4);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+/* set Record MIC input audio without playback */ -+static void set_record_mic_input_audio_without_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 1; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ mdelay(10); -+ write_codec_file_bit(1, 1, 2); -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ -+ write_codec_file(22, 0x40);//mic 1 -+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ //write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file(1, 0x4); -+} -+ -+/* unset Record MIC input audio without playback */ -+static void unset_record_mic_input_audio_without_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 0; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+/* set Record LINE input audio without playback */ -+static void set_record_line_input_audio_without_playback(void) -+{ -+ /* ADC path for LINE IN */ -+ jz_mic_only = 1; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ write_codec_file(22, 0xf6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ mdelay(10); -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file(1, 0x4); -+} -+ -+/* unset Record LINE input audio without playback */ -+static void unset_record_line_input_audio_without_playback(void) -+{ -+ /* ADC path for LINE IN */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1 -+ -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+/* set Playback LINE input audio direct only */ -+static void set_playback_line_input_audio_direct_only() -+{ -+ jz_audio_reset();//or init_codec() -+ REG_AIC_I2SCR = 0x10; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ write_codec_file(22, 0xf6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ mdelay(10); -+ write_codec_file_bit(1, 1, 2);//CR1.HP_BYPASS->1 -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ //write_codec_file_bit(5, 1, 7);//PMR1.SB_DAC->1 -+ //write_codec_file_bit(5, 1, 4);//PMR1.SB_ADC->1 -+} -+ -+/* unset Playback LINE input audio direct only */ -+static void unset_playback_line_input_audio_direct_only() -+{ -+ write_codec_file_bit(6, 0, 3);//GIM->0 -+ write_codec_file_bit(1, 0, 2);//PMR1.BYPASS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LINE->1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ mdelay(100); -+ write_codec_file_bit(5, 1, 5);//PMR1.SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+/* set Record MIC input audio with direct playback */ -+static void set_record_mic_input_audio_with_direct_playback(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ jz_mic_only = 0; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ -+ write_codec_file(22, 0x60);//mic 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ //write_codec_file(1, 0x4); -+} -+ -+/* unset Record MIC input audio with direct playback */ -+static void unset_record_mic_input_audio_with_direct_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 0; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+/* set Record playing audio mixed with MIC input audio */ -+static void set_record_playing_audio_mixed_with_mic_input_audio(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ mdelay(10); -+ -+ write_codec_file(22, 0x63);//mic 1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ write_codec_file_bit(5, 0, 4);//PMR1.SB_MIX->0 -+} -+ -+/* unset Record playing audio mixed with MIC input audio */ -+static void unset_record_playing_audio_mixed_with_mic_input_audio(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+/* set Record MIC input audio with Audio data replay (full duplex) */ -+static void set_record_mic_input_audio_with_audio_data_replay(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+} -+ -+/* unset Record MIC input audio with Audio data replay (full duplex) */ -+static void unset_record_mic_input_audio_with_audio_data_replay(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+///////// -+/* set Record LINE input audio with Audio data replay (full duplex for linein) */ -+static void set_record_line_input_audio_with_audio_data_replay(void) -+{ -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ -+ -+ //jz_mic_only = 1; -+ write_codec_file(22, 0xc6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+} -+ -+/* unset Record LINE input audio with Audio data replay (full duplex for linein) */ -+static void unset_record_line_input_audio_with_audio_data_replay(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+///////// -+static inline int get_buffer_id(struct buffer_queue_s *q) -+{ -+ int r; -+ unsigned long flags; -+ int i; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ if (q->count == 0) { -+ spin_unlock_irqrestore(&q->lock, flags); -+ return -1; -+ } -+ r = *(q->id + 0); -+ for (i=0;i < q->count-1;i++) -+ *(q->id + i) = *(q->id + (i+1)); -+ q->count --; -+ spin_unlock_irqrestore(&q->lock, flags); -+ -+ return r; -+} -+ -+static inline void put_buffer_id(struct buffer_queue_s *q, int id) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ *(q->id + q->count) = id; -+ q->count ++; -+ spin_unlock_irqrestore(&q->lock, flags); -+} -+ -+static inline int elements_in_queue(struct buffer_queue_s *q) -+{ -+ int r; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ r = q->count; -+ spin_unlock_irqrestore(&q->lock, flags); -+ -+ return r; -+} -+ -+static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode) -+{ -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ jz_audio_dma_tran_count = count / jz_audio_b; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ flags = claim_dma_lock(); -+ disable_dma(chan); -+ clear_dma_ff(chan); -+ //set_dma_mode(chan, mode); -+ jz_set_oss_dma(chan, mode, jz_audio_format); -+ set_dma_addr(chan, phyaddr); -+ if (count == 0) { -+ count++; -+ printk("JzSOC DMA controller can't set dma 0 count!\n"); -+ } -+ set_dma_count(chan, count); -+ enable_dma(chan); -+ release_dma_lock(flags); -+} -+ -+static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id) -+{ -+ int id1, id2; -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ int dma = controller->dma2; -+ -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ -+ if(drain_flag == 1) -+ wake_up(&drain_wait_queue); -+ /* for DSP_GETIPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ id1 = get_buffer_id(&in_busy_queue); -+ put_buffer_id(&in_full_queue, id1); -+ -+ wake_up(&rx_wait_queue); -+ wake_up(&controller->adc_wait); -+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id2); -+ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1); -+ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2)); -+ audio_start_dma(dma,dev_id, -+ *(in_dma_pbuf + id2), -+ *(in_dma_buf_data_count + id2), -+ DMA_MODE_READ); -+ } else -+ in_busy_queue.count = 0; -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id) -+{ -+ int id; -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ int dma = controller->dma1; -+ -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ -+ if(pop_dma_flag == 1) { -+ pop_dma_flag = 0; -+ wake_up(&pop_wait_queue); -+ } else { -+ if(drain_flag == 1) { -+ /* Is replay dma buffer over ? */ -+ if(elements_in_queue(&out_full_queue) <= 0) { -+ drain_flag = 0; -+ wake_up(&drain_wait_queue); -+ } -+ } -+ -+ /* for DSP_GETOPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ if ((id = get_buffer_id(&out_busy_queue)) < 0) -+ printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n"); -+ put_buffer_id(&out_empty_queue, id); -+ if ((id = get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_busy_queue, id); -+ if(*(out_dma_buf_data_count + id) > 0) { -+ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id), -+ *(out_dma_buf_data_count + id), -+ DMA_MODE_WRITE); -+ last_dma_buffer_id = id; -+ } -+ } else -+ out_busy_queue.count = 0; -+ -+ if (elements_in_queue(&out_empty_queue) > 0) { -+ wake_up(&tx_wait_queue); -+ wake_up(&controller->dac_wait); -+ } -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static void jz_i2s_initHw(int set) -+{ -+#if defined(CONFIG_MIPS_JZ_URANUS) -+ i2s_clk = 48000000; -+#else -+ i2s_clk = __cpm_get_i2sclk(); -+#endif -+ __i2s_disable(); -+ if(set) -+ __i2s_reset(); -+ schedule_timeout(5); -+ if(each_time_init_codec) -+ each_time_init_codec(); -+ __i2s_disable_record(); -+ __i2s_disable_replay(); -+ __i2s_disable_loopback(); -+ __i2s_set_transmit_trigger(4); -+ __i2s_set_receive_trigger(3); -+} -+ -+static int Init_In_Out_queue(int fragstotal,int fragsize) -+{ -+ int i; -+ -+ /* recording */ -+ in_empty_queue.count = fragstotal; -+ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_buf) -+ goto all_mem_err; -+ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_pbuf) -+ goto all_mem_err; -+ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_buf_data_count) -+ goto all_mem_err; -+ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_empty_queue.id) -+ goto all_mem_err; -+ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_full_queue.id) -+ goto all_mem_err; -+ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_busy_queue.id) -+ goto all_mem_err; -+ -+ for (i=0;i < fragstotal;i++) -+ *(in_empty_queue.id + i) = i; -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ -+ for (i = 0; i < fragstotal; i++) { -+ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); -+ if (*(in_dma_buf + i) == 0) -+ goto mem_failed_in; -+ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i))); -+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); -+ } -+ -+ /* playing */ -+ out_empty_queue.count = fragstotal; -+ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!out_dma_buf) -+ goto all_mem_err; -+ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!out_dma_pbuf) -+ goto all_mem_err; -+ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ -+ if (!out_dma_buf_data_count) -+ goto all_mem_err; -+ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_empty_queue.id) -+ goto all_mem_err; -+ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_full_queue.id) -+ goto all_mem_err; -+ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_busy_queue.id) -+ goto all_mem_err; -+ for (i=0;i < fragstotal;i++) -+ *(out_empty_queue.id + i) = i; -+ -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ /* alloc DMA buffer */ -+ for (i = 0; i < fragstotal; i++) { -+ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); -+ if (*(out_dma_buf + i) == 0) { -+ printk(" can't allocate required DMA(OUT) buffers.\n"); -+ goto mem_failed_out; -+ } -+ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); -+ } -+ -+ return 1; -+all_mem_err: -+ printk("error:allocate memory occur error 1!\n"); -+ return 0; -+mem_failed_out: -+ printk("error:allocate memory occur error 2!\n"); -+ for (i = 0; i < fragstotal; i++) { -+ if(*(out_dma_buf + i)) -+ free_pages(*(out_dma_buf + i), get_order(fragsize)); -+ } -+ -+ return 0; -+mem_failed_in: -+ printk("error:allocate memory occur error 3!\n"); -+ for (i = 0; i < fragstotal; i++) { -+ if(*(in_dma_buf + i)) -+ free_pages(*(in_dma_buf + i), get_order(fragsize)); -+ } -+ return 0; -+} -+ -+static int Free_In_Out_queue(int fragstotal,int fragsize) -+{ -+ int i; -+ /* playing */ -+ if(out_dma_buf != NULL) { -+ for (i = 0; i < fragstotal; i++) { -+ if(*(out_dma_buf + i)) -+ free_pages(*(out_dma_buf + i), get_order(fragsize)); -+ *(out_dma_buf + i) = 0; -+ } -+ kfree(out_dma_buf); -+ out_dma_buf = NULL; -+ } -+ if(out_dma_pbuf) { -+ kfree(out_dma_pbuf); -+ out_dma_pbuf = NULL; -+ } -+ if(out_dma_buf_data_count) { -+ kfree(out_dma_buf_data_count); -+ out_dma_buf_data_count = NULL; -+ } -+ if(out_empty_queue.id) { -+ kfree(out_empty_queue.id); -+ out_empty_queue.id = NULL; -+ } -+ if(out_full_queue.id) { -+ kfree(out_full_queue.id); -+ out_full_queue.id = NULL; -+ } -+ if(out_busy_queue.id) { -+ kfree(out_busy_queue.id); -+ out_busy_queue.id = NULL; -+ } -+ out_empty_queue.count = fragstotal; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ -+ /* recording */ -+ if(in_dma_buf) { -+ for (i = 0; i < fragstotal; i++) { -+ if(*(in_dma_buf + i)) { -+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); -+ free_pages(*(in_dma_buf + i), get_order(fragsize)); -+ } -+ *(in_dma_buf + i) = 0; -+ } -+ kfree(in_dma_buf); -+ in_dma_buf = NULL; -+ } -+ if(in_dma_pbuf) { -+ kfree(in_dma_pbuf); -+ in_dma_pbuf = NULL; -+ } -+ if(in_dma_buf_data_count) { -+ kfree(in_dma_buf_data_count); -+ in_dma_buf_data_count = NULL; -+ } -+ if(in_empty_queue.id) { -+ kfree(in_empty_queue.id); -+ in_empty_queue.id = NULL; -+ } -+ if(in_full_queue.id) { -+ kfree(in_full_queue.id); -+ in_full_queue.id = NULL; -+ } -+ if(in_busy_queue.id) { -+ kfree(in_busy_queue.id); -+ in_busy_queue.id = NULL; -+ } -+ -+ in_empty_queue.count = fragstotal; -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ -+ return 1; -+} -+ -+static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller) -+{ -+ jz_i2s_initHw(0); -+} -+ -+static int jz_audio_set_speed(int dev, int rate) -+{ -+ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */ -+ jz_audio_speed = rate; -+ if (rate > 48000) -+ rate = 48000; -+ if (rate < 8000) -+ rate = 8000; -+ jz_audio_rate = rate; -+ -+ if(set_codec_speed) -+ set_codec_speed(rate); -+ -+ return jz_audio_rate; -+} -+ -+ -+static int record_fill_1x8_u(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long data; -+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ volatile unsigned char *dp = (unsigned char*)dst_start; -+ -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt++; -+ data = *(s++); -+ *(dp ++) = ((data << 16) >> 24) + 0x80; -+ s++; /* skip the other channel */ -+ } -+ -+ return cnt; -+} -+ -+ -+static int record_fill_2x8_u(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1, d2; -+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ volatile unsigned char *dp = (unsigned char*)dst_start; -+ -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ *(dp ++) = ((d1 << 16) >> 24) + 0x80; -+ d2 = *(s++); -+ *(dp ++) = ((d2 << 16) >> 24) + 0x80; -+ } -+ -+ return cnt; -+} -+ -+ -+static int record_fill_1x16_s(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1; -+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ unsigned short *dp = (unsigned short *)dst_start; -+ -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt += 2; /* count in byte */ -+ d1 = *(s++); -+ *(dp ++) = (d1 << 16) >> 16; -+ s++; /* skip the other channel */ -+ } -+ -+ return cnt; -+} -+ -+ -+static int record_fill_2x16_s(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1, d2; -+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ unsigned short *dp = (unsigned short *)dst_start; -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt += 4; /* count in byte */ -+ d1 = *(s++); -+ d2 = *(s++); -+ if(abnormal_data_count > 0) { -+ d1 = d2 = 0; -+ abnormal_data_count --; -+ } -+ *(dp ++) = (d1 << 16) >> 16; -+ *(dp ++) = (d2 << 16) >> 16; -+ } -+ -+ return cnt; -+} -+ -+static void replay_fill_1x8_u(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned char data; -+ unsigned long ddata; -+ volatile unsigned char *s = (unsigned char *)src_start; -+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count--; -+ cnt += 1; -+ data = *(s++) - 0x80; -+ ddata = (unsigned long) data << 8; -+ *(dp ++) = ddata; -+ *(dp ++) = ddata; -+ -+ /* save last left and right */ -+ if(count == 1) { -+ save_last_samples[id].left = ddata; -+ save_last_samples[id].right = ddata; -+ } -+ } -+ cnt = cnt * 2 * jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+ -+static void replay_fill_2x8_u(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned char d1; -+ unsigned long dd1; -+ volatile unsigned char *s = (unsigned char *)src_start; -+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count -= 1; -+ cnt += 1 ; -+ d1 = *(s++) - 0x80; -+ dd1 = (unsigned long) d1 << 8; -+ *(dp ++) = dd1; -+ /* save last left */ -+ if(count == 2) -+ save_last_samples[id].left = dd1; -+ /* save last right */ -+ if(count == 1) -+ save_last_samples[id].right = dd1; -+ } -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+ -+static void replay_fill_1x16_s(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed short d1; -+ signed long l1; -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count -= 2; -+ cnt += 2 ; -+ d1 = *(s++); -+ l1 = (signed long)d1; -+ *(dp ++) = l1; -+ *(dp ++) = l1; -+ -+ /* save last left and right */ -+ if(count == 1) { -+ save_last_samples[id].left = l1; -+ save_last_samples[id].right = l1; -+ } -+ } -+ cnt = cnt * 2 * jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+#if 0 -+static void replay_fill_2x16_s(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed short d1; -+ signed long l1; -+ int mute_cnt = 0; -+ signed long tmp1,tmp2; -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+#if defined(CONFIG_I2S_ICDC) -+ volatile signed long *before_dp; -+ int sam_rate = jz_audio_rate / 20; -+ -+ tmp1 = tmp2 = 0; -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ -+ l1 = (signed long)d1; -+ l1 >>= codec_volue_shift; -+ -+ if(l1 == 0) { -+ mute_cnt ++; -+ if(mute_cnt >= sam_rate) { -+ before_dp = dp - 10; -+ *(before_dp) = (signed long)1; -+ before_dp = dp - 11; -+ *(before_dp) = (signed long)1; -+ mute_cnt = 0; -+ } -+ } else -+ mute_cnt = 0; -+ -+ *(dp ++) = l1; -+ -+ tmp1 = tmp2; -+ tmp2 = l1; -+ } -+ -+ /* save last left */ -+ save_last_samples[id].left = tmp1; -+ /* save last right */ -+ save_last_samples[id].right = tmp2; -+#endif -+#if defined(CONFIG_I2S_DLV) -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ -+ l1 = (signed long)d1; -+ -+ *(dp ++) = l1; -+ } -+#endif -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+#else -+static void replay_fill_2x16_s(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed short d1; -+ signed long l1; -+ int mute_cnt = 0; -+ signed long tmp1,tmp2; -+ -+#if 0 -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed short *dp = (signed short*)(*(out_dma_buf + id)); -+ memcpy((char*)dp, (char*)s, count); -+ *(out_dma_buf_data_count + id) = count; -+#else -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ -+ l1 = (signed long)d1; -+ -+ *(dp ++) = l1; -+ } -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+#endif -+} -+#endif -+ -+ -+static unsigned int jz_audio_set_format(int dev, unsigned int fmt) -+{ -+ switch (fmt) { -+ case AFMT_U8: -+ __i2s_set_oss_sample_size(8); -+ __i2s_set_iss_sample_size(8); -+ jz_audio_format = fmt; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+ break; -+ case AFMT_S16_LE: -+#if defined(CONFIG_I2S_DLV) -+ /* DAC path and ADC path */ -+ write_codec_file(2, 0x00); -+ //write_codec_file(2, 0x60); -+#endif -+ jz_audio_format = fmt; -+ jz_update_filler(jz_audio_format,jz_audio_channels); -+ /* print all files */ -+ __i2s_set_oss_sample_size(16); -+ __i2s_set_iss_sample_size(16); -+ break; -+ -+ case AFMT_QUERY: -+ break; -+ } -+ -+ return jz_audio_format; -+} -+ -+ -+static short jz_audio_set_channels(int dev, short channels) -+{ -+ switch (channels) { -+ case 1: -+ if(set_codec_some_func) -+ set_codec_some_func(); -+ jz_audio_channels = channels; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono -+#endif -+ break; -+ case 2: -+ jz_audio_channels = channels; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo -+#endif -+ break; -+ case 0: -+ break; -+ } -+ -+ return jz_audio_channels; -+} -+ -+static void init_codec(void) -+{ -+ /* inititalize internal I2S codec */ -+ if(init_codec_pin) -+ init_codec_pin(); -+ -+#if defined(CONFIG_I2S_ICDC) -+ /* initialize AIC but not reset it */ -+ jz_i2s_initHw(0); -+#endif -+ if(reset_codec) -+ reset_codec(); -+} -+ -+static void jz_audio_reset(void) -+{ -+ __i2s_disable_replay(); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+ __i2s_disable_transmit_dma(); -+#if defined(CONFIG_I2S_DLV) -+ REG_AIC_I2SCR = 0x10; -+#endif -+ init_codec(); -+} -+ -+static int jz_audio_release(struct inode *inode, struct file *file); -+static int jz_audio_open(struct inode *inode, struct file *file); -+static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg); -+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait); -+static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos); -+static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos); -+ -+/* static struct file_operations jz_i2s_audio_fops */ -+static struct file_operations jz_i2s_audio_fops = -+{ -+ owner: THIS_MODULE, -+ open: jz_audio_open, -+ release: jz_audio_release, -+ write: jz_audio_write, -+ read: jz_audio_read, -+ poll: jz_audio_poll, -+ ioctl: jz_audio_ioctl -+}; -+ -+static int jz_i2s_open_mixdev(struct inode *inode, struct file *file) -+{ -+ int i; -+ int minor = MINOR(inode->i_rdev); -+ struct jz_i2s_controller_info *controller = i2s_controller; -+ -+ for (i = 0; i < NR_I2S; i++) -+ if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor) -+ goto match; -+ -+ if (!controller) -+ return -ENODEV; -+match: -+ file->private_data = controller->i2s_codec[i]; -+ -+ return 0; -+} -+ -+static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ struct i2s_codec *codec = (struct i2s_codec *)file->private_data; -+ return codec->mixer_ioctl(codec, cmd, arg); -+} -+ -+static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin) -+{ -+ return -ESPIPE; -+} -+ -+static struct file_operations jz_i2s_mixer_fops = -+{ -+ owner: THIS_MODULE, -+ llseek: jz_i2s_llseek, -+ ioctl: jz_i2s_ioctl_mixdev, -+ open: jz_i2s_open_mixdev, -+}; -+ -+static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg) -+{ -+ int ret; -+ long val = 0; -+ switch (cmd) { -+ case SOUND_MIXER_INFO: -+ -+ if(codec_mixer_info_id_name) -+ codec_mixer_info_id_name(); -+ info.modify_counter = audio_mix_modcnt; -+ -+ return copy_to_user((void *)arg, &info, sizeof(info)); -+ case SOUND_OLD_MIXER_INFO: -+ -+ if(codec_mixer_old_info_id_name) -+ codec_mixer_old_info_id_name(); -+ -+ return copy_to_user((void *)arg, &old_info, sizeof(info)); -+ case SOUND_MIXER_READ_STEREODEVS: -+ -+ return put_user(0, (long *) arg); -+ case SOUND_MIXER_READ_CAPS: -+ -+ val = SOUND_CAP_EXCL_INPUT; -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_READ_DEVMASK: -+ break; -+ case SOUND_MIXER_READ_RECMASK: -+ break; -+ case SOUND_MIXER_READ_RECSRC: -+ break; -+ case SOUND_MIXER_WRITE_SPEAKER: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ switch(val) { -+ case 100: -+ if(set_codec_direct_mode) -+ set_codec_direct_mode(); -+ break; -+ case 0: -+ if(clear_codec_direct_mode) -+ clear_codec_direct_mode(); -+ break; -+ } -+ break; -+ case SOUND_MIXER_WRITE_BASS: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ codec_bass_gain = val; -+ if(set_codec_bass) -+ set_codec_bass(val); -+ -+ return 0; -+ case SOUND_MIXER_READ_BASS: -+ -+ val = codec_bass_gain; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_WRITE_VOLUME: -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ if (val > 31) -+ val = 31; -+ jz_audio_volume = val; -+ -+ if(set_codec_volume) -+ set_codec_volume(val); -+ return 0; -+ case SOUND_MIXER_READ_VOLUME: -+ -+ val = jz_audio_volume; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_WRITE_MIC: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ codec_mic_gain = val; -+ if(set_codec_mic) -+ set_codec_mic(val); -+ -+ return 0; -+ case SOUND_MIXER_READ_MIC: -+ -+ val = codec_mic_gain; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ default: -+ return -ENOSYS; -+ } -+ audio_mix_modcnt ++; -+ return 0; -+} -+ -+ -+int i2s_probe_codec(struct i2s_codec *codec) -+{ -+ /* generic OSS to I2S wrapper */ -+ codec->mixer_ioctl = i2s_mixer_ioctl; -+ return 1; -+} -+ -+ -+/* I2S codec initialisation. */ -+static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller) -+{ -+ int num_i2s = 0; -+ struct i2s_codec *codec; -+ -+ for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) { -+ if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL) -+ return -ENOMEM; -+ memset(codec, 0, sizeof(struct i2s_codec)); -+ codec->private_data = controller; -+ codec->id = num_i2s; -+ -+ if (i2s_probe_codec(codec) == 0) -+ break; -+ if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) { -+ printk(KERN_ERR "Jz I2S: couldn't register mixer!\n"); -+ kfree(codec); -+ break; -+ } -+ controller->i2s_codec[num_i2s] = codec; -+ } -+ return num_i2s; -+} -+ -+ -+static void jz_update_filler(int format, int channels) -+{ -+#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) -+ -+ switch (TYPE(format, channels)) -+ { -+ -+ case TYPE(AFMT_U8, 1): -+ jz_audio_b = 4; /* 4bytes * 8bits =32bits */ -+ replay_filler = replay_fill_1x8_u; -+ record_filler = record_fill_1x8_u; -+ break; -+ case TYPE(AFMT_U8, 2): -+ jz_audio_b = 4; -+ replay_filler = replay_fill_2x8_u; -+ record_filler = record_fill_2x8_u; -+ break; -+ case TYPE(AFMT_S16_LE, 1): -+ jz_audio_b = 2; /* 2bytes * 16bits =32bits */ -+ replay_filler = replay_fill_1x16_s; -+ record_filler = record_fill_1x16_s; -+ break; -+ case TYPE(AFMT_S16_LE, 2): -+ jz_audio_b = 2; -+ replay_filler = replay_fill_2x16_s; -+ record_filler = record_fill_2x16_s; -+ break; -+ default: -+ ; -+ } -+} -+ -+ -+#ifdef CONFIG_PROC_FS -+extern struct proc_dir_entry *proc_jz_root; -+int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) -+{ -+ return 0; -+} -+ -+static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller) -+{ -+ if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0])) -+ return -EIO; -+ return 0; -+} -+ -+static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller) -+{ -+} -+#endif -+ -+static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller) -+{ -+ char *name; -+ int adev; /* No of Audio device. */ -+ -+ name = controller->name; -+ /* initialize AIC controller and reset it */ -+ jz_i2s_initHw(1); -+ adev = register_sound_dsp(&jz_i2s_audio_fops, -1); -+ if (adev < 0) -+ goto audio_failed; -+ /* initialize I2S codec and register /dev/mixer */ -+ if (jz_i2s_codec_init(controller) <= 0) -+ goto mixer_failed; -+ -+#ifdef CONFIG_PROC_FS -+ if (jz_i2s_init_proc(controller) < 0) { -+ printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name); -+ goto proc_failed; -+ } -+#endif -+ -+ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8); -+ if (!controller->tmp1) { -+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); -+ goto tmp1_failed; -+ } -+ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8); -+ if (!controller->tmp2) { -+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); -+ goto tmp2_failed; -+ } -+ if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) { -+ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name); -+ goto dma2_failed; -+ } -+ if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) { -+ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name); -+ goto dma1_failed; -+ } -+ printk("JzSOC On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2)); -+ -+ controller->dev_audio = adev; -+ pop_turn_onoff_buf = __get_free_pages(GFP_KERNEL | GFP_DMA, 8); -+ if(!pop_turn_onoff_buf) -+ printk("pop_turn_onoff_buf alloc is wrong!\n"); -+ pop_turn_onoff_pbuf = virt_to_phys((void *)pop_turn_onoff_buf); -+ -+ return; -+dma2_failed: -+ jz_free_dma(controller->dma1); -+dma1_failed: -+ free_pages((unsigned long)controller->tmp2, 8); -+tmp2_failed: -+ free_pages((unsigned long)controller->tmp1, 8); -+tmp1_failed: -+ -+#ifdef CONFIG_PROC_FS -+ jz_i2s_cleanup_proc(controller); -+#endif -+proc_failed: -+ /* unregister mixer dev */ -+mixer_failed: -+ unregister_sound_dsp(adev); -+audio_failed: -+ return; -+} -+ -+static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller) -+{ -+ if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info), -+ GFP_KERNEL)) == NULL) { -+ printk(KERN_ERR "Jz I2S Controller: out of memory.\n"); -+ return -ENOMEM; -+ } -+ (*controller)->name = "Jz I2S controller"; -+ (*controller)->opened1 = 0; -+ (*controller)->opened2 = 0; -+ init_waitqueue_head(&(*controller)->adc_wait); -+ init_waitqueue_head(&(*controller)->dac_wait); -+ spin_lock_init(&(*controller)->lock); -+ init_waitqueue_head(&rx_wait_queue); -+ init_waitqueue_head(&tx_wait_queue); -+ init_waitqueue_head(&pop_wait_queue); -+ init_waitqueue_head(&drain_wait_queue); -+ -+ return 0; -+} -+ -+static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller) -+{ -+ int adev = controller->dev_audio; -+ -+ jz_i2s_full_reset(controller); -+ controller->dev_audio = -1; -+ if (old_mksound) -+ kd_mksound = old_mksound;/* Our driver support bell for kb, see vt.c */ -+ -+#ifdef CONFIG_PROC_FS -+ jz_i2s_cleanup_proc(controller); -+#endif -+ -+ jz_free_dma(controller->dma1); -+ jz_free_dma(controller->dma2); -+ free_pages((unsigned long)controller->tmp1, 8); -+ free_pages((unsigned long)controller->tmp2, 8); -+ free_pages((unsigned long)pop_turn_onoff_buf, 8); -+ -+ if (adev >= 0) { -+ /* unregister_sound_mixer(audio_devs[adev]->mixer_dev); */ -+ unregister_sound_dsp(controller->dev_audio); -+ } -+} -+ -+#ifdef CONFIG_PM -+static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state) -+{ -+ if(i2s_suspend_codec) -+ i2s_suspend_codec(controller->opened1,controller->opened2); -+ printk("Aic and codec are suspended!\n"); -+ return 0; -+} -+ -+static int jz_i2s_resume(struct jz_i2s_controller_info *controller) -+{ -+ if(i2s_resume_codec) -+ i2s_resume_codec(); -+ -+#if defined(CONFIG_I2S_AK4642EN) -+ jz_i2s_initHw(0); -+ jz_audio_reset(); -+ __i2s_enable(); -+ jz_audio_set_speed(controller->dev_audio,jz_audio_speed); -+ /* playing */ -+ if(controller->opened1) { -+ if(set_codec_replay) -+ set_codec_replay(); -+ int dma = controller->dma1; -+ int id; -+ unsigned long flags; -+ disable_dma(dma); -+ if(__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if(__dmac_channel_transmit_end_detected(dma)) -+ __dmac_channel_clear_transmit_end(dma); -+ -+ /* for DSP_GETOPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ while((id = get_buffer_id(&out_busy_queue)) >= 0) -+ put_buffer_id(&out_empty_queue, id); -+ -+ out_busy_queue.count=0; -+ if((id = get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_empty_queue, id); -+ } -+ if (elements_in_queue(&out_empty_queue) > 0) { -+ wake_up(&tx_wait_queue); -+ wake_up(&controller->dac_wait); -+ } else -+ printk("pm out_empty_queue empty"); -+ } -+ -+ /* recording */ -+ if(controller->opened2) { -+ if(set_codec_record) -+ set_codec_record(); -+ int dma = controller->dma2; -+ int id1, id2; -+ unsigned long flags; -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ } -+ /* for DSP_GETIPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ id1 = get_buffer_id(&in_busy_queue); -+ put_buffer_id(&in_full_queue, id1); -+ wake_up(&rx_wait_queue); -+ wake_up(&controller->adc_wait); -+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_full_queue, id2); -+ } -+ in_busy_queue.count = 0; -+ } -+#endif -+ -+ return 0; -+} -+ -+static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) -+{ -+ int ret; -+ struct jz_i2s_controller_info *controller = pm_dev->data; -+ -+ if (!controller) return -EINVAL; -+ -+ switch (req) { -+ case PM_SUSPEND: -+ ret = jz_i2s_suspend(controller, (int)data); -+ break; -+ case PM_RESUME: -+ ret = jz_i2s_resume(controller); -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+#endif /* CONFIG_PM */ -+static irqreturn_t aic_codec_irq(int irq, void *dev_id) -+{ -+ u8 file_9 = read_codec_file(9); -+ u8 file_8 = read_codec_file(8); -+ -+ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9); -+ if ((file_9 & 0x1f) == 0x10) { -+ -+ write_codec_file(8, 0x3f); -+ write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ mdelay(300); -+ while ((read_codec_file(9) & 0x4) != 0x4); -+ while ((read_codec_file(9) & 0x10) == 0x10) { -+ write_codec_file(9, 0x10); -+ } -+ write_codec_file_bit(5, 0, 6);//SB_OUT->0 -+ mdelay(300); -+ while ((read_codec_file(9) & 0x8) != 0x8); -+ write_codec_file(9, file_9); -+ write_codec_file(8, file_8); -+ -+ return IRQ_HANDLED; -+ } -+ -+ if (file_9 & 0x8) -+ ramp_up_end = jiffies; -+ else if (file_9 & 0x4) -+ ramp_down_end = jiffies; -+ else if (file_9 & 0x2) -+ gain_up_end = jiffies; -+ else if (file_9 & 0x1) -+ gain_down_end = jiffies; -+ -+ write_codec_file(9, file_9); -+ if (file_9 & 0xf) -+ wake_up(&pop_wait_queue); -+ while (REG_ICDC_RGDATA & 0x100); -+ -+ return IRQ_HANDLED; -+} -+ -+static int __init init_jz_i2s(void) -+{ -+ int errno, retval; -+#if defined(CONFIG_I2S_DLV) -+ -+ ramp_up_start = 0; -+ ramp_up_end = 0; -+ gain_up_start = 0; -+ gain_up_end = 0; -+ ramp_down_start = 0; -+ ramp_down_end = 0; -+ gain_down_start = 0; -+ gain_down_end = 0; -+#endif -+ -+ abnormal_data_count = 0; -+ if(set_codec_mode) -+ set_codec_mode(); -+ -+ drain_flag = 0; -+ if ((errno = probe_jz_i2s(&i2s_controller)) < 0) -+ return errno; -+ if(set_codec_gpio_pin) -+ set_codec_gpio_pin(); -+ -+ attach_jz_i2s(i2s_controller); -+ if(set_codec_startup_param) -+ set_codec_startup_param(); -+#if defined(CONFIG_I2S_DLV) -+ jz_codec_config = 0; -+ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL); -+ if (retval) { -+ printk("Could not get aic codec irq %d\n", IRQ_AIC); -+ return retval; -+ } -+#endif -+ if(set_codec_volume_table) -+ set_codec_volume_table(); -+ -+ out_empty_queue.id = NULL; -+ out_full_queue.id = NULL; -+ out_busy_queue.id = NULL; -+ in_empty_queue.id = NULL; -+ in_full_queue.id = NULL; -+ in_busy_queue.id = NULL; -+ -+ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE; -+ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ; -+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ -+#ifdef CONFIG_PM -+ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, -+ jz_i2s_pm_callback); -+ if (i2s_controller->pm) -+ i2s_controller->pm->data = i2s_controller; -+#endif -+ -+#if defined(CONFIG_I2S_DLV) -+ __cpm_start_idct(); -+ __cpm_start_db(); -+ __cpm_start_me(); -+ __cpm_start_mc(); -+ __cpm_start_ipu(); -+#endif -+ -+ printk("JZ I2S OSS audio driver initialized\n"); -+ -+ return 0; -+} -+ -+static void __exit cleanup_jz_i2s(void) -+{ -+#ifdef CONFIG_PM -+ /* pm_unregister(i2s_controller->pm); */ -+#endif -+#if defined(CONFIG_I2S_DLV) -+ free_irq(IRQ_AIC, NULL); -+#endif -+ unload_jz_i2s(i2s_controller); -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ if(clear_codec_mode) -+ clear_codec_mode(); -+} -+ -+module_init(init_jz_i2s); -+module_exit(cleanup_jz_i2s); -+ -+#if defined(CONFIG_SOC_JZ4730) -+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count,con; -+ -+ if(elements_in_queue(&in_busy_queue) > 0) { -+ if (nonblock) -+ return -EBUSY; -+ drain_flag = 1; -+ sleep_on(&drain_wait_queue); -+ drain_flag = 0; -+ } else { -+ add_wait_queue(&ctrl->adc_wait, &wait); -+ for (con = 0; con < 1000; con ++) { -+ udelay(1); -+ set_current_state(TASK_INTERRUPTIBLE); -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ if (nonblock) { -+ remove_wait_queue(&ctrl->adc_wait, &wait); -+ current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ } -+ remove_wait_queue(&ctrl->adc_wait, &wait); -+ current->state = TASK_RUNNING; -+ } -+ return 0; -+} -+ -+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count; -+ -+ if(elements_in_queue(&out_full_queue) > 0) { -+ if (nonblock) -+ return -EBUSY; -+ -+ drain_flag = 1; -+ sleep_on(&drain_wait_queue); -+ drain_flag = 0; -+ } else { -+ add_wait_queue(&(ctrl->dac_wait), &wait); -+ for (;;) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ if(elements_in_queue(&out_full_queue) <= 0) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if(count <= 0) -+ break; -+ } -+ if (nonblock) { -+ remove_wait_queue(&ctrl->dac_wait, &wait); -+ current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ } -+ remove_wait_queue(&ctrl->dac_wait, &wait); -+ current->state = TASK_RUNNING; -+ } -+ -+ return 0; -+} -+#endif -+ -+#if defined(CONFIG_SOC_JZ4750) -+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ //DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count,i=0; -+ -+ //add_wait_queue(&ctrl->adc_wait, &wait); -+ for (;;) { -+ if (i < MAXDELAY) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ //set_current_state(TASK_INTERRUPTIBLE); -+ spin_lock_irqsave(&ctrl->lock, flags); -+ //spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ //spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ -+ /*if (signal_pending(current)) -+ break;*/ -+ if (nonblock) { -+ //remove_wait_queue(&ctrl->adc_wait, &wait); -+ //current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ } -+ //remove_wait_queue(&ctrl->adc_wait, &wait); -+ //current->state = TASK_RUNNING; -+ /*if (signal_pending(current)) -+ return -ERESTARTSYS;*/ -+ return 0; -+} -+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ unsigned long flags; -+ int count,ele,busyele,emptyele,i=0; -+ -+ for (;;) { -+ if(!nonblock) {//blocked -+ if (i < MAXDELAY) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ -+ ele = elements_in_queue(&out_full_queue); -+ if(ele <= 0) { -+ udelay(200); -+ -+ busyele = elements_in_queue(&out_busy_queue); -+ emptyele = elements_in_queue(&out_empty_queue); -+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ } -+ } -+ } else {//non-blocked -+ //mdelay(100); -+ ele = elements_in_queue(&out_full_queue); -+ -+ if(ele <= 0) { -+ //mdelay(100); -+ busyele = elements_in_queue(&out_busy_queue); -+ emptyele = elements_in_queue(&out_empty_queue); -+ -+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ } -+ } -+ } -+ } -+ -+ return 0; -+} -+#endif -+ -+#if defined(CONFIG_SOC_JZ4740) -+#define MAXDELAY 50000 -+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ int count,ele,i=0; -+ -+ for (;;) { -+ if(!nonblock) {//blocked -+ if ( i < MAXDELAY ) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ -+ ele = elements_in_queue(&out_full_queue); -+ if(ele <= 0) { -+ udelay(10); -+ spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ } -+ } else {//non-blocked -+ mdelay(100); -+ ele = elements_in_queue(&out_full_queue); -+ -+ if(ele <= 0) { -+ mdelay(100); -+ -+ spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ int count,i=0; -+ -+ for (;;) { -+ if ( i < MAXDELAY ) -+ { -+ udelay(10); -+ i++; -+ } -+ else -+ break; -+ spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ -+ if (nonblock) { -+ return -EBUSY; -+ } -+ } -+ -+ return 0; -+} -+#endif -+ -+static int jz_audio_release(struct inode *inode, struct file *file) -+{ -+ unsigned long flags; -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ unsigned long tfl; -+ -+ if (controller == NULL) -+ return -ENODEV; -+ -+ pop_dma_flag = 0; -+ if (controller->opened1 == 1) { -+ controller->opened1 = 0; -+ __i2s_enable_transmit_dma(); -+ __i2s_enable_replay(); -+ drain_dac(controller, file->f_flags & O_NONBLOCK); -+ /* add some mute to anti-pop */ -+#if defined(CONFIG_I2S_DLV) -+ /* wait for fifo empty */ -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ gain_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //gain_down_end = jiffies; -+ while (1) { -+ tfl = REG_AIC_SR & 0x00003f00; -+ if (tfl == 0) { -+ udelay(500); -+ break; -+ } -+ mdelay(2); -+ } -+#endif -+ disable_dma(controller->dma1); -+ set_dma_count(controller->dma1, 0); -+ __i2s_disable_transmit_dma(); -+ __i2s_disable_replay(); -+ __aic_flush_fifo(); -+ if(clear_codec_replay) -+ clear_codec_replay(); -+ __aic_flush_fifo(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ ramp_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //ramp_down_end = jiffies; -+ unset_audio_data_replay(); -+#endif -+ __i2s_disable(); -+ if(turn_off_codec) -+ turn_off_codec(); -+ } -+ -+ if (controller->opened2 == 1) { -+ controller->opened2 = 0; -+ first_record_call = 1; -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ drain_adc(controller, file->f_flags & O_NONBLOCK); -+ disable_dma(controller->dma2); -+ set_dma_count(controller->dma2, 0); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+ -+ if(clear_codec_record) -+ clear_codec_record(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ __i2s_disable(); -+ if(turn_off_codec) -+ turn_off_codec(); -+ abnormal_data_count = 0; -+ } -+ -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+#endif -+ return 0; -+} -+ -+static int jz_audio_open(struct inode *inode, struct file *file) -+{ -+ int i; -+ struct jz_i2s_controller_info *controller = i2s_controller; -+ -+ if (controller == NULL) -+ return -ENODEV; -+ -+ mdelay(2); -+ REG_DMAC_DMACKE(0) = 0x3f; -+ pop_dma_flag = 0; -+ if (controller->opened1 == 1 || controller->opened2 == 1 ) { -+ printk("\naudio is busy!\n"); -+ return -EBUSY; -+ } -+ jz_codec_config = 0; -+ -+ ramp_up_start = 0; -+ ramp_up_end = 0; -+ gain_up_start = 0; -+ gain_up_end = 0; -+ ramp_down_start = 0; -+ ramp_down_end = 0; -+ gain_down_start = 0; -+ gain_down_end = 0; -+ if (file->f_mode & FMODE_WRITE) { -+ if (controller->opened1 == 1) -+ return -EBUSY; -+ -+ controller->opened1 = 1; -+ /* for ioctl */ -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ -+ for(i=0;i < 64;i++) { -+ save_last_samples[i].left = 0; -+ save_last_samples[i].right = 0; -+ } -+ -+ out_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(out_empty_queue.id + i) = i; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ last_dma_buffer_id = 0; -+ } -+ -+ if (file->f_mode & FMODE_READ) { -+ if (controller->opened2 == 1) -+ return -EBUSY; -+ -+ controller->opened2 = 1; -+ first_record_call = 1; -+ /* for ioctl */ -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ -+ in_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(in_empty_queue.id + i) = i; -+ -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ } -+ -+ file->private_data = controller; -+ jz_audio_reset(); -+ REG_AIC_FR |= (1 << 6); -+ -+ if (file->f_mode & FMODE_WRITE) { -+ if(set_codec_replay) -+ set_codec_replay(); -+ } -+ -+ if (file->f_mode & FMODE_READ) { -+ abnormal_data_count = 0; -+ if(set_codec_record) -+ set_codec_record(); -+ } -+ -+#if defined(CONFIG_I2S_DLV) -+ __aic_reset(); -+ -+ mdelay(10); -+ REG_AIC_I2SCR = 0x10; -+ mdelay(20); -+ __aic_flush_fifo(); -+#endif -+ -+ __i2s_enable(); -+ -+#if defined(CONFIG_I2S_DLV) -+ if (file->f_mode & FMODE_WRITE) { -+ -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ ramp_up_start = jiffies; -+ /*while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_RCR = 0x1; -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_RGR = 1;*/ -+ sleep_on(&pop_wait_queue); -+ //ramp_up_end = jiffies; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ } else if (file->f_mode & FMODE_READ) { -+ if (jz_mic_only) -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ else -+ write_codec_file_bit(5, 0, 7);//SB_DAC->0 -+ mdelay(500); -+ } -+ -+#endif -+ -+ return 0; -+} -+ -+ -+static int jz_audio_ioctl(struct inode *inode, struct file *file, -+unsigned int cmd, unsigned long arg) -+{ -+ int val,fullc,busyc,unfinish,newfragstotal,newfragsize; -+ unsigned int flags; -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ count_info cinfo; -+ audio_buf_info abinfo; -+ int id, i; -+ -+ val = 0; -+ switch (cmd) { -+ case OSS_GETVERSION: -+ return put_user(SOUND_VERSION, (int *)arg); -+ case SNDCTL_DSP_RESET: -+#if 0 -+ jz_audio_reset(); -+ __i2s_disable_replay(); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+ __i2s_disable_transmit_dma(); -+#endif -+ return 0; -+ case SNDCTL_DSP_SYNC: -+ if (file->f_mode & FMODE_WRITE) -+ return drain_dac(controller, file->f_flags & O_NONBLOCK); -+ return 0; -+ case SNDCTL_DSP_SPEED: -+ /* set smaple rate */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ if (val >= 0) -+ jz_audio_set_speed(controller->dev_audio, val); -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_STEREO: -+ /* set stereo or mono channel */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); -+ -+ return 0; -+ case SNDCTL_DSP_GETBLKSIZE: -+ //return put_user(jz_audio_fragsize / jz_audio_b, (int *)arg); -+ return put_user(jz_audio_fragsize, (int *)arg); -+ case SNDCTL_DSP_GETFMTS: -+ /* Returns a mask of supported sample format*/ -+ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); -+ case SNDCTL_DSP_SETFMT: -+ /* Select sample format */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ if (val != AFMT_QUERY) -+ jz_audio_set_format(controller->dev_audio,val); -+ else { -+ if (file->f_mode & FMODE_READ) -+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; -+ else -+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; -+ } -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_CHANNELS: -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ jz_audio_set_channels(controller->dev_audio, val); -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_POST: -+ /* FIXME: the same as RESET ?? */ -+ return 0; -+ case SNDCTL_DSP_SUBDIVIDE: -+ return 0; -+ case SNDCTL_DSP_SETFRAGMENT: -+ get_user(val, (long *) arg); -+ newfragsize = 1 << (val & 0xFFFF); -+ if (newfragsize < 4 * PAGE_SIZE) -+ newfragsize = 4 * PAGE_SIZE; -+ if (newfragsize > (16 * PAGE_SIZE)) -+ newfragsize = 16 * PAGE_SIZE; -+ -+ newfragstotal = (val >> 16) & 0x7FFF; -+ if (newfragstotal < 2) -+ newfragstotal = 2; -+ if (newfragstotal > 32) -+ newfragstotal = 32; -+ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize)) -+ return 0; -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ mdelay(500); -+ jz_audio_fragstotal = newfragstotal; -+ jz_audio_fragsize = newfragsize; -+ -+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ mdelay(10); -+ -+ return 0; -+ case SNDCTL_DSP_GETCAPS: -+ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg); -+ case SNDCTL_DSP_NONBLOCK: -+ file->f_flags |= O_NONBLOCK; -+ return 0; -+ case SNDCTL_DSP_SETDUPLEX: -+ return -EINVAL; -+ case SNDCTL_DSP_GETOSPACE: -+ { -+ int i, bytes = 0; -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ jz_audio_fragments = elements_in_queue(&out_empty_queue); -+ for (i = 0; i < jz_audio_fragments; i++) -+ bytes += jz_audio_fragsize; -+ -+ if (jz_audio_channels == 2) -+ bytes /= jz_audio_b; -+ else if (jz_audio_channels == 1) -+ bytes /= 4; -+ else -+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 1!\n"); -+ -+ -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ /* unused fragment amount */ -+ abinfo.fragments = jz_audio_fragments; -+ /* amount of fragments */ -+ abinfo.fragstotal = jz_audio_fragstotal; -+ /* fragment size in bytes */ -+ if (jz_audio_channels == 2) -+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; -+ else if (jz_audio_channels == 1) -+ abinfo.fragsize = jz_audio_fragsize / 4; -+ else -+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 2!\n"); -+ -+ /* write size count without blocking in bytes */ -+ abinfo.bytes = bytes; -+ -+ return copy_to_user((void *)arg, &abinfo, -+ sizeof(abinfo)) ? -EFAULT : 0; -+ } -+ case SNDCTL_DSP_GETISPACE: -+ { -+ int i, bytes = 0; -+ if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ jz_audio_fragments = elements_in_queue(&in_empty_queue); -+ for (i = 0; i < jz_audio_fragments; i++) -+ bytes += jz_audio_fragsize; -+ -+ if (jz_audio_channels == 2) -+ bytes /= jz_audio_b; -+ else if (jz_audio_channels == 1) -+ bytes /= 4; -+ else -+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 1!\n"); -+ -+ abinfo.fragments = jz_audio_fragments; -+ abinfo.fragstotal = jz_audio_fragstotal; -+ -+ if (jz_audio_channels == 2) -+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; -+ else if (jz_audio_channels == 1) -+ abinfo.fragsize = jz_audio_fragsize / 4; -+ else -+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 2!\n"); -+ -+ abinfo.bytes = bytes; -+ -+ return copy_to_user((void *)arg, &abinfo, -+ sizeof(abinfo)) ? -EFAULT : 0; -+ } -+ case SNDCTL_DSP_GETTRIGGER: -+ val = 0; -+ if (file->f_mode & FMODE_READ && in_dma_buf) -+ val |= PCM_ENABLE_INPUT; -+ if (file->f_mode & FMODE_WRITE && out_dma_buf) -+ val |= PCM_ENABLE_OUTPUT; -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_SETTRIGGER: -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ return 0; -+ case SNDCTL_DSP_GETIPTR: -+ if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ cinfo.bytes = controller->total_bytes; -+ cinfo.blocks = controller->blocks; -+ cinfo.ptr = controller->nextIn; -+ controller->blocks = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); -+ case SNDCTL_DSP_GETOPTR: -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ cinfo.bytes = controller->total_bytes; -+ cinfo.blocks = controller->blocks; -+ cinfo.ptr = controller->nextOut; -+ controller->blocks = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); -+ case SNDCTL_DSP_GETODELAY: -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ unfinish = 0; -+ fullc = elements_in_queue(&out_full_queue); -+ busyc = elements_in_queue(&out_busy_queue); -+ for(i = 0;i < fullc ;i ++) { -+ id = *(out_full_queue.id + i); -+ unfinish += *(out_dma_buf_data_count + id); -+ } -+ for(i = 0;i < busyc ;i ++) { -+ id = *(out_busy_queue.id + i); -+ unfinish += get_dma_residue(controller->dma1); -+ } -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ if (jz_audio_channels == 2) -+ unfinish /= jz_audio_b; -+ else if (jz_audio_channels == 1) -+ unfinish /= 4; -+ else -+ printk("SNDCTL_DSP_GETODELAY : channels is wrong !\n"); -+ -+ return put_user(unfinish, (int *) arg); -+ case SOUND_PCM_READ_RATE: -+ return put_user(jz_audio_rate, (int *)arg); -+ case SOUND_PCM_READ_CHANNELS: -+ return put_user(jz_audio_channels, (int *)arg); -+ case SOUND_PCM_READ_BITS: -+ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg); -+ case SNDCTL_DSP_MAPINBUF: -+ case SNDCTL_DSP_MAPOUTBUF: -+ case SNDCTL_DSP_SETSYNCRO: -+ case SOUND_PCM_WRITE_FILTER: -+ case SOUND_PCM_READ_FILTER: -+ return -EINVAL; -+ } -+ return -EINVAL; -+} -+ -+ -+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait) -+{ -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ unsigned long flags; -+ unsigned int mask = 0; -+ -+ if (file->f_mode & FMODE_WRITE) { -+ if (elements_in_queue(&out_empty_queue) > 0) -+ return POLLOUT | POLLWRNORM; -+ -+ poll_wait(file, &controller->dac_wait, wait); -+ } -+ -+ if (file->f_mode & FMODE_READ) { -+ if (elements_in_queue(&in_full_queue) > 0) -+ return POLLIN | POLLRDNORM; -+ -+ poll_wait(file, &controller->adc_wait, wait); -+ } -+ -+ spin_lock_irqsave(&controller->lock, flags); -+ if (file->f_mode & FMODE_WRITE) { -+ if (elements_in_queue(&out_empty_queue) > 0) -+ mask |= POLLOUT | POLLWRNORM; -+ } else if (file->f_mode & FMODE_READ) { -+ if (elements_in_queue(&in_full_queue) > 0) -+ mask |= POLLIN | POLLRDNORM; -+ } -+ spin_unlock_irqrestore(&controller->lock, flags); -+ -+ return mask; -+} -+ -+static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) -+{ -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ int id, ret = 0, left_count, copy_count, cnt = 0; -+ unsigned long flags; -+ -+ if (count < 0) -+ return -EINVAL; -+ -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextIn = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ copy_count = jz_audio_fragsize / 4; -+ -+ left_count = count; -+ if (first_record_call) { -+ first_record_call = 0; -+ audio_read_back_first: -+ if ((id = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id); -+ spin_lock(&controller->lock); -+ *(in_dma_buf_data_count + id) = copy_count * 4; -+ -+ spin_unlock(&controller->lock); -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); -+ audio_start_dma(controller->dma2,file->private_data, -+ *(in_dma_pbuf + id), -+ *(in_dma_buf_data_count + id), -+ DMA_MODE_READ); -+ sleep_on(&rx_wait_queue); -+ } else -+ goto audio_read_back_first; -+ } -+ -+ while (left_count > 0) { -+ audio_read_back_second: -+ if (elements_in_queue(&in_full_queue) <= 0) { -+ if (file->f_flags & O_NONBLOCK) -+ return ret ? ret : -EAGAIN; -+ else -+ sleep_on(&rx_wait_queue); -+ } -+ -+ if ((id = get_buffer_id(&in_full_queue)) >= 0) { -+ spin_lock(&controller->lock); -+ cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id); -+ spin_unlock(&controller->lock); -+ put_buffer_id(&in_empty_queue, id); -+ } else -+ goto audio_read_back_second; -+ -+ if (elements_in_queue(&in_busy_queue) == 0) { -+ if ((id=get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id); -+ spin_lock(&controller->lock); -+ *(in_dma_buf_data_count + id) = copy_count * 4; -+ spin_unlock(&controller->lock); -+ -+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); -+ audio_start_dma(controller->dma2,file->private_data, -+ *(in_dma_pbuf + id), -+ *(in_dma_buf_data_count + id), -+ DMA_MODE_READ); -+ } -+ } -+ if (ret + cnt > count) { -+ spin_lock(&controller->lock); -+ cnt = count - ret; -+ spin_unlock(&controller->lock); -+ } -+ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt)) -+ return ret ? ret : -EFAULT; -+ -+ spin_lock(&controller->lock); -+ ret += cnt; -+ spin_unlock(&controller->lock); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextIn += ret; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ spin_lock(&controller->lock); -+ left_count -= cnt; -+ spin_unlock(&controller->lock); -+ } -+ return ret; -+} -+ -+static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) -+{ -+ int id, ret = 0, left_count, copy_count = 0; -+ unsigned int flags; -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ -+ if (count <= 0) -+ return -EINVAL; -+ -+ if(set_replay_hp_or_speaker) -+ set_replay_hp_or_speaker(); -+ -+ __i2s_enable_transmit_dma(); -+ __i2s_enable_replay(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextOut = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ if (jz_audio_channels == 2) -+ copy_count = jz_audio_fragsize / jz_audio_b; -+ else if(jz_audio_channels == 1) -+ copy_count = jz_audio_fragsize / 4; -+ left_count = count; -+ if (copy_from_user(controller->tmp1, buffer, count)) { -+ printk("copy_from_user failed:%d",ret); -+ return ret ? ret : -EFAULT; -+ } -+ -+ while (left_count > 0) { -+ audio_write_back: -+ /*if (file->f_flags & O_NONBLOCK) -+ udelay(2);*/ -+ if (elements_in_queue(&out_empty_queue) == 0) { -+ if (file->f_flags & O_NONBLOCK) -+ return ret; -+ else -+ sleep_on(&tx_wait_queue); -+ } -+ /* the end fragment size in this write */ -+ if (ret + copy_count > count) -+ copy_count = count - ret; -+ if ((id = get_buffer_id(&out_empty_queue)) >= 0) { -+ replay_filler((signed long)controller->tmp1 + ret, copy_count, id); -+ if(*(out_dma_buf_data_count + id) > 0) { -+ put_buffer_id(&out_full_queue, id); -+ dma_cache_wback_inv(*(out_dma_buf + id), -+ *(out_dma_buf_data_count + id)); -+ } else -+ put_buffer_id(&out_empty_queue, id); -+ } else -+ goto audio_write_back; -+ -+ left_count = left_count - copy_count; -+ ret += copy_count; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextOut += ret; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ if (elements_in_queue(&out_busy_queue) == 0) { -+ if ((id=get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_busy_queue, id); -+ -+ if(*(out_dma_buf_data_count + id) > 0) { -+ audio_start_dma(controller->dma1, -+ file->private_data, -+ *(out_dma_pbuf + id), -+ *(out_dma_buf_data_count + id), -+ DMA_MODE_WRITE); -+ last_dma_buffer_id = id; -+ if (jz_codec_config == 0) { -+ write_codec_file_bit(1, 0, 5); -+ gain_up_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //gain_up_end = jiffies; -+ jz_codec_config = 1; -+ //SB_ADC->1 -+ //write_codec_file_bit(5, 1, 4); -+ //while(1); -+ } -+ } -+ } -+ } -+ } -+ -+ return ret; -+} -+ -+#if defined(CONFIG_I2S_ICODEC) -+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample) -+{ -+ int i,step_len; -+ unsigned long *pop_buf = (unsigned long*)pop_turn_onoff_buf; -+ unsigned int sample_oss = (REG_AIC_CR & 0x00380000) >> 19; -+ unsigned long l_sample_count,r_sample_count,sample_count; -+ struct jz_i2s_controller_info *controller = i2s_controller; -+ signed int left_sam=0,right_sam=0,l_val,r_val; -+ -+ switch (sample_oss) { -+ case 0x0: -+ break; -+ case 0x1: -+ left_sam = (signed int)l_sample; -+ right_sam = (signed int)r_sample; -+ break; -+ case 0x2: -+ break; -+ case 0x3: -+ break; -+ case 0x4: -+ break; -+ } -+ -+ if(left_sam == 0 && right_sam == 0) -+ return; -+ -+ switch (sample_oss) { -+ case 0x0: -+ break; -+ case 0x1: -+ step_len = jz_audio_speed / 10 * 3; -+ step_len = step_len / 2; -+ step_len = 0x7fff / step_len + 1; -+ -+ l_sample_count = 0; -+ l_val = left_sam; -+ -+ while(1) { -+ if(l_val > 0) { -+ if(l_val >= step_len) { -+ l_val -= step_len; -+ l_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(l_val < 0) { -+ if(l_val <= -step_len) { -+ l_val += step_len; -+ l_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(l_val == 0) -+ break; -+ } -+ -+ r_sample_count = 0; -+ r_val = right_sam; -+ while(1) { -+ if(r_val > 0) { -+ if(r_val >= step_len) { -+ r_val -= step_len; -+ r_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(r_val < 0) { -+ if(r_val <= -step_len) { -+ r_val += step_len; -+ r_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(r_val == 0) -+ break; -+ } -+ /* fill up */ -+ if(l_sample_count > r_sample_count) -+ sample_count = l_sample_count; -+ else -+ sample_count = r_sample_count; -+ -+ l_val = left_sam; -+ r_val = right_sam; -+ for(i=0;i <= sample_count;i++) { -+ -+ *pop_buf = (unsigned long)l_val; -+ pop_buf ++; -+ -+ if(l_val > step_len) -+ l_val -= step_len; -+ else if(l_val < -step_len) -+ l_val += step_len; -+ else if(l_val >= -step_len && l_val <= step_len) -+ l_val = 0; -+ -+ *pop_buf = (unsigned long)r_val; -+ pop_buf ++; -+ if(r_val > step_len) -+ r_val -= step_len; -+ else if(r_val < -step_len) -+ r_val += step_len; -+ else if(r_val >= -step_len && r_val <= step_len) -+ r_val = 0; -+ } -+ -+ *pop_buf = 0; -+ pop_buf ++; -+ *pop_buf = 0; -+ -+ pop_buf ++; -+ sample_count += 2; -+ dma_cache_wback_inv(pop_turn_onoff_buf, sample_count*8); -+ -+ pop_dma_flag = 1; -+ audio_start_dma(controller->dma1,controller,pop_turn_onoff_pbuf,sample_count*8,DMA_MODE_WRITE); -+ sleep_on(&pop_wait_queue); -+ pop_dma_flag = 0; -+ break; -+ case 0x2: -+ break; -+ case 0x3: -+ break; -+ case 0x4: -+ break; -+ } -+} -+#endif ++/* ++ * linux/drivers/sound/Jz_i2s.c ++ * ++ * JzSOC On-Chip I2S audio driver. ++ * ++ * Copyright (C) 2005 by Junzheng Corp. ++ * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using ++ * dma channel 4&3,noah is tested. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Because the normal application of AUDIO devices are focused on Little_endian, ++ * then we only perform the little endian data format in driver. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "sound_config.h" ++ ++#define DPRINTK(args...) printk(args) ++#define DMA_ID_I2S_TX DMA_ID_AIC_TX ++#define DMA_ID_I2S_RX DMA_ID_AIC_RX ++#define NR_I2S 2 ++#define MAXDELAY 50000 ++#define JZCODEC_RW_BUFFER_SIZE 2 ++#define JZCODEC_RW_BUFFER_TOTAL 6 ++ ++typedef struct hpvol_shift_s ++{ ++ int hpvol; ++ int shift; ++} hpvol_shift_t; ++ ++mixer_info info; ++_old_mixer_info old_info; ++int codec_volue_shift; ++hpvol_shift_t hpvol_shift_table[72]; ++int abnormal_data_count; ++unsigned long i2s_clk; ++ ++void (*set_codec_mode)(void) = NULL; ++void (*clear_codec_mode)(void) = NULL; ++void (*set_codec_gpio_pin)(void) = NULL; ++void (*each_time_init_codec)(void) = NULL; ++int (*set_codec_startup_param)(void) = NULL; ++void (*set_codec_volume_table)(void) = NULL; ++void (*set_codec_record)(void) = NULL; ++void (*set_codec_replay)(void) = NULL; ++void (*set_codec_replay_record)(void); ++void (*turn_on_codec)(void) = NULL; ++void (*turn_off_codec)(void) = NULL; ++void (*set_codec_speed)(int rate) = NULL; ++void (*reset_codec)(void) = NULL; ++void (*codec_mixer_old_info_id_name)(void) = NULL; ++void (*codec_mixer_info_id_name)(void) = NULL; ++void (*set_codec_bass)(int val) = NULL; ++void (*set_codec_volume)(int val) = NULL; ++void (*set_codec_mic)(int val) = NULL; ++void (*i2s_resume_codec)(void) = NULL; ++void (*i2s_suspend_codec)(int wr,int rd) = NULL; ++void (*init_codec_pin)(void) = NULL; ++void (*set_codec_some_func)(void) = NULL; ++void (*clear_codec_record)(void) = NULL; ++void (*clear_codec_replay)(void) = NULL; ++void (*set_replay_hp_or_speaker)(void) = NULL; ++void (*set_codec_direct_mode)(void) = NULL; ++void (*clear_codec_direct_mode)(void) = NULL; ++ ++static int jz_audio_rate; ++static int jz_audio_format; ++static int jz_audio_volume; ++static int jz_audio_channels; ++static int jz_audio_b; /* bits expand multiple */ ++static int jz_audio_fragments; /* unused fragment amount */ ++static int jz_audio_fragstotal; ++static int jz_audio_fragsize; ++static int jz_audio_speed; ++ ++static int codec_bass_gain; ++static int audio_mix_modcnt; ++static int jz_audio_dma_tran_count; /* bytes count of one DMA transfer */ ++static int jz_mic_only = 1; ++static int jz_codec_config = 0; ++static unsigned long ramp_up_start; ++static unsigned long ramp_up_end; ++static unsigned long gain_up_start; ++static unsigned long gain_up_end; ++static unsigned long ramp_down_start; ++static unsigned long ramp_down_end; ++static unsigned long gain_down_start; ++static unsigned long gain_down_end; ++ ++static int codec_mic_gain; ++static int pop_dma_flag; ++static int last_dma_buffer_id; ++static int drain_flag; ++ ++static void (*old_mksound)(unsigned int hz, unsigned int ticks); ++extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); ++static void jz_update_filler(int bits, int channels); ++ ++static int Init_In_Out_queue(int fragstotal,int fragsize); ++static int Free_In_Out_queue(int fragstotal,int fragsize); ++static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref); ++static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref); ++static void (*replay_filler)(signed long src_start, int count, int id); ++static int (*record_filler)(unsigned long dst_start, int count, int id); ++#if defined(CONFIG_I2S_ICODEC) ++static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample); ++#endif ++static void jz_audio_reset(void); ++static struct file_operations jz_i2s_audio_fops; ++ ++static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (drain_wait_queue); ++static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue); ++ ++struct jz_i2s_controller_info ++{ ++ int io_base; ++ int dma1; /* for play */ ++ int dma2; /* for record */ ++ char *name; ++ int dev_audio; ++ struct i2s_codec *i2s_codec[NR_I2S]; ++ int opened1; ++ int opened2; ++ unsigned char *tmp1; /* tmp buffer for sample conversions */ ++ unsigned char *tmp2; ++ spinlock_t lock; ++ spinlock_t ioctllock; ++ ++ wait_queue_head_t dac_wait; ++ wait_queue_head_t adc_wait; ++ int nextIn; /* byte index to next-in to DMA buffer */ ++ int nextOut; /* byte index to next-out from DMA buffer */ ++ int count; /* current byte count in DMA buffer */ ++ int finish; /* current transfered byte count in DMA buffer */ ++ unsigned total_bytes; /* total bytes written or read */ ++ unsigned blocks; ++ unsigned error; /* over/underrun */ ++#ifdef CONFIG_PM ++ struct pm_dev *pm; ++#endif ++}; ++ ++ ++static struct jz_i2s_controller_info *i2s_controller = NULL; ++struct i2s_codec ++{ ++ /* I2S controller connected with */ ++ void *private_data; ++ char *name; ++ int id; ++ int dev_mixer; ++ /* controller specific lower leverl i2s accessing routines */ ++ u16 (*codec_read) (u8 reg); /* the function accessing Codec REGs */ ++ void (*codec_write) (u8 reg, u16 val); ++ /* Wait for codec-ready */ ++ void (*codec_wait) (struct i2s_codec *codec); ++ /* OSS mixer masks */ ++ int modcnt; ++ int supported_mixers; ++ int stereo_mixers; ++ int record_sources; ++ int bit_resolution; ++ /* OSS mixer interface */ ++ int (*read_mixer) (struct i2s_codec *codec, int oss_channel); ++ void (*write_mixer)(struct i2s_codec *codec, int oss_channel, ++ unsigned int left, unsigned int right); ++ int (*recmask_io) (struct i2s_codec *codec, int rw, int mask); ++ int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg); ++ /* saved OSS mixer states */ ++ unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; ++}; ++ ++ ++typedef struct buffer_queue_s ++{ ++ int count; ++ int *id; ++ int lock; ++} buffer_queue_t; ++ ++typedef struct left_right_sample_s ++{ ++ signed long left; ++ signed long right; ++} left_right_sample_t; ++ ++static unsigned long pop_turn_onoff_buf; ++static unsigned long pop_turn_onoff_pbuf; ++ ++static unsigned long *out_dma_buf = NULL; ++static unsigned long *out_dma_pbuf = NULL; ++static unsigned long *out_dma_buf_data_count = NULL; ++static unsigned long *in_dma_buf = NULL; ++static unsigned long *in_dma_pbuf = NULL; ++static unsigned long *in_dma_buf_data_count = NULL; ++ ++static buffer_queue_t out_empty_queue; ++static buffer_queue_t out_full_queue; ++static buffer_queue_t out_busy_queue; ++static buffer_queue_t in_empty_queue; ++static buffer_queue_t in_full_queue; ++static buffer_queue_t in_busy_queue; ++static int first_record_call = 0; ++ ++static left_right_sample_t save_last_samples[64]; ++static int read_codec_file(int addr) ++{ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ mdelay(1); ++ return(__icdc_get_value()); ++} ++ ++static void printk_codec_files(void) ++{ ++ int cnt; ++ ++ printk("\n"); ++ ++ printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR); ++ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR); ++ printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR); ++ printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR); ++ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR); ++ printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR); ++ printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR); ++ printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA); ++ ++ for (cnt = 0; cnt <= 27 ; cnt++) { ++ printk(" ( %d : 0x%x ) ",cnt ,read_codec_file(cnt)); ++ } ++ printk("\n"); ++} ++ ++static void write_codec_file(int addr, int val) ++{ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ __icdc_set_cmd(val); /* write */ ++ mdelay(1); ++ __icdc_set_rgwr(); ++ mdelay(1); ++} ++ ++static int write_codec_file_bit(int addr, int bitval, int mask_bit) ++{ ++ int val; ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ mdelay(1); ++ val = __icdc_get_value(); /* read */ ++ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ val &= ~(1 << mask_bit); ++ if (bitval == 1) ++ val |= 1 << mask_bit; ++ ++ __icdc_set_cmd(val); /* write */ ++ mdelay(1); ++ __icdc_set_rgwr(); ++ mdelay(1); ++ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ val = __icdc_get_value(); /* read */ ++ ++ if (((val >> mask_bit) & bitval) == bitval) ++ return 1; ++ else ++ return 0; ++} ++ ++/* set Audio data replay */ ++static void set_audio_data_replay() ++{ ++ /* DAC path */ ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ mdelay(10); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ //mdelay(100); ++ //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //mdelay(300); ++} ++ ++/* unset Audio data replay */ ++static void unset_audio_data_replay(void) ++{ ++ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ //mdelay(800); ++ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ //mdelay(800); ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 4);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++/* set Record MIC input audio without playback */ ++static void set_record_mic_input_audio_without_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 1; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ mdelay(10); ++ write_codec_file_bit(1, 1, 2); ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ ++ write_codec_file(22, 0x40);//mic 1 ++ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ //write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file(1, 0x4); ++} ++ ++/* unset Record MIC input audio without playback */ ++static void unset_record_mic_input_audio_without_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 0; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++/* set Record LINE input audio without playback */ ++static void set_record_line_input_audio_without_playback(void) ++{ ++ /* ADC path for LINE IN */ ++ jz_mic_only = 1; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ write_codec_file(22, 0xf6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ mdelay(10); ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file(1, 0x4); ++} ++ ++/* unset Record LINE input audio without playback */ ++static void unset_record_line_input_audio_without_playback(void) ++{ ++ /* ADC path for LINE IN */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1 ++ ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++/* set Playback LINE input audio direct only */ ++static void set_playback_line_input_audio_direct_only() ++{ ++ jz_audio_reset();//or init_codec() ++ REG_AIC_I2SCR = 0x10; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ write_codec_file(22, 0xf6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ mdelay(10); ++ write_codec_file_bit(1, 1, 2);//CR1.HP_BYPASS->1 ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ //write_codec_file_bit(5, 1, 7);//PMR1.SB_DAC->1 ++ //write_codec_file_bit(5, 1, 4);//PMR1.SB_ADC->1 ++} ++ ++/* unset Playback LINE input audio direct only */ ++static void unset_playback_line_input_audio_direct_only() ++{ ++ write_codec_file_bit(6, 0, 3);//GIM->0 ++ write_codec_file_bit(1, 0, 2);//PMR1.BYPASS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LINE->1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ mdelay(100); ++ write_codec_file_bit(5, 1, 5);//PMR1.SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++/* set Record MIC input audio with direct playback */ ++static void set_record_mic_input_audio_with_direct_playback(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ jz_mic_only = 0; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ ++ write_codec_file(22, 0x60);//mic 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ //write_codec_file(1, 0x4); ++} ++ ++/* unset Record MIC input audio with direct playback */ ++static void unset_record_mic_input_audio_with_direct_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 0; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++/* set Record playing audio mixed with MIC input audio */ ++static void set_record_playing_audio_mixed_with_mic_input_audio(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ mdelay(10); ++ ++ write_codec_file(22, 0x63);//mic 1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ write_codec_file_bit(5, 0, 4);//PMR1.SB_MIX->0 ++} ++ ++/* unset Record playing audio mixed with MIC input audio */ ++static void unset_record_playing_audio_mixed_with_mic_input_audio(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++/* set Record MIC input audio with Audio data replay (full duplex) */ ++static void set_record_mic_input_audio_with_audio_data_replay(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++} ++ ++/* unset Record MIC input audio with Audio data replay (full duplex) */ ++static void unset_record_mic_input_audio_with_audio_data_replay(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++ ++///////// ++/* set Record LINE input audio with Audio data replay (full duplex for linein) */ ++static void set_record_line_input_audio_with_audio_data_replay(void) ++{ ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ ++ ++ //jz_mic_only = 1; ++ write_codec_file(22, 0xc6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++} ++ ++/* unset Record LINE input audio with Audio data replay (full duplex for linein) */ ++static void unset_record_line_input_audio_with_audio_data_replay(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++///////// ++static inline int get_buffer_id(struct buffer_queue_s *q) ++{ ++ int r; ++ unsigned long flags; ++ int i; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ if (q->count == 0) { ++ spin_unlock_irqrestore(&q->lock, flags); ++ return -1; ++ } ++ r = *(q->id + 0); ++ for (i=0;i < q->count-1;i++) ++ *(q->id + i) = *(q->id + (i+1)); ++ q->count --; ++ spin_unlock_irqrestore(&q->lock, flags); ++ ++ return r; ++} ++ ++static inline void put_buffer_id(struct buffer_queue_s *q, int id) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ *(q->id + q->count) = id; ++ q->count ++; ++ spin_unlock_irqrestore(&q->lock, flags); ++} ++ ++static inline int elements_in_queue(struct buffer_queue_s *q) ++{ ++ int r; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&q->lock, flags); ++ r = q->count; ++ spin_unlock_irqrestore(&q->lock, flags); ++ ++ return r; ++} ++ ++static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode) ++{ ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ jz_audio_dma_tran_count = count / jz_audio_b; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ flags = claim_dma_lock(); ++ disable_dma(chan); ++ clear_dma_ff(chan); ++ //set_dma_mode(chan, mode); ++ jz_set_oss_dma(chan, mode, jz_audio_format); ++ set_dma_addr(chan, phyaddr); ++ if (count == 0) { ++ count++; ++ printk("JzSOC DMA controller can't set dma 0 count!\n"); ++ } ++ set_dma_count(chan, count); ++ enable_dma(chan); ++ release_dma_lock(flags); ++} ++ ++static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id) ++{ ++ int id1, id2; ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ int dma = controller->dma2; ++ ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ ++ if(drain_flag == 1) ++ wake_up(&drain_wait_queue); ++ /* for DSP_GETIPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ id1 = get_buffer_id(&in_busy_queue); ++ put_buffer_id(&in_full_queue, id1); ++ ++ wake_up(&rx_wait_queue); ++ wake_up(&controller->adc_wait); ++ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id2); ++ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1); ++ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2)); ++ audio_start_dma(dma,dev_id, ++ *(in_dma_pbuf + id2), ++ *(in_dma_buf_data_count + id2), ++ DMA_MODE_READ); ++ } else ++ in_busy_queue.count = 0; ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id) ++{ ++ int id; ++ unsigned long flags; ++ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; ++ int dma = controller->dma1; ++ ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ ++ if(pop_dma_flag == 1) { ++ pop_dma_flag = 0; ++ wake_up(&pop_wait_queue); ++ } else { ++ if(drain_flag == 1) { ++ /* Is replay dma buffer over ? */ ++ if(elements_in_queue(&out_full_queue) <= 0) { ++ drain_flag = 0; ++ wake_up(&drain_wait_queue); ++ } ++ } ++ ++ /* for DSP_GETOPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ if ((id = get_buffer_id(&out_busy_queue)) < 0) ++ printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n"); ++ put_buffer_id(&out_empty_queue, id); ++ if ((id = get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_busy_queue, id); ++ if(*(out_dma_buf_data_count + id) > 0) { ++ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id), ++ *(out_dma_buf_data_count + id), ++ DMA_MODE_WRITE); ++ last_dma_buffer_id = id; ++ } ++ } else ++ out_busy_queue.count = 0; ++ ++ if (elements_in_queue(&out_empty_queue) > 0) { ++ wake_up(&tx_wait_queue); ++ wake_up(&controller->dac_wait); ++ } ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static void jz_i2s_initHw(int set) ++{ ++#if defined(CONFIG_MIPS_JZ_URANUS) ++ i2s_clk = 48000000; ++#else ++ i2s_clk = __cpm_get_i2sclk(); ++#endif ++ __i2s_disable(); ++ if(set) ++ __i2s_reset(); ++ schedule_timeout(5); ++ if(each_time_init_codec) ++ each_time_init_codec(); ++ __i2s_disable_record(); ++ __i2s_disable_replay(); ++ __i2s_disable_loopback(); ++ __i2s_set_transmit_trigger(4); ++ __i2s_set_receive_trigger(3); ++} ++ ++static int Init_In_Out_queue(int fragstotal,int fragsize) ++{ ++ int i; ++ ++ /* recording */ ++ in_empty_queue.count = fragstotal; ++ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_buf) ++ goto all_mem_err; ++ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_pbuf) ++ goto all_mem_err; ++ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!in_dma_buf_data_count) ++ goto all_mem_err; ++ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_empty_queue.id) ++ goto all_mem_err; ++ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_full_queue.id) ++ goto all_mem_err; ++ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!in_busy_queue.id) ++ goto all_mem_err; ++ ++ for (i=0;i < fragstotal;i++) ++ *(in_empty_queue.id + i) = i; ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ ++ for (i = 0; i < fragstotal; i++) { ++ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); ++ if (*(in_dma_buf + i) == 0) ++ goto mem_failed_in; ++ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i))); ++ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); ++ } ++ ++ /* playing */ ++ out_empty_queue.count = fragstotal; ++ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!out_dma_buf) ++ goto all_mem_err; ++ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ if (!out_dma_pbuf) ++ goto all_mem_err; ++ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); ++ ++ if (!out_dma_buf_data_count) ++ goto all_mem_err; ++ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_empty_queue.id) ++ goto all_mem_err; ++ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_full_queue.id) ++ goto all_mem_err; ++ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); ++ if (!out_busy_queue.id) ++ goto all_mem_err; ++ for (i=0;i < fragstotal;i++) ++ *(out_empty_queue.id + i) = i; ++ ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ /* alloc DMA buffer */ ++ for (i = 0; i < fragstotal; i++) { ++ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); ++ if (*(out_dma_buf + i) == 0) { ++ printk(" can't allocate required DMA(OUT) buffers.\n"); ++ goto mem_failed_out; ++ } ++ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); ++ } ++ ++ return 1; ++all_mem_err: ++ printk("error:allocate memory occur error 1!\n"); ++ return 0; ++mem_failed_out: ++ printk("error:allocate memory occur error 2!\n"); ++ for (i = 0; i < fragstotal; i++) { ++ if(*(out_dma_buf + i)) ++ free_pages(*(out_dma_buf + i), get_order(fragsize)); ++ } ++ ++ return 0; ++mem_failed_in: ++ printk("error:allocate memory occur error 3!\n"); ++ for (i = 0; i < fragstotal; i++) { ++ if(*(in_dma_buf + i)) ++ free_pages(*(in_dma_buf + i), get_order(fragsize)); ++ } ++ return 0; ++} ++ ++static int Free_In_Out_queue(int fragstotal,int fragsize) ++{ ++ int i; ++ /* playing */ ++ if(out_dma_buf != NULL) { ++ for (i = 0; i < fragstotal; i++) { ++ if(*(out_dma_buf + i)) ++ free_pages(*(out_dma_buf + i), get_order(fragsize)); ++ *(out_dma_buf + i) = 0; ++ } ++ kfree(out_dma_buf); ++ out_dma_buf = NULL; ++ } ++ if(out_dma_pbuf) { ++ kfree(out_dma_pbuf); ++ out_dma_pbuf = NULL; ++ } ++ if(out_dma_buf_data_count) { ++ kfree(out_dma_buf_data_count); ++ out_dma_buf_data_count = NULL; ++ } ++ if(out_empty_queue.id) { ++ kfree(out_empty_queue.id); ++ out_empty_queue.id = NULL; ++ } ++ if(out_full_queue.id) { ++ kfree(out_full_queue.id); ++ out_full_queue.id = NULL; ++ } ++ if(out_busy_queue.id) { ++ kfree(out_busy_queue.id); ++ out_busy_queue.id = NULL; ++ } ++ out_empty_queue.count = fragstotal; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ ++ /* recording */ ++ if(in_dma_buf) { ++ for (i = 0; i < fragstotal; i++) { ++ if(*(in_dma_buf + i)) { ++ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); ++ free_pages(*(in_dma_buf + i), get_order(fragsize)); ++ } ++ *(in_dma_buf + i) = 0; ++ } ++ kfree(in_dma_buf); ++ in_dma_buf = NULL; ++ } ++ if(in_dma_pbuf) { ++ kfree(in_dma_pbuf); ++ in_dma_pbuf = NULL; ++ } ++ if(in_dma_buf_data_count) { ++ kfree(in_dma_buf_data_count); ++ in_dma_buf_data_count = NULL; ++ } ++ if(in_empty_queue.id) { ++ kfree(in_empty_queue.id); ++ in_empty_queue.id = NULL; ++ } ++ if(in_full_queue.id) { ++ kfree(in_full_queue.id); ++ in_full_queue.id = NULL; ++ } ++ if(in_busy_queue.id) { ++ kfree(in_busy_queue.id); ++ in_busy_queue.id = NULL; ++ } ++ ++ in_empty_queue.count = fragstotal; ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ ++ return 1; ++} ++ ++static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller) ++{ ++ jz_i2s_initHw(0); ++} ++ ++static int jz_audio_set_speed(int dev, int rate) ++{ ++ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */ ++ jz_audio_speed = rate; ++ if (rate > 48000) ++ rate = 48000; ++ if (rate < 8000) ++ rate = 8000; ++ jz_audio_rate = rate; ++ ++ if(set_codec_speed) ++ set_codec_speed(rate); ++ ++ return jz_audio_rate; ++} ++ ++ ++static int record_fill_1x8_u(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long data; ++ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ volatile unsigned char *dp = (unsigned char*)dst_start; ++ ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt++; ++ data = *(s++); ++ *(dp ++) = ((data << 16) >> 24) + 0x80; ++ s++; /* skip the other channel */ ++ } ++ ++ return cnt; ++} ++ ++ ++static int record_fill_2x8_u(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1, d2; ++ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ volatile unsigned char *dp = (unsigned char*)dst_start; ++ ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ *(dp ++) = ((d1 << 16) >> 24) + 0x80; ++ d2 = *(s++); ++ *(dp ++) = ((d2 << 16) >> 24) + 0x80; ++ } ++ ++ return cnt; ++} ++ ++ ++static int record_fill_1x16_s(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1; ++ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ unsigned short *dp = (unsigned short *)dst_start; ++ ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt += 2; /* count in byte */ ++ d1 = *(s++); ++ *(dp ++) = (d1 << 16) >> 16; ++ s++; /* skip the other channel */ ++ } ++ ++ return cnt; ++} ++ ++ ++static int record_fill_2x16_s(unsigned long dst_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned long d1, d2; ++ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); ++ unsigned short *dp = (unsigned short *)dst_start; ++ while (count > 0) { ++ count -= 2; /* count in dword */ ++ cnt += 4; /* count in byte */ ++ d1 = *(s++); ++ d2 = *(s++); ++ if(abnormal_data_count > 0) { ++ d1 = d2 = 0; ++ abnormal_data_count --; ++ } ++ *(dp ++) = (d1 << 16) >> 16; ++ *(dp ++) = (d2 << 16) >> 16; ++ } ++ ++ return cnt; ++} ++ ++static void replay_fill_1x8_u(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned char data; ++ unsigned long ddata; ++ volatile unsigned char *s = (unsigned char *)src_start; ++ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count--; ++ cnt += 1; ++ data = *(s++) - 0x80; ++ ddata = (unsigned long) data << 8; ++ *(dp ++) = ddata; ++ *(dp ++) = ddata; ++ ++ /* save last left and right */ ++ if(count == 1) { ++ save_last_samples[id].left = ddata; ++ save_last_samples[id].right = ddata; ++ } ++ } ++ cnt = cnt * 2 * jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++ ++static void replay_fill_2x8_u(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ unsigned char d1; ++ unsigned long dd1; ++ volatile unsigned char *s = (unsigned char *)src_start; ++ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count -= 1; ++ cnt += 1 ; ++ d1 = *(s++) - 0x80; ++ dd1 = (unsigned long) d1 << 8; ++ *(dp ++) = dd1; ++ /* save last left */ ++ if(count == 2) ++ save_last_samples[id].left = dd1; ++ /* save last right */ ++ if(count == 1) ++ save_last_samples[id].right = dd1; ++ } ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++ ++static void replay_fill_1x16_s(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed short d1; ++ signed long l1; ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++ ++ while (count > 0) { ++ count -= 2; ++ cnt += 2 ; ++ d1 = *(s++); ++ l1 = (signed long)d1; ++ *(dp ++) = l1; ++ *(dp ++) = l1; ++ ++ /* save last left and right */ ++ if(count == 1) { ++ save_last_samples[id].left = l1; ++ save_last_samples[id].right = l1; ++ } ++ } ++ cnt = cnt * 2 * jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++ ++#if 0 ++static void replay_fill_2x16_s(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed short d1; ++ signed long l1; ++ int mute_cnt = 0; ++ signed long tmp1,tmp2; ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++#if defined(CONFIG_I2S_ICDC) ++ volatile signed long *before_dp; ++ int sam_rate = jz_audio_rate / 20; ++ ++ tmp1 = tmp2 = 0; ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ ++ l1 = (signed long)d1; ++ l1 >>= codec_volue_shift; ++ ++ if(l1 == 0) { ++ mute_cnt ++; ++ if(mute_cnt >= sam_rate) { ++ before_dp = dp - 10; ++ *(before_dp) = (signed long)1; ++ before_dp = dp - 11; ++ *(before_dp) = (signed long)1; ++ mute_cnt = 0; ++ } ++ } else ++ mute_cnt = 0; ++ ++ *(dp ++) = l1; ++ ++ tmp1 = tmp2; ++ tmp2 = l1; ++ } ++ ++ /* save last left */ ++ save_last_samples[id].left = tmp1; ++ /* save last right */ ++ save_last_samples[id].right = tmp2; ++#endif ++#if defined(CONFIG_I2S_DLV) ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ ++ l1 = (signed long)d1; ++ ++ *(dp ++) = l1; ++ } ++#endif ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++} ++#else ++static void replay_fill_2x16_s(signed long src_start, int count, int id) ++{ ++ int cnt = 0; ++ signed short d1; ++ signed long l1; ++ int mute_cnt = 0; ++ signed long tmp1,tmp2; ++ ++#if 0 ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed short *dp = (signed short*)(*(out_dma_buf + id)); ++ memcpy((char*)dp, (char*)s, count); ++ *(out_dma_buf_data_count + id) = count; ++#else ++ volatile signed short *s = (signed short *)src_start; ++ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); ++ while (count > 0) { ++ count -= 2; ++ cnt += 2; ++ d1 = *(s++); ++ ++ l1 = (signed long)d1; ++ ++ *(dp ++) = l1; ++ } ++ cnt *= jz_audio_b; ++ *(out_dma_buf_data_count + id) = cnt; ++#endif ++} ++#endif ++ ++ ++static unsigned int jz_audio_set_format(int dev, unsigned int fmt) ++{ ++ switch (fmt) { ++ case AFMT_U8: ++ __i2s_set_oss_sample_size(8); ++ __i2s_set_iss_sample_size(8); ++ jz_audio_format = fmt; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++ break; ++ case AFMT_S16_LE: ++#if defined(CONFIG_I2S_DLV) ++ /* DAC path and ADC path */ ++ write_codec_file(2, 0x00); ++ //write_codec_file(2, 0x60); ++#endif ++ jz_audio_format = fmt; ++ jz_update_filler(jz_audio_format,jz_audio_channels); ++ /* print all files */ ++ __i2s_set_oss_sample_size(16); ++ __i2s_set_iss_sample_size(16); ++ break; ++ ++ case AFMT_QUERY: ++ break; ++ } ++ ++ return jz_audio_format; ++} ++ ++ ++static short jz_audio_set_channels(int dev, short channels) ++{ ++ switch (channels) { ++ case 1: ++ if(set_codec_some_func) ++ set_codec_some_func(); ++ jz_audio_channels = channels; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono ++#endif ++ break; ++ case 2: ++ jz_audio_channels = channels; ++ jz_update_filler(jz_audio_format, jz_audio_channels); ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo ++#endif ++ break; ++ case 0: ++ break; ++ } ++ ++ return jz_audio_channels; ++} ++ ++static void init_codec(void) ++{ ++ /* inititalize internal I2S codec */ ++ if(init_codec_pin) ++ init_codec_pin(); ++ ++#if defined(CONFIG_I2S_ICDC) ++ /* initialize AIC but not reset it */ ++ jz_i2s_initHw(0); ++#endif ++ if(reset_codec) ++ reset_codec(); ++} ++ ++static void jz_audio_reset(void) ++{ ++ __i2s_disable_replay(); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++ __i2s_disable_transmit_dma(); ++#if defined(CONFIG_I2S_DLV) ++ REG_AIC_I2SCR = 0x10; ++#endif ++ init_codec(); ++} ++ ++static int jz_audio_release(struct inode *inode, struct file *file); ++static int jz_audio_open(struct inode *inode, struct file *file); ++static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg); ++static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait); ++static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos); ++static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos); ++ ++/* static struct file_operations jz_i2s_audio_fops */ ++static struct file_operations jz_i2s_audio_fops = ++{ ++ owner: THIS_MODULE, ++ open: jz_audio_open, ++ release: jz_audio_release, ++ write: jz_audio_write, ++ read: jz_audio_read, ++ poll: jz_audio_poll, ++ ioctl: jz_audio_ioctl ++}; ++ ++static int jz_i2s_open_mixdev(struct inode *inode, struct file *file) ++{ ++ int i; ++ int minor = MINOR(inode->i_rdev); ++ struct jz_i2s_controller_info *controller = i2s_controller; ++ ++ for (i = 0; i < NR_I2S; i++) ++ if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor) ++ goto match; ++ ++ if (!controller) ++ return -ENODEV; ++match: ++ file->private_data = controller->i2s_codec[i]; ++ ++ return 0; ++} ++ ++static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ struct i2s_codec *codec = (struct i2s_codec *)file->private_data; ++ return codec->mixer_ioctl(codec, cmd, arg); ++} ++ ++static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin) ++{ ++ return -ESPIPE; ++} ++ ++static struct file_operations jz_i2s_mixer_fops = ++{ ++ owner: THIS_MODULE, ++ llseek: jz_i2s_llseek, ++ ioctl: jz_i2s_ioctl_mixdev, ++ open: jz_i2s_open_mixdev, ++}; ++ ++static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg) ++{ ++ int ret; ++ long val = 0; ++ switch (cmd) { ++ case SOUND_MIXER_INFO: ++ ++ if(codec_mixer_info_id_name) ++ codec_mixer_info_id_name(); ++ info.modify_counter = audio_mix_modcnt; ++ ++ return copy_to_user((void *)arg, &info, sizeof(info)); ++ case SOUND_OLD_MIXER_INFO: ++ ++ if(codec_mixer_old_info_id_name) ++ codec_mixer_old_info_id_name(); ++ ++ return copy_to_user((void *)arg, &old_info, sizeof(info)); ++ case SOUND_MIXER_READ_STEREODEVS: ++ ++ return put_user(0, (long *) arg); ++ case SOUND_MIXER_READ_CAPS: ++ ++ val = SOUND_CAP_EXCL_INPUT; ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_READ_DEVMASK: ++ break; ++ case SOUND_MIXER_READ_RECMASK: ++ break; ++ case SOUND_MIXER_READ_RECSRC: ++ break; ++ case SOUND_MIXER_WRITE_SPEAKER: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ switch(val) { ++ case 100: ++ if(set_codec_direct_mode) ++ set_codec_direct_mode(); ++ break; ++ case 0: ++ if(clear_codec_direct_mode) ++ clear_codec_direct_mode(); ++ break; ++ } ++ break; ++ case SOUND_MIXER_WRITE_BASS: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ codec_bass_gain = val; ++ if(set_codec_bass) ++ set_codec_bass(val); ++ ++ return 0; ++ case SOUND_MIXER_READ_BASS: ++ ++ val = codec_bass_gain; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_WRITE_VOLUME: ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ if (val > 31) ++ val = 31; ++ jz_audio_volume = val; ++ ++ if(set_codec_volume) ++ set_codec_volume(val); ++ return 0; ++ case SOUND_MIXER_READ_VOLUME: ++ ++ val = jz_audio_volume; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ case SOUND_MIXER_WRITE_MIC: ++ ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ ++ val = val & 0xff; ++ if(val < 0) ++ val = 0; ++ if(val > 100) ++ val = 100; ++ codec_mic_gain = val; ++ if(set_codec_mic) ++ set_codec_mic(val); ++ ++ return 0; ++ case SOUND_MIXER_READ_MIC: ++ ++ val = codec_mic_gain; ++ ret = val << 8; ++ val = val | ret; ++ ++ return put_user(val, (long *) arg); ++ default: ++ return -ENOSYS; ++ } ++ audio_mix_modcnt ++; ++ return 0; ++} ++ ++ ++int i2s_probe_codec(struct i2s_codec *codec) ++{ ++ /* generic OSS to I2S wrapper */ ++ codec->mixer_ioctl = i2s_mixer_ioctl; ++ return 1; ++} ++ ++ ++/* I2S codec initialisation. */ ++static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller) ++{ ++ int num_i2s = 0; ++ struct i2s_codec *codec; ++ ++ for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) { ++ if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL) ++ return -ENOMEM; ++ memset(codec, 0, sizeof(struct i2s_codec)); ++ codec->private_data = controller; ++ codec->id = num_i2s; ++ ++ if (i2s_probe_codec(codec) == 0) ++ break; ++ if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) { ++ printk(KERN_ERR "Jz I2S: couldn't register mixer!\n"); ++ kfree(codec); ++ break; ++ } ++ controller->i2s_codec[num_i2s] = codec; ++ } ++ return num_i2s; ++} ++ ++ ++static void jz_update_filler(int format, int channels) ++{ ++#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) ++ ++ switch (TYPE(format, channels)) ++ { ++ ++ case TYPE(AFMT_U8, 1): ++ jz_audio_b = 4; /* 4bytes * 8bits =32bits */ ++ replay_filler = replay_fill_1x8_u; ++ record_filler = record_fill_1x8_u; ++ break; ++ case TYPE(AFMT_U8, 2): ++ jz_audio_b = 4; ++ replay_filler = replay_fill_2x8_u; ++ record_filler = record_fill_2x8_u; ++ break; ++ case TYPE(AFMT_S16_LE, 1): ++ jz_audio_b = 2; /* 2bytes * 16bits =32bits */ ++ replay_filler = replay_fill_1x16_s; ++ record_filler = record_fill_1x16_s; ++ break; ++ case TYPE(AFMT_S16_LE, 2): ++ jz_audio_b = 2; ++ replay_filler = replay_fill_2x16_s; ++ record_filler = record_fill_2x16_s; ++ break; ++ default: ++ ; ++ } ++} ++ ++ ++#ifdef CONFIG_PROC_FS ++extern struct proc_dir_entry *proc_jz_root; ++int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ return 0; ++} ++ ++static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller) ++{ ++ if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0])) ++ return -EIO; ++ return 0; ++} ++ ++static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller) ++{ ++} ++#endif ++ ++static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller) ++{ ++ char *name; ++ int adev; /* No of Audio device. */ ++ ++ name = controller->name; ++ /* initialize AIC controller and reset it */ ++ jz_i2s_initHw(1); ++ adev = register_sound_dsp(&jz_i2s_audio_fops, -1); ++ if (adev < 0) ++ goto audio_failed; ++ /* initialize I2S codec and register /dev/mixer */ ++ if (jz_i2s_codec_init(controller) <= 0) ++ goto mixer_failed; ++ ++#ifdef CONFIG_PROC_FS ++ if (jz_i2s_init_proc(controller) < 0) { ++ printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name); ++ goto proc_failed; ++ } ++#endif ++ ++ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8); ++ if (!controller->tmp1) { ++ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); ++ goto tmp1_failed; ++ } ++ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8); ++ if (!controller->tmp2) { ++ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); ++ goto tmp2_failed; ++ } ++ if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) { ++ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name); ++ goto dma2_failed; ++ } ++ if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) { ++ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name); ++ goto dma1_failed; ++ } ++ printk("JzSOC On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2)); ++ ++ controller->dev_audio = adev; ++ pop_turn_onoff_buf = __get_free_pages(GFP_KERNEL | GFP_DMA, 8); ++ if(!pop_turn_onoff_buf) ++ printk("pop_turn_onoff_buf alloc is wrong!\n"); ++ pop_turn_onoff_pbuf = virt_to_phys((void *)pop_turn_onoff_buf); ++ ++ return; ++dma2_failed: ++ jz_free_dma(controller->dma1); ++dma1_failed: ++ free_pages((unsigned long)controller->tmp2, 8); ++tmp2_failed: ++ free_pages((unsigned long)controller->tmp1, 8); ++tmp1_failed: ++ ++#ifdef CONFIG_PROC_FS ++ jz_i2s_cleanup_proc(controller); ++#endif ++proc_failed: ++ /* unregister mixer dev */ ++mixer_failed: ++ unregister_sound_dsp(adev); ++audio_failed: ++ return; ++} ++ ++static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller) ++{ ++ if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info), ++ GFP_KERNEL)) == NULL) { ++ printk(KERN_ERR "Jz I2S Controller: out of memory.\n"); ++ return -ENOMEM; ++ } ++ (*controller)->name = "Jz I2S controller"; ++ (*controller)->opened1 = 0; ++ (*controller)->opened2 = 0; ++ init_waitqueue_head(&(*controller)->adc_wait); ++ init_waitqueue_head(&(*controller)->dac_wait); ++ spin_lock_init(&(*controller)->lock); ++ init_waitqueue_head(&rx_wait_queue); ++ init_waitqueue_head(&tx_wait_queue); ++ init_waitqueue_head(&pop_wait_queue); ++ init_waitqueue_head(&drain_wait_queue); ++ ++ return 0; ++} ++ ++static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller) ++{ ++ int adev = controller->dev_audio; ++ ++ jz_i2s_full_reset(controller); ++ controller->dev_audio = -1; ++ if (old_mksound) ++ kd_mksound = old_mksound;/* Our driver support bell for kb, see vt.c */ ++ ++#ifdef CONFIG_PROC_FS ++ jz_i2s_cleanup_proc(controller); ++#endif ++ ++ jz_free_dma(controller->dma1); ++ jz_free_dma(controller->dma2); ++ free_pages((unsigned long)controller->tmp1, 8); ++ free_pages((unsigned long)controller->tmp2, 8); ++ free_pages((unsigned long)pop_turn_onoff_buf, 8); ++ ++ if (adev >= 0) { ++ /* unregister_sound_mixer(audio_devs[adev]->mixer_dev); */ ++ unregister_sound_dsp(controller->dev_audio); ++ } ++} ++ ++#ifdef CONFIG_PM ++static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state) ++{ ++ if(i2s_suspend_codec) ++ i2s_suspend_codec(controller->opened1,controller->opened2); ++ printk("Aic and codec are suspended!\n"); ++ return 0; ++} ++ ++static int jz_i2s_resume(struct jz_i2s_controller_info *controller) ++{ ++ if(i2s_resume_codec) ++ i2s_resume_codec(); ++ ++#if defined(CONFIG_I2S_AK4642EN) ++ jz_i2s_initHw(0); ++ jz_audio_reset(); ++ __i2s_enable(); ++ jz_audio_set_speed(controller->dev_audio,jz_audio_speed); ++ /* playing */ ++ if(controller->opened1) { ++ if(set_codec_replay) ++ set_codec_replay(); ++ int dma = controller->dma1; ++ int id; ++ unsigned long flags; ++ disable_dma(dma); ++ if(__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if(__dmac_channel_transmit_end_detected(dma)) ++ __dmac_channel_clear_transmit_end(dma); ++ ++ /* for DSP_GETOPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ while((id = get_buffer_id(&out_busy_queue)) >= 0) ++ put_buffer_id(&out_empty_queue, id); ++ ++ out_busy_queue.count=0; ++ if((id = get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_empty_queue, id); ++ } ++ if (elements_in_queue(&out_empty_queue) > 0) { ++ wake_up(&tx_wait_queue); ++ wake_up(&controller->dac_wait); ++ } else ++ printk("pm out_empty_queue empty"); ++ } ++ ++ /* recording */ ++ if(controller->opened2) { ++ if(set_codec_record) ++ set_codec_record(); ++ int dma = controller->dma2; ++ int id1, id2; ++ unsigned long flags; ++ disable_dma(dma); ++ if (__dmac_channel_address_error_detected(dma)) { ++ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); ++ __dmac_channel_clear_address_error(dma); ++ } ++ if (__dmac_channel_transmit_end_detected(dma)) { ++ __dmac_channel_clear_transmit_end(dma); ++ } ++ /* for DSP_GETIPTR */ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes += jz_audio_dma_tran_count; ++ controller->blocks ++; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ id1 = get_buffer_id(&in_busy_queue); ++ put_buffer_id(&in_full_queue, id1); ++ wake_up(&rx_wait_queue); ++ wake_up(&controller->adc_wait); ++ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_full_queue, id2); ++ } ++ in_busy_queue.count = 0; ++ } ++#endif ++ ++ return 0; ++} ++ ++static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ int ret; ++ struct jz_i2s_controller_info *controller = pm_dev->data; ++ ++ if (!controller) return -EINVAL; ++ ++ switch (req) { ++ case PM_SUSPEND: ++ ret = jz_i2s_suspend(controller, (int)data); ++ break; ++ case PM_RESUME: ++ ret = jz_i2s_resume(controller); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++#endif /* CONFIG_PM */ ++static irqreturn_t aic_codec_irq(int irq, void *dev_id) ++{ ++ u8 file_9 = read_codec_file(9); ++ u8 file_8 = read_codec_file(8); ++ ++ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9); ++ if ((file_9 & 0x1f) == 0x10) { ++ ++ write_codec_file(8, 0x3f); ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ mdelay(300); ++ while ((read_codec_file(9) & 0x4) != 0x4); ++ while ((read_codec_file(9) & 0x10) == 0x10) { ++ write_codec_file(9, 0x10); ++ } ++ write_codec_file_bit(5, 0, 6);//SB_OUT->0 ++ mdelay(300); ++ while ((read_codec_file(9) & 0x8) != 0x8); ++ write_codec_file(9, file_9); ++ write_codec_file(8, file_8); ++ ++ return IRQ_HANDLED; ++ } ++ ++ if (file_9 & 0x8) ++ ramp_up_end = jiffies; ++ else if (file_9 & 0x4) ++ ramp_down_end = jiffies; ++ else if (file_9 & 0x2) ++ gain_up_end = jiffies; ++ else if (file_9 & 0x1) ++ gain_down_end = jiffies; ++ ++ write_codec_file(9, file_9); ++ if (file_9 & 0xf) ++ wake_up(&pop_wait_queue); ++ while (REG_ICDC_RGDATA & 0x100); ++ ++ return IRQ_HANDLED; ++} ++ ++static int __init init_jz_i2s(void) ++{ ++ int errno, retval; ++#if defined(CONFIG_I2S_DLV) ++ ++ ramp_up_start = 0; ++ ramp_up_end = 0; ++ gain_up_start = 0; ++ gain_up_end = 0; ++ ramp_down_start = 0; ++ ramp_down_end = 0; ++ gain_down_start = 0; ++ gain_down_end = 0; ++#endif ++ ++ abnormal_data_count = 0; ++ if(set_codec_mode) ++ set_codec_mode(); ++ ++ drain_flag = 0; ++ if ((errno = probe_jz_i2s(&i2s_controller)) < 0) ++ return errno; ++ if(set_codec_gpio_pin) ++ set_codec_gpio_pin(); ++ ++ attach_jz_i2s(i2s_controller); ++ if(set_codec_startup_param) ++ set_codec_startup_param(); ++#if defined(CONFIG_I2S_DLV) ++ jz_codec_config = 0; ++ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL); ++ if (retval) { ++ printk("Could not get aic codec irq %d\n", IRQ_AIC); ++ return retval; ++ } ++#endif ++ if(set_codec_volume_table) ++ set_codec_volume_table(); ++ ++ out_empty_queue.id = NULL; ++ out_full_queue.id = NULL; ++ out_busy_queue.id = NULL; ++ in_empty_queue.id = NULL; ++ in_full_queue.id = NULL; ++ in_busy_queue.id = NULL; ++ ++ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE; ++ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ; ++ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ ++#ifdef CONFIG_PM ++ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ++ jz_i2s_pm_callback); ++ if (i2s_controller->pm) ++ i2s_controller->pm->data = i2s_controller; ++#endif ++ ++#if defined(CONFIG_I2S_DLV) ++ __cpm_start_idct(); ++ __cpm_start_db(); ++ __cpm_start_me(); ++ __cpm_start_mc(); ++ __cpm_start_ipu(); ++#endif ++ ++ printk("JZ I2S OSS audio driver initialized\n"); ++ ++ return 0; ++} ++ ++static void __exit cleanup_jz_i2s(void) ++{ ++#ifdef CONFIG_PM ++ /* pm_unregister(i2s_controller->pm); */ ++#endif ++#if defined(CONFIG_I2S_DLV) ++ free_irq(IRQ_AIC, NULL); ++#endif ++ unload_jz_i2s(i2s_controller); ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ if(clear_codec_mode) ++ clear_codec_mode(); ++} ++ ++module_init(init_jz_i2s); ++module_exit(cleanup_jz_i2s); ++ ++#if defined(CONFIG_SOC_JZ4730) ++static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count,con; ++ ++ if(elements_in_queue(&in_busy_queue) > 0) { ++ if (nonblock) ++ return -EBUSY; ++ drain_flag = 1; ++ sleep_on(&drain_wait_queue); ++ drain_flag = 0; ++ } else { ++ add_wait_queue(&ctrl->adc_wait, &wait); ++ for (con = 0; con < 1000; con ++) { ++ udelay(1); ++ set_current_state(TASK_INTERRUPTIBLE); ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ if (nonblock) { ++ remove_wait_queue(&ctrl->adc_wait, &wait); ++ current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ } ++ remove_wait_queue(&ctrl->adc_wait, &wait); ++ current->state = TASK_RUNNING; ++ } ++ return 0; ++} ++ ++static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count; ++ ++ if(elements_in_queue(&out_full_queue) > 0) { ++ if (nonblock) ++ return -EBUSY; ++ ++ drain_flag = 1; ++ sleep_on(&drain_wait_queue); ++ drain_flag = 0; ++ } else { ++ add_wait_queue(&(ctrl->dac_wait), &wait); ++ for (;;) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ if(elements_in_queue(&out_full_queue) <= 0) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if(count <= 0) ++ break; ++ } ++ if (nonblock) { ++ remove_wait_queue(&ctrl->dac_wait, &wait); ++ current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ } ++ remove_wait_queue(&ctrl->dac_wait, &wait); ++ current->state = TASK_RUNNING; ++ } ++ ++ return 0; ++} ++#endif ++ ++#if defined(CONFIG_SOC_JZ4750) ++static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ //DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int count,i=0; ++ ++ //add_wait_queue(&ctrl->adc_wait, &wait); ++ for (;;) { ++ if (i < MAXDELAY) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ //set_current_state(TASK_INTERRUPTIBLE); ++ spin_lock_irqsave(&ctrl->lock, flags); ++ //spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ //spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ ++ /*if (signal_pending(current)) ++ break;*/ ++ if (nonblock) { ++ //remove_wait_queue(&ctrl->adc_wait, &wait); ++ //current->state = TASK_RUNNING; ++ return -EBUSY; ++ } ++ } ++ //remove_wait_queue(&ctrl->adc_wait, &wait); ++ //current->state = TASK_RUNNING; ++ /*if (signal_pending(current)) ++ return -ERESTARTSYS;*/ ++ return 0; ++} ++static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ unsigned long flags; ++ int count,ele,busyele,emptyele,i=0; ++ ++ for (;;) { ++ if(!nonblock) {//blocked ++ if (i < MAXDELAY) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ ++ ele = elements_in_queue(&out_full_queue); ++ if(ele <= 0) { ++ udelay(200); ++ ++ busyele = elements_in_queue(&out_busy_queue); ++ emptyele = elements_in_queue(&out_empty_queue); ++ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ } ++ } ++ } else {//non-blocked ++ //mdelay(100); ++ ele = elements_in_queue(&out_full_queue); ++ ++ if(ele <= 0) { ++ //mdelay(100); ++ busyele = elements_in_queue(&out_busy_queue); ++ emptyele = elements_in_queue(&out_empty_queue); ++ ++ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { ++ spin_lock_irqsave(&ctrl->lock, flags); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (count <= 0) ++ break; ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++#if defined(CONFIG_SOC_JZ4740) ++#define MAXDELAY 50000 ++static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ int count,ele,i=0; ++ ++ for (;;) { ++ if(!nonblock) {//blocked ++ if ( i < MAXDELAY ) { ++ udelay(10); ++ i++; ++ } else ++ break; ++ ++ ele = elements_in_queue(&out_full_queue); ++ if(ele <= 0) { ++ udelay(10); ++ spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ } ++ } else {//non-blocked ++ mdelay(100); ++ ele = elements_in_queue(&out_full_queue); ++ ++ if(ele <= 0) { ++ mdelay(100); ++ ++ spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma1); ++ spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) ++{ ++ int count,i=0; ++ ++ for (;;) { ++ if ( i < MAXDELAY ) ++ { ++ udelay(10); ++ i++; ++ } ++ else ++ break; ++ spin_lock(&ctrl->lock); ++ count = get_dma_residue(ctrl->dma2); ++ spin_unlock(&ctrl->lock); ++ if (count <= 0) ++ break; ++ ++ if (nonblock) { ++ return -EBUSY; ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++static int jz_audio_release(struct inode *inode, struct file *file) ++{ ++ unsigned long flags; ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ unsigned long tfl; ++ ++ if (controller == NULL) ++ return -ENODEV; ++ ++ pop_dma_flag = 0; ++ if (controller->opened1 == 1) { ++ controller->opened1 = 0; ++ __i2s_enable_transmit_dma(); ++ __i2s_enable_replay(); ++ drain_dac(controller, file->f_flags & O_NONBLOCK); ++ /* add some mute to anti-pop */ ++#if defined(CONFIG_I2S_DLV) ++ /* wait for fifo empty */ ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ gain_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //gain_down_end = jiffies; ++ while (1) { ++ tfl = REG_AIC_SR & 0x00003f00; ++ if (tfl == 0) { ++ udelay(500); ++ break; ++ } ++ mdelay(2); ++ } ++#endif ++ disable_dma(controller->dma1); ++ set_dma_count(controller->dma1, 0); ++ __i2s_disable_transmit_dma(); ++ __i2s_disable_replay(); ++ __aic_flush_fifo(); ++ if(clear_codec_replay) ++ clear_codec_replay(); ++ __aic_flush_fifo(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ ramp_down_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //ramp_down_end = jiffies; ++ unset_audio_data_replay(); ++#endif ++ __i2s_disable(); ++ if(turn_off_codec) ++ turn_off_codec(); ++ } ++ ++ if (controller->opened2 == 1) { ++ controller->opened2 = 0; ++ first_record_call = 1; ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ drain_adc(controller, file->f_flags & O_NONBLOCK); ++ disable_dma(controller->dma2); ++ set_dma_count(controller->dma2, 0); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++ ++ if(clear_codec_record) ++ clear_codec_record(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ __i2s_disable(); ++ if(turn_off_codec) ++ turn_off_codec(); ++ abnormal_data_count = 0; ++ } ++ ++#if defined(CONFIG_I2S_DLV) ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++#endif ++ return 0; ++} ++ ++static int jz_audio_open(struct inode *inode, struct file *file) ++{ ++ int i; ++ struct jz_i2s_controller_info *controller = i2s_controller; ++ ++ if (controller == NULL) ++ return -ENODEV; ++ ++ mdelay(2); ++ REG_DMAC_DMACKE(0) = 0x3f; ++ pop_dma_flag = 0; ++ if (controller->opened1 == 1 || controller->opened2 == 1 ) { ++ printk("\naudio is busy!\n"); ++ return -EBUSY; ++ } ++ jz_codec_config = 0; ++ ++ ramp_up_start = 0; ++ ramp_up_end = 0; ++ gain_up_start = 0; ++ gain_up_end = 0; ++ ramp_down_start = 0; ++ ramp_down_end = 0; ++ gain_down_start = 0; ++ gain_down_end = 0; ++ if (file->f_mode & FMODE_WRITE) { ++ if (controller->opened1 == 1) ++ return -EBUSY; ++ ++ controller->opened1 = 1; ++ /* for ioctl */ ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextOut = 0; ++ ++ for(i=0;i < 64;i++) { ++ save_last_samples[i].left = 0; ++ save_last_samples[i].right = 0; ++ } ++ ++ out_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(out_empty_queue.id + i) = i; ++ out_busy_queue.count = 0; ++ out_full_queue.count = 0; ++ last_dma_buffer_id = 0; ++ } ++ ++ if (file->f_mode & FMODE_READ) { ++ if (controller->opened2 == 1) ++ return -EBUSY; ++ ++ controller->opened2 = 1; ++ first_record_call = 1; ++ /* for ioctl */ ++ controller->total_bytes = 0; ++ jz_audio_dma_tran_count = 0; ++ controller->count = 0; ++ controller->finish = 0; ++ controller->blocks = 0; ++ controller->nextIn = 0; ++ ++ in_empty_queue.count = jz_audio_fragstotal; ++ for (i=0;i < jz_audio_fragstotal;i++) ++ *(in_empty_queue.id + i) = i; ++ ++ in_full_queue.count = 0; ++ in_busy_queue.count = 0; ++ } ++ ++ file->private_data = controller; ++ jz_audio_reset(); ++ REG_AIC_FR |= (1 << 6); ++ ++ if (file->f_mode & FMODE_WRITE) { ++ if(set_codec_replay) ++ set_codec_replay(); ++ } ++ ++ if (file->f_mode & FMODE_READ) { ++ abnormal_data_count = 0; ++ if(set_codec_record) ++ set_codec_record(); ++ } ++ ++#if defined(CONFIG_I2S_DLV) ++ __aic_reset(); ++ ++ mdelay(10); ++ REG_AIC_I2SCR = 0x10; ++ mdelay(20); ++ __aic_flush_fifo(); ++#endif ++ ++ __i2s_enable(); ++ ++#if defined(CONFIG_I2S_DLV) ++ if (file->f_mode & FMODE_WRITE) { ++ ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ ramp_up_start = jiffies; ++ /*while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_RCR = 0x1; ++ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); ++ REG_RTC_RGR = 1;*/ ++ sleep_on(&pop_wait_queue); ++ //ramp_up_end = jiffies; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ } else if (file->f_mode & FMODE_READ) { ++ if (jz_mic_only) ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ else ++ write_codec_file_bit(5, 0, 7);//SB_DAC->0 ++ mdelay(500); ++ } ++ ++#endif ++ ++ return 0; ++} ++ ++ ++static int jz_audio_ioctl(struct inode *inode, struct file *file, ++unsigned int cmd, unsigned long arg) ++{ ++ int val,fullc,busyc,unfinish,newfragstotal,newfragsize; ++ unsigned int flags; ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ count_info cinfo; ++ audio_buf_info abinfo; ++ int id, i; ++ ++ val = 0; ++ switch (cmd) { ++ case OSS_GETVERSION: ++ return put_user(SOUND_VERSION, (int *)arg); ++ case SNDCTL_DSP_RESET: ++#if 0 ++ jz_audio_reset(); ++ __i2s_disable_replay(); ++ __i2s_disable_receive_dma(); ++ __i2s_disable_record(); ++ __i2s_disable_transmit_dma(); ++#endif ++ return 0; ++ case SNDCTL_DSP_SYNC: ++ if (file->f_mode & FMODE_WRITE) ++ return drain_dac(controller, file->f_flags & O_NONBLOCK); ++ return 0; ++ case SNDCTL_DSP_SPEED: ++ /* set smaple rate */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ if (val >= 0) ++ jz_audio_set_speed(controller->dev_audio, val); ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_STEREO: ++ /* set stereo or mono channel */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); ++ ++ return 0; ++ case SNDCTL_DSP_GETBLKSIZE: ++ //return put_user(jz_audio_fragsize / jz_audio_b, (int *)arg); ++ return put_user(jz_audio_fragsize, (int *)arg); ++ case SNDCTL_DSP_GETFMTS: ++ /* Returns a mask of supported sample format*/ ++ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); ++ case SNDCTL_DSP_SETFMT: ++ /* Select sample format */ ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ if (val != AFMT_QUERY) ++ jz_audio_set_format(controller->dev_audio,val); ++ else { ++ if (file->f_mode & FMODE_READ) ++ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; ++ else ++ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; ++ } ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_CHANNELS: ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ jz_audio_set_channels(controller->dev_audio, val); ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_POST: ++ /* FIXME: the same as RESET ?? */ ++ return 0; ++ case SNDCTL_DSP_SUBDIVIDE: ++ return 0; ++ case SNDCTL_DSP_SETFRAGMENT: ++ get_user(val, (long *) arg); ++ newfragsize = 1 << (val & 0xFFFF); ++ if (newfragsize < 4 * PAGE_SIZE) ++ newfragsize = 4 * PAGE_SIZE; ++ if (newfragsize > (16 * PAGE_SIZE)) ++ newfragsize = 16 * PAGE_SIZE; ++ ++ newfragstotal = (val >> 16) & 0x7FFF; ++ if (newfragstotal < 2) ++ newfragstotal = 2; ++ if (newfragstotal > 32) ++ newfragstotal = 32; ++ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize)) ++ return 0; ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ mdelay(500); ++ jz_audio_fragstotal = newfragstotal; ++ jz_audio_fragsize = newfragsize; ++ ++ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ mdelay(10); ++ ++ return 0; ++ case SNDCTL_DSP_GETCAPS: ++ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg); ++ case SNDCTL_DSP_NONBLOCK: ++ file->f_flags |= O_NONBLOCK; ++ return 0; ++ case SNDCTL_DSP_SETDUPLEX: ++ return -EINVAL; ++ case SNDCTL_DSP_GETOSPACE: ++ { ++ int i, bytes = 0; ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ jz_audio_fragments = elements_in_queue(&out_empty_queue); ++ for (i = 0; i < jz_audio_fragments; i++) ++ bytes += jz_audio_fragsize; ++ ++ if (jz_audio_channels == 2) ++ bytes /= jz_audio_b; ++ else if (jz_audio_channels == 1) ++ bytes /= 4; ++ else ++ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 1!\n"); ++ ++ ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ /* unused fragment amount */ ++ abinfo.fragments = jz_audio_fragments; ++ /* amount of fragments */ ++ abinfo.fragstotal = jz_audio_fragstotal; ++ /* fragment size in bytes */ ++ if (jz_audio_channels == 2) ++ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; ++ else if (jz_audio_channels == 1) ++ abinfo.fragsize = jz_audio_fragsize / 4; ++ else ++ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 2!\n"); ++ ++ /* write size count without blocking in bytes */ ++ abinfo.bytes = bytes; ++ ++ return copy_to_user((void *)arg, &abinfo, ++ sizeof(abinfo)) ? -EFAULT : 0; ++ } ++ case SNDCTL_DSP_GETISPACE: ++ { ++ int i, bytes = 0; ++ if (!(file->f_mode & FMODE_READ)) ++ return -EINVAL; ++ jz_audio_fragments = elements_in_queue(&in_empty_queue); ++ for (i = 0; i < jz_audio_fragments; i++) ++ bytes += jz_audio_fragsize; ++ ++ if (jz_audio_channels == 2) ++ bytes /= jz_audio_b; ++ else if (jz_audio_channels == 1) ++ bytes /= 4; ++ else ++ printk("SNDCTL_DSP_GETISPACE : channels is wrong 1!\n"); ++ ++ abinfo.fragments = jz_audio_fragments; ++ abinfo.fragstotal = jz_audio_fragstotal; ++ ++ if (jz_audio_channels == 2) ++ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; ++ else if (jz_audio_channels == 1) ++ abinfo.fragsize = jz_audio_fragsize / 4; ++ else ++ printk("SNDCTL_DSP_GETISPACE : channels is wrong 2!\n"); ++ ++ abinfo.bytes = bytes; ++ ++ return copy_to_user((void *)arg, &abinfo, ++ sizeof(abinfo)) ? -EFAULT : 0; ++ } ++ case SNDCTL_DSP_GETTRIGGER: ++ val = 0; ++ if (file->f_mode & FMODE_READ && in_dma_buf) ++ val |= PCM_ENABLE_INPUT; ++ if (file->f_mode & FMODE_WRITE && out_dma_buf) ++ val |= PCM_ENABLE_OUTPUT; ++ ++ return put_user(val, (int *)arg); ++ case SNDCTL_DSP_SETTRIGGER: ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ return 0; ++ case SNDCTL_DSP_GETIPTR: ++ if (!(file->f_mode & FMODE_READ)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ cinfo.bytes = controller->total_bytes; ++ cinfo.blocks = controller->blocks; ++ cinfo.ptr = controller->nextIn; ++ controller->blocks = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); ++ case SNDCTL_DSP_GETOPTR: ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ cinfo.bytes = controller->total_bytes; ++ cinfo.blocks = controller->blocks; ++ cinfo.ptr = controller->nextOut; ++ controller->blocks = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); ++ case SNDCTL_DSP_GETODELAY: ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ unfinish = 0; ++ fullc = elements_in_queue(&out_full_queue); ++ busyc = elements_in_queue(&out_busy_queue); ++ for(i = 0;i < fullc ;i ++) { ++ id = *(out_full_queue.id + i); ++ unfinish += *(out_dma_buf_data_count + id); ++ } ++ for(i = 0;i < busyc ;i ++) { ++ id = *(out_busy_queue.id + i); ++ unfinish += get_dma_residue(controller->dma1); ++ } ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ if (jz_audio_channels == 2) ++ unfinish /= jz_audio_b; ++ else if (jz_audio_channels == 1) ++ unfinish /= 4; ++ else ++ printk("SNDCTL_DSP_GETODELAY : channels is wrong !\n"); ++ ++ return put_user(unfinish, (int *) arg); ++ case SOUND_PCM_READ_RATE: ++ return put_user(jz_audio_rate, (int *)arg); ++ case SOUND_PCM_READ_CHANNELS: ++ return put_user(jz_audio_channels, (int *)arg); ++ case SOUND_PCM_READ_BITS: ++ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg); ++ case SNDCTL_DSP_MAPINBUF: ++ case SNDCTL_DSP_MAPOUTBUF: ++ case SNDCTL_DSP_SETSYNCRO: ++ case SOUND_PCM_WRITE_FILTER: ++ case SOUND_PCM_READ_FILTER: ++ return -EINVAL; ++ } ++ return -EINVAL; ++} ++ ++ ++static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait) ++{ ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ unsigned long flags; ++ unsigned int mask = 0; ++ ++ if (file->f_mode & FMODE_WRITE) { ++ if (elements_in_queue(&out_empty_queue) > 0) ++ return POLLOUT | POLLWRNORM; ++ ++ poll_wait(file, &controller->dac_wait, wait); ++ } ++ ++ if (file->f_mode & FMODE_READ) { ++ if (elements_in_queue(&in_full_queue) > 0) ++ return POLLIN | POLLRDNORM; ++ ++ poll_wait(file, &controller->adc_wait, wait); ++ } ++ ++ spin_lock_irqsave(&controller->lock, flags); ++ if (file->f_mode & FMODE_WRITE) { ++ if (elements_in_queue(&out_empty_queue) > 0) ++ mask |= POLLOUT | POLLWRNORM; ++ } else if (file->f_mode & FMODE_READ) { ++ if (elements_in_queue(&in_full_queue) > 0) ++ mask |= POLLIN | POLLRDNORM; ++ } ++ spin_unlock_irqrestore(&controller->lock, flags); ++ ++ return mask; ++} ++ ++static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) ++{ ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ int id, ret = 0, left_count, copy_count, cnt = 0; ++ unsigned long flags; ++ ++ if (count < 0) ++ return -EINVAL; ++ ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextIn = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ copy_count = jz_audio_fragsize / 4; ++ ++ left_count = count; ++ if (first_record_call) { ++ first_record_call = 0; ++ audio_read_back_first: ++ if ((id = get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id); ++ spin_lock(&controller->lock); ++ *(in_dma_buf_data_count + id) = copy_count * 4; ++ ++ spin_unlock(&controller->lock); ++ __i2s_enable_receive_dma(); ++ __i2s_enable_record(); ++ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); ++ audio_start_dma(controller->dma2,file->private_data, ++ *(in_dma_pbuf + id), ++ *(in_dma_buf_data_count + id), ++ DMA_MODE_READ); ++ sleep_on(&rx_wait_queue); ++ } else ++ goto audio_read_back_first; ++ } ++ ++ while (left_count > 0) { ++ audio_read_back_second: ++ if (elements_in_queue(&in_full_queue) <= 0) { ++ if (file->f_flags & O_NONBLOCK) ++ return ret ? ret : -EAGAIN; ++ else ++ sleep_on(&rx_wait_queue); ++ } ++ ++ if ((id = get_buffer_id(&in_full_queue)) >= 0) { ++ spin_lock(&controller->lock); ++ cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id); ++ spin_unlock(&controller->lock); ++ put_buffer_id(&in_empty_queue, id); ++ } else ++ goto audio_read_back_second; ++ ++ if (elements_in_queue(&in_busy_queue) == 0) { ++ if ((id=get_buffer_id(&in_empty_queue)) >= 0) { ++ put_buffer_id(&in_busy_queue, id); ++ spin_lock(&controller->lock); ++ *(in_dma_buf_data_count + id) = copy_count * 4; ++ spin_unlock(&controller->lock); ++ ++ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); ++ audio_start_dma(controller->dma2,file->private_data, ++ *(in_dma_pbuf + id), ++ *(in_dma_buf_data_count + id), ++ DMA_MODE_READ); ++ } ++ } ++ if (ret + cnt > count) { ++ spin_lock(&controller->lock); ++ cnt = count - ret; ++ spin_unlock(&controller->lock); ++ } ++ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt)) ++ return ret ? ret : -EFAULT; ++ ++ spin_lock(&controller->lock); ++ ret += cnt; ++ spin_unlock(&controller->lock); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextIn += ret; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ spin_lock(&controller->lock); ++ left_count -= cnt; ++ spin_unlock(&controller->lock); ++ } ++ return ret; ++} ++ ++static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) ++{ ++ int id, ret = 0, left_count, copy_count = 0; ++ unsigned int flags; ++ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; ++ ++ if (count <= 0) ++ return -EINVAL; ++ ++ if(set_replay_hp_or_speaker) ++ set_replay_hp_or_speaker(); ++ ++ __i2s_enable_transmit_dma(); ++ __i2s_enable_replay(); ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextOut = 0; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ if (jz_audio_channels == 2) ++ copy_count = jz_audio_fragsize / jz_audio_b; ++ else if(jz_audio_channels == 1) ++ copy_count = jz_audio_fragsize / 4; ++ left_count = count; ++ if (copy_from_user(controller->tmp1, buffer, count)) { ++ printk("copy_from_user failed:%d",ret); ++ return ret ? ret : -EFAULT; ++ } ++ ++ while (left_count > 0) { ++ audio_write_back: ++ /*if (file->f_flags & O_NONBLOCK) ++ udelay(2);*/ ++ if (elements_in_queue(&out_empty_queue) == 0) { ++ if (file->f_flags & O_NONBLOCK) ++ return ret; ++ else ++ sleep_on(&tx_wait_queue); ++ } ++ /* the end fragment size in this write */ ++ if (ret + copy_count > count) ++ copy_count = count - ret; ++ if ((id = get_buffer_id(&out_empty_queue)) >= 0) { ++ replay_filler((signed long)controller->tmp1 + ret, copy_count, id); ++ if(*(out_dma_buf_data_count + id) > 0) { ++ put_buffer_id(&out_full_queue, id); ++ dma_cache_wback_inv(*(out_dma_buf + id), ++ *(out_dma_buf_data_count + id)); ++ } else ++ put_buffer_id(&out_empty_queue, id); ++ } else ++ goto audio_write_back; ++ ++ left_count = left_count - copy_count; ++ ret += copy_count; ++ ++ spin_lock_irqsave(&controller->ioctllock, flags); ++ controller->nextOut += ret; ++ spin_unlock_irqrestore(&controller->ioctllock, flags); ++ ++ if (elements_in_queue(&out_busy_queue) == 0) { ++ if ((id=get_buffer_id(&out_full_queue)) >= 0) { ++ put_buffer_id(&out_busy_queue, id); ++ ++ if(*(out_dma_buf_data_count + id) > 0) { ++ audio_start_dma(controller->dma1, ++ file->private_data, ++ *(out_dma_pbuf + id), ++ *(out_dma_buf_data_count + id), ++ DMA_MODE_WRITE); ++ last_dma_buffer_id = id; ++ if (jz_codec_config == 0) { ++ write_codec_file_bit(1, 0, 5); ++ gain_up_start = jiffies; ++ sleep_on(&pop_wait_queue); ++ //gain_up_end = jiffies; ++ jz_codec_config = 1; ++ //SB_ADC->1 ++ //write_codec_file_bit(5, 1, 4); ++ //while(1); ++ } ++ } ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++#if defined(CONFIG_I2S_ICODEC) ++static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample) ++{ ++ int i,step_len; ++ unsigned long *pop_buf = (unsigned long*)pop_turn_onoff_buf; ++ unsigned int sample_oss = (REG_AIC_CR & 0x00380000) >> 19; ++ unsigned long l_sample_count,r_sample_count,sample_count; ++ struct jz_i2s_controller_info *controller = i2s_controller; ++ signed int left_sam=0,right_sam=0,l_val,r_val; ++ ++ switch (sample_oss) { ++ case 0x0: ++ break; ++ case 0x1: ++ left_sam = (signed int)l_sample; ++ right_sam = (signed int)r_sample; ++ break; ++ case 0x2: ++ break; ++ case 0x3: ++ break; ++ case 0x4: ++ break; ++ } ++ ++ if(left_sam == 0 && right_sam == 0) ++ return; ++ ++ switch (sample_oss) { ++ case 0x0: ++ break; ++ case 0x1: ++ step_len = jz_audio_speed / 10 * 3; ++ step_len = step_len / 2; ++ step_len = 0x7fff / step_len + 1; ++ ++ l_sample_count = 0; ++ l_val = left_sam; ++ ++ while(1) { ++ if(l_val > 0) { ++ if(l_val >= step_len) { ++ l_val -= step_len; ++ l_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(l_val < 0) { ++ if(l_val <= -step_len) { ++ l_val += step_len; ++ l_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(l_val == 0) ++ break; ++ } ++ ++ r_sample_count = 0; ++ r_val = right_sam; ++ while(1) { ++ if(r_val > 0) { ++ if(r_val >= step_len) { ++ r_val -= step_len; ++ r_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(r_val < 0) { ++ if(r_val <= -step_len) { ++ r_val += step_len; ++ r_sample_count ++; ++ } else ++ break; ++ } ++ ++ if(r_val == 0) ++ break; ++ } ++ /* fill up */ ++ if(l_sample_count > r_sample_count) ++ sample_count = l_sample_count; ++ else ++ sample_count = r_sample_count; ++ ++ l_val = left_sam; ++ r_val = right_sam; ++ for(i=0;i <= sample_count;i++) { ++ ++ *pop_buf = (unsigned long)l_val; ++ pop_buf ++; ++ ++ if(l_val > step_len) ++ l_val -= step_len; ++ else if(l_val < -step_len) ++ l_val += step_len; ++ else if(l_val >= -step_len && l_val <= step_len) ++ l_val = 0; ++ ++ *pop_buf = (unsigned long)r_val; ++ pop_buf ++; ++ if(r_val > step_len) ++ r_val -= step_len; ++ else if(r_val < -step_len) ++ r_val += step_len; ++ else if(r_val >= -step_len && r_val <= step_len) ++ r_val = 0; ++ } ++ ++ *pop_buf = 0; ++ pop_buf ++; ++ *pop_buf = 0; ++ ++ pop_buf ++; ++ sample_count += 2; ++ dma_cache_wback_inv(pop_turn_onoff_buf, sample_count*8); ++ ++ pop_dma_flag = 1; ++ audio_start_dma(controller->dma1,controller,pop_turn_onoff_pbuf,sample_count*8,DMA_MODE_WRITE); ++ sleep_on(&pop_wait_queue); ++ pop_dma_flag = 0; ++ break; ++ case 0x2: ++ break; ++ case 0x3: ++ break; ++ case 0x4: ++ break; ++ } ++} ++#endif --- linux-2.6.24.7.old/sound/oss/jz_pcm_tlv320aic1106_dma.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7/sound/oss/jz_pcm_tlv320aic1106_dma.c 2009-04-12 18:13:57.000000000 +0200 @@ -0,0 +1,1839 @@ @@ -18475,13 +14989,13 @@ + unsigned char *tmp2; + spinlock_t lock; + spinlock_t ioctllock; -+ ++ + wait_queue_head_t dac_wait; + wait_queue_head_t adc_wait; + int nextIn; // byte index to next-in to DMA buffer + int nextOut; // byte index to next-out from DMA buffer + int count; // current byte count in DMA buffer -+ int finish; // current transfered byte count in DMA buffer ++ int finish; // current transfered byte count in DMA buffer + unsigned long total_bytes; // total bytes written or read + unsigned long blocks; + unsigned long error; // over/underrun @@ -18493,7 +15007,7 @@ + void *private_data; + char *name; + int id; -+ int dev_mixer; ++ int dev_mixer; + /* controller specific lower leverl pcm accessing routines */ + u16 (*codec_read) (u8 reg);//the function accessing Codec REGs + void (*codec_write) (u8 reg, u16 val); @@ -18535,14 +15049,14 @@ +static buffer_queue_t in_full_queue; +static buffer_queue_t in_busy_queue; +static int first_record_call = 0; -+ ++ +static inline int get_buffer_id(struct buffer_queue_s *q) +{ + int r, i; + unsigned long flags; + + spin_lock_irqsave(&q->lock, flags); -+ if (q->count == 0) { ++ if (q->count == 0) { + spin_unlock_irqrestore(&q->lock, flags); + return -1; + } @@ -18551,7 +15065,7 @@ + *(q->id + i) = *(q->id + (i+1)); + q->count --; + spin_unlock_irqrestore(&q->lock, flags); -+ ++ + return r; +} + @@ -18581,7 +15095,7 @@ +{ + unsigned long flags; + struct jz_pcm_controller_info * controller = (struct jz_pcm_controller_info *) dev_id; -+ ++ + //for DSP_GETOPTR + //spin_lock_irqsave(&controller->ioctllock, flags); + spin_lock(&controller->ioctllock); @@ -18641,7 +15155,7 @@ + set_dma_count(chan, count); + enable_dma(chan); + release_dma_lock(flags); -+#if 0 ++#if 0 + __pcm_enable_tfs_intr(); + __pcm_enable_tur_intr(); + __pcm_enable_rfs_intr(); @@ -18670,22 +15184,22 @@ + spin_unlock(&controller->ioctllock); + id1 = get_buffer_id(&in_busy_queue); + put_buffer_id(&in_full_queue, id1); -+ ++ + wake_up(&rx_wait_queue); + wake_up(&controller->adc_wait); + if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { + put_buffer_id(&in_busy_queue, id2); + *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1); -+ ++ + dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2)); + audio_start_dma(dma,dev_id, + *(in_dma_pbuf + id2), + *(in_dma_buf_data_count + id2), + DMA_MODE_READ); -+ } else ++ } else + in_busy_queue.count = 0; + } -+ ++ + return IRQ_HANDLED; +} + @@ -18693,7 +15207,7 @@ +{ + struct jz_pcm_controller_info * controller = (struct jz_pcm_controller_info *) dev_id; + printk("pcm interrupt REG_PCM_INTS : 0x%08x\n",REG_PCM_INTS); -+ ++ + return IRQ_HANDLED; +} + @@ -18796,7 +15310,7 @@ + out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); + if (!out_busy_queue.id) + goto all_mem_err; -+ for (i=0;i < fragstotal;i++) ++ for (i=0;i < fragstotal;i++) + *(out_empty_queue.id + i) = i; + + out_busy_queue.count = 0; @@ -18810,7 +15324,7 @@ + } + *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); + } -+ ++ + return 1; +all_mem_err: + printk("error:allocate memory occur error 1!\n"); @@ -18876,7 +15390,7 @@ + dma_cache_wback_inv(*(in_dma_buf + i), fragsize); + free_pages(*(in_dma_buf + i), get_order(fragsize)); + } -+ *(in_dma_buf + i) = 0; //release page error ++ *(in_dma_buf + i) = 0; //release page error + } + kfree(in_dma_buf); + in_dma_buf = NULL; @@ -18905,7 +15419,7 @@ + in_empty_queue.count = fragstotal; + in_full_queue.count = 0; + in_busy_queue.count = 0; -+ ++ + return 1; +} + @@ -18914,14 +15428,14 @@ + /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000 */ + long codec_speed; + long speed = 0; -+ ++ + jz_audio_speed = rate; + if (rate > 48000) + rate = 48000; + if (rate < 8000) + rate = 8000; + jz_audio_rate = rate; -+ ++ + /*switch (rate) { + case 8000: + speed = 0; @@ -19045,7 +15559,7 @@ + cnt += 2;/* count in byte */ + } +#endif -+ ++ + return cnt; +} + @@ -19123,7 +15637,7 @@ + } + d1 = (unsigned short)sam_to; + d1 = d1 << 3; -+ l1 = d1 | jz_audio_volume; ++ l1 = d1 | jz_audio_volume; + + *dp = l1; + s ++; @@ -19140,11 +15654,11 @@ + unsigned short d1, l1; + volatile unsigned short *s = (unsigned short *)src_start; + volatile unsigned short *dp = (unsigned short*)(*(out_dma_buf + id)); -+ ++ +#if 1 + while (count > 0) { + d1 = *s; -+ l1 = (d1 & 0xfff8) | jz_audio_volume; ++ l1 = (d1 & 0xfff8) | jz_audio_volume; + *dp = l1; + s ++; + dp ++; @@ -19276,7 +15790,7 @@ + return -ESPIPE; +} + -+static struct file_operations jz_pcm_mixer_fops = ++static struct file_operations jz_pcm_mixer_fops = +{ + owner: THIS_MODULE, + llseek: jz_pcm_llseek, @@ -19288,7 +15802,7 @@ +{ + int ret; + long val = 0; -+ ++ + switch (cmd) { + case SOUND_MIXER_READ_STEREODEVS: + return put_user(0, (long *) arg); @@ -19360,7 +15874,7 @@ + default: + return -ENOSYS; + } -+ ++ + return 0; +} + @@ -19377,14 +15891,14 @@ +{ + int num_pcm = 0; + struct pcm_codec *codec; -+ ++ + for (num_pcm = 0; num_pcm < NR_PCM; num_pcm++) { + if ((codec = kmalloc(sizeof(struct pcm_codec),GFP_KERNEL)) == NULL) + return -ENOMEM; + memset(codec, 0, sizeof(struct pcm_codec)); + codec->private_data = controller; + codec->id = num_pcm; -+ ++ + if (pcm_probe_codec(codec) == 0) + break; + if ((codec->dev_mixer = register_sound_mixer(&jz_pcm_mixer_fops, -1)) < 0) { @@ -19394,7 +15908,7 @@ + } + controller->pcm_codec[num_pcm] = codec; + } -+ ++ + return num_pcm; +} + @@ -19430,7 +15944,7 @@ + char *name; + int adev;//No of Audio device. + int err; -+ ++ + name = controller->name; + /* register /dev/audio */ + adev = register_sound_dsp(&jz_pcm_audio_fops, -1); @@ -19457,10 +15971,10 @@ + printk("JzSOC On-Chip PCM controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2)); + + err = request_irq(IRQ_PCM, jz_pcm_irq, IRQF_DISABLED, "pcm irq", controller); -+ if (err < 0) ++ if (err < 0) + printk("can't allocate pcm irq.\n"); + controller->dev_audio = adev; -+ ++ + return; +dma2_failed: + jz_free_dma(controller->dma2); @@ -19468,7 +15982,7 @@ + jz_free_dma(controller->dma1); +tmp1_failed: + free_pages((unsigned long)controller->tmp1, JZCODEC_USER_BUFFER); -+ ++ +mixer_failed: + unregister_sound_dsp(adev); +audio_failed: @@ -19499,18 +16013,18 @@ +static void __exit unload_jz_pcm(struct jz_pcm_controller_info *controller) +{ + int adev = controller->dev_audio; -+ ++ + __pcm_reset(); + schedule_timeout(5); + __pcm_disable(); + __pcm_clk_disable(); + __pcm_flush_fifo(); -+ ++ + controller->dev_audio = -1; + jz_free_dma(controller->dma1); + jz_free_dma(controller->dma2); + free_pages((unsigned long)controller->tmp1, JZCODEC_USER_BUFFER); -+ ++ + if (adev >= 0) + unregister_sound_dsp(controller->dev_audio); +} @@ -19520,7 +16034,7 @@ + int errno; + /* 24M OSC ---> CPCCR.ECS ---> PCMCDR.PCMS ---> cpm_pcm_sysclk(X) */ + long X = 12000000; //in Hz /* 6.144 MHz <= X <= 264.192 MHz */ -+ ++ +#if 0 + /* pcm_sys_clk is from PLL divsion */ + REG_CPM_PCMCDR = 0x8000001b; @@ -19544,7 +16058,7 @@ + __pcm_set_sync_rate(2048000, 8000); + //__pcm_set_sync_rate(2000000, 8000); + __pcm_set_sync_len(0); -+ ++ + __pcm_flush_fifo(); + __pcm_disable_txfifo(); + __pcm_disable_rxfifo(); @@ -19575,7 +16089,7 @@ + + __pcm_enable(); + __pcm_clk_enable(); -+ ++ + if ((errno = probe_jz_pcm(&pcm_controller)) < 0) + return errno; + attach_jz_pcm(pcm_controller); @@ -19590,10 +16104,10 @@ + jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE; + jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ; + Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ ++ + __gpio_clear_pin(32 * 5 + 4); + udelay(100); -+ ++ + __gpio_set_pin(32 * 5 + 4); + dump_pcmc_reg(); + @@ -19604,7 +16118,7 @@ +static void __exit cleanup_jz_pcm(void) +{ + unload_jz_pcm(pcm_controller); -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); ++ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); +} + +module_init(init_jz_pcm); @@ -19614,24 +16128,24 @@ +{ + unsigned long flags; + int count, i=0; -+ ++ + for (;;) { + if ( i < MAXDELAY ) { + udelay(10); + i++; + } else -+ break; -+ ++ break; ++ + spin_lock_irqsave(&ctrl->lock, flags); + count = get_dma_residue(ctrl->dma2); + spin_unlock_irqrestore(&ctrl->lock, flags); + if (count <= 0) + break; -+ ++ + if (nonblock) + return -EBUSY; + } -+ ++ + return 0; +} +static int drain_dac(struct jz_pcm_controller_info *ctrl, int nonblock) @@ -19645,8 +16159,8 @@ + udelay(10); + i++; + } else -+ break; -+ ++ break; ++ + ele = elements_in_queue(&out_full_queue); + if(ele <= 0) { + udelay(10); @@ -19659,10 +16173,10 @@ + } else {//non-blocked + mdelay(100); + ele = elements_in_queue(&out_full_queue); -+ ++ + if(ele <= 0) { -+ mdelay(100); -+ ++ mdelay(100); ++ + spin_lock_irqsave(&ctrl->lock, flags); + count = get_dma_residue(ctrl->dma1); + spin_unlock_irqrestore(&ctrl->lock, flags); @@ -19678,7 +16192,7 @@ +static int jz_audio_release(struct inode *inode, struct file *file) +{ + struct jz_pcm_controller_info *controller = (struct jz_pcm_controller_info *) file->private_data; -+ ++ + if (controller == NULL) + return -ENODEV; + @@ -19688,7 +16202,7 @@ + drain_dac(controller, file->f_flags & O_NONBLOCK); + disable_dma(controller->dma1); + set_dma_count(controller->dma1, 0); -+ ++ + __pcm_disable_transmit_dma(); + __pcm_disable_txfifo(); + @@ -19703,7 +16217,7 @@ + //__pcm_disable(); + controller->opened1 = 0; + } -+ ++ + if ( controller->opened2 == 1 ) { + first_record_call = 1; + __pcm_enable_receive_dma(); @@ -19729,7 +16243,7 @@ + __pcm_disable_tur_intr(); + __pcm_disable_rfs_intr(); + __pcm_disable_ror_intr(); -+ ++ + return 0; +} + @@ -19740,7 +16254,7 @@ + + if (controller == NULL) + return -ENODEV; -+ ++ + if (controller->opened1 == 1 || controller->opened2 == 1 ) { + printk("\naudio is busy!\n"); + return -EBUSY; @@ -19759,7 +16273,7 @@ + controller->blocks = 0; + controller->nextOut = 0; + -+ out_empty_queue.count = jz_audio_fragstotal; ++ out_empty_queue.count = jz_audio_fragstotal; + for (i=0;i < jz_audio_fragstotal;i++) + *(out_empty_queue.id + i) = i; + out_busy_queue.count = 0; @@ -19800,10 +16314,10 @@ + int val,fullc,busyc,unfinish,newfragstotal,newfragsize; + unsigned int flags; + audio_buf_info abinfo; -+ int i, bytes, id; ++ int i, bytes, id; + count_info cinfo; + struct jz_pcm_controller_info *controller = (struct jz_pcm_controller_info *) file->private_data; -+ ++ + val = 0; + bytes = 0; + switch (cmd) { @@ -19831,14 +16345,14 @@ + + jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); + return 0; -+ ++ + case SNDCTL_DSP_GETBLKSIZE: + //return put_user(4*PAGE_SIZE, (int *)arg); + return put_user(jz_audio_fragsize , (int *)arg); + case SNDCTL_DSP_GETFMTS: + /* Returns a mask of supported sample format*/ + return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); -+ ++ + case SNDCTL_DSP_SETFMT: + { + if (get_user(val, (int *)arg)) @@ -19853,30 +16367,30 @@ + val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; + return put_user(val, (int *)arg); + } -+ ++ + case SNDCTL_DSP_CHANNELS: + if (get_user(val, (int *)arg)) + return -EFAULT; + printk("%s:%s:%d\n",__FILE__,__FUNCTION__,__LINE__); + jz_audio_set_channels(controller->dev_audio, val); + return put_user(val, (int *)arg); -+ ++ + case SNDCTL_DSP_POST: + /* FIXME: the same as RESET ?? */ + return 0; -+ ++ + case SNDCTL_DSP_SUBDIVIDE: + return 0; -+ ++ + case SNDCTL_DSP_SETFRAGMENT: + get_user(val, (long *) arg); + newfragsize = 1 << (val & 0xFFFF);//16 least bits -+ ++ + if (newfragsize < 4 * PAGE_SIZE) + newfragsize = 4 * PAGE_SIZE; + if (newfragsize > (16 * PAGE_SIZE)) //16 PAGE_SIZE + newfragsize = 16 * PAGE_SIZE; -+ ++ + newfragstotal = (val >> 16) & 0x7FFF; + if (newfragstotal < 2) + newfragstotal = 2; @@ -19888,7 +16402,7 @@ + mdelay(500); + jz_audio_fragstotal = newfragstotal; + jz_audio_fragsize = newfragsize; -+ ++ + Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); + mdelay(10); + @@ -19925,7 +16439,7 @@ + jz_audio_fragments = elements_in_queue(&in_empty_queue); + for (i = 0; i < jz_audio_fragments; i++) + bytes += jz_audio_fragsize; -+ ++ + abinfo.fragments = jz_audio_fragments; + abinfo.fragstotal = jz_audio_fragstotal; + abinfo.fragsize = jz_audio_fragsize; @@ -19938,7 +16452,7 @@ + if (file->f_mode & FMODE_WRITE && out_dma_buf) + val |= PCM_ENABLE_OUTPUT; + return put_user(val, (int *)arg); -+ ++ + case SNDCTL_DSP_SETTRIGGER: + if (get_user(val, (int *)arg)) + return -EFAULT; @@ -19953,7 +16467,7 @@ + cinfo.ptr = controller->nextIn; + controller->blocks = 0; + spin_unlock_irqrestore(&controller->ioctllock, flags); -+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); ++ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + case SNDCTL_DSP_GETOPTR: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; @@ -19973,7 +16487,7 @@ + busyc = elements_in_queue(&out_busy_queue); + for(i = 0;i < fullc ;i ++) { + id = *(out_full_queue.id + i); -+ unfinish += *(out_dma_buf_data_count + id); ++ unfinish += *(out_dma_buf_data_count + id); + } + for(i = 0;i < busyc ;i ++) { + id = *(out_busy_queue.id + i); @@ -20002,13 +16516,13 @@ + unsigned long flags; + unsigned int mask = 0; + struct jz_pcm_controller_info *controller = (struct jz_pcm_controller_info *) file->private_data; -+ ++ + if (file->f_mode & FMODE_WRITE) { + if (elements_in_queue(&out_empty_queue) > 0) + return POLLOUT | POLLWRNORM; + poll_wait(file, &controller->dac_wait, wait); + } -+ ++ + if (file->f_mode & FMODE_READ) { + if (elements_in_queue(&in_full_queue) > 0) + return POLLIN | POLLRDNORM; @@ -20038,7 +16552,7 @@ + + __pcm_enable_receive_dma(); + __pcm_enable_rxfifo(); -+ ++ + spin_lock(&controller->ioctllock); + controller->nextIn = 0; + spin_unlock(&controller->ioctllock); @@ -20059,14 +16573,14 @@ + + left_count = count; + spin_unlock(&controller->lock); -+ ++ + if (first_record_call) { + first_record_call = 0; +audio_read_back_first: + if ((id = get_buffer_id(&in_empty_queue)) >= 0) { + put_buffer_id(&in_busy_queue, id); -+ -+ spin_lock(&controller->lock); ++ ++ spin_lock(&controller->lock); + *(in_dma_buf_data_count + id) = copy_count; + spin_unlock(&controller->lock); + @@ -20075,7 +16589,7 @@ + *(in_dma_pbuf + id), + *(in_dma_buf_data_count + id), + DMA_MODE_READ); -+ ++ + sleep_on(&rx_wait_queue); + } else + goto audio_read_back_first; @@ -20097,7 +16611,7 @@ + put_buffer_id(&in_empty_queue, id); + } else + goto audio_read_back_second; -+ ++ + if (elements_in_queue(&in_busy_queue) == 0) { + if ((id=get_buffer_id(&in_empty_queue)) >= 0) { + put_buffer_id(&in_busy_queue, id); @@ -20131,7 +16645,7 @@ + left_count -= cnt; + spin_unlock(&controller->lock); + } -+ ++ + return ret; +} + @@ -20140,13 +16654,13 @@ + int id, ret, left_count, copy_count; + unsigned int flags; + struct jz_pcm_controller_info *controller = (struct jz_pcm_controller_info *) file->private_data; -+ ++ + if (count <= 0) + return -EINVAL; -+ ++ + __pcm_enable_transmit_dma(); + __pcm_enable_txfifo(); -+ ++ + spin_lock_irqsave(&controller->ioctllock, flags); + controller->nextOut = 0; + spin_unlock_irqrestore(&controller->ioctllock, flags); @@ -20160,7 +16674,7 @@ + if (count <= jz_audio_fragsize) + copy_count = count; + else -+ copy_count = jz_audio_fragsize; ++ copy_count = jz_audio_fragsize; +#endif + + left_count = count; @@ -20170,7 +16684,7 @@ + printk("copy_from_user failed:%d",ret); + return ret ? ret : -EFAULT; + } -+ ++ + while (left_count > 0) { +audio_write_back: + if (elements_in_queue(&out_empty_queue) == 0) { @@ -20192,10 +16706,10 @@ + put_buffer_id(&out_empty_queue, id); //spare + } else + goto audio_write_back; -+ ++ + left_count = left_count - copy_count; + ret += copy_count;//all is in byte -+ ++ + spin_lock(&controller->ioctllock); + controller->nextOut += ret; + spin_unlock(&controller->ioctllock); @@ -20203,14 +16717,14 @@ + if (elements_in_queue(&out_busy_queue) == 0) { + if ((id=get_buffer_id(&out_full_queue)) >= 0) { + put_buffer_id(&out_busy_queue, id); -+ ++ + if(*(out_dma_buf_data_count + id) > 0) { + audio_start_dma(controller->dma1, + file->private_data, + *(out_dma_pbuf + id), + *(out_dma_buf_data_count + id), + DMA_MODE_WRITE); -+ ++ + } + } + } @@ -20235,1120 +16749,1120 @@ --- linux-2.6.24.7.old/sound/oss/jzcodec.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7/sound/oss/jzcodec.c 2009-04-12 18:13:57.000000000 +0200 @@ -0,0 +1,443 @@ -+/* -+ * linux/drivers/sound/jzcodec.c -+ * -+ * JzSOC internal audio driver. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "sound_config.h" -+ -+#define USE_NONE 1 -+#define USE_MIC 2 -+#define USE_LINEIN 3 -+ -+typedef struct hpvol_shift_s -+{ -+ int hpvol; -+ int shift; -+} hpvol_shift_t; -+ -+extern mixer_info info; -+extern _old_mixer_info old_info; -+extern int codec_volue_shift; -+extern hpvol_shift_t hpvol_shift_table[72]; -+extern int abnormal_data_count; -+ -+extern void (*set_codec_mode)(void); -+extern void (*each_time_init_codec)(void); -+extern int (*set_codec_startup_param)(void); -+extern void (*set_codec_volume_table)(void); -+extern void (*set_codec_record)(int mode); -+extern void (*set_codec_replay)(void); -+extern void (*set_codec_replay_record)(int mode); -+extern void (*turn_on_codec)(void); -+extern void (*turn_off_codec)(void); -+extern void (*set_codec_speed)(int rate); -+extern void (*reset_codec)(void); -+extern void (*codec_mixer_old_info_id_name)(void); -+extern void (*codec_mixer_info_id_name)(void); -+extern void (*set_codec_bass)(int val); -+extern void (*set_codec_volume)(int val); -+extern void (*set_codec_mic)(int val); -+extern void (*set_codec_line)(int val); -+extern void (*i2s_resume_codec)(void); -+extern void (*i2s_suspend_codec)(void); -+extern void (*set_codec_direct_mode)(void); -+extern void (*clear_codec_direct_mode)(void); -+ -+static int jzcodec_reg[2]; -+ -+void set_jzcodec_mode(void); -+void each_time_init_jzcodec(void); -+int set_jzcodec_startup_param(void); -+void set_jzcodec_volume_table(void); -+void set_jzcodec_replay(void); -+void set_jzcodec_record(int mode); -+void turn_on_jzcodec(void); -+void turn_off_jzcodec(void); -+void set_jzcodec_speed(int rate); -+void reset_jzcodec(void); -+void jzcodec_mixer_old_info_id_name(void); -+void jzcodec_mixer_info_id_name(void); -+void set_jzcodec_bass(int val); -+void set_jzcodec_volume(int val); -+void set_jzcodec_mic(int val); -+void set_jzcodec_line(int val); -+void in_codec_app1(void); -+void in_codec_app12(void); -+void HP_turn_on(void); -+void HP_turn_off(void); -+void resume_jzcodec(void); -+void suspend_jzcodec(void); -+void set_jzcodec_replay_record(int mode); -+ -+void set_jzcodec_mode(void) -+{ -+ __i2s_internal_codec(); -+ __i2s_as_slave(); -+ __i2s_select_i2s(); -+ __aic_select_i2s(); -+ -+ REG_ICDC_CDCCR1 = 0x001b2303; -+ schedule_timeout(1); -+ REG_ICDC_CDCCR1 = 0x001b2302; -+} -+ -+void each_time_init_jzcodec(void) -+{ -+ __i2s_disable(); -+ __i2s_as_slave(); -+ __i2s_set_oss_sample_size(16); -+ __i2s_set_iss_sample_size(16); -+} -+ -+int set_jzcodec_startup_param(void) -+{ -+ REG_ICDC_CDCCR1 = 0x001b2300; -+ schedule_timeout(50); -+ REG_ICDC_CDCCR1 = 0x00033300; -+ schedule_timeout(5); -+ REG_ICDC_CDCCR1 = 0x17026300; -+ -+ return 1; -+} -+void set_jzcodec_volume_table(void) -+{ -+ int errno,hpvol_step,sample_shift; -+ -+ codec_volue_shift = 0; -+ hpvol_step = 3; -+ sample_shift = 0; -+ for(errno = 0;errno < 72;errno++) { -+ hpvol_shift_table[errno].hpvol = hpvol_step; -+ hpvol_shift_table[errno].shift = sample_shift; -+ hpvol_step --; -+ if(hpvol_step <= 0) { -+ hpvol_step = 3; -+ sample_shift ++; -+ } -+ } -+} -+ -+void set_jzcodec_replay(void) -+{ -+ in_codec_app1(); -+} -+ -+void set_jzcodec_record(int mode) -+{ -+ switch (mode) { -+ case USE_NONE: -+ case USE_MIC: -+ in_codec_app12(); -+ abnormal_data_count = 0; -+ break; -+ case USE_LINEIN: -+ REG_ICDC_CDCCR1 = 0x27022000;//for linein -+ mdelay(300); -+ break; -+ } -+} -+ -+void set_jzcodec_replay_record(int mode) -+{ -+ long val = 0; -+ REG_ICDC_CDCCR1 = 0x00037302; -+ mdelay(2); -+ REG_ICDC_CDCCR1 = 0x03006000; -+ mdelay(2); -+ -+ switch (mode) { -+ case USE_NONE: -+ case USE_MIC: -+ REG_ICDC_CDCCR1 = 0x17022000;//for mic -+ break; -+ case USE_LINEIN: -+ REG_ICDC_CDCCR1 = 0x27022000;//for linein -+ break; -+ } -+ -+ val = REG_ICDC_CDCCR2; -+ val &= 0x0000ff00; -+ val |= 0x00170030; -+ REG_ICDC_CDCCR2 = val; -+} -+ -+void turn_on_jzcodec(void) -+{ -+ HP_turn_on(); -+} -+ -+void set_jzcodec_direct_mode(void) -+{ -+ long val = 0; -+ REG_ICDC_CDCCR1 = 0x14000000; -+ val &= 0x0000ff00; -+ val |= 0x001f0033; -+ REG_ICDC_CDCCR2 = val; -+ mdelay(300); -+} -+ -+void clear_jzcodec_direct_mode(void) -+{ -+ HP_turn_off(); -+} -+ -+void turn_off_jzcodec(void) -+{ -+ HP_turn_off(); -+} -+ -+void set_jzcodec_speed(int rate) -+{ -+ long codec_speed,speed = 0; -+ switch (rate) { -+ case 8000: -+ speed = 0; -+ break; -+ case 11025: -+ speed = 1; -+ break; -+ case 12000: -+ speed = 2; -+ break; -+ case 16000: -+ speed = 3; -+ break; -+ case 22050: -+ speed = 4; -+ break; -+ case 24000: -+ speed = 5; -+ break; -+ case 32000: -+ speed = 6; -+ break; -+ case 44100: -+ speed = 7; -+ break; -+ case 48000: -+ speed = 8; -+ break; -+ default: -+ break; -+ } -+ -+ codec_speed = REG_ICDC_CDCCR2; -+ codec_speed |= 0x00000f00; -+ -+ speed = speed << 8; -+ speed |= 0xfffff0ff; -+ codec_speed &= speed; -+ REG_ICDC_CDCCR2 = codec_speed; -+} -+ -+void reset_jzcodec(void) -+{ -+ REG_ICDC_CDCCR1 |= 1; -+ mdelay(1); -+ REG_ICDC_CDCCR1 &= 0xfffffffe; -+} -+ -+void jzcodec_mixer_old_info_id_name(void) -+{ -+ strncpy(info.id, "JZCODEC", sizeof(info.id)); -+ strncpy(info.name,"Jz internal codec", sizeof(info.name)); -+} -+ -+void jzcodec_mixer_info_id_name(void) -+{ -+ strncpy(old_info.id, "JZCODEC", sizeof(old_info.id)); -+ strncpy(old_info.name,"Jz internal codec", sizeof(old_info.name)); -+} -+ -+void set_jzcodec_bass(int val) -+{ -+ int bass_gain = 0; -+ if(val < 25) -+ bass_gain = 0; -+ if(val >= 25 && val < 50) -+ bass_gain = 1; -+ if(val >= 50 && val < 75) -+ bass_gain = 2; -+ if(val >= 75 && val <= 100 ) -+ bass_gain = 3; -+ -+ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x3 << 4)) | (bass_gain << 4)); -+} -+ -+void set_jzcodec_volume(int val) -+{ -+ unsigned int sample_oss; -+ int index,shift_max,vol_scale,vol_step,codec_volume; -+ shift_max = 0; -+ sample_oss = (REG_AIC_CR & 0x00380000) >> 19; -+ -+ switch(sample_oss) -+ { -+ case 0x0: -+ shift_max = 4; /* 8 bits */ -+ break; -+ case 0x1: -+ shift_max = 10; /* 16 bits */ -+ break; -+ case 0x2: -+ shift_max = 12; /* 18 bits */ -+ break; -+ case 0x3: -+ shift_max = 15; /* 20 bits */ -+ break; -+ case 0x4: -+ shift_max = 19; /* 24 bits */ -+ break; -+ } -+ -+ vol_scale = 3 * (shift_max + 1); -+ vol_step = 100 / vol_scale; -+ -+ for(index = 0;index <= 100;index += vol_step) -+ if( val <= index ) -+ break; -+ -+ if(index == 0) -+ index = vol_step; -+ index = index / vol_step; -+ if(index > vol_scale) -+ index = vol_scale; -+ -+ index = vol_scale - index; -+ codec_volume = hpvol_shift_table[index].hpvol; -+ codec_volue_shift = hpvol_shift_table[index].shift; -+ codec_volume = 3; -+ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x3)) | codec_volume); -+} -+ -+void set_jzcodec_mic(int val) -+{ -+ long mic_gain; -+ -+ mic_gain = 31 * val /100; -+ REG_ICDC_CDCCR2 = (REG_ICDC_CDCCR2 | (0x3 << 4)); -+ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x1f << 16)) | (mic_gain << 16)); -+} -+ -+void set_jzcodec_line(int val) -+{ -+ long line_gain; -+ -+ line_gain = 31 * val /100; -+ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x1f << 16)) | (line_gain << 16)); -+} -+ -+void HP_turn_on(void) -+{ -+ long val = 0; -+ /* simple and slow anti-pop */ -+ REG_ICDC_CDCCR1 = 0x00037302; -+ mdelay(2); -+ REG_ICDC_CDCCR1 = 0x03006000; -+ mdelay(2); -+ REG_ICDC_CDCCR1 = 0x03002000; -+ -+ val = REG_ICDC_CDCCR2; -+ val &= 0x0000ff00; -+ val |= 0x001f0033; -+ REG_ICDC_CDCCR2 = val; -+} -+ -+void HP_turn_off(void) -+{ -+ mdelay(20); -+ REG_ICDC_CDCCR1 = 0x00033300; -+} -+ -+void in_codec_app1(void) -+{ -+ /* test is OK */ -+ HP_turn_on(); -+} -+ -+void in_codec_app12(void) -+{ -+ REG_ICDC_CDCCR1 = 0x14024300; -+ mdelay(300); -+} -+ -+void resume_jzcodec(void) -+{ -+ REG_ICDC_CDCCR2 = 0x00170800; -+ mdelay(2); -+ REG_ICDC_CDCCR1 = 0x001f2102; -+ mdelay(5); -+ REG_ICDC_CDCCR1 = 0x00033302; -+ mdelay(550); -+ REG_ICDC_CDCCR1 = 0x00033300; -+ REG_ICDC_CDCCR1 = jzcodec_reg[0]; -+ REG_ICDC_CDCCR2 = jzcodec_reg[1]; -+} -+ -+void suspend_jzcodec(void) -+{ -+ -+ jzcodec_reg[0] = REG_ICDC_CDCCR1; -+ jzcodec_reg[1] = REG_ICDC_CDCCR2; -+ -+ REG_ICDC_CDCCR1 = 0x001b2302; -+ mdelay(1); -+ REG_ICDC_CDCCR1 = 0x001b2102; -+} -+ -+static int __init init_jzcodec(void) -+{ -+ set_codec_mode = set_jzcodec_mode; -+ each_time_init_codec = each_time_init_jzcodec; -+ -+ set_codec_startup_param = set_jzcodec_startup_param; -+ set_codec_volume_table = set_jzcodec_volume_table; -+ set_codec_record = set_jzcodec_record; -+ set_codec_replay = set_jzcodec_replay; -+ set_codec_replay_record = set_jzcodec_replay_record; -+ turn_on_codec = turn_on_jzcodec; -+ turn_off_codec = turn_off_jzcodec; -+ set_codec_speed = set_jzcodec_speed; -+ reset_codec = reset_jzcodec; -+ codec_mixer_old_info_id_name = jzcodec_mixer_old_info_id_name; -+ codec_mixer_info_id_name = jzcodec_mixer_info_id_name; -+ set_codec_bass = set_jzcodec_bass; -+ set_codec_volume = set_jzcodec_volume; -+ set_codec_mic = set_jzcodec_mic; -+ set_codec_line = set_jzcodec_line; -+ i2s_resume_codec = resume_jzcodec; -+ i2s_suspend_codec = suspend_jzcodec; -+ set_codec_direct_mode = set_jzcodec_direct_mode; -+ clear_codec_direct_mode = clear_jzcodec_direct_mode; -+ -+ return 0; -+} -+ -+ -+static void __exit cleanup_jzcodec(void) -+{ -+ REG_ICDC_CDCCR1 = 0x001b2302; -+ -+} -+ -+module_init(init_jzcodec); -+module_exit(cleanup_jzcodec); ++/* ++ * linux/drivers/sound/jzcodec.c ++ * ++ * JzSOC internal audio driver. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "sound_config.h" ++ ++#define USE_NONE 1 ++#define USE_MIC 2 ++#define USE_LINEIN 3 ++ ++typedef struct hpvol_shift_s ++{ ++ int hpvol; ++ int shift; ++} hpvol_shift_t; ++ ++extern mixer_info info; ++extern _old_mixer_info old_info; ++extern int codec_volue_shift; ++extern hpvol_shift_t hpvol_shift_table[72]; ++extern int abnormal_data_count; ++ ++extern void (*set_codec_mode)(void); ++extern void (*each_time_init_codec)(void); ++extern int (*set_codec_startup_param)(void); ++extern void (*set_codec_volume_table)(void); ++extern void (*set_codec_record)(int mode); ++extern void (*set_codec_replay)(void); ++extern void (*set_codec_replay_record)(int mode); ++extern void (*turn_on_codec)(void); ++extern void (*turn_off_codec)(void); ++extern void (*set_codec_speed)(int rate); ++extern void (*reset_codec)(void); ++extern void (*codec_mixer_old_info_id_name)(void); ++extern void (*codec_mixer_info_id_name)(void); ++extern void (*set_codec_bass)(int val); ++extern void (*set_codec_volume)(int val); ++extern void (*set_codec_mic)(int val); ++extern void (*set_codec_line)(int val); ++extern void (*i2s_resume_codec)(void); ++extern void (*i2s_suspend_codec)(void); ++extern void (*set_codec_direct_mode)(void); ++extern void (*clear_codec_direct_mode)(void); ++ ++static int jzcodec_reg[2]; ++ ++void set_jzcodec_mode(void); ++void each_time_init_jzcodec(void); ++int set_jzcodec_startup_param(void); ++void set_jzcodec_volume_table(void); ++void set_jzcodec_replay(void); ++void set_jzcodec_record(int mode); ++void turn_on_jzcodec(void); ++void turn_off_jzcodec(void); ++void set_jzcodec_speed(int rate); ++void reset_jzcodec(void); ++void jzcodec_mixer_old_info_id_name(void); ++void jzcodec_mixer_info_id_name(void); ++void set_jzcodec_bass(int val); ++void set_jzcodec_volume(int val); ++void set_jzcodec_mic(int val); ++void set_jzcodec_line(int val); ++void in_codec_app1(void); ++void in_codec_app12(void); ++void HP_turn_on(void); ++void HP_turn_off(void); ++void resume_jzcodec(void); ++void suspend_jzcodec(void); ++void set_jzcodec_replay_record(int mode); ++ ++void set_jzcodec_mode(void) ++{ ++ __i2s_internal_codec(); ++ __i2s_as_slave(); ++ __i2s_select_i2s(); ++ __aic_select_i2s(); ++ ++ REG_ICDC_CDCCR1 = 0x001b2303; ++ schedule_timeout(1); ++ REG_ICDC_CDCCR1 = 0x001b2302; ++} ++ ++void each_time_init_jzcodec(void) ++{ ++ __i2s_disable(); ++ __i2s_as_slave(); ++ __i2s_set_oss_sample_size(16); ++ __i2s_set_iss_sample_size(16); ++} ++ ++int set_jzcodec_startup_param(void) ++{ ++ REG_ICDC_CDCCR1 = 0x001b2300; ++ schedule_timeout(50); ++ REG_ICDC_CDCCR1 = 0x00033300; ++ schedule_timeout(5); ++ REG_ICDC_CDCCR1 = 0x17026300; ++ ++ return 1; ++} ++void set_jzcodec_volume_table(void) ++{ ++ int errno,hpvol_step,sample_shift; ++ ++ codec_volue_shift = 0; ++ hpvol_step = 3; ++ sample_shift = 0; ++ for(errno = 0;errno < 72;errno++) { ++ hpvol_shift_table[errno].hpvol = hpvol_step; ++ hpvol_shift_table[errno].shift = sample_shift; ++ hpvol_step --; ++ if(hpvol_step <= 0) { ++ hpvol_step = 3; ++ sample_shift ++; ++ } ++ } ++} ++ ++void set_jzcodec_replay(void) ++{ ++ in_codec_app1(); ++} ++ ++void set_jzcodec_record(int mode) ++{ ++ switch (mode) { ++ case USE_NONE: ++ case USE_MIC: ++ in_codec_app12(); ++ abnormal_data_count = 0; ++ break; ++ case USE_LINEIN: ++ REG_ICDC_CDCCR1 = 0x27022000;//for linein ++ mdelay(300); ++ break; ++ } ++} ++ ++void set_jzcodec_replay_record(int mode) ++{ ++ long val = 0; ++ REG_ICDC_CDCCR1 = 0x00037302; ++ mdelay(2); ++ REG_ICDC_CDCCR1 = 0x03006000; ++ mdelay(2); ++ ++ switch (mode) { ++ case USE_NONE: ++ case USE_MIC: ++ REG_ICDC_CDCCR1 = 0x17022000;//for mic ++ break; ++ case USE_LINEIN: ++ REG_ICDC_CDCCR1 = 0x27022000;//for linein ++ break; ++ } ++ ++ val = REG_ICDC_CDCCR2; ++ val &= 0x0000ff00; ++ val |= 0x00170030; ++ REG_ICDC_CDCCR2 = val; ++} ++ ++void turn_on_jzcodec(void) ++{ ++ HP_turn_on(); ++} ++ ++void set_jzcodec_direct_mode(void) ++{ ++ long val = 0; ++ REG_ICDC_CDCCR1 = 0x14000000; ++ val &= 0x0000ff00; ++ val |= 0x001f0033; ++ REG_ICDC_CDCCR2 = val; ++ mdelay(300); ++} ++ ++void clear_jzcodec_direct_mode(void) ++{ ++ HP_turn_off(); ++} ++ ++void turn_off_jzcodec(void) ++{ ++ HP_turn_off(); ++} ++ ++void set_jzcodec_speed(int rate) ++{ ++ long codec_speed,speed = 0; ++ switch (rate) { ++ case 8000: ++ speed = 0; ++ break; ++ case 11025: ++ speed = 1; ++ break; ++ case 12000: ++ speed = 2; ++ break; ++ case 16000: ++ speed = 3; ++ break; ++ case 22050: ++ speed = 4; ++ break; ++ case 24000: ++ speed = 5; ++ break; ++ case 32000: ++ speed = 6; ++ break; ++ case 44100: ++ speed = 7; ++ break; ++ case 48000: ++ speed = 8; ++ break; ++ default: ++ break; ++ } ++ ++ codec_speed = REG_ICDC_CDCCR2; ++ codec_speed |= 0x00000f00; ++ ++ speed = speed << 8; ++ speed |= 0xfffff0ff; ++ codec_speed &= speed; ++ REG_ICDC_CDCCR2 = codec_speed; ++} ++ ++void reset_jzcodec(void) ++{ ++ REG_ICDC_CDCCR1 |= 1; ++ mdelay(1); ++ REG_ICDC_CDCCR1 &= 0xfffffffe; ++} ++ ++void jzcodec_mixer_old_info_id_name(void) ++{ ++ strncpy(info.id, "JZCODEC", sizeof(info.id)); ++ strncpy(info.name,"Jz internal codec", sizeof(info.name)); ++} ++ ++void jzcodec_mixer_info_id_name(void) ++{ ++ strncpy(old_info.id, "JZCODEC", sizeof(old_info.id)); ++ strncpy(old_info.name,"Jz internal codec", sizeof(old_info.name)); ++} ++ ++void set_jzcodec_bass(int val) ++{ ++ int bass_gain = 0; ++ if(val < 25) ++ bass_gain = 0; ++ if(val >= 25 && val < 50) ++ bass_gain = 1; ++ if(val >= 50 && val < 75) ++ bass_gain = 2; ++ if(val >= 75 && val <= 100 ) ++ bass_gain = 3; ++ ++ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x3 << 4)) | (bass_gain << 4)); ++} ++ ++void set_jzcodec_volume(int val) ++{ ++ unsigned int sample_oss; ++ int index,shift_max,vol_scale,vol_step,codec_volume; ++ shift_max = 0; ++ sample_oss = (REG_AIC_CR & 0x00380000) >> 19; ++ ++ switch(sample_oss) ++ { ++ case 0x0: ++ shift_max = 4; /* 8 bits */ ++ break; ++ case 0x1: ++ shift_max = 10; /* 16 bits */ ++ break; ++ case 0x2: ++ shift_max = 12; /* 18 bits */ ++ break; ++ case 0x3: ++ shift_max = 15; /* 20 bits */ ++ break; ++ case 0x4: ++ shift_max = 19; /* 24 bits */ ++ break; ++ } ++ ++ vol_scale = 3 * (shift_max + 1); ++ vol_step = 100 / vol_scale; ++ ++ for(index = 0;index <= 100;index += vol_step) ++ if( val <= index ) ++ break; ++ ++ if(index == 0) ++ index = vol_step; ++ index = index / vol_step; ++ if(index > vol_scale) ++ index = vol_scale; ++ ++ index = vol_scale - index; ++ codec_volume = hpvol_shift_table[index].hpvol; ++ codec_volue_shift = hpvol_shift_table[index].shift; ++ codec_volume = 3; ++ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x3)) | codec_volume); ++} ++ ++void set_jzcodec_mic(int val) ++{ ++ long mic_gain; ++ ++ mic_gain = 31 * val /100; ++ REG_ICDC_CDCCR2 = (REG_ICDC_CDCCR2 | (0x3 << 4)); ++ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x1f << 16)) | (mic_gain << 16)); ++} ++ ++void set_jzcodec_line(int val) ++{ ++ long line_gain; ++ ++ line_gain = 31 * val /100; ++ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x1f << 16)) | (line_gain << 16)); ++} ++ ++void HP_turn_on(void) ++{ ++ long val = 0; ++ /* simple and slow anti-pop */ ++ REG_ICDC_CDCCR1 = 0x00037302; ++ mdelay(2); ++ REG_ICDC_CDCCR1 = 0x03006000; ++ mdelay(2); ++ REG_ICDC_CDCCR1 = 0x03002000; ++ ++ val = REG_ICDC_CDCCR2; ++ val &= 0x0000ff00; ++ val |= 0x001f0033; ++ REG_ICDC_CDCCR2 = val; ++} ++ ++void HP_turn_off(void) ++{ ++ mdelay(20); ++ REG_ICDC_CDCCR1 = 0x00033300; ++} ++ ++void in_codec_app1(void) ++{ ++ /* test is OK */ ++ HP_turn_on(); ++} ++ ++void in_codec_app12(void) ++{ ++ REG_ICDC_CDCCR1 = 0x14024300; ++ mdelay(300); ++} ++ ++void resume_jzcodec(void) ++{ ++ REG_ICDC_CDCCR2 = 0x00170800; ++ mdelay(2); ++ REG_ICDC_CDCCR1 = 0x001f2102; ++ mdelay(5); ++ REG_ICDC_CDCCR1 = 0x00033302; ++ mdelay(550); ++ REG_ICDC_CDCCR1 = 0x00033300; ++ REG_ICDC_CDCCR1 = jzcodec_reg[0]; ++ REG_ICDC_CDCCR2 = jzcodec_reg[1]; ++} ++ ++void suspend_jzcodec(void) ++{ ++ ++ jzcodec_reg[0] = REG_ICDC_CDCCR1; ++ jzcodec_reg[1] = REG_ICDC_CDCCR2; ++ ++ REG_ICDC_CDCCR1 = 0x001b2302; ++ mdelay(1); ++ REG_ICDC_CDCCR1 = 0x001b2102; ++} ++ ++static int __init init_jzcodec(void) ++{ ++ set_codec_mode = set_jzcodec_mode; ++ each_time_init_codec = each_time_init_jzcodec; ++ ++ set_codec_startup_param = set_jzcodec_startup_param; ++ set_codec_volume_table = set_jzcodec_volume_table; ++ set_codec_record = set_jzcodec_record; ++ set_codec_replay = set_jzcodec_replay; ++ set_codec_replay_record = set_jzcodec_replay_record; ++ turn_on_codec = turn_on_jzcodec; ++ turn_off_codec = turn_off_jzcodec; ++ set_codec_speed = set_jzcodec_speed; ++ reset_codec = reset_jzcodec; ++ codec_mixer_old_info_id_name = jzcodec_mixer_old_info_id_name; ++ codec_mixer_info_id_name = jzcodec_mixer_info_id_name; ++ set_codec_bass = set_jzcodec_bass; ++ set_codec_volume = set_jzcodec_volume; ++ set_codec_mic = set_jzcodec_mic; ++ set_codec_line = set_jzcodec_line; ++ i2s_resume_codec = resume_jzcodec; ++ i2s_suspend_codec = suspend_jzcodec; ++ set_codec_direct_mode = set_jzcodec_direct_mode; ++ clear_codec_direct_mode = clear_jzcodec_direct_mode; ++ ++ return 0; ++} ++ ++ ++static void __exit cleanup_jzcodec(void) ++{ ++ REG_ICDC_CDCCR1 = 0x001b2302; ++ ++} ++ ++module_init(init_jzcodec); ++module_exit(cleanup_jzcodec); --- linux-2.6.24.7.old/sound/oss/jzdlv.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7/sound/oss/jzdlv.c 2009-04-12 18:13:57.000000000 +0200 @@ -0,0 +1,644 @@ -+/* -+ * linux/drivers/sound/jzcodec.c -+ * -+ * JzSOC internal audio driver. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "sound_config.h" -+#include "jzdlv.h" -+ -+#define USE_NONE 1 -+#define USE_MIC 2 -+#define USE_LINEIN 3 -+ -+extern mixer_info info; -+extern _old_mixer_info old_info; -+extern int codec_volue_shift; -+ -+extern void (*set_codec_mode)(void); -+extern void (*each_time_init_codec)(void); -+extern int (*set_codec_startup_param)(void); -+extern void (*set_codec_record)(void); -+extern void (*set_codec_replay)(void); -+extern void (*set_codec_replay_record)(void); -+extern void (*turn_on_codec)(void); -+extern void (*turn_off_codec)(void); -+extern void (*set_codec_speed)(int rate); -+extern void (*reset_codec)(void); -+extern void (*codec_mixer_old_info_id_name)(void); -+extern void (*codec_mixer_info_id_name)(void); -+extern void (*set_codec_bass)(int val); -+extern void (*set_codec_volume)(int val); -+extern void (*set_codec_mic)(int val); -+extern void (*set_codec_line)(int val); -+extern void (*i2s_resume_codec)(void); -+extern void (*i2s_suspend_codec)(void); -+extern void (*set_codec_direct_mode)(void); -+extern void (*clear_codec_direct_mode)(void); -+ -+ -+void set_dlv_mode(void); -+void each_time_init_jzcodec(void); -+int set_dlv_startup_param(void); -+void set_dlvjzcodec_volume_table(void); -+void set_dlv_replay(void); -+void set_dlv_record(void); -+void set_dlv_speed(int rate); -+void reset_dlv(void); -+void jzcodec_mixer_old_info_id_name(void); -+void jzcodec_mixer_info_id_name(void); -+void set_dlv_volume(int val); -+void set_dlv_mic(int val); -+ -+extern int jz_mic_only; -+int read_codec_file(int addr) -+{ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ mdelay(1); -+ return(__icdc_get_value()); -+} -+ -+#if 0 -+void printk_codec_files(void) -+{ -+ int cnt; -+ -+ printk("\n"); -+ -+ printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR); -+ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR); -+ printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR); -+ printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR); -+ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR); -+ printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR); -+ printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR); -+ printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA); -+ -+ for (cnt = 0; cnt <= 27 ; cnt++) { -+ printk(" ( %d : 0x%x ) ",cnt ,read_codec_file(cnt)); -+ } -+ printk("\n"); -+} -+#endif -+ -+void write_codec_file(int addr, int val) -+{ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ __icdc_set_cmd(val); /* write */ -+ mdelay(1); -+ __icdc_set_rgwr(); -+ mdelay(1); -+} -+ -+int write_codec_file_bit(int addr, int bitval, int mask_bit) -+{ -+ int val; -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ mdelay(1); -+ val = __icdc_get_value(); /* read */ -+ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ val &= ~(1 << mask_bit); -+ if (bitval == 1) -+ val |= 1 << mask_bit; -+ -+ __icdc_set_cmd(val); /* write */ -+ mdelay(1); -+ __icdc_set_rgwr(); -+ mdelay(1); -+ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ val = __icdc_get_value(); /* read */ -+ -+ if (((val >> mask_bit) & bitval) == bitval) -+ return 1; -+ else -+ return 0; -+} -+void set_dlv_mode(void) -+{ -+ /*REG_CPM_CPCCR &= ~(1 << 31); -+ REG_CPM_CPCCR &= ~(1 << 30);*/ -+ write_codec_file(0, 0xf); -+ -+ REG_AIC_I2SCR = 0x10; -+ __i2s_internal_codec(); -+ __i2s_as_slave(); -+ __i2s_select_i2s(); -+ __aic_select_i2s(); -+ __aic_reset(); -+ mdelay(10); -+ REG_AIC_I2SCR = 0x10; -+ mdelay(20); -+ -+ /* power on DLV */ -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+} -+void reset_dlv_codec(void) -+{ -+ /* reset DLV codec. from hibernate mode to sleep mode */ -+ write_codec_file(0, 0xf); -+ write_codec_file_bit(6, 0, 0); -+ write_codec_file_bit(6, 0, 1); -+ mdelay(200); -+ //write_codec_file(0, 0xf); -+ write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0 -+ write_codec_file_bit(5, 0, 4);//PMR1.SB_ADC->0 -+ mdelay(10);//wait for stability -+} -+ -+void each_time_init_dlv(void) -+{ -+ __i2s_disable(); -+ __i2s_as_slave(); -+ __aic_internal_codec(); -+ __i2s_set_oss_sample_size(16); -+ __i2s_set_iss_sample_size(16); -+} -+ -+int set_dlv_startup_param(void) -+{ -+ __i2s_disable_transmit_intr(); -+ __i2s_disable_receive_intr(); -+ -+ return 1; -+} -+/* set Audio data replay */ -+void set_audio_data_replay(void) -+{ -+ /* DAC path */ -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ mdelay(10); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ //mdelay(100); -+ //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //mdelay(300); -+} -+ -+#if 1 /* mask warning */ -+/* set Record MIC input audio without playback */ -+void set_record_mic_input_audio_without_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 1; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ mdelay(10); -+ write_codec_file_bit(1, 1, 2); -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ -+ write_codec_file(22, 0x40);//mic 1 -+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ //write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file(1, 0x4); -+} -+#endif -+ -+#if 1 /* mask warning */ -+/* unset Record MIC input audio without playback */ -+void unset_record_mic_input_audio_without_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 0; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Record LINE input audio without playback */ -+void set_record_line_input_audio_without_playback(void) -+{ -+ /* ADC path for LINE IN */ -+ jz_mic_only = 1; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ write_codec_file(22, 0xf6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ mdelay(10); -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file(1, 0x4); -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Record LINE input audio without playback */ -+void unset_record_line_input_audio_without_playback(void) -+{ -+ /* ADC path for LINE IN */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1 -+ -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Playback LINE input audio direct only */ -+void set_playback_line_input_audio_direct_only(void) -+{ -+ jz_audio_reset();//or init_codec() -+ REG_AIC_I2SCR = 0x10; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ write_codec_file(22, 0xf6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ mdelay(10); -+ write_codec_file_bit(1, 1, 2);//CR1.HP_BYPASS->1 -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ //write_codec_file_bit(5, 1, 7);//PMR1.SB_DAC->1 -+ //write_codec_file_bit(5, 1, 4);//PMR1.SB_ADC->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Playback LINE input audio direct only */ -+void unset_playback_line_input_audio_direct_only(void) -+{ -+ write_codec_file_bit(6, 0, 3);//GIM->0 -+ write_codec_file_bit(1, 0, 2);//PMR1.BYPASS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LINE->1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ mdelay(100); -+ write_codec_file_bit(5, 1, 5);//PMR1.SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Record MIC input audio with direct playback */ -+void set_record_mic_input_audio_with_direct_playback(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ jz_mic_only = 0; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ -+ write_codec_file(22, 0x60);//mic 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ //write_codec_file(1, 0x4); -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Record MIC input audio with direct playback */ -+void unset_record_mic_input_audio_with_direct_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 0; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Record playing audio mixed with MIC input audio */ -+void set_record_playing_audio_mixed_with_mic_input_audio(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ mdelay(10); -+ -+ write_codec_file(22, 0x63);//mic 1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ write_codec_file_bit(5, 0, 4);//PMR1.SB_MIX->0 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Record playing audio mixed with MIC input audio */ -+void unset_record_playing_audio_mixed_with_mic_input_audio(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 1 /* mask warning */ -+/* set Record MIC input audio with Audio data replay (full duplex) */ -+void set_record_mic_input_audio_with_audio_data_replay(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+} -+#endif -+ -+#if 1 /* mask warning */ -+/* unset Record MIC input audio with Audio data replay (full duplex) */ -+void unset_record_mic_input_audio_with_audio_data_replay(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 1 /* mask warning */ -+/* set Record LINE input audio with Audio data replay (full duplex for linein) */ -+void set_record_line_input_audio_with_audio_data_replay(void) -+{ -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ -+ -+ //jz_mic_only = 1; -+ write_codec_file(22, 0xc6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+} -+#endif -+ -+#if 1 /* mask warning */ -+/* unset Record LINE input audio with Audio data replay (full duplex for linein) */ -+void unset_record_line_input_audio_with_audio_data_replay(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 1 -+/* unset Audio data replay */ -+void unset_audio_data_replay(void) -+{ -+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ //mdelay(800); -+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ //mdelay(800); -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 4);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+void set_dlv_replay(void) -+{ -+ set_audio_data_replay(); -+} -+ -+void set_dlv_speed(int rate) -+{ -+ int speed = 0, val; -+ speed = 0; -+ switch (rate) { -+ case 8000: -+ speed = 10; -+ break; -+ case 9600: -+ speed = 9; -+ break; -+ case 11025: -+ speed = 8; -+ break; -+ case 12000: -+ speed = 7; -+ break; -+ case 16000: -+ speed = 6; -+ break; -+ case 22050: -+ speed = 5; -+ break; -+ case 24000: -+ speed = 4; -+ break; -+ case 32000: -+ speed = 3; -+ break; -+ case 44100: -+ speed = 2; -+ break; -+ case 48000: -+ speed = 1; -+ break; -+ case 96000: -+ speed = 0; -+ break; -+ default: -+ break; -+ } -+ -+ val = read_codec_file(4); -+ val = (speed << 4) | speed; -+ write_codec_file(4, val); -+} -+ -+void reset_jzcodec(void) -+{ -+ -+} -+ -+void dlv_mixer_old_info_id_name(void) -+{ -+ strncpy(info.id, "JZDLV", sizeof(info.id)); -+ strncpy(info.name,"Jz internal codec dlv on jz4750", sizeof(info.name)); -+} -+ -+void dlv_mixer_info_id_name(void) -+{ -+ strncpy(old_info.id, "JZDLV", sizeof(old_info.id)); -+ strncpy(old_info.name,"Jz internal codec dlv on jz4750", sizeof(old_info.name)); -+} -+ -+void set_dlv_mic(int val) -+{ -+ int cur_vol ; -+ /* set gain */ -+ //write_codec_file_bit(6, 1, 3);//GIM -+ cur_vol = 31 * val / 100; -+ cur_vol |= cur_vol << 4; -+ write_codec_file(19, cur_vol);//GIL,GIR -+} -+ -+void set_dlv_line(int val) -+{ -+ int cur_vol; -+ /* set gain */ -+ cur_vol = 31 * val / 100; -+ cur_vol &= 0x1f; -+ write_codec_file(11, cur_vol);//GO1L -+ write_codec_file(12, cur_vol);//GO1R -+} -+ -+void set_dlv_volume(int val) -+{ -+ unsigned long cur_vol; -+ cur_vol = 31 * (100 - val) / 100; -+ write_codec_file(17, cur_vol | 0xc0); -+ write_codec_file(18, cur_vol); -+} -+ -+static int __init init_dlv(void) -+{ -+ set_codec_mode = set_dlv_mode; -+ each_time_init_codec = each_time_init_dlv; -+ reset_codec = reset_dlv_codec; -+ set_codec_startup_param = set_dlv_startup_param; -+ -+ set_codec_replay = set_dlv_replay; -+ -+ set_codec_speed = set_dlv_speed; -+ -+ codec_mixer_old_info_id_name = dlv_mixer_old_info_id_name; -+ codec_mixer_info_id_name = dlv_mixer_info_id_name; -+ -+ set_codec_volume = set_dlv_volume; -+ set_codec_mic = set_dlv_mic; -+ set_codec_line = set_dlv_line; -+ -+ return 0; -+} -+ -+ -+static void __exit cleanup_dlv(void) -+{ -+ -+} -+ -+module_init(init_dlv); -+module_exit(cleanup_dlv); ++/* ++ * linux/drivers/sound/jzcodec.c ++ * ++ * JzSOC internal audio driver. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "sound_config.h" ++#include "jzdlv.h" ++ ++#define USE_NONE 1 ++#define USE_MIC 2 ++#define USE_LINEIN 3 ++ ++extern mixer_info info; ++extern _old_mixer_info old_info; ++extern int codec_volue_shift; ++ ++extern void (*set_codec_mode)(void); ++extern void (*each_time_init_codec)(void); ++extern int (*set_codec_startup_param)(void); ++extern void (*set_codec_record)(void); ++extern void (*set_codec_replay)(void); ++extern void (*set_codec_replay_record)(void); ++extern void (*turn_on_codec)(void); ++extern void (*turn_off_codec)(void); ++extern void (*set_codec_speed)(int rate); ++extern void (*reset_codec)(void); ++extern void (*codec_mixer_old_info_id_name)(void); ++extern void (*codec_mixer_info_id_name)(void); ++extern void (*set_codec_bass)(int val); ++extern void (*set_codec_volume)(int val); ++extern void (*set_codec_mic)(int val); ++extern void (*set_codec_line)(int val); ++extern void (*i2s_resume_codec)(void); ++extern void (*i2s_suspend_codec)(void); ++extern void (*set_codec_direct_mode)(void); ++extern void (*clear_codec_direct_mode)(void); ++ ++ ++void set_dlv_mode(void); ++void each_time_init_jzcodec(void); ++int set_dlv_startup_param(void); ++void set_dlvjzcodec_volume_table(void); ++void set_dlv_replay(void); ++void set_dlv_record(void); ++void set_dlv_speed(int rate); ++void reset_dlv(void); ++void jzcodec_mixer_old_info_id_name(void); ++void jzcodec_mixer_info_id_name(void); ++void set_dlv_volume(int val); ++void set_dlv_mic(int val); ++ ++extern int jz_mic_only; ++int read_codec_file(int addr) ++{ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ mdelay(1); ++ return(__icdc_get_value()); ++} ++ ++#if 0 ++void printk_codec_files(void) ++{ ++ int cnt; ++ ++ printk("\n"); ++ ++ printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR); ++ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR); ++ printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR); ++ printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR); ++ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR); ++ printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR); ++ printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR); ++ printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA); ++ ++ for (cnt = 0; cnt <= 27 ; cnt++) { ++ printk(" ( %d : 0x%x ) ",cnt ,read_codec_file(cnt)); ++ } ++ printk("\n"); ++} ++#endif ++ ++void write_codec_file(int addr, int val) ++{ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ __icdc_set_cmd(val); /* write */ ++ mdelay(1); ++ __icdc_set_rgwr(); ++ mdelay(1); ++} ++ ++int write_codec_file_bit(int addr, int bitval, int mask_bit) ++{ ++ int val; ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ mdelay(1); ++ val = __icdc_get_value(); /* read */ ++ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ val &= ~(1 << mask_bit); ++ if (bitval == 1) ++ val |= 1 << mask_bit; ++ ++ __icdc_set_cmd(val); /* write */ ++ mdelay(1); ++ __icdc_set_rgwr(); ++ mdelay(1); ++ ++ while (__icdc_rgwr_ready()); ++ __icdc_set_addr(addr); ++ val = __icdc_get_value(); /* read */ ++ ++ if (((val >> mask_bit) & bitval) == bitval) ++ return 1; ++ else ++ return 0; ++} ++void set_dlv_mode(void) ++{ ++ /*REG_CPM_CPCCR &= ~(1 << 31); ++ REG_CPM_CPCCR &= ~(1 << 30);*/ ++ write_codec_file(0, 0xf); ++ ++ REG_AIC_I2SCR = 0x10; ++ __i2s_internal_codec(); ++ __i2s_as_slave(); ++ __i2s_select_i2s(); ++ __aic_select_i2s(); ++ __aic_reset(); ++ mdelay(10); ++ REG_AIC_I2SCR = 0x10; ++ mdelay(20); ++ ++ /* power on DLV */ ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++} ++void reset_dlv_codec(void) ++{ ++ /* reset DLV codec. from hibernate mode to sleep mode */ ++ write_codec_file(0, 0xf); ++ write_codec_file_bit(6, 0, 0); ++ write_codec_file_bit(6, 0, 1); ++ mdelay(200); ++ //write_codec_file(0, 0xf); ++ write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0 ++ write_codec_file_bit(5, 0, 4);//PMR1.SB_ADC->0 ++ mdelay(10);//wait for stability ++} ++ ++void each_time_init_dlv(void) ++{ ++ __i2s_disable(); ++ __i2s_as_slave(); ++ __aic_internal_codec(); ++ __i2s_set_oss_sample_size(16); ++ __i2s_set_iss_sample_size(16); ++} ++ ++int set_dlv_startup_param(void) ++{ ++ __i2s_disable_transmit_intr(); ++ __i2s_disable_receive_intr(); ++ ++ return 1; ++} ++/* set Audio data replay */ ++void set_audio_data_replay(void) ++{ ++ /* DAC path */ ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ mdelay(10); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ //mdelay(100); ++ //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //mdelay(300); ++} ++ ++#if 1 /* mask warning */ ++/* set Record MIC input audio without playback */ ++void set_record_mic_input_audio_without_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 1; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ mdelay(10); ++ write_codec_file_bit(1, 1, 2); ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ ++ write_codec_file(22, 0x40);//mic 1 ++ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ //write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file(1, 0x4); ++} ++#endif ++ ++#if 1 /* mask warning */ ++/* unset Record MIC input audio without playback */ ++void unset_record_mic_input_audio_without_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 0; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Record LINE input audio without playback */ ++void set_record_line_input_audio_without_playback(void) ++{ ++ /* ADC path for LINE IN */ ++ jz_mic_only = 1; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ write_codec_file(22, 0xf6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ mdelay(10); ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ write_codec_file(1, 0x4); ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Record LINE input audio without playback */ ++void unset_record_line_input_audio_without_playback(void) ++{ ++ /* ADC path for LINE IN */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1 ++ ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Playback LINE input audio direct only */ ++void set_playback_line_input_audio_direct_only(void) ++{ ++ jz_audio_reset();//or init_codec() ++ REG_AIC_I2SCR = 0x10; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ write_codec_file(22, 0xf6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ mdelay(10); ++ write_codec_file_bit(1, 1, 2);//CR1.HP_BYPASS->1 ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ //write_codec_file_bit(5, 1, 7);//PMR1.SB_DAC->1 ++ //write_codec_file_bit(5, 1, 4);//PMR1.SB_ADC->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Playback LINE input audio direct only */ ++void unset_playback_line_input_audio_direct_only(void) ++{ ++ write_codec_file_bit(6, 0, 3);//GIM->0 ++ write_codec_file_bit(1, 0, 2);//PMR1.BYPASS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LINE->1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ mdelay(100); ++ write_codec_file_bit(5, 1, 5);//PMR1.SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Record MIC input audio with direct playback */ ++void set_record_mic_input_audio_with_direct_playback(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ jz_mic_only = 0; ++ write_codec_file(9, 0xff); ++ write_codec_file(8, 0x3f); ++ mdelay(10); ++ ++ write_codec_file(22, 0x60);//mic 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 ++ write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ mdelay(100); ++ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 ++ //write_codec_file(1, 0x4); ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Record MIC input audio with direct playback */ ++void unset_record_mic_input_audio_with_direct_playback(void) ++{ ++ /* ADC path for MIC IN */ ++ jz_mic_only = 0; ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1 ++ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 ++ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* set Record playing audio mixed with MIC input audio */ ++void set_record_playing_audio_mixed_with_mic_input_audio(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ mdelay(10); ++ ++ write_codec_file(22, 0x63);//mic 1 ++ ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(6, 1, 3);// gain set ++ ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ write_codec_file_bit(5, 0, 4);//PMR1.SB_MIX->0 ++} ++#endif ++ ++#if 0 /* mask warning */ ++/* unset Record playing audio mixed with MIC input audio */ ++void unset_record_playing_audio_mixed_with_mic_input_audio(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 1 /* mask warning */ ++/* set Record MIC input audio with Audio data replay (full duplex) */ ++void set_record_mic_input_audio_with_audio_data_replay(void) ++{ ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ ++ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 ++ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 ++ ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++} ++#endif ++ ++#if 1 /* mask warning */ ++/* unset Record MIC input audio with Audio data replay (full duplex) */ ++void unset_record_mic_input_audio_with_audio_data_replay(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 1 /* mask warning */ ++/* set Record LINE input audio with Audio data replay (full duplex for linein) */ ++void set_record_line_input_audio_with_audio_data_replay(void) ++{ ++ write_codec_file(9, 0xff); ++ //write_codec_file(8, 0x30); ++ write_codec_file(8, 0x20); ++ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 ++ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 ++ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1 ++ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++ ++ ++ //jz_mic_only = 1; ++ write_codec_file(22, 0xc6);//line in 1 ++ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 ++ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 ++ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 ++} ++#endif ++ ++#if 1 /* mask warning */ ++/* unset Record LINE input audio with Audio data replay (full duplex for linein) */ ++void unset_record_line_input_audio_with_audio_data_replay(void) ++{ ++ /* ADC path */ ++ write_codec_file_bit(5, 1, 4);//SB_ADC->1 ++ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 ++ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 ++ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 5);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++#if 1 ++/* unset Audio data replay */ ++void unset_audio_data_replay(void) ++{ ++ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 ++ //mdelay(800); ++ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 ++ //mdelay(800); ++ write_codec_file_bit(5, 1, 7);//SB_DAC->1 ++ write_codec_file_bit(5, 1, 4);//SB_MIX->1 ++ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 ++ write_codec_file_bit(6, 1, 1);//SB->1 ++} ++#endif ++ ++void set_dlv_replay(void) ++{ ++ set_audio_data_replay(); ++} ++ ++void set_dlv_speed(int rate) ++{ ++ int speed = 0, val; ++ speed = 0; ++ switch (rate) { ++ case 8000: ++ speed = 10; ++ break; ++ case 9600: ++ speed = 9; ++ break; ++ case 11025: ++ speed = 8; ++ break; ++ case 12000: ++ speed = 7; ++ break; ++ case 16000: ++ speed = 6; ++ break; ++ case 22050: ++ speed = 5; ++ break; ++ case 24000: ++ speed = 4; ++ break; ++ case 32000: ++ speed = 3; ++ break; ++ case 44100: ++ speed = 2; ++ break; ++ case 48000: ++ speed = 1; ++ break; ++ case 96000: ++ speed = 0; ++ break; ++ default: ++ break; ++ } ++ ++ val = read_codec_file(4); ++ val = (speed << 4) | speed; ++ write_codec_file(4, val); ++} ++ ++void reset_jzcodec(void) ++{ ++ ++} ++ ++void dlv_mixer_old_info_id_name(void) ++{ ++ strncpy(info.id, "JZDLV", sizeof(info.id)); ++ strncpy(info.name,"Jz internal codec dlv on jz4750", sizeof(info.name)); ++} ++ ++void dlv_mixer_info_id_name(void) ++{ ++ strncpy(old_info.id, "JZDLV", sizeof(old_info.id)); ++ strncpy(old_info.name,"Jz internal codec dlv on jz4750", sizeof(old_info.name)); ++} ++ ++void set_dlv_mic(int val) ++{ ++ int cur_vol ; ++ /* set gain */ ++ //write_codec_file_bit(6, 1, 3);//GIM ++ cur_vol = 31 * val / 100; ++ cur_vol |= cur_vol << 4; ++ write_codec_file(19, cur_vol);//GIL,GIR ++} ++ ++void set_dlv_line(int val) ++{ ++ int cur_vol; ++ /* set gain */ ++ cur_vol = 31 * val / 100; ++ cur_vol &= 0x1f; ++ write_codec_file(11, cur_vol);//GO1L ++ write_codec_file(12, cur_vol);//GO1R ++} ++ ++void set_dlv_volume(int val) ++{ ++ unsigned long cur_vol; ++ cur_vol = 31 * (100 - val) / 100; ++ write_codec_file(17, cur_vol | 0xc0); ++ write_codec_file(18, cur_vol); ++} ++ ++static int __init init_dlv(void) ++{ ++ set_codec_mode = set_dlv_mode; ++ each_time_init_codec = each_time_init_dlv; ++ reset_codec = reset_dlv_codec; ++ set_codec_startup_param = set_dlv_startup_param; ++ ++ set_codec_replay = set_dlv_replay; ++ ++ set_codec_speed = set_dlv_speed; ++ ++ codec_mixer_old_info_id_name = dlv_mixer_old_info_id_name; ++ codec_mixer_info_id_name = dlv_mixer_info_id_name; ++ ++ set_codec_volume = set_dlv_volume; ++ set_codec_mic = set_dlv_mic; ++ set_codec_line = set_dlv_line; ++ ++ return 0; ++} ++ ++ ++static void __exit cleanup_dlv(void) ++{ ++ ++} ++ ++module_init(init_dlv); ++module_exit(cleanup_dlv); --- linux-2.6.24.7.old/sound/oss/jzdlv.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7/sound/oss/jzdlv.h 2009-04-12 18:13:57.000000000 +0200 @@ -0,0 +1,21 @@ -+/* header file for dlv */ -+void write_codec_file(int addr, int val); -+int read_codec_file(int addr); -+void printk_codec_files(void); -+int write_codec_file_bit(int addr, int bitval, int mask_bit); -+void set_audio_data_replay(void); -+void unset_audio_data_replay(void); -+void set_record_mic_input_audio_without_playback(void); -+void unset_record_mic_input_audio_without_playback(void); -+void set_record_line_input_audio_without_playback(void); -+void unset_record_line_input_audio_without_playback(void); -+void set_playback_line_input_audio_direct_only(void); -+void unset_playback_line_input_audio_direct_only(void); -+void set_record_mic_input_audio_with_direct_playback(void); -+void unset_record_mic_input_audio_with_direct_playback(void); -+void set_record_playing_audio_mixed_with_mic_input_audio(void); -+void unset_record_playing_audio_mixed_with_mic_input_audio(void); -+void set_record_mic_input_audio_with_audio_data_replay(void); -+void unset_record_mic_input_audio_with_audio_data_replay(void); -+void set_record_line_input_audio_with_audio_data_replay(void); -+void unset_record_line_input_audio_with_audio_data_replay(void); ++/* header file for dlv */ ++void write_codec_file(int addr, int val); ++int read_codec_file(int addr); ++void printk_codec_files(void); ++int write_codec_file_bit(int addr, int bitval, int mask_bit); ++void set_audio_data_replay(void); ++void unset_audio_data_replay(void); ++void set_record_mic_input_audio_without_playback(void); ++void unset_record_mic_input_audio_without_playback(void); ++void set_record_line_input_audio_without_playback(void); ++void unset_record_line_input_audio_without_playback(void); ++void set_playback_line_input_audio_direct_only(void); ++void unset_playback_line_input_audio_direct_only(void); ++void set_record_mic_input_audio_with_direct_playback(void); ++void unset_record_mic_input_audio_with_direct_playback(void); ++void set_record_playing_audio_mixed_with_mic_input_audio(void); ++void unset_record_playing_audio_mixed_with_mic_input_audio(void); ++void set_record_mic_input_audio_with_audio_data_replay(void); ++void unset_record_mic_input_audio_with_audio_data_replay(void); ++void set_record_line_input_audio_with_audio_data_replay(void); ++void unset_record_line_input_audio_with_audio_data_replay(void); --- linux-2.6.24.7.old/sound/oss/os.h 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/sound/oss/os.h 2009-04-12 18:13:57.000000000 +0200 @@ -9,7 +9,6 @@ @@ -21362,27 +17876,28 @@ --- linux-2.6.24.7.old/sound/soc/Kconfig 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/sound/soc/Kconfig 2009-04-12 18:13:57.000000000 +0200 @@ -28,6 +28,7 @@ - source "sound/soc/pxa/Kconfig" - source "sound/soc/s3c24xx/Kconfig" - source "sound/soc/sh/Kconfig" + source "sound/soc/davinci/Kconfig" + source "sound/soc/omap/Kconfig" + source "sound/soc/blackfin/Kconfig" +source "sound/soc/jz4740/Kconfig" - + # Supported codecs source "sound/soc/codecs/Kconfig" --- linux-2.6.24.7.old/sound/soc/Makefile 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/sound/soc/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -1,4 +1,4 @@ - snd-soc-core-objs := soc-core.o soc-dapm.o - +@@ -2,4 +2,4 @@ + obj-$(CONFIG_SND_SOC) += snd-soc-core.o --obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ s3c24xx/ sh/ -+obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ s3c24xx/ sh/ jz4740/ + obj-$(CONFIG_SND_SOC) += codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ +-obj-$(CONFIG_SND_SOC) += omap/ au1x/ blackfin/ ++obj-$(CONFIG_SND_SOC) += omap/ au1x/ blackfin/ jz4740/ --- linux-2.6.24.7.old/sound/soc/codecs/Kconfig 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/sound/soc/codecs/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -37,3 +37,8 @@ - bool - depends on SND_SOC_CS4270 - +@@ -110,3 +110,9 @@ + + config SND_SOC_WM9713 + tristate ++ +config SND_SOC_ICODEC + tristate "Jz4740 internal codec" + depends on SND_SOC && SND_JZ4740_SOC_PAVO && SND_JZ4740_SOC_I2S @@ -21391,17 +17906,17 @@ --- linux-2.6.24.7.old/sound/soc/codecs/Makefile 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/sound/soc/codecs/Makefile 2009-04-12 18:13:57.000000000 +0200 @@ -4,6 +4,7 @@ - snd-soc-wm8753-objs := wm8753.o + snd-soc-wm8990-objs := wm8990.o snd-soc-wm9712-objs := wm9712.o - snd-soc-cs4270-objs := cs4270.o + snd-soc-wm9713-objs := wm9713.o +snd-soc-jzcodec-objs := jzcodec.o - + obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o - obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o + obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o @@ -11,3 +12,4 @@ - obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o + obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o - obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o + obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o +obj-$(CONFIG_SND_SOC_ICODEC) += snd-soc-jzcodec.o --- linux-2.6.24.7.old/sound/soc/codecs/jzcodec.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7/sound/soc/codecs/jzcodec.c 2009-04-12 18:13:57.000000000 +0200 @@ -21500,13 +18015,13 @@ + case 0: + case 1: + reg_val = cache[0] & 0xffff; -+ reg_val = reg_val | (cache[1] << 16); ++ reg_val = reg_val | (cache[1] << 16); + jzcodec_reg[0] = reg_val; + break; + case 2: + case 3: + reg_val = cache[2] & 0xffff; -+ reg_val = reg_val | (cache[3] << 16); ++ reg_val = reg_val | (cache[3] << 16); + jzcodec_reg[1] = reg_val; + break; + } @@ -21520,7 +18035,7 @@ +{ + jzcodec_write_reg_cache(codec, reg, value); + if(codec->hw_write) -+ codec->hw_write(&value, NULL, reg); ++ codec->hw_write(&value, NULL, reg); + return 0; +} + @@ -21532,7 +18047,7 @@ + val = val | 0x1; + jzcodec_write(codec, ICODEC_1_LOW, val); + mdelay(1); -+ ++ + val = jzcodec_read_reg_cache(codec, ICODEC_1_LOW); + val = val & ~0x1; + jzcodec_write(codec, ICODEC_1_LOW, val); @@ -21554,13 +18069,13 @@ +static int jzcodec_add_controls(struct snd_soc_codec *codec) +{ + int err, i; -+ ++ + for (i = 0; i < ARRAY_SIZE(jzcodec_snd_controls); i++) { + if ((err = snd_ctl_add(codec->card, + snd_soc_cnew(&jzcodec_snd_controls[i], codec, NULL))) < 0) + return err; + } -+ ++ + return 0; +} + @@ -21603,7 +18118,7 @@ +static int jzcodec_add_widgets(struct snd_soc_codec *codec) +{ + int i,cnt; -+ ++ + cnt = ARRAY_SIZE(jzcodec_dapm_widgets); + for(i = 0; i < ARRAY_SIZE(jzcodec_dapm_widgets); i++) { + snd_soc_dapm_new_control(codec, &jzcodec_dapm_widgets[i]); @@ -21757,13 +18272,13 @@ + struct snd_soc_codec *codec = dai->codec; + u16 reg_val = jzcodec_read_reg_cache(codec, ICODEC_1_LOW); + -+ if (mute != 0) ++ if (mute != 0) + mute = 1; + if (mute) + reg_val = reg_val | (0x1 << 14); + else + reg_val = reg_val & ~(0x1 << 14); -+ ++ + jzcodec_write(codec, ICODEC_1_LOW, reg_val); + return 0; +} @@ -21799,7 +18314,7 @@ + + /* interface format . set some parameter for codec side */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { -+ case SND_SOC_DAIFMT_I2S: ++ case SND_SOC_DAIFMT_I2S: + /* set I2S mode for codec */ + break; + case SND_SOC_DAIFMT_RIGHT_J: @@ -21822,7 +18337,7 @@ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; -+ case SND_SOC_DAIFMT_IB_IF: ++ case SND_SOC_DAIFMT_IB_IF: + break; + case SND_SOC_DAIFMT_IB_NF: + break; @@ -21996,7 +18511,7 @@ + codec->reg_cache = kmemdup(jzcodec_reg_LH, sizeof(jzcodec_reg_LH), GFP_KERNEL); + if (codec->reg_cache == NULL) + return -ENOMEM; -+ ++ + jzcodec_reset(codec); + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); @@ -22007,7 +18522,7 @@ + + /* power on device */ + jzcodec_dapm_event(codec, SNDRV_CTL_POWER_D3hot); -+ ++ + /* clear suspend bit of jz4740 internal codec */ + reg_val = jzcodec_read_reg_cache(codec, ICODEC_1_LOW); + reg_val = reg_val & ~(0x2); @@ -22570,7 +19085,7 @@ + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: -+ /* 0 : slave */ ++ /* 0 : slave */ + break; + case SND_SOC_DAIFMT_CBM_CFS: + /* 1 : master */ @@ -22578,11 +19093,11 @@ + default: + break; + } -+ ++ + return 0; +} + -+/* ++/* +* Set Jz4740 Clock source +*/ +static int jz4740_i2s_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, @@ -22593,7 +19108,7 @@ + +static void jz4740_snd_tx_ctrl(int on) +{ -+ if (on) { ++ if (on) { + /* enable replay */ + __i2s_enable_transmit_dma(); + __i2s_enable_replay(); @@ -22611,13 +19126,13 @@ + +static void jz4740_snd_rx_ctrl(int on) +{ -+ if (on) { ++ if (on) { + /* enable capture */ + __i2s_enable_receive_dma(); + __i2s_enable_record(); + __i2s_enable(); + -+ } else { ++ } else { + /* disable replay & capture */ + __i2s_disable_replay(); + __i2s_disable_record(); @@ -22633,7 +19148,7 @@ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; + int channels = params_channels(params); -+ ++ + jz4740_snd_rx_ctrl(0); + jz4740_snd_rx_ctrl(0); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -22775,7 +19290,7 @@ + .channels_min = 1, + .channels_max = 2, + .rates = JZ4740_I2S_RATES, -+ .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,}, ++ .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,}, + .capture = { + .channels_min = 1, + .channels_max = 2, @@ -22915,7 +19430,7 @@ + * +*/ +static int jz4740_dma_buf_enqueue(struct jz4740_runtime_data *prtd, dma_addr_t data, int size) -+{ ++{ + struct jz4740_dma_buf_aic *aic_buf; + + aic_buf = kzalloc(sizeof(struct jz4740_dma_buf_aic), GFP_KERNEL); @@ -22967,9 +19482,9 @@ + } + } + -+ aic_buf = prtd->next; ++ aic_buf = prtd->next; + channel = prtd->params->channel; -+ if (aic_buf) { ++ if (aic_buf) { + flags = claim_dma_lock(); + disable_dma(channel); + jz_set_alsa_dma(channel, mode, tran_bit); @@ -23002,7 +19517,7 @@ + aic_buf = prtd->next; + channel = prtd->params->channel; + -+ if (aic_buf) { ++ if (aic_buf) { + flags = claim_dma_lock(); + disable_dma(channel); + jz_set_alsa_dma(channel, mode, tran_bit); @@ -23010,7 +19525,7 @@ + set_dma_count(channel, aic_buf->size); + enable_dma(channel); + release_dma_lock(flags); -+ prtd->aic_dma_flag |= AIC_START_DMA; ++ prtd->aic_dma_flag |= AIC_START_DMA; + } else { + printk("next buffer is NULL for capture\n"); + prtd->aic_dma_flag &= ~AIC_START_DMA; @@ -23044,15 +19559,15 @@ + pos += prtd->dma_period; + if (pos >= prtd->dma_end) + pos = prtd->dma_start; -+ } else ++ } else + break; + } + + prtd->dma_pos = pos; +} + -+/* -+ * call the function:jz4740_pcm_dma_irq() after DMA has transfered the current buffer ++/* ++ * call the function:jz4740_pcm_dma_irq() after DMA has transfered the current buffer + */ +static irqreturn_t jz4740_pcm_dma_irq(int dma_ch, void *dev_id) +{ @@ -23133,13 +19648,13 @@ + /* prepare DMA */ + prtd->params = dma; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ ret = jz_request_dma(DMA_ID_AIC_TX, prtd->params->client->name, ++ ret = jz_request_dma(DMA_ID_AIC_TX, prtd->params->client->name, + jz4740_pcm_dma_irq, IRQF_DISABLED, substream); + if (ret < 0) + return ret; + prtd->params->channel = ret; + } else { -+ ret = jz_request_dma(DMA_ID_AIC_RX, prtd->params->client->name, ++ ret = jz_request_dma(DMA_ID_AIC_RX, prtd->params->client->name, + jz4740_pcm_dma_irq, IRQF_DISABLED, substream); + if (ret < 0) + return ret; @@ -23153,7 +19668,7 @@ + prtd->dma_loaded = 0; + prtd->aic_dma_flag = 0; + prtd->dma_limit = runtime->hw.periods_min; -+ prtd->dma_period = params_period_bytes(params); ++ prtd->dma_period = params_period_bytes(params); + prtd->dma_start = runtime->dma_addr; + prtd->dma_pos = prtd->dma_start; + prtd->dma_end = prtd->dma_start + totbytes; @@ -23203,7 +19718,7 @@ + } + + return 0; -+ ++ +} + +static int jz4740_pcm_prepare(struct snd_pcm_substream *substream) @@ -23219,7 +19734,7 @@ + jz4740_dma_ctrl(prtd->params->channel); + prtd->dma_loaded = 0; + prtd->dma_pos = prtd->dma_start; -+ ++ + /* enqueue dma buffers */ + jz4740_pcm_enqueue(substream); + @@ -23242,7 +19757,7 @@ + } else { + audio_start_dma(prtd, DMA_MODE_READ); + } -+ ++ + break; + + case SNDRV_PCM_TRIGGER_STOP: @@ -23276,7 +19791,7 @@ + dma_addr_t ptr; + snd_pcm_uframes_t x; + int channel = prtd->params->channel; -+ ++ + spin_lock(&prtd->lock); +#if 1 + @@ -23289,7 +19804,7 @@ + count = get_dma_residue(channel); + count = aic_buf->size - count; + ptr = aic_buf->data + count; -+ res = ptr - prtd->dma_start; ++ res = ptr - prtd->dma_start; + } + +# else @@ -23319,7 +19834,7 @@ + if (ptr == 0x0) + printk("\ndma address is 00000000 in running!\n"); + res = ptr - prtd->dma_start; -+ } ++ } + } +#endif + spin_unlock(&prtd->lock); @@ -23360,7 +19875,7 @@ + hw_params_cnt = 0; +#endif + -+ if (prtd) ++ if (prtd) + aic_buf = prtd->curr; + + while (aic_buf != NULL) { @@ -23371,7 +19886,7 @@ + aic_buf = NULL; + aic_buf = prtd->curr; + } -+ ++ + if (prtd) { + prtd->curr = NULL; + prtd->next = NULL; @@ -23768,7 +20283,7 @@ + else + //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS); + ; -+ ++ + return 0; +} +