s3c2410-uda1341_c.txt

来自「2410uda1341的测试代码」· 文本 代码 · 共 1,285 行 · 第 1/4 页

TXT
1,285
字号
        int ret;
        long val = 0;

        switch (cmd) {
                case SOUND_MIXER_INFO:
                {
                        mixer_info info;
                        strncpy(info.id, "UDA1341", sizeof(info.id));
                        strncpy(info.name,"Philips UDA1341", sizeof(info.name));
                        info.modify_counter = audio_mix_modcnt;
                        return copy_to_user((void *)arg, &info, sizeof(info));
                }
       
                case SOUND_OLD_MIXER_INFO:
                {
                        _old_mixer_info info;
                        strncpy(info.id, "UDA1341", sizeof(info.id));
                        strncpy(info.name,"Philips UDA1341", sizeof(info.name));
                        return copy_to_user((void *)arg, &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_WRITE_VOLUME:
                        ret = get_user(val, (long *) arg);
                        if (ret)
                                return ret;
                        uda1341_volume = 63 - (((val & 0xff) + 1) * 63) / 100;
                        uda1341_l3_address(UDA1341_REG_DATA0);
                        uda1341_l3_data(uda1341_volume);
                        break;
               
                case SOUND_MIXER_READ_VOLUME:
                        val = ((63 - uda1341_volume) * 100) / 63;
                        val |= val << 8;
                        return put_user(val, (long *) arg);
       
                case SOUND_MIXER_READ_IGAIN:
                        val = ((31- mixer_igain) * 100) / 31;
                        return put_user(val, (int *) arg);

                case SOUND_MIXER_WRITE_IGAIN:
                        ret = get_user(val, (int *) arg);
                        if (ret)
                                return ret;
                        mixer_igain = 31 - (val * 31 / 100);               
                        /* use mixer gain channel 1*/
                        uda1341_l3_address(UDA1341_REG_DATA0);
                        uda1341_l3_data(EXTADDR(EXT0));
                        uda1341_l3_data(EXTDATA(EXT0_CH1_GAIN(mixer_igain)));                       
                        break;

                default:
                        DPRINTK("mixer ioctl %u unknown\n", cmd);
                        return -ENOSYS;
        }                       

        audio_mix_modcnt++;
        return 0;
}


static int iispsr_value(int s_bit_clock, int sample_rate)
{
        int i, prescaler = 0;
        unsigned long tmpval;
        unsigned long tmpval384;
        unsigned long tmpval384min = 0xffff;

        tmpval384 = clk_get_rate(iis_clock) / s_bit_clock;

        for (i = 0; i < 32; i++) {
                tmpval = tmpval384/(i+1);
                if (PCM_ABS((sample_rate - tmpval)) < tmpval384min) {
                        tmpval384min = PCM_ABS((sample_rate - tmpval));
                        prescaler = i;
                }
        }

        DPRINTK("prescaler = %d\n", prescaler);

        return prescaler;
}


static long audio_set_dsp_speed(long val)
{
        unsigned int prescaler;
        prescaler=(IISPSR_A(iispsr_value(S_CLOCK_FREQ, val))
                | IISPSR_B(iispsr_value(S_CLOCK_FREQ, val)));
        writel(prescaler, iis_base + S3C2410_IISPSR);

        printk(PFX "audio_set_dsp_speed:%ld prescaler:%i\n",val,prescaler);
        return (audio_rate = val);
}

static int smdk2410_audio_ioctl(struct inode *inode, struct file *file,
                                uint cmd, ulong arg)
{
        long val;

        switch (cmd) {
                  case SNDCTL_DSP_SETFMT:
                        get_user(val, (long *) arg);
                          if (val & AUDIO_FMT_MASK) {
                                    audio_fmt = val;
                                    break;
                          } else
                                return -EINVAL;

                  case SNDCTL_DSP_CHANNELS:
                  case SNDCTL_DSP_STEREO:
                          get_user(val, (long *) arg);
                          if (cmd == SNDCTL_DSP_STEREO)
                                  val = val ? 2 : 1;
                          if (val != 1 && val != 2)
                                  return -EINVAL;
                          audio_channels = val;
                          break;

                  case SOUND_PCM_READ_CHANNELS:
                          put_user(audio_channels, (long *) arg);
                         break;

                  case SNDCTL_DSP_SPEED:
                          get_user(val, (long *) arg);
                          val = audio_set_dsp_speed(val);
                        if (val < 0)
                                return -EINVAL;
                          put_user(val, (long *) arg);
                          break;

                  case SOUND_PCM_READ_RATE:
                          put_user(audio_rate, (long *) arg);
                          break;

                  case SNDCTL_DSP_GETFMTS:
                          put_user(AUDIO_FMT_MASK, (long *) arg);
                          break;

                  case SNDCTL_DSP_GETBLKSIZE:
                        if(file->f_mode & FMODE_WRITE)
                                  return put_user(audio_fragsize, (long *) arg);
                        else               
                                return put_user(audio_fragsize, (int *) arg);

                  case SNDCTL_DSP_SETFRAGMENT:
                        if (file->f_mode & FMODE_WRITE) {       
                                  if (output_stream.buffers)
                                          return -EBUSY;
                                  get_user(val, (long *) arg);
                                  audio_fragsize = 1 << (val & 0xFFFF);
                                  if (audio_fragsize < 16)
                                          audio_fragsize = 16;
                                  if (audio_fragsize > 16384)
                                          audio_fragsize = 16384;
                                  audio_nbfrags = (val >> 16) & 0x7FFF;
                                if (audio_nbfrags < 2)
                                        audio_nbfrags = 2;
                                  if (audio_nbfrags * audio_fragsize > 128 * 1024)
                                          audio_nbfrags = 128 * 1024 / audio_fragsize;
                                  if (audio_setup_buf(&output_stream))
                                          return -ENOMEM;
       
                        }
                        if (file->f_mode & FMODE_READ) {
                                if (input_stream.buffers)
                                        return -EBUSY;
                                get_user(val, (int *) arg);
                                audio_fragsize =  1 << (val & 0xFFFF);
                                if (audio_fragsize < 16)
                                        audio_fragsize = 16;
                                if (audio_fragsize > 16384)
                                        audio_fragsize = 16384;
                                audio_nbfrags = (val >> 16) & 0x7FFF;
                                if (audio_nbfrags < 2)
                                        audio_nbfrags = 2;
                                if (audio_nbfrags * audio_fragsize > 128 * 1024)
                                        audio_nbfrags = 128 * 1024 / audio_fragsize;
                                if (audio_setup_buf(&input_stream))
                                        return -ENOMEM;

                        }
                         break;

                  case SNDCTL_DSP_SYNC:
                          return audio_sync(file);

                  case SNDCTL_DSP_GETOSPACE:
                {
                        audio_stream_t *s = &output_stream;
                        audio_buf_info *inf = (audio_buf_info *) arg;
                        int err = access_ok(VERIFY_WRITE, inf, sizeof(*inf));
                        int i;
                        int frags = 0, bytes = 0;

                        if (err)
                                return err;
                        for (i = 0; i < s->nbfrags; i++) {
                                if (atomic_read(&s->buffers[i].sem.count) > 0) {
                                        if (s->buffers[i].size == 0) frags++;
                                        bytes += s->fragsize - s->buffers[i].size;
                                }
                        }
                        put_user(frags, &inf->fragments);
                        put_user(s->nbfrags, &inf->fragstotal);
                        put_user(s->fragsize, &inf->fragsize);
                        put_user(bytes, &inf->bytes);
                        break;
                }

                case SNDCTL_DSP_GETISPACE:
                {
                        audio_stream_t *s = &input_stream;
                        audio_buf_info *inf = (audio_buf_info *) arg;
                        int err = access_ok(VERIFY_WRITE, inf, sizeof(*inf));
                        int i;
                        int frags = 0, bytes = 0;

                        if (!(file->f_mode & FMODE_READ))
                                return -EINVAL;

                        if (err)
                                return err;
                        for(i = 0; i < s->nbfrags; i++){
                        if (atomic_read(&s->buffers[i].sem.count) > 0)
                                {
                                        if (s->buffers[i].size == s->fragsize)
                                                frags++;
                                        bytes += s->buffers[i].size;
                                }
                        }
                        put_user(frags, &inf->fragments);
                        put_user(s->nbfrags, &inf->fragstotal);
                        put_user(s->fragsize, &inf->fragsize);
                        put_user(bytes, &inf->bytes);
                        break;
                }
                  case SNDCTL_DSP_RESET:
                        if (file->f_mode & FMODE_READ) {
                                audio_clear_buf(&input_stream);
                        }
                        if (file->f_mode & FMODE_WRITE) {
                                audio_clear_buf(&output_stream);
                        }
                        return 0;
                case SNDCTL_DSP_NONBLOCK:
                        file->f_flags |= O_NONBLOCK;
                        return 0;
                 case SNDCTL_DSP_POST:
                      case SNDCTL_DSP_SUBDIVIDE:
                      case SNDCTL_DSP_GETCAPS:
                      case SNDCTL_DSP_GETTRIGGER:
                      case SNDCTL_DSP_SETTRIGGER:
                      case SNDCTL_DSP_GETIPTR:
                      case SNDCTL_DSP_GETOPTR:
                      case SNDCTL_DSP_MAPINBUF:
                      case SNDCTL_DSP_MAPOUTBUF:
                      case SNDCTL_DSP_SETSYNCRO:
                      case SNDCTL_DSP_SETDUPLEX:
                          return -ENOSYS;
                  default:
                          return smdk2410_mixer_ioctl(inode, file, cmd, arg);
        }

        return 0;
}


static int smdk2410_audio_open(struct inode *inode, struct file *file)
{
        int cold = !audio_active;

        DPRINTK("audio_open\n");
        if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
                if (audio_rd_refcount || audio_wr_refcount)
                        return -EBUSY;
                audio_rd_refcount++;
        } else if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
                if (audio_wr_refcount)
                        return -EBUSY;
                audio_wr_refcount++;
        } else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
                if (audio_rd_refcount || audio_wr_refcount)
                        return -EBUSY;
                audio_rd_refcount++;
                audio_wr_refcount++;
        } else
                return -EINVAL;

        if (cold) {
                audio_rate = AUDIO_RATE_DEFAULT;
                audio_channels = AUDIO_CHANNELS_DEFAULT;
                audio_fragsize = AUDIO_FRAGSIZE_DEFAULT;
                audio_nbfrags = AUDIO_NBFRAGS_DEFAULT;
                if ((file->f_mode & FMODE_WRITE)){
                                init_s3c2410_iis_bus_tx();
                                audio_clear_buf(&output_stream);
                }
                if ((file->f_mode & FMODE_READ)){
                                init_s3c2410_iis_bus_rx();
                                audio_clear_buf(&input_stream);
                }
        }
        return 0;
}


static int smdk2410_mixer_open(struct inode *inode, struct file *file)
{
        return 0;
}


static int smdk2410_audio_release(struct inode *inode, struct file *file)
{
        DPRINTK("audio_release\n");

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?