wm8750.c

来自「xen虚拟机源代码安装包」· C语言 代码 · 共 736 行 · 第 1/2 页

C
736
字号
    if (s->i2c_len >= 2) {        printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len);#ifdef VERBOSE        return 1;#endif    }    s->i2c_data[s->i2c_len ++] = data;    if (s->i2c_len != 2)        return 0;    cmd = s->i2c_data[0] >> 1;    value = ((s->i2c_data[0] << 8) | s->i2c_data[1]) & 0x1ff;    switch (cmd) {    case WM8750_LADCIN:	/* ADC Signal Path Control (Left) */        s->diff[0] = (((value >> 6) & 3) == 3);	/* LINSEL */        if (s->diff[0])            s->in[0] = &s->adc_voice[0 + s->ds * 1];        else            s->in[0] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];        break;    case WM8750_RADCIN:	/* ADC Signal Path Control (Right) */        s->diff[1] = (((value >> 6) & 3) == 3);	/* RINSEL */        if (s->diff[1])            s->in[1] = &s->adc_voice[0 + s->ds * 1];        else            s->in[1] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];        break;    case WM8750_ADCIN:	/* ADC Input Mode */        s->ds = (value >> 8) & 1;	/* DS */        if (s->diff[0])            s->in[0] = &s->adc_voice[0 + s->ds * 1];        if (s->diff[1])            s->in[1] = &s->adc_voice[0 + s->ds * 1];        s->monomix[0] = (value >> 6) & 3;	/* MONOMIX */        break;    case WM8750_ADCTL1:	/* Additional Control (1) */        s->monomix[1] = (value >> 1) & 1;	/* DMONOMIX */        break;    case WM8750_PWR1:	/* Power Management (1) */        s->enable = ((value >> 6) & 7) == 3;	/* VMIDSEL, VREF */        wm8750_set_format(s);        break;    case WM8750_LINVOL:	/* Left Channel PGA */        s->invol[0] = value & 0x3f;		/* LINVOL */        s->inmute[0] = (value >> 7) & 1;	/* LINMUTE */        wm8750_vol_update(s);        break;    case WM8750_RINVOL:	/* Right Channel PGA */        s->invol[1] = value & 0x3f;		/* RINVOL */        s->inmute[1] = (value >> 7) & 1;	/* RINMUTE */        wm8750_vol_update(s);        break;    case WM8750_ADCDAC:	/* ADC and DAC Control */        s->pol = (value >> 5) & 3;		/* ADCPOL */        s->mute = (value >> 3) & 1;		/* DACMU */        wm8750_vol_update(s);        break;    case WM8750_ADCTL3:	/* Additional Control (3) */        break;    case WM8750_LADC:	/* Left ADC Digital Volume */        s->invol[2] = value & 0xff;		/* LADCVOL */        wm8750_vol_update(s);        break;    case WM8750_RADC:	/* Right ADC Digital Volume */        s->invol[3] = value & 0xff;		/* RADCVOL */        wm8750_vol_update(s);        break;    case WM8750_ALC1:	/* ALC Control (1) */        s->alc = (value >> 7) & 3;		/* ALCSEL */        break;    case WM8750_NGATE:	/* Noise Gate Control */    case WM8750_3D:	/* 3D enhance */        break;    case WM8750_LDAC:	/* Left Channel Digital Volume */        s->outvol[0] = value & 0xff;		/* LDACVOL */        wm8750_vol_update(s);        break;    case WM8750_RDAC:	/* Right Channel Digital Volume */        s->outvol[1] = value & 0xff;		/* RDACVOL */        wm8750_vol_update(s);        break;    case WM8750_BASS:	/* Bass Control */        break;    case WM8750_LOUTM1:	/* Left Mixer Control (1) */        s->path[0] = (value >> 8) & 1;		/* LD2LO */        /* TODO: mute/unmute respective paths */        wm8750_vol_update(s);        break;    case WM8750_LOUTM2:	/* Left Mixer Control (2) */        s->path[1] = (value >> 8) & 1;		/* RD2LO */        /* TODO: mute/unmute respective paths */        wm8750_vol_update(s);        break;    case WM8750_ROUTM1:	/* Right Mixer Control (1) */        s->path[2] = (value >> 8) & 1;		/* LD2RO */        /* TODO: mute/unmute respective paths */        wm8750_vol_update(s);        break;    case WM8750_ROUTM2:	/* Right Mixer Control (2) */        s->path[3] = (value >> 8) & 1;		/* RD2RO */        /* TODO: mute/unmute respective paths */        wm8750_vol_update(s);        break;    case WM8750_MOUTM1:	/* Mono Mixer Control (1) */        s->mpath[0] = (value >> 8) & 1;		/* LD2MO */        /* TODO: mute/unmute respective paths */        wm8750_vol_update(s);        break;    case WM8750_MOUTM2:	/* Mono Mixer Control (2) */        s->mpath[1] = (value >> 8) & 1;		/* RD2MO */        /* TODO: mute/unmute respective paths */        wm8750_vol_update(s);        break;    case WM8750_LOUT1V:	/* LOUT1 Volume */        s->outvol[2] = value & 0x7f;		/* LOUT1VOL */        wm8750_vol_update(s);        break;    case WM8750_LOUT2V:	/* LOUT2 Volume */        s->outvol[4] = value & 0x7f;		/* LOUT2VOL */        wm8750_vol_update(s);        break;    case WM8750_ROUT1V:	/* ROUT1 Volume */        s->outvol[3] = value & 0x7f;		/* ROUT1VOL */        wm8750_vol_update(s);        break;    case WM8750_ROUT2V:	/* ROUT2 Volume */        s->outvol[5] = value & 0x7f;		/* ROUT2VOL */        wm8750_vol_update(s);        break;    case WM8750_MOUTV:	/* MONOOUT Volume */        s->outvol[6] = value & 0x7f;		/* MONOOUTVOL */        wm8750_vol_update(s);        break;    case WM8750_ADCTL2:	/* Additional Control (2) */        break;    case WM8750_PWR2:	/* Power Management (2) */        s->power = value & 0x7e;        /* TODO: mute/unmute respective paths */        wm8750_vol_update(s);        break;    case WM8750_IFACE:	/* Digital Audio Interface Format */        s->format = value;        s->master = (value >> 6) & 1;			/* MS */        wm8750_clk_update(s, s->master);        break;    case WM8750_SRATE:	/* Clocking and Sample Rate Control */        s->rate = &wm_rate_table[(value >> 1) & 0x1f];        wm8750_clk_update(s, 0);        break;    case WM8750_RESET:	/* Reset */        wm8750_reset(&s->i2c);        break;#ifdef VERBOSE    default:        printf("%s: unknown register %02x\n", __FUNCTION__, cmd);#endif    }    return 0;}static int wm8750_rx(i2c_slave *i2c){    return 0x00;}static void wm8750_save(QEMUFile *f, void *opaque){    struct wm8750_s *s = (struct wm8750_s *) opaque;    int i;    qemu_put_8s(f, &s->i2c_data[0]);    qemu_put_8s(f, &s->i2c_data[1]);    qemu_put_be32(f, s->i2c_len);    qemu_put_be32(f, s->enable);    qemu_put_be32(f, s->idx_in);    qemu_put_be32(f, s->req_in);    qemu_put_be32(f, s->idx_out);    qemu_put_be32(f, s->req_out);    for (i = 0; i < 7; i ++)        qemu_put_8s(f, &s->outvol[i]);    for (i = 0; i < 2; i ++)        qemu_put_8s(f, &s->outmute[i]);    for (i = 0; i < 4; i ++)        qemu_put_8s(f, &s->invol[i]);    for (i = 0; i < 2; i ++)        qemu_put_8s(f, &s->inmute[i]);    for (i = 0; i < 2; i ++)        qemu_put_8s(f, &s->diff[i]);    qemu_put_8s(f, &s->pol);    qemu_put_8s(f, &s->ds);    for (i = 0; i < 2; i ++)        qemu_put_8s(f, &s->monomix[i]);    qemu_put_8s(f, &s->alc);    qemu_put_8s(f, &s->mute);    for (i = 0; i < 4; i ++)        qemu_put_8s(f, &s->path[i]);    for (i = 0; i < 2; i ++)        qemu_put_8s(f, &s->mpath[i]);    qemu_put_8s(f, &s->format);    qemu_put_8s(f, &s->power);    qemu_put_byte(f, (s->rate - wm_rate_table) / sizeof(*s->rate));    i2c_slave_save(f, &s->i2c);}static int wm8750_load(QEMUFile *f, void *opaque, int version_id){    struct wm8750_s *s = (struct wm8750_s *) opaque;    int i;    qemu_get_8s(f, &s->i2c_data[0]);    qemu_get_8s(f, &s->i2c_data[1]);    s->i2c_len = qemu_get_be32(f);    s->enable = qemu_get_be32(f);    s->idx_in = qemu_get_be32(f);    s->req_in = qemu_get_be32(f);    s->idx_out = qemu_get_be32(f);    s->req_out = qemu_get_be32(f);    for (i = 0; i < 7; i ++)        qemu_get_8s(f, &s->outvol[i]);    for (i = 0; i < 2; i ++)        qemu_get_8s(f, &s->outmute[i]);    for (i = 0; i < 4; i ++)        qemu_get_8s(f, &s->invol[i]);    for (i = 0; i < 2; i ++)        qemu_get_8s(f, &s->inmute[i]);    for (i = 0; i < 2; i ++)        qemu_get_8s(f, &s->diff[i]);    qemu_get_8s(f, &s->pol);    qemu_get_8s(f, &s->ds);    for (i = 0; i < 2; i ++)        qemu_get_8s(f, &s->monomix[i]);    qemu_get_8s(f, &s->alc);    qemu_get_8s(f, &s->mute);    for (i = 0; i < 4; i ++)        qemu_get_8s(f, &s->path[i]);    for (i = 0; i < 2; i ++)        qemu_get_8s(f, &s->mpath[i]);    qemu_get_8s(f, &s->format);    qemu_get_8s(f, &s->power);    s->rate = &wm_rate_table[(uint8_t) qemu_get_byte(f) & 0x1f];    i2c_slave_load(f, &s->i2c);    return 0;}static int wm8750_iid = 0;i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio){    struct wm8750_s *s = (struct wm8750_s *)            i2c_slave_init(bus, 0, sizeof(struct wm8750_s));    s->i2c.event = wm8750_event;    s->i2c.recv = wm8750_rx;    s->i2c.send = wm8750_tx;    AUD_register_card(audio, CODEC, &s->card);    wm8750_reset(&s->i2c);    register_savevm(CODEC, wm8750_iid ++, 0, wm8750_save, wm8750_load, s);    return &s->i2c;}#if 0static void wm8750_fini(i2c_slave *i2c){    struct wm8750_s *s = (struct wm8750_s *) i2c;    wm8750_reset(&s->i2c);    AUD_remove_card(&s->card);    qemu_free(s);}#endifvoid wm8750_data_req_set(i2c_slave *i2c,                void (*data_req)(void *, int, int), void *opaque){    struct wm8750_s *s = (struct wm8750_s *) i2c;    s->data_req = data_req;    s->opaque = opaque;}void wm8750_dac_dat(void *opaque, uint32_t sample){    struct wm8750_s *s = (struct wm8750_s *) opaque;    *(uint32_t *) &s->data_out[s->idx_out] = sample;    s->req_out -= 4;    s->idx_out += 4;    if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0)        wm8750_out_flush(s);}void *wm8750_dac_buffer(void *opaque, int samples){    struct wm8750_s *s = (struct wm8750_s *) opaque;    /* XXX: Should check if there are <i>samples</i> free samples available */    void *ret = s->data_out + s->idx_out;    s->idx_out += samples << 2;    s->req_out -= samples << 2;    return ret;}void wm8750_dac_commit(void *opaque){    struct wm8750_s *s = (struct wm8750_s *) opaque;    return wm8750_out_flush(s);}uint32_t wm8750_adc_dat(void *opaque){    struct wm8750_s *s = (struct wm8750_s *) opaque;    uint32_t *data;    if (s->idx_in >= sizeof(s->data_in))        wm8750_in_load(s);    data = (uint32_t *) &s->data_in[s->idx_in];    s->req_in -= 4;    s->idx_in += 4;    return *data;}void wm8750_set_bclk_in(void *opaque, int hz){    struct wm8750_s *s = (struct wm8750_s *) opaque;    s->ext_adc_hz = hz;    s->ext_dac_hz = hz;    wm8750_clk_update(s, 1);}

⌨️ 快捷键说明

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