!C99Shell v. 1.0 pre-release build #13!

Software: Apache/2.0.54 (Unix) mod_perl/1.99_09 Perl/v5.8.0 mod_ssl/2.0.54 OpenSSL/0.9.7l DAV/2 FrontPage/5.0.2.2635 PHP/4.4.0 mod_gzip/2.0.26.1a 

uname -a: Linux snow.he.net 4.4.276-v2-mono-1 #1 SMP Wed Jul 21 11:21:17 PDT 2021 i686 

uid=99(nobody) gid=98(nobody) groups=98(nobody) 

Safe-mode: OFF (not secure)

/usr/src/linux-2.4.18-xfs-1.1/drivers/sound/dmasound/   drwxr-xr-x
Free 318.32 GB of 458.09 GB (69.49%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     tas3001c.c (9.66 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
 * Driver for the i2c/i2s based TA3001C sound chip used
 * on some Apple hardware. Also known as "tumbler".
 *
 *  This file is subject to the terms and conditions of the GNU General Public
 *  License.  See the file COPYING in the main directory of this archive
 *  for more details.
 *
 * Modified by Christopher C. Chimelis <chris@debian.org>:
 *
 *   TODO:
 *   -----
 *   * Enable DRC since the TiBook speakers are less than good
 *   * Enable control over input line 2 (is this connected?)
 *   * Play with the dual six-stage cascading biquad filtering to see how
 *     we can use it to our advantage (currently not implemented)
 *   * Reorganise driver a bit to make it cleaner and easier to work with
 *     (read: use the header file more :-P)
 *   * Implement sleep support
 *
 *   Version 0.4:
 *   ------------
 *   * Balance control finally works (can someone document OSS better please?)
 *   * Moved to a struct for common values referenced in the driver
 *   * Put stubs in for sleep/wake-up support for now.  This will take some
 *     experimentation to make sure that the timing is right, since the
 *     TAS hardware requires specific timing while enabling low-power mode.
 *     I may cheat for now and just reset the chip on wake-up, but I'd rather
 *     not if I don't have to.
 *
 *   Version 0.3:
 *   ------------
 *   * Fixed volume control
 *   * Added bass and treble control
 *   * Added PCM line level control (mixer 1 in the TAS manual)
 *
 */

#include <linux/version.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/ioport.h>
#include <linux/sysctl.h>
#include <linux/types.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/errno.h>
#include <asm/io.h>
#include <asm/prom.h>

#include "dmasound.h"
#include "tas3001c.h"

#define I2C_DRIVERID_TAS (0xFEBA)

#define TAS_VERSION    "0.3"
#define TAS_DATE    "20011214"

#define TAS_SETTING_MAX    100

#define VOL_DEFAULT    (((((TAS_SETTING_MAX*4)/5)<<0)<<8) | (((TAS_SETTING_MAX*4)/5)<<0))
#define INPUT_DEFAULT    (((TAS_SETTING_MAX*4)/5)<<0)
#define BASS_DEFAULT    ((TAS_SETTING_MAX/2)<<0)
#define TREBLE_DEFAULT    ((TAS_SETTING_MAX/2)<<0)

static struct i2c_client * tumbler_client = NULL;

int tumbler_enter_sleep(void);
int tumbler_leave_sleep(void);

static int tas_attach_adapter(struct i2c_adapter *adapter);
static int tas_detect_client(struct i2c_adapter *adapter, int address);
static int tas_detach_client(struct i2c_client *client);

/* Unique ID allocation */
static int tas_id;
static int tas_initialized;

static struct device_node* tas_node;
static u8 tas_i2c_address = 0x34;

struct tas_data_t {
    uint left_vol;        /* left volume */
    uint right_vol;        /* right volume */
    uint treble;        /* treble */
    uint bass;        /* bass */
    uint pcm_level;        /* pcm level */
};

struct i2c_driver tas_driver = {  
    name:        "TAS3001C driver  V 0.3",
    id:        I2C_DRIVERID_TAS,
    flags:        I2C_DF_NOTIFY,
    attach_adapter:    &tas_attach_adapter,
    detach_client:    &tas_detach_client,
    command:    NULL,
    inc_use:    NULL, /* &tas_inc_use, */
    dec_use:    NULL  /* &tas_dev_use  */
};

int
tumbler_get_volume(uint * left_vol, uint  *right_vol)
{
    struct tas_data_t *data;

    if (!tumbler_client)
        return -1;

    data = (struct tas_data_t *) (tumbler_client->data);
    *left_vol = data->left_vol;
    *right_vol = data->right_vol;
    
    return 0;
}

int
tumbler_set_register(uint reg, uint size, char *block)
{
    if (i2c_smbus_write_block_data(tumbler_client, reg, size, block) < 0) {
        printk("tas3001c: I2C write failed \n");  
        return -1; 
    }
    return 0;
}

int
tumbler_get_pcm_lvl(uint *pcm_lvl)
{
    struct tas_data_t *data;

    if (!tumbler_client)
        return -1;

    data = (struct tas_data_t *) (tumbler_client->data);
    *pcm_lvl = data->pcm_level;

    return 0;
}

int
tumbler_get_treble(uint *treble)
{
    struct tas_data_t *data;

    if (!tumbler_client)
        return -1;

    data = (struct tas_data_t *) (tumbler_client->data);
    *treble = data->treble;
    
    return 0;
}

int
tumbler_get_bass(uint *bass)
{
    struct tas_data_t *data;

    if (!tumbler_client)
        return -1;

    data = (struct tas_data_t *) (tumbler_client->data);
    *bass = data->bass;

    return 0;
}

int
tumbler_set_bass(uint bass)
{
    uint cur_bass_pers = bass;
    char block;
    struct tas_data_t *data;

    if (!tumbler_client)
        return -1;

    data = (struct tas_data_t *) (tumbler_client->data);

    bass &= 0xff;
    if (bass > TAS_SETTING_MAX)
        bass = TAS_SETTING_MAX;
    bass = ((bass * 72) / TAS_SETTING_MAX) << 0;
    bass = tas_bass_table[bass];
    block = (bass >> 0)  & 0xff;

    if (tumbler_set_register(TAS_SET_BASS, &block) < 0) {
        printk("tas3001c: failed to set bass \n");  
        return -1; 
    }
    data->bass = cur_bass_pers;
    return 0;
}

int
tumbler_set_treble(uint treble)
{
    uint cur_treble_pers = treble;
    char block;
    struct tas_data_t *data;

    if (!tumbler_client)
        return -1;

    data = (struct tas_data_t *) (tumbler_client->data);

    treble &= 0xff;
    if (treble > TAS_SETTING_MAX)
        treble = TAS_SETTING_MAX;
    treble = ((treble * 72) / TAS_SETTING_MAX) << 0;
    treble = tas_treble_table[treble];
    block = (treble >> 0)  & 0xff;

    if (tumbler_set_register(TAS_SET_TREBLE, &block) < 0) {
        printk("tas3001c: failed to set treble \n");  
        return -1; 
    }
    data->treble = cur_treble_pers;
    return 0;
}

int
tumbler_set_pcm_lvl(uint pcm_lvl)
{
    uint pcm_lvl_pers = pcm_lvl;
    unsigned char block[3];
    struct tas_data_t *data;

    if (!tumbler_client)
        return -1;

    data = (struct tas_data_t *) (tumbler_client->data);

    pcm_lvl &= 0xff;
    if (pcm_lvl > TAS_SETTING_MAX)
        pcm_lvl = TAS_SETTING_MAX;
    pcm_lvl = ((pcm_lvl * 176) / TAS_SETTING_MAX) << 0;

    pcm_lvl = tas_input_table[pcm_lvl];

    block[0] = (pcm_lvl >> 16) & 0xff;
    block[1] = (pcm_lvl >> 8)  & 0xff;
    block[2] = (pcm_lvl >> 0)  & 0xff;

    if (tumbler_set_register(TAS_SET_MIXER1, block) < 0) {
        printk("tas3001c: failed to set input level \n");  
        return -1; 
    }
    data->pcm_level = pcm_lvl_pers;

    return 0;
}

int
tumbler_set_volume(uint left_vol, uint right_vol)
{
    uint left_vol_pers = left_vol;
    uint right_vol_pers = right_vol;
    unsigned char block[6];
    struct tas_data_t *data;

    if (!tumbler_client)
        return -1;

    data = (struct tas_data_t *) (tumbler_client->data);

    left_vol &= 0xff;
    if (left_vol > TAS_SETTING_MAX)
        left_vol = TAS_SETTING_MAX;

    right_vol = (right_vol >> 8) & 0xff;
    if (right_vol > TAS_SETTING_MAX)
        right_vol = TAS_SETTING_MAX;

    left_vol = ((left_vol * 176) / TAS_SETTING_MAX) << 0;
    right_vol = ((right_vol * 176) / TAS_SETTING_MAX) << 0;

    left_vol = tas_volume_table[left_vol];
    right_vol = tas_volume_table[right_vol];

    block[0] = (left_vol >> 16) & 0xff;
    block[1] = (left_vol >> 8)  & 0xff;
    block[2] = (left_vol >> 0)  & 0xff;

    block[3] = (right_vol >> 16) & 0xff;
    block[4] = (right_vol >> 8)  & 0xff;
    block[5] = (right_vol >> 0)  & 0xff;

    if (tumbler_set_register(TAS_SET_VOLUME, block) < 0) {
        printk("tas3001c: failed to set volume \n");  
        return -1; 
    }
    data->left_vol = left_vol_pers;
    data->right_vol = right_vol_pers;

    return 0;
}

int
tumbler_leave_sleep(void)
{
    /* Stub for now, but I have the details on low-power mode */
    if (!tumbler_client)
        return -1;

    return 0;
}

int
tumbler_enter_sleep(void)
{
    /* Stub for now, but I have the details on low-power mode */
    if (!tumbler_client)
        return -1;

    return 0;
}

static int
tas_attach_adapter(struct i2c_adapter *adapter)
{
    if (!strncmp(adapter->name, "mac-io", 6))
        tas_detect_client(adapter, tas_i2c_address);

    return 0;
}

static int
tas_init_client(struct i2c_client * new_client)
{
    /* Make sure something answers on the i2c bus
    */

    if (i2c_smbus_write_byte_data(new_client, 1, (1<<6)+(2<<4)+(2<<2)+0) < 0)
        return -1;

    tumbler_client = new_client;

    tumbler_set_volume(VOL_DEFAULT, VOL_DEFAULT);
    tumbler_set_pcm_lvl(INPUT_DEFAULT);
    tumbler_set_bass(BASS_DEFAULT);
    tumbler_set_treble(TREBLE_DEFAULT);

    return 0;
}

static int
tas_detect_client(struct i2c_adapter *adapter, int address)
{
    int rc = 0;
    struct i2c_client *new_client;
    struct tas_data_t *data;
    const char *client_name = "tas 3001c Digital Equalizer";

    new_client = kmalloc(
                 sizeof(struct i2c_client) + sizeof(struct tas_data_t),
                 GFP_KERNEL);
    if (!new_client) {
        rc = -ENOMEM;
        goto bail;
    }

    /* This is tricky, but it will set the data to the right value. */
    new_client->data = new_client + 1;
    data = (struct tas_data_t *) (new_client->data);

    new_client->addr = address;
    new_client->data = data;
    new_client->adapter = adapter;
    new_client->driver = &tas_driver;
    new_client->flags = 0;

    strcpy(new_client->name,client_name);

    new_client->id = tas_id++; /* Automatically unique */

    if (tas_init_client(new_client)) {
        rc = -ENODEV;
        goto bail;
    }

    /* Tell the i2c layer a new client has arrived */
    if (i2c_attach_client(new_client)) {
        rc = -ENODEV;
        goto bail;
    }
bail:
    if (rc && new_client)
        kfree(new_client);
    return rc;
}

static int
tas_detach_client(struct i2c_client *client)
{
    if (client == tumbler_client)
        tumbler_client = NULL;

    i2c_detach_client(client);
    kfree(client);

    return 0;
}

int
tas_cleanup(void)
{
    if (!tas_initialized)
        return -ENODEV;
    i2c_del_driver(&tas_driver);
    tas_initialized = 0;

    return 0;
}

int
tas_init(void)
{
    int rc;
    u32* paddr;

    if (tas_initialized)
        return 0;

    tas_node = find_devices("deq");
    if (tas_node == NULL)
        return -ENODEV;

    printk(KERN_INFO "tas3001c driver version %s (%s)\n",TAS_VERSION,TAS_DATE);
    paddr = (u32 *)get_property(tas_node, "i2c-address", NULL);
    if (paddr) {
        tas_i2c_address = (*paddr) >> 1;
        printk(KERN_INFO "using i2c address: 0x%x from device-tree\n",
               tas_i2c_address);
    } else    
        printk(KERN_INFO "using i2c address: 0x%x (default)\n", tas_i2c_address);

    if ((rc = i2c_add_driver(&tas_driver))) {
        printk("tas3001c: Driver registration failed, module not inserted.\n");
        tas_cleanup();
        return rc;
    }
    tas_initialized = 1;
    return 0;
}

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0207 ]--