diff -ur --new-file /usr/src/origs/linux-2.4-benh.dist/drivers/sound/dmasound/Makefile linux-2.4-benh/drivers/sound/dmasound/Makefile --- /usr/src/origs/linux-2.4-benh.dist/drivers/sound/dmasound/Makefile Sun Sep 23 17:19:15 2001 +++ linux-2.4-benh/drivers/sound/dmasound/Makefile Wed Oct 3 07:47:52 2001 @@ -13,7 +13,7 @@ list-multi := dmasound_pmac.o -dmasound_pmac-objs := dmasound_awacs.o trans_16.o tas3001c.o +dmasound_pmac-objs := dmasound_awacs.o trans_16.o tas3001c.o dac3550a.o obj-$(CONFIG_DMASOUND) += dmasound_core.o obj-$(CONFIG_DMASOUND_ATARI) += dmasound_atari.o diff -ur --new-file /usr/src/origs/linux-2.4-benh.dist/drivers/sound/dmasound/dac3550a.c linux-2.4-benh/drivers/sound/dmasound/dac3550a.c --- /usr/src/origs/linux-2.4-benh.dist/drivers/sound/dmasound/dac3550a.c Wed Dec 31 17:00:00 1969 +++ linux-2.4-benh/drivers/sound/dmasound/dac3550a.c Wed Oct 3 07:47:52 2001 @@ -0,0 +1,292 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* FYI: This code was derived from the tas3001c.c Texas/Tumbler mixer + * control code, as well as info derived from the AppleDACAAudio driver + * from Darwin CVS (main thing I derived being register numbers and + * values, as well as when to make the calls). */ + +#define I2C_DRIVERID_DACA (0xFDCB) + +#define DACA_VERSION "0.1" +#define DACA_DATE "20010930" + +/* UGLY. + * But... + */ +static int cur_left_vol; +static int cur_right_vol; +static struct i2c_client * daca_client = NULL; + +static int daca_attach_adapter(struct i2c_adapter *adapter); + +static int daca_attach_adapter(struct i2c_adapter *adapter); +static int daca_detect_client(struct i2c_adapter *adapter, int address); +static int daca_detach_client(struct i2c_client *client); + +/* Unique ID allocation */ +static int daca_id = 0; +static int /* __initdata */ daca_initialized = 0; + +struct daca_data { + int arf; +}; + +struct i2c_driver daca_driver = + { + /* name */ "DAC3550A driver V " DACA_VERSION, + /* id */ I2C_DRIVERID_DACA, + /* flags */ I2C_DF_NOTIFY, + /* attach_adapter */ &daca_attach_adapter, + /* detach_client */ &daca_detach_client, + /* command */ NULL, + /* inc_use */ NULL, /* &tas_inc_use, */ + /* dec_use */ NULL /* &tas_dev_use */ + }; + + +#define VOL_MAX ((1<<20) - 1) + +void daca_get_volume(uint * left_vol, uint *right_vol) { + *left_vol = cur_left_vol>>5; + *right_vol = cur_right_vol>>5; +} + +int daca_set_volume(uint left_vol, uint right_vol) { + unsigned short voldata; + + if (! daca_client) { + printk("Try to set volume with no client !!!\n"); + return -1; + } + + left_vol<<=5; /* Derived from experience, not from any specific values */ + right_vol<<=5; + + if (left_vol > VOL_MAX) + left_vol = VOL_MAX; + + if (right_vol > VOL_MAX) + right_vol = VOL_MAX; + + voldata = ((left_vol >> 14) & 0x3f) << 8; + voldata |= (right_vol >> 14) & 0x3f; + + if (i2c_smbus_write_word_data(daca_client, 2, voldata) < 0) { + printk("daca: failed to set volume \n"); + return -1; + } else { + cur_left_vol = left_vol; + cur_right_vol = right_vol; + } + + return 0; +} + +int daca_leave_sleep(void) { + if (!daca_client) { + printk("Entering sleep, but no client to sleep for\n"); + return -1; + } + + /* Write the sample rate reg the value it needs */ + i2c_smbus_write_byte_data(daca_client, 1, 8); + daca_set_volume(cur_left_vol >> 5, cur_right_vol >> 5); + /* Write the global config reg - invert right power amp, + * DAC on, use 5-volt mode */ + i2c_smbus_write_byte_data(daca_client, 3, 0x45); + + return 0; + +} + +int daca_enter_sleep(void) { + if (!daca_client) { + printk("Entering sleep, but no client to sleep for\n"); + return -1; + } + + i2c_smbus_write_byte_data(daca_client, 1, 8); + daca_set_volume(cur_left_vol >> 5, cur_right_vol >> 5); + /* Write the global config reg - invert right power amp, + * DAC on, enter low-power mode, use 5-volt mode */ + i2c_smbus_write_byte_data(daca_client, 3, 0x65); + + return 0; + +} + +static int daca_attach_adapter(struct i2c_adapter *adapter) +{ + printk("In daca_attach_adapter (cheating)\n"); + daca_detect_client(adapter, 0x4d); + return (0); +} + +static int daca_init_client(struct i2c_client * new_client) +{ + /* + * Probe is not working with i2c-keywest... + * + * We try to use addr 0x4d on each adapter, by writing the global config register. + * + */ + + /* Write the global config reg - invert right power amp, + * DAC on, use 5-volt mode */ + if (i2c_smbus_write_byte_data(new_client, 3, 0x45)) { + return -1; + } else { + i2c_smbus_write_byte_data(new_client, 1, 8); + printk("Hm, I think we have a DACA...\n"); + daca_client = new_client; + daca_set_volume(15000, 15000); + return 0; + } + return 0; +} + +static int daca_detect_client(struct i2c_adapter *adapter, int address) +{ + int err = 0; + struct i2c_client *new_client; + + struct daca_data *data; + const char *client_name = "DAC 3550A Digital Equalizer"; + + printk("IN daca_detect_client\n"); + + /* Let's see whether this adapter can support what we need. + Please substitute the things you need here! + For `sensors' drivers, add `! is_isa &&' to the if statement */ + + /* FIXME: dunno what to check. + */ + if (!i2c_check_functionality(adapter,I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_WRITE_BYTE | I2C_FUNC_SMBUS_READ_BYTE)) + printk("what, we can't read?\n"); + + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access several i2c functions safely */ + + /* Note that we reserve some space for foo_data too. If you don't + need it, remove it. We do it here to help to lessen memory + fragmentation. */ + + if (! (new_client = kmalloc(sizeof(struct i2c_client) + + sizeof(struct daca_data), + GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR0; + } + + /* This is tricky, but it will set the data to the right value. */ + new_client->data = new_client + 1; + data = (struct daca_data *) (new_client->data); + + new_client->addr = address; + new_client->data = data; + new_client->adapter = adapter; + new_client->driver = &daca_driver; + new_client->flags = 0; + + + strcpy(new_client->name,client_name); + + new_client->id = daca_id++; /* Automatically unique */ + + /* Any other initializations in data must be done here too. */ + + if (daca_init_client(new_client)) { + goto ERROR3; + } + + /* Tell the i2c layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto ERROR3; + + /* This function can write default values to the client registers, if + needed. */ + return 0; + + /* OK, this is not exactly good programming practice, usually. But it is + very code-efficient in this case. */ +/* + ERROR4: + i2c_detach_client(new_client); +*/ + ERROR3: +/* + ERROR2: + ERROR1: +*/ + kfree(new_client); + ERROR0: + return err; +} + + +static int daca_detach_client(struct i2c_client *client) +{ + int err; + + if (client==daca_client) { + daca_client = NULL; + } + + /* Try to detach the client from i2c space */ + if ((err = i2c_detach_client(client))) { + printk("dac3550a: Client deregistration failed, client not detached.\n"); + return err; + } + + kfree(client); /* Frees client data too, if allocated at the same time */ + return 0; +} + + + +/* KERNEL REGISTRATION */ + + +/* Keep track of how far we got in the initialization process. If several + things have to initialized, and we fail halfway, only those things + have to be cleaned up! */ + +int daca_cleanup(void) +{ + int res; + if (daca_initialized == 1) { + if ((res = i2c_del_driver(&daca_driver))) { + printk("dac3550a: Driver registration failed, module not removed.\n"); + return res; + } + daca_initialized--; + } + return 0; +} + +int daca_init(void) + { + int res; + printk("dac3550a driver version %s (%s)\n",DACA_VERSION,DACA_DATE); + + if ((res = i2c_add_driver(&daca_driver))) { + printk("dac3550a: Driver registration failed, module not inserted.\n"); + daca_cleanup(); + return res; + } + daca_initialized ++; + return 0; + } diff -ur --new-file /usr/src/origs/linux-2.4-benh.dist/drivers/sound/dmasound/dmasound_awacs.c linux-2.4-benh/drivers/sound/dmasound/dmasound_awacs.c --- /usr/src/origs/linux-2.4-benh.dist/drivers/sound/dmasound/dmasound_awacs.c Sat Sep 29 10:28:30 2001 +++ linux-2.4-benh/drivers/sound/dmasound/dmasound_awacs.c Wed Oct 3 07:52:13 2001 @@ -282,6 +282,13 @@ extern TRANS transAwacsNormalRead ; +extern int daca_init(void); +extern int daca_cleanup(void); +extern int daca_set_volume(uint left_vol, uint right_vol); +extern void daca_get_volume(uint * left_vol, uint *right_vol); +extern int daca_enter_sleep(void); +extern int daca_leave_sleep(void); + extern int tas_init(void); extern int tas_cleanup(void); extern int tumbler_set_volume(uint left_vol, uint right_vol); @@ -673,10 +680,16 @@ case AFMT_S8: size = 8; break; - case AFMT_S16_BE: - case AFMT_U16_BE: case AFMT_S16_LE: + if(!hw_can_byteswap) + format = AFMT_S16_BE; + case AFMT_S16_BE: + size = 16; + break; case AFMT_U16_LE: + if(!hw_can_byteswap) + format = AFMT_U16_BE; + case AFMT_U16_BE: size = 16; break; default: /* :-) */ @@ -1221,8 +1234,10 @@ /* deny interrupts */ switch (awacs_revision) { case AWACS_TUMBLER: - case AWACS_DACA: break ; /* dont know how yet */ + case AWACS_DACA: + daca_enter_sleep(); + break ; case AWACS_BURGUNDY: break ; case AWACS_SCREAMER: @@ -1257,19 +1272,6 @@ awacs_write(MASK_ADDR1 | awacs_reg[1]); mdelay(200); } - /* restore settings */ - switch (awacs_revision) { - case AWACS_TUMBLER: - case AWACS_DACA: - break ; /* dont know how yet */ - case AWACS_BURGUNDY: - break ; - case AWACS_SCREAMER: - case AWACS_AWACS: - default: - load_awacs() ; - break ; - } /* Recalibrate chip */ if (awacs_revision == AWACS_SCREAMER) awacs_recalibrate(); @@ -1292,8 +1294,24 @@ awacs_revision == AWACS_AWACS) { awacs_reg[1] = awacs_reg1_save; awacs_write(MASK_ADDR1 | awacs_reg[1]); + /* restore settings */ + switch (awacs_revision) { + case AWACS_TUMBLER: + break ; /* dont know how yet */ + case AWACS_DACA: + /* this MUST happen after interrupts are + * reenabled, else driver must be unloaded + * and reloaded */ + daca_leave_sleep(); + break ; /* dont know how yet */ + case AWACS_BURGUNDY: + break ; + case AWACS_SCREAMER: + case AWACS_AWACS: + default: + load_awacs() ; + break ; } - /* Resume pending sounds. */ /* we don't try to restart input... */ PMacPlay(); @@ -1944,6 +1962,54 @@ return -EINVAL; } +static int daca_mixer_ioctl(u_int cmd, u_long arg) +{ + int data; + + /* And the DACA's no genius either! */ + + switch(cmd) { + + case SOUND_MIXER_READ_DEVMASK: + data = SOUND_MASK_VOLUME; + 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); + daca_set_volume(data, data); + /* Fall through */ + case SOUND_MIXER_READ_VOLUME: + daca_get_volume(& data, &data); + return IOCTL_OUT(arg, data); + + case SOUND_MIXER_OUTMASK: + break; + case SOUND_MIXER_OUTSRC: + break; + } + return -EINVAL; +} + static int PMacMixerIoctl(u_int cmd, u_long arg) { /* Different IOCTLS for burgundy and, eventually, DACA & Tumbler */ @@ -1952,9 +2018,10 @@ return burgundy_mixer_ioctl(cmd, arg); break ; case AWACS_DACA: + return daca_mixer_ioctl(cmd, arg); + break; case AWACS_TUMBLER: - return tumbler_mixer_ioctl(cmd, arg); - /* return -EINVAL; we don't know how to do these yet*/ + return tumbler_mixer_ioctl(cmd, arg); break ; default: /* ;-)) */ return awacs_mixer_ioctl(cmd, arg); @@ -2265,6 +2332,10 @@ is_ibook = 1 ; return ; } + if (machine_is_compatible("PowerBook2,2")) { /* ibook 2 (firewire) */ + is_ibook = 1 ; + return ; + } } /* Get the OF node that tells us about the registers, interrupts etc. to use @@ -2519,10 +2590,10 @@ break; } } - if (rev == 2) { + if (rev >= 2) { hw_can_byteswap = 0; #ifdef DEBUG_DMASOUND -printk("dmasound_pmac: found Keylargo rev 2 - H/W byte-swap disabled\n") ; +printk("dmasound_pmac: found Keylargo rev 2 or later - H/W byte-swap disabled\n") ; #endif } } @@ -2765,7 +2836,8 @@ tas_init(); break ; case AWACS_DACA: - break ; /* dont know how yet */ + daca_init(); + break ; case AWACS_BURGUNDY: awacs_burgundy_init(); break ; @@ -2884,6 +2956,9 @@ awacs_tumbler_cleanup(); tas_cleanup(); break ; + case AWACS_DACA: + daca_cleanup(); + break; } dmasound_deinit(); }