* ibook sound, limping mixer
@ 2001-01-09 21:29 Conrad H Ziesler
0 siblings, 0 replies; 3+ messages in thread
From: Conrad H Ziesler @ 2001-01-09 21:29 UTC (permalink / raw)
To: linuxppc-dev
[-- Attachment #1: Type: TEXT/PLAIN, Size: 1251 bytes --]
in case this is of any use to anyone:
i've attached /dev/mixer code to talk to the dac3550a chip through some
i2c interface. it just calls i2c bus write operations.
the lmsensors package provides an apple 'keywest' i2c controller
interface, which is a polling driver which appears to do the
same stuff as the PPCI2CInterface.cpp from IO/Drivers/.. in darwin
it all seems simple enough. i hacked up a simple i2c driver merged into
the mixer code from above, cut apart dmasound to eliminate the mixer
device and extraneous stuff, and added the appropriate missing
KL1_AUDIO_XXX and KL1_I2S_) bits to arch/ppc/kernel/feature.c (in
feature_bits_keylargo[], under FEATURE_Sound_xxx so the daca gets powered
up)
then i rebooted and had sound and a mixer device, and was able to
hear some sound, fiddle with the mixer controls, and then hear no sound
once or twice i was able to reenable sound by randomly fiddling with the
mixer.
so apparently SOME data was getting across the i2c bus to the daca chip,
but probably it was reading trash.
since the dac3550a has write-only i2c registers, its pretty hard to debug
the i2c interface. probably if someone puts an oscilloscope probe on the
i2c bus signals it should all become clear.
--conrad
[-- Attachment #2: mixer --]
[-- Type: TEXT/PLAIN, Size: 8811 bytes --]
#include <stdarg.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/major.h>
#include <linux/config.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/sound.h>
#include <linux/delay.h>
#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/blkdev.h>
#include <linux/pci.h>
#include <linux/poll.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/prom.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/init.h>
#include <asm/irq.h>
#include <asm/feature.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/setup.h>
#include <linux/soundcard.h>
/* requires i2c access functions:
struct i2c_t *i2c_find(void);
i2c_open(i2c_t *dp);
i2c_close(i2c_t *dp);
i2c_write(i2c_t *dp, uchar addr, uchar subaddr, uchar *data, int len);
*/
/* dmasound keeps this */
extern int beep_volume;
/* note: the daca i2c registers are write only */
/* i2c address */
#define DACAI2Caddr 0x4d
/* i2c control or subaddresses
#define DACAI2Csrate 0x01
#define DACAI2Cavol 0x02
#define DACAI2Cgcfg 0x03
/* gcfg register */
#define DACAhvolt 0x40
#define DACAlowp 0x20
#define DACAaux2on 0x10
#define DACAaux1on 0x08
#define DACAdacon 0x04
#define DACAmono 0x02
#define DACAinvert 0x01
/* srate register */
#define DACAlrsel_r 0x10
#define DACAlrsel_l 0x00
#define DACAdelay_1 0x08
#define DACAsrc48 0x00
#define DACAsrc32 0x01
#define DACAsrc24 0x02
#define DACAsrc16 0x03
#define DACAsrc12 0x04
#define DACAsrc8 0x05
#define DACAsrca 0x06
typedef struct daca_i2c_regs_st
{
void *i2c;
unsigned short int avol_reg;
unsigned char sr_reg;
unsigned char gcfg_reg;
}daca_i2c_regs_t;
/* mirror state daca regs (since they are read only) */
daca_i2c_regs_t daca_regs;
void daca_update(daca_i2c_regs_t *dacap)
{
i2c_open(dacap->i2c);
i2c_write(dacap->i2c,DACAI2Caddr, DACAI2Cgcfg, &(dacap->gcfg_reg), 1);
i2c_write(dacap->i2c,DACAI2Caddr, DACAI2Cavol, &(dacap->avol_reg), 2);
i2c_write(dacap->i2c,DACAI2Caddr, DACAI2Csrate, &(dacap->sr_reg), 1);
i2c_close(dacap->i2c);
}
struct sound_mixer
{
int busy;
int modify_counter;
/* keep track of status */
int v_left;
int v_right;
int aux1;
int aux2;
int headphones_speaker;
};
static void mixer_update(struct sound_mixer *mix)
{
uchar gcfg;
uchar vols[2];
if(mix==0)return;
if(mix->dev==0)return;
if(!mix->dev->initted)return;
if(!mix->dev->open)return;
if(!mix->headphones_speaker)
{
vols[0]=mix->v_left&0x3f;
vols[1]=mix->v_right&0x3f;
}
else
{
vols[0]=vols[1]= ((mix->v_left+mix->v_right)/2);
}
gcfg= DACAhvolt | ((mix->aux1)?DACAaux1on:0)| ((mix->aux2)?DACAaux2on:0) |
( (mix->headphones_speaker)?(DACAmono|DACAinvert):0);
daca.gcfg_reg=gcfg;
daca.avol_reg= (((unsigned short) vols[1] << 8) | vols[0]);
daca_update(&daca);
}
static struct sound_mixer mixer;
static int mixer_unit=-1;
static int mixer_open(struct inode *inode, struct file *file)
{
MOD_INC_USE_COUNT;
printk("mixer open %p %p\n",inode,file);
mixer.busy = 1;
return 0;
}
static int mixer_release(struct inode *inode, struct file *file)
{
printk("mixer close %p %p\n",inode,file);
mixer.busy = 0;
MOD_DEC_USE_COUNT;
return 0;
}
#define IOCTL_IN(arg, ret) \
do { int error = get_user(ret, (int *)(arg)); \
if (error) return error; \
} while (0)
#define IOCTL_OUT(arg, ret) ioctl_return((int *)(arg), ret)
static long long sound_lseek(struct file *file, long long offset, int orig)
{
return -ESPIPE;
}
static inline int ioctl_return(int *addr, int value)
{
if (value < 0)
return(value);
return put_user(value, addr)? -EFAULT: 0;
}
#define MINL 0
#define MINLR 0
#define MAXL 100
#define MAXLR ((100<<8)|100)
int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
u_long arg)
{
unsigned int data;
if(0)printk("mixer ioctl: %p %p %x %lx\n",inode,file,cmd,arg);
if (_SIOC_DIR(cmd) & _SIOC_WRITE)
mixer.modify_counter++;
switch (cmd)
{
case OSS_GETVERSION:
return IOCTL_OUT(arg,SOUND_VERSION);
case SOUND_MIXER_INFO:
{
mixer_info info;
strncpy(info.id, "DACA", sizeof(info.id));
strncpy(info.name, "DACA-i2c", sizeof(info.name));
info.name[sizeof(info.name)-1] = 0;
info.modify_counter = mixer.modify_counter;
copy_to_user_ret((int *)arg, &info,
sizeof(info), -EFAULT);
return 0;
}
case SOUND_MIXER_READ_DEVMASK:
data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
| SOUND_MASK_LINE | SOUND_MASK_ALTPCM
| SOUND_MASK_CD ;
return IOCTL_OUT(arg, data);
case SOUND_MIXER_READ_RECMASK:
data = 0;
return IOCTL_OUT(arg, data);
case SOUND_MIXER_READ_RECSRC:
data = 0;
return IOCTL_OUT(arg, data);
case SOUND_MIXER_WRITE_RECSRC:
IOCTL_IN(arg, data);
data=0;
return IOCTL_OUT(arg, data);
case SOUND_MIXER_READ_STEREODEVS:
data = SOUND_MASK_VOLUME ;
return IOCTL_OUT(arg, data);
case SOUND_MIXER_READ_CAPS:
return IOCTL_OUT(arg, 0);
case SOUND_MIXER_WRITE_VOLUME:
IOCTL_IN(arg, data);
mixer.v_left = (((data&0xff) * 0x30)/100);
mixer.v_right= ((((data>>8)&0xff)* 0x30)/100);
if(mixer.v_left>0x30)mixer.v_left=0x30;
if(mixer.v_right>0x30)mixer.v_right=0x30;
mixer_update(&mixer);
/* fall through */
case SOUND_MIXER_READ_VOLUME:
data = ((mixer.v_left*100)/0x30) | (((mixer.v_right*100)/0x30) << 8);
return IOCTL_OUT(arg, data);
case SOUND_MIXER_WRITE_SPEAKER:
IOCTL_IN(arg, data);
if(0)printk("mixer: write speaker %x\n",data);
if ( !mixer.headphones_speaker && ((data & 0xff) > MINL) ) mixer.headphones_speaker=1;
else if ( mixer.headphones_speaker && ((data & 0xff) < MAXL) ) mixer.headphones_speaker=0;
mixer_update(&mixer);
/* fall through */
case SOUND_MIXER_READ_SPEAKER:
data= (mixer.headphones_speaker)?MAXLR:MINLR;
return IOCTL_OUT(arg, data);
case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */
IOCTL_IN(arg, data);
if((data&0xff)> 50)
{
printk("hacking... fixing vols to 1,0 \n");
mixer.v_left=1;
mixer.v_right=0;
mixer_update(&mixer);
}
beep_volume = ((data & 0xff) + ((data>>8)&0xff))/2;
/* fall through */
case SOUND_MIXER_READ_ALTPCM:
data=(beep_volume) | (beep_volume<<8);
return IOCTL_OUT(arg, data);
case SOUND_MIXER_WRITE_LINE: /* treat line as aux1 (modem?) */
IOCTL_IN(arg, data);
if(0)printk("mixer: write line %x\n",data);
if ( !mixer.aux1 && ((data & 0xff) > MINL) ) mixer.aux1=1;
else if ( mixer.aux1 && ((data & 0xff) < MAXL) ) mixer.aux1=0;
mixer_update(&mixer);
/* fall through */
case SOUND_MIXER_READ_LINE:
data = (mixer.aux1)? MAXLR: MINLR;
return IOCTL_OUT(arg, data);
case SOUND_MIXER_WRITE_CD:
IOCTL_IN(arg, data);
if(0)printk("mixer: write cd %x\n",data);
if ( !mixer.aux2 && ((data & 0xff) > MINL) ) mixer.aux2=1;
else if ( mixer.aux2 && ((data & 0xff) < MAXL) ) mixer.aux2=0;
mixer_update(&mixer);
/* fall through */
case SOUND_MIXER_READ_CD:
data = (mixer.aux2)? MAXLR: MINLR;
return IOCTL_OUT(arg, data);
}
return -EINVAL;
}
static struct file_operations mixer_fops =
{
sound_lseek,
NULL, /* mixer_read */
NULL, /* mixer_write */
NULL, /* mixer_readdir */
NULL, /* mixer_poll */
mixer_ioctl,
NULL, /* mixer_mmap */
mixer_open,
NULL, /* flush */
mixer_release,
};
#endif
static void __init mixer_init(void)
{
mixer.dev=&audio_i2c_control;
mixer.headphones_speaker=1;
mixer.v_left=32; /* 5 bits worth */
mixer.v_right=32;
mixer.aux1=0;
mixer.aux2=0;
mixer_unit = register_sound_mixer(&mixer_fops, -1);
if (mixer_unit < 0)
return;
printk("daca_i2c_mixer: registered as unit %i\n",mixer_unit);
mixer.busy = 0;
}
MODULE_DESCRIPTION("mixer for dac3550a sound chip");
int init_module(void)
{
daca->i2c=i2c_find("daca");
mixer_init();
return 0;
}
void cleanup_module(void)
{
if (mixer_unit >= 0)
unregister_sound_mixer(mixer_unit);
}
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: ibook sound, limping mixer
@ 2001-01-10 8:48 Christof Petig
0 siblings, 0 replies; 3+ messages in thread
From: Christof Petig @ 2001-01-10 8:48 UTC (permalink / raw)
To: Conrad H Ziesler, linuxppc-dev
Conrad H Ziesler wrote:
> in case this is of any use to anyone:
>
Yes, I'm very interested. Since I actually started looking into the
specs and sources, but did not find the time to start coding the same.
> it all seems simple enough. i hacked up a simple i2c driver merged into
> the mixer code from above, cut apart dmasound to eliminate the mixer
> device and extraneous stuff,
>
can you send me a patch?
> and added the appropriate missing
> KL1_AUDIO_XXX and KL1_I2S_) bits to arch/ppc/kernel/feature.c (in
> feature_bits_keylargo[], under FEATURE_Sound_xxx so the daca gets powered
> up)
>
> then i rebooted and had sound and a mixer device, and was able to
> hear some sound, fiddle with the mixer controls, and then hear no sound
> once or twice i was able to reenable sound by randomly fiddling with the
> mixer.
>
> so apparently SOME data was getting across the i2c bus to the daca chip,
> but probably it was reading trash.
>
Hmm. I first thought it might be an byte order issue but then realized
it would only swap left and right volume. No idea yet. I'll give it a
try myself later.
>
> since the dac3550a has write-only i2c registers, its pretty hard to debug
> the i2c interface. probably if someone puts an oscilloscope probe on the
> i2c bus signals it should all become clear.
>
I would recommend a logic analyzer or better an i2c analyzer. I have an
oscilloscope but I would not dare to try reading i2c signals by hand.
Christof
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: ibook sound, limping mixer
@ 2001-01-10 14:29 Iain Sandoe
0 siblings, 0 replies; 3+ messages in thread
From: Iain Sandoe @ 2001-01-10 14:29 UTC (permalink / raw)
To: Christof Petig, Conrad H Ziesler, linuxppc-dev
on Wed, Jan 10, 2001, Christof Petig wrote:
> Conrad H Ziesler wrote:
>> in case this is of any use to anyone:
> Yes, I'm very interested. Since I actually started looking into the
> specs and sources, but did not find the time to start coding the same.
so am I (of course). I've taken a copy over to my devl area - and I will
figure out how to include it into the next stage of dmasound devl soon.
>> since the dac3550a has write-only i2c registers, its pretty hard to debug
>> the i2c interface. probably if someone puts an oscilloscope probe on the
>> i2c bus signals it should all become clear.
>>
> I would recommend a logic analyzer or better an i2c analyzer. I have an
> oscilloscope but I would not dare to try reading i2c signals by hand.
well, I have a storage scope (which would possibly do it) [I don't run to a
logic analyser]
- but more fundamental problem - no iBook - if someone in the UK (unless
someone from elsewhere is prepared to ship one) wants to lend one - I'll see
what I can do... it's not a machine I can justify buying at the moment.
[my test set is G3/Beige, Lombard, 9600/233, and, when I get the disk
re-partitioned G4/500].
ciao,
Iain.
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2001-01-10 14:29 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2001-01-10 14:29 ibook sound, limping mixer Iain Sandoe
-- strict thread matches above, loose matches on Subject: below --
2001-01-10 8:48 Christof Petig
2001-01-09 21:29 Conrad H Ziesler
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).