diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/misc')
33 files changed, 11149 insertions, 0 deletions
diff --git a/ANDROID_3.4.5/drivers/misc/Kconfig b/ANDROID_3.4.5/drivers/misc/Kconfig index 1a0254a1..cdd400f4 100644 --- a/ANDROID_3.4.5/drivers/misc/Kconfig +++ b/ANDROID_3.4.5/drivers/misc/Kconfig @@ -60,6 +60,13 @@ config ATMEL_PWM purposes including software controlled power-efficient backlights on LCD displays, motor control, and waveform generation. +config BCM2079X_NFC + tristate "bcm2079x NFC driver" + default m + ---help--- + Say yes if you want bcm2079x Near Field Communication driver. + This is for i2c connected version. If unsure, say N here. + config AB8500_PWM bool "AB8500 PWM support" depends on AB8500_CORE && ARCH_U8500 @@ -517,6 +524,19 @@ config WL127X_RFKILL ---help--- Creates an rfkill entry in sysfs for power control of Bluetooth TI wl127x chips. + +config PN547_NFC + tristate "PN547 NFC driver" + depends on I2C + select CRC_CCITT + default n + ---help--- + Say yes if you want PN547 Near Field Communication driver. + This is for i2c connected version. If unsure, say N here. + + To compile this driver as a module, choose m here. The module will + be called pn547. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" diff --git a/ANDROID_3.4.5/drivers/misc/Makefile b/ANDROID_3.4.5/drivers/misc/Makefile index 89540d14..f2e3c9ef 100644 --- a/ANDROID_3.4.5/drivers/misc/Makefile +++ b/ANDROID_3.4.5/drivers/misc/Makefile @@ -52,3 +52,11 @@ obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o obj-$(CONFIG_WL127X_RFKILL) += wl127x-rfkill.o obj-$(CONFIG_SENSORS_AK8975) += akm8975.o +obj-y += rsa/ +obj-y += viatel/ +obj-y += mediatek/ +wmt_pn547-objs += pn547.o +obj-$(CONFIG_PN547_NFC) += wmt_pn547.o + +s_wmt_nfc_bcm2079x-objs += bcm2079x-i2c.o +obj-$(CONFIG_BCM2079X_NFC) += s_wmt_nfc_bcm2079x.o
\ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/misc/bcm2079x-i2c.c b/ANDROID_3.4.5/drivers/misc/bcm2079x-i2c.c new file mode 100644 index 00000000..34f15cdf --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/bcm2079x-i2c.c @@ -0,0 +1,736 @@ +/* + * Copyright (C) 2012 Broadcom Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/i2c.h> +#include <linux/irq.h> +#include <linux/jiffies.h> +#include <linux/uaccess.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/miscdevice.h> +#include <linux/spinlock.h> +#include <linux/poll.h> +#include <linux/version.h> + +//Platform specific +#include <mach/gpio.h> +#include <mach/wmt_iomux.h> +#include <mach/hardware.h> +#include <mach/wmt_pmc.h> + +//#include <mach/sys_config.h> +//Platform specific +#include <linux/nfc/bcm2079x.h> + +#define USE_WAKE_LOCK + +#ifdef USE_WAKE_LOCK +#include <linux/wakelock.h> +#endif + +#define TRUE 1 +#define FALSE 0 +#define STATE_HIGH 1 +#define STATE_LOW 0 + +unsigned int enable; + + +/* end of compile options */ + +/* do not change below */ +#define MAX_BUFFER_SIZE 780 + + /* Read data */ +#define PACKET_HEADER_SIZE_NCI (4) +#define PACKET_HEADER_SIZE_HCI (3) +#define PACKET_TYPE_NCI (16) +#define PACKET_TYPE_HCIEV (4) +#define MAX_PACKET_SIZE (PACKET_HEADER_SIZE_NCI + 255) + +#define CLIENT_ADDR 0x77 +#define WMT_BCM2079X_I2C_CHANNEL 3 +struct i2c_client *bcm2079x_client; + + +struct bcm2079x_dev { + wait_queue_head_t read_wq; + struct mutex read_mutex; + struct i2c_client *client; + struct miscdevice bcm2079x_device; + unsigned int wake_gpio; + unsigned int en_gpio; + unsigned int irq_gpio; + unsigned int irq_no; + bool irq_enabled; + spinlock_t irq_enabled_lock; + unsigned int error_write; + unsigned int error_read; + unsigned int count_read; + unsigned int count_irq; + int original_address; +#ifdef USE_WAKE_LOCK + struct wake_lock wake_lock; +#endif +}; + +#define BCM2079X_NAME "bcm2079x-i2c" +#define VERSION "AMPAK-BCM2079X-DRIVER-VERSION-1.0.0" +unsigned int nfc_handle = -1; +unsigned int bcm2079x_irq_handle(void *para); + +/*hang on i2c bus no.3*/ +static __u32 twi_id = 3; + +static struct bcm2079x_platform_data bcm2079x_pdata = { + .irq_gpio = WMT_PIN_GP62_WAKEUP3,//GPIOG(11), //NFC_IRQ, GPIOG(11) + .irq_no = IRQ_PMC_WAKEUP, + .en_gpio = WMT_PIN_GP62_SUSGPIO0,//GPIOM(5), //NFC_EN, GPIOM(5) + .wake_gpio = WMT_PIN_GP1_GPIO9,//GPIOG(10), //NFC_FIRM, +}; + +int bcm2079x_detect(struct i2c_client *client, struct i2c_board_info *info) +{ + struct i2c_adapter *adapter = client->adapter; + + if(twi_id == adapter->nr) + { + dev_info(&client->dev, "%s: Detected chip %s at adapter %d, address 0x%02x\n",\ + __func__, BCM2079X_NAME, i2c_adapter_id(adapter), client->addr); + strlcpy(info->type, BCM2079X_NAME, I2C_NAME_SIZE); + info->platform_data = &bcm2079x_pdata; + return 0; + }else{ + return -ENODEV; + } +} + +static void bcm2079x_init_stat(struct bcm2079x_dev *bcm2079x_dev) +{ + bcm2079x_dev->error_write = 0; + bcm2079x_dev->error_read = 0; + bcm2079x_dev->count_read = 0; + bcm2079x_dev->count_irq = 0; +} + +static void bcm2079x_disable_irq(struct bcm2079x_dev *bcm2079x_dev) +{ + unsigned long flags; + + spin_lock_irqsave(&bcm2079x_dev->irq_enabled_lock, flags); + if (bcm2079x_dev->irq_enabled) { + pmc_disable_wakeup_isr(WKS_WK3);//disable_irq_nosync(bcm2079x_dev->client->irq); + bcm2079x_dev->irq_enabled = false; + } + spin_unlock_irqrestore(&bcm2079x_dev->irq_enabled_lock, flags); +} + +static void bcm2079x_enable_irq(struct bcm2079x_dev *bcm2079x_dev) +{ + unsigned long flags; + spin_lock_irqsave(&bcm2079x_dev->irq_enabled_lock, flags); + if (!bcm2079x_dev->irq_enabled) { + bcm2079x_dev->irq_enabled = true; + pmc_enable_wakeup_isr(WKS_WK3,3);//enable_irq(bcm2079x_dev->client->irq); + } + spin_unlock_irqrestore(&bcm2079x_dev->irq_enabled_lock, flags); +} + +/* + The alias address 0x79, when sent as a 7-bit address from the host processor + will match the first byte (highest 2 bits) of the default client address + (0x1FA) that is programmed in bcm20791. + When used together with the first byte (0xFA) of the byte sequence below, + it can be used to address the bcm20791 in a system that does not support + 10-bit address and change the default address to 0x38. + the new address can be changed by changing the CLIENT_ADDRESS below if 0x38 + conflicts with other device on the same i2c bus. + */ +#define ALIAS_ADDRESS 0x79 + +static void set_client_addr(struct bcm2079x_dev *bcm2079x_dev, int addr) +{ + struct i2c_client *client = bcm2079x_dev->client; + client->addr = addr; + if (addr > 0x7F) + client->flags |= I2C_CLIENT_TEN; + else + client->flags &= ~I2C_CLIENT_TEN; + + dev_info(&client->dev, + "Set client device changed to (0x%04X) flag = %04x\n", + client->addr, client->flags); +} + +static void change_client_addr(struct bcm2079x_dev *bcm2079x_dev, int addr) +{ + struct i2c_client *client; + int ret; + int i; + int offset = 1; + char addr_data[] = { + 0xFA, 0xF2, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x2A + }; + + client = bcm2079x_dev->client; + if ((client->flags & I2C_CLIENT_TEN) == I2C_CLIENT_TEN) { + client->addr = ALIAS_ADDRESS; + client->flags &= ~I2C_CLIENT_TEN; + offset = 0; + } + + addr_data[5] = addr & 0xFF; + ret = 0; + for (i = 1; i < sizeof(addr_data) - 1; ++i) + ret += addr_data[i]; + addr_data[sizeof(addr_data) - 1] = (ret & 0xFF); + dev_info(&client->dev, + "Change client device from (0x%04X) flag = "\ + "%04x, addr_data[%d] = %02x\n", + client->addr, client->flags, sizeof(addr_data) - 1, + addr_data[sizeof(addr_data) - 1]); + ret = i2c_master_send(client, addr_data+offset, sizeof(addr_data)-offset); + if (ret != sizeof(addr_data)-offset) { + client->addr = ALIAS_ADDRESS; + client->flags &= ~I2C_CLIENT_TEN; + dev_info(&client->dev, + "Change client device from (0x%04X) flag = "\ + "%04x, addr_data[%d] = %02x\n", + client->addr, client->flags, sizeof(addr_data) - 1, + addr_data[sizeof(addr_data) - 1]); + ret = i2c_master_send(client, addr_data, sizeof(addr_data)); + } + client->addr = addr_data[5]; + + dev_info(&client->dev, + "Change client device changed to (0x%04X) flag = %04x, ret = %d\n", + client->addr, client->flags, ret); +} + +static irqreturn_t bcm2079x_dev_irq_handler(int irq, void *dev_id) +{ + struct bcm2079x_dev *bcm2079x_dev = dev_id; + unsigned long flags; + //unsigned int status_i; + + //status_i = PMCIS_VAL; + + //rmb(); + if(bcm2079x_dev->client == bcm2079x_client){ + if(enable){ + #ifdef USE_WAKE_LOCK + int wakelockcnt = 0; + if(! (wakelockcnt = wake_lock_active(&bcm2079x_dev->wake_lock ))) + { + printk("irq aquire wake lock\n"); + wake_lock(&bcm2079x_dev->wake_lock); + }else + { + // printk("irq wake lock count = %d\n", wakelockcnt); + } + //printk("irq handler ( wake lock %d)...\n", wakelockcnt); + #endif + + spin_lock_irqsave(&bcm2079x_dev->irq_enabled_lock, flags); + bcm2079x_dev->count_irq++; + spin_unlock_irqrestore(&bcm2079x_dev->irq_enabled_lock, flags); + wake_up(&bcm2079x_dev->read_wq); + } + pmc_clear_intr_status(WKS_WK3); + return IRQ_HANDLED; + } + else + return IRQ_NONE; +} + +static unsigned int bcm2079x_dev_poll(struct file *filp, poll_table *wait) +{ + struct bcm2079x_dev *bcm2079x_dev = filp->private_data; + unsigned int mask = 0; + unsigned long flags; + + spin_lock_irqsave(&bcm2079x_dev->irq_enabled_lock, flags); + //if(!gpio_get_value(bcm2079x_dev->irq_gpio) && (bcm2079x_dev->count_irq < 1) ) + //Platform specific API + if(!__gpio_get_value(bcm2079x_dev->irq_gpio) && (bcm2079x_dev->count_irq < 1) ) + { + spin_unlock_irqrestore(&bcm2079x_dev->irq_enabled_lock, flags); + printk("poll wait, irq count %d, irq_gpio %d\n", bcm2079x_dev->count_irq, bcm2079x_dev->irq_gpio ); + poll_wait(filp, &bcm2079x_dev->read_wq, wait); + }else + { + if (bcm2079x_dev->count_irq < 1) + bcm2079x_dev->count_irq = 1; + + spin_unlock_irqrestore(&bcm2079x_dev->irq_enabled_lock, flags); + printk("poll there is data to read!!! no wait any more.\n"); + return (POLLIN | POLLRDNORM); + } + + spin_lock_irqsave(&bcm2079x_dev->irq_enabled_lock, flags); + if (bcm2079x_dev->count_irq > 0) + mask |= POLLIN | POLLRDNORM; + spin_unlock_irqrestore(&bcm2079x_dev->irq_enabled_lock, flags); + + return mask; +} + +static ssize_t bcm2079x_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + struct bcm2079x_dev *bcm2079x_dev = filp->private_data; + unsigned char tmp[MAX_BUFFER_SIZE]; + int total, len, ret; + + total = 0; + len = 0; + + if (bcm2079x_dev->count_irq > 0) + bcm2079x_dev->count_irq--; + + bcm2079x_dev->count_read++; + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + mutex_lock(&bcm2079x_dev->read_mutex); + + /** Read the first 4 bytes to include the length of the NCI or HCI packet. + **/ + ret = i2c_master_recv(bcm2079x_dev->client, tmp, 4); + if (ret == 4) { + total = ret; + /** First byte is the packet type + **/ + switch(tmp[0]) { + case PACKET_TYPE_NCI: + len = tmp[PACKET_HEADER_SIZE_NCI-1]; + break; + + case PACKET_TYPE_HCIEV: + len = tmp[PACKET_HEADER_SIZE_HCI-1]; + if (len == 0) + total--; /*Since payload is 0, decrement total size (from 4 to 3) */ + else + len--; /*First byte of payload is in tmp[3] already */ + break; + + default: + len = 0; /*Unknown packet byte */ + break; + } /* switch*/ + + /** make sure full packet fits in the buffer + **/ + if (len > 0 && (len + total) <= count) { + /** read the remainder of the packet. + **/ + ret = i2c_master_recv(bcm2079x_dev->client, tmp+total, len); + if (ret == len) + total += len; + } /* if */ + } /* if */ + + mutex_unlock(&bcm2079x_dev->read_mutex); + + if (total > count || copy_to_user(buf, tmp, total)) { + dev_err(&bcm2079x_dev->client->dev, + "failed to copy to user space, total = %d\n", total); + total = -EFAULT; + bcm2079x_dev->error_read++; + } + + return total; +} + +static ssize_t bcm2079x_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + struct bcm2079x_dev *bcm2079x_dev = filp->private_data; + char tmp[MAX_BUFFER_SIZE]; + int ret; + + if (count > MAX_BUFFER_SIZE) { + dev_err(&bcm2079x_dev->client->dev, "out of memory\n"); + return -ENOMEM; + } + + if (copy_from_user(tmp, buf, count)) { + dev_err(&bcm2079x_dev->client->dev, + "failed to copy from user space\n"); + return -EFAULT; + } + + mutex_lock(&bcm2079x_dev->read_mutex); + /* Write data */ + + ret = i2c_master_send(bcm2079x_dev->client, tmp, count); + if (ret != count) { + if ((bcm2079x_dev->client->flags & I2C_CLIENT_TEN) != I2C_CLIENT_TEN && bcm2079x_dev->error_write == 0) { + set_client_addr(bcm2079x_dev, 0x1FA); + ret = i2c_master_send(bcm2079x_dev->client, tmp, count); + if (ret != count) + bcm2079x_dev->error_write++; + set_client_addr(bcm2079x_dev, bcm2079x_dev->original_address); + } else { + dev_err(&bcm2079x_dev->client->dev, + "failed to write %d\n", ret); + ret = -EIO; + bcm2079x_dev->error_write++; + } + } + mutex_unlock(&bcm2079x_dev->read_mutex); + + return ret; +} + +static int bcm2079x_dev_open(struct inode *inode, struct file *filp) +{ + int ret = 0; + + struct bcm2079x_dev *bcm2079x_dev = container_of(filp->private_data, + struct bcm2079x_dev, + bcm2079x_device); + filp->private_data = bcm2079x_dev; + bcm2079x_init_stat(bcm2079x_dev); + bcm2079x_enable_irq(bcm2079x_dev); + dev_info(&bcm2079x_dev->client->dev, + "device node major=%d, minor=%d\n", imajor(inode), iminor(inode)); + + return ret; +} + +static long bcm2079x_dev_unlocked_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct bcm2079x_dev *bcm2079x_dev = filp->private_data; + + switch (cmd) { + case BCMNFC_READ_FULL_PACKET: + break; + case BCMNFC_READ_MULTI_PACKETS: + break; + case BCMNFC_CHANGE_ADDR: + dev_info(&bcm2079x_dev->client->dev, + "%s, BCMNFC_CHANGE_ADDR (%x, %lx):\n", __func__, cmd, + arg); + change_client_addr(bcm2079x_dev, arg); + break; + case BCMNFC_POWER_CTL: + dev_info(&bcm2079x_dev->client->dev, + "%s, BCMNFC_POWER_CTL (%x, %lx):\n", __func__, cmd, + arg); + if (arg != 1) + set_client_addr(bcm2079x_dev, bcm2079x_dev->original_address); + //gpio_set_value(bcm2079x_dev->en_gpio, arg); + //Platform specific API + __gpio_set_value(bcm2079x_dev->en_gpio, arg); + enable = arg; + break; + case BCMNFC_WAKE_CTL: + dev_info(&bcm2079x_dev->client->dev, + "%s, BCMNFC_WAKE_CTL (%x, %lx):\n", __func__, cmd, + arg); +#ifdef USE_WAKE_LOCK + if(arg != 0) + { + while(wake_lock_active(&bcm2079x_dev->wake_lock )) + { + printk("release wake lock!!!\n"); + wake_unlock(&bcm2079x_dev->wake_lock); + } + //wake_lock_timeout(&bcm2079x_dev->wake_lock, HZ*2); + } +#endif + //gpio_set_value(bcm2079x_dev->wake_gpio, arg); + //Platform specific API + __gpio_set_value(bcm2079x_dev->wake_gpio, arg); + break; + default: + dev_err(&bcm2079x_dev->client->dev, + "%s, unknown cmd (%x, %lx)\n", __func__, cmd, arg); + return 0; + } + + return 0; +} + +static const struct file_operations bcm2079x_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .poll = bcm2079x_dev_poll, + .read = bcm2079x_dev_read, + .write = bcm2079x_dev_write, + .open = bcm2079x_dev_open, + .unlocked_ioctl = bcm2079x_dev_unlocked_ioctl +}; + +unsigned int bcm2079x_irq_handle(void *para) +{ + bcm2079x_dev_irq_handler(0, para); + return 0; +} + +static int bcm2079x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct bcm2079x_platform_data *platform_data; + struct bcm2079x_dev *bcm2079x_dev; + + platform_data = client->dev.platform_data; + /*Keep this DRIVER information*/ + dev_info(&client->dev, "Driver Version: %s\n", VERSION); + + dev_info(&client->dev, "%s, probing bcm2079x driver flags = %x\n", __func__, client->flags); + if (platform_data == NULL) { + dev_err(&client->dev, "nfc probe fail\n"); + return -ENODEV; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "need I2C_FUNC_I2C\n"); + return -ENODEV; + } + + ret = gpio_request(platform_data->irq_gpio, "nfc_int"); + if (ret) + //dev_err(&client->dev, "fail to request nfc_int\n"); + return -ENODEV; + + ret = gpio_request(platform_data->en_gpio, "nfc_ven"); + if (ret) + //dev_err(&client->dev, "fail to request nfc_ven\n"); + goto err_en; + + ret = gpio_request(platform_data->wake_gpio, "nfc_firm"); + if (ret) + //dev_err(&client->dev, "fail to request nfc_firm\n"); + goto err_firm; + + gpio_direction_output(platform_data->en_gpio, 0 ); + gpio_direction_output(platform_data->wake_gpio, 0); + //gpio_set_value(platform_data->en_gpio, 0); + //gpio_set_value(platform_data->wake_gpio, 0); + + //Platform specific API + __gpio_set_value(platform_data->en_gpio, 0); + __gpio_set_value(platform_data->wake_gpio, 0); + + gpio_direction_input(platform_data->irq_gpio ); + wmt_gpio_setpull(platform_data->irq_gpio, WMT_GPIO_PULL_DOWN); + + bcm2079x_dev = kzalloc(sizeof(*bcm2079x_dev), GFP_KERNEL); + if (bcm2079x_dev == NULL) { + dev_err(&client->dev, + "failed to allocate memory for module data\n"); + ret = -ENOMEM; + goto err_exit; + } + + //Platform specific API + client->irq = platform_data->irq_no;//__gpio_to_irq(platform_data->irq_gpio); + if (client->irq == -ENXIO) { + dev_err(&client->dev,"[bcm2079x]: get gpio irq fail.\n"); + goto err_exit; + } + + bcm2079x_dev->wake_gpio = platform_data->wake_gpio; + bcm2079x_dev->irq_gpio = platform_data->irq_gpio; + bcm2079x_dev->irq_no = platform_data->irq_no; + bcm2079x_dev->en_gpio = platform_data->en_gpio; + bcm2079x_dev->client = client; + + /* init mutex and queues */ + init_waitqueue_head(&bcm2079x_dev->read_wq); + mutex_init(&bcm2079x_dev->read_mutex); + spin_lock_init(&bcm2079x_dev->irq_enabled_lock); + + bcm2079x_dev->bcm2079x_device.minor = MISC_DYNAMIC_MINOR; + bcm2079x_dev->bcm2079x_device.name = "bcm2079x"; + bcm2079x_dev->bcm2079x_device.fops = &bcm2079x_dev_fops; + + ret = misc_register(&bcm2079x_dev->bcm2079x_device); + if (ret) { + dev_err(&client->dev, "misc_register failed\n"); + goto err_misc_register; + } + + dev_info(&client->dev, + "%s, saving address %d\n", + __func__, client->addr); + bcm2079x_dev->original_address = client->addr; + + /* request irq. the irq is set whenever the chip has data available + * for reading. it is cleared when all data has been read. + */ + dev_info(&client->dev, "requesting IRQ %d with IRQF_NO_SUSPEND\n", client->irq); + bcm2079x_dev->irq_enabled = true; + /* + ret = request_irq(client->irq, bcm2079x_dev_irq_handler, + IRQF_TRIGGER_RISING|IRQF_NO_SUSPEND, client->name, bcm2079x_dev); + if (ret) { + dev_err(&client->dev, "request_irq failed\n"); + goto err_request_irq_failed; + } + enable_irq_wake(client->irq); + + */ + //Platform specific API + nfc_handle = request_irq(bcm2079x_dev->irq_no, bcm2079x_dev_irq_handler,IRQF_NO_SUSPEND|IRQF_SHARED,BCM2079X_NAME, + bcm2079x_dev); + + if (nfc_handle) { + dev_err(&client->dev, "request_irq failed.\n"); + goto err_request_irq_failed; + } + + bcm2079x_disable_irq(bcm2079x_dev); + i2c_set_clientdata(client, bcm2079x_dev); + dev_info(&client->dev, + "%s, probing bcm2079x driver exited successfully\n", + __func__); + +#ifdef USE_WAKE_LOCK + wake_lock_init(&bcm2079x_dev->wake_lock , WAKE_LOCK_SUSPEND, "nfcwakelock" ); +#endif + return 0; + +err_request_irq_failed: + misc_deregister(&bcm2079x_dev->bcm2079x_device); +err_misc_register: + mutex_destroy(&bcm2079x_dev->read_mutex); + kfree(bcm2079x_dev); +err_exit: + gpio_free(platform_data->wake_gpio); +err_firm: + gpio_free(platform_data->en_gpio); +err_en: + gpio_free(platform_data->irq_gpio); + return ret; +} + +static int bcm2079x_remove(struct i2c_client *client) +{ + struct bcm2079x_dev *bcm2079x_dev; + + bcm2079x_dev = i2c_get_clientdata(client); + //free_irq(client->irq, bcm2079x_dev); + //Platform specific API + if (!nfc_handle) + free_irq(bcm2079x_dev->irq_no,bcm2079x_dev); + + misc_deregister(&bcm2079x_dev->bcm2079x_device); + mutex_destroy(&bcm2079x_dev->read_mutex); + gpio_free(bcm2079x_dev->irq_gpio); + gpio_free(bcm2079x_dev->en_gpio); + gpio_free(bcm2079x_dev->wake_gpio); + kfree(bcm2079x_dev); + + return 0; +} + +static const struct i2c_device_id bcm2079x_id[] = { + {"bcm2079x-i2c", 0}, + {} +}; + +/*******************************************************************/ +/* AP6493 */ +/*******************************************************************/ +static const unsigned short normal_i2c[] = {0x77, I2C_CLIENT_END}; +/*******************************************************************/ +/* AP6441 */ +/*******************************************************************/ +//static const unsigned short normal_i2c[] = {0x76, I2C_CLIENT_END}; + +static struct i2c_driver bcm2079x_driver = { + .class = I2C_CLASS_HWMON, + .id_table = bcm2079x_id, + .probe = bcm2079x_probe, + .remove = bcm2079x_remove, + .driver = { + .owner = THIS_MODULE, + .name = "bcm2079x-i2c", + }, + .address_list = normal_i2c, +}; + +/* + * module load/unload record keeping + */ + struct i2c_board_info wmt_bcm2079x_bi = { + .type = BCM2079X_NAME, + .flags = 0x00, + .addr = CLIENT_ADDR, + .platform_data = &bcm2079x_pdata, + .archdata = NULL, + .irq = IRQ_PMC_WAKEUP, + }; + +static int __init bcm2079x_dev_init(void) +{ + int r; + struct i2c_adapter *adapter; + + adapter = i2c_get_adapter(WMT_BCM2079X_I2C_CHANNEL); + if (adapter == NULL) { + printk("can not get i2c adapter, client address error"); + return -ENODEV; + } + + bcm2079x_client = i2c_new_device(adapter, &wmt_bcm2079x_bi); + if ( bcm2079x_client == NULL) { + printk("allocate i2c client failed"); + return -ENOMEM; + } + + i2c_put_adapter(adapter); + + r = i2c_add_driver(&bcm2079x_driver); + if (r) { + pr_err(BCM2079X_NAME ": driver registration failed\n"); + return r; + } + + return 0; + /*bcm2079x_driver.detect = bcm2079x_detect; + + return i2c_add_driver(&bcm2079x_driver);*/ +} +module_init(bcm2079x_dev_init); + +static void __exit bcm2079x_dev_exit(void) +{ + i2c_del_driver(&bcm2079x_driver); + i2c_unregister_device(bcm2079x_client); +} +module_exit(bcm2079x_dev_exit); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("NFC bcm2079x driver"); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/misc/mediatek/Kconfig b/ANDROID_3.4.5/drivers/misc/mediatek/Kconfig new file mode 100755 index 00000000..d882c767 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/mediatek/Kconfig @@ -0,0 +1,9 @@ +menuconfig MTK_WIRELESS_SOLUTION + bool "MTK wireless chip configuration" + help + "enable/disable and config MTK wireless solution" + +if MTK_WIRELESS_SOLUTION +source "drivers/misc/mediatek/combo_mt66xx/Kconfig" +source "drivers/misc/mediatek/mt6622/Kconfig" +endif diff --git a/ANDROID_3.4.5/drivers/misc/mediatek/Makefile b/ANDROID_3.4.5/drivers/misc/mediatek/Makefile new file mode 100755 index 00000000..d308cb1c --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/mediatek/Makefile @@ -0,0 +1,3 @@ +obj-y += combo_mt66xx/ +#obj-$(CONFIG_MTK_MT6622) += mt6622/ + diff --git a/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/Kconfig b/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/Kconfig new file mode 100755 index 00000000..148f0505 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/Kconfig @@ -0,0 +1,35 @@ +menuconfig MTK_COMBO_MT66XX + bool "MediaTek combo_mt66xx Config" + help + Config MTK combo chip mt6628&mt6620 + +if MTK_COMBO_MT66XX + +config MTK_COMBO_WMT + tristate "MediaTek Combo Chip wireless managment tool" + default y + help + MTK wireless managment tool for WIFI/BT/GPS/FM + +config MTK_COMBO_BT + tristate "MediaTek Combo Chip BT driver" + default y + #depends on MTK_COMBO_WMT + help + MTK BT /dev/stpbt driver for Bluedroid (mtk_stp_bt.ko) + +config MTK_COMBO_FM + tristate "MediaTek Combo Chip FM driver" + default y + #depends on MTK_COMBO_WMT + help + MTK FM /dev/fm driver + +config MTK_COMBO_GPS + tristate "MediaTek GPS Support" + default y + #depends on MTK_COMBO_WMT + help + MTK GPS /dev/gps driver (mtk_gps.ko) + +endif diff --git a/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/Makefile b/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/Makefile new file mode 100755 index 00000000..3ec2afb7 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/Makefile @@ -0,0 +1,39 @@ +# Copyright Statement: +# +# This software/firmware and related documentation ("MediaTek Software") are +# protected under relevant copyright laws. The information contained herein +# is confidential and proprietary to MediaTek Inc. and/or its licensors. +# Without the prior written permission of MediaTek inc. and/or its licensors, +# any reproduction, modification, use or disclosure of MediaTek Software, +# and information contained herein, in whole or in part, shall be strictly prohibited. +# +# MediaTek Inc. (C) 2010. All rights reserved. +# +# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES +# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") +# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON +# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. +# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE +# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR +# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH +# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES +# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES +# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK +# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR +# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND +# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, +# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, +# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO +# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +# +# The following software/firmware and/or related documentation ("MediaTek Software") +# have been modified by MediaTek Inc. All revisions are subject to any receiver's +# applicable license agreements with MediaTek Inc. + +obj-y += wmt/ +obj-y += fm/ +obj-y += bt/ +obj-y += gps/ + diff --git a/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/bt/Makefile b/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/bt/Makefile new file mode 100755 index 00000000..41612ef7 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/bt/Makefile @@ -0,0 +1,41 @@ +# Copyright Statement: +# +# This software/firmware and related documentation ("MediaTek Software") are +# protected under relevant copyright laws. The information contained herein +# is confidential and proprietary to MediaTek Inc. and/or its licensors. +# Without the prior written permission of MediaTek inc. and/or its licensors, +# any reproduction, modification, use or disclosure of MediaTek Software, +# and information contained herein, in whole or in part, shall be strictly prohibited. +# +# MediaTek Inc. (C) 2010. All rights reserved. +# +# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES +# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") +# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON +# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. +# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE +# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR +# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH +# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES +# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES +# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK +# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR +# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND +# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, +# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, +# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO +# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +# +# The following software/firmware and/or related documentation ("MediaTek Software") +# have been modified by MediaTek Inc. All revisions are subject to any receiver's +# applicable license agreements with MediaTek Inc. + + +# +# Makefile for the Linux Bluetooth HCI device drivers. +# + +obj-y += uhid/ + diff --git a/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/bt/uhid/Makefile b/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/bt/uhid/Makefile new file mode 100755 index 00000000..f2e00c9d --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/bt/uhid/Makefile @@ -0,0 +1,46 @@ +# Copyright Statement: +# +# This software/firmware and related documentation ("MediaTek Software") are +# protected under relevant copyright laws. The information contained herein +# is confidential and proprietary to MediaTek Inc. and/or its licensors. +# Without the prior written permission of MediaTek inc. and/or its licensors, +# any reproduction, modification, use or disclosure of MediaTek Software, +# and information contained herein, in whole or in part, shall be strictly prohibited. + +# MediaTek Inc. (C) 2010. All rights reserved. +# +# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES +# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") +# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON +# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. +# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE +# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR +# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH +# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES +# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES +# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK +# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR +# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND +# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, +# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, +# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO +# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +# +# The following software/firmware and/or related documentation ("MediaTek Software") +# have been modified by MediaTek Inc. All revisions are subject to any receiver's +# applicable license agreements with MediaTek Inc. + + +# +# Makefile for the Bluetooth UHID driver. +# +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. + +obj-y += bt_uhid.o + +# EOF diff --git a/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/fm/Makefile b/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/fm/Makefile new file mode 100755 index 00000000..11c3ca61 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/fm/Makefile @@ -0,0 +1,72 @@ +# Makefile generated by Mediatek +CONFIG_MTK_COMBO_FM:=m +#mt6628 fm +ccflags-y += -I$(src)/inc \ + -I$(src)/mt6628/inc \ + -I$(src)/../wmt/include \ + -I$(src)/../wmt/linux/include \ + -I$(src)/cust/mt6628 \ + -I$(src)/private/inc \ + -DMT6628_FM + +obj-$(CONFIG_MTK_COMBO_FM) += mtk_fm_drv.o + mtk_fm_drv-objs += core/fm_module.o \ + core/fm_main.o \ + core/fm_config.o \ + core/fm_rds_parser.o \ + core/fm_patch.o \ + core/fm_utils.o \ + core/fm_link.o \ + core/fm_eint.o \ + mt6628/pub/mt6628_fm_lib.o \ + mt6628/pub/mt6628_fm_rds.o \ + mt6628/pub/mt6628_fm_cmd.o \ + mt6628/pub/mt6628_fm_config.o +#mt6620 fm start + ccflags-y += -I$(src)/inc \ + -I$(src)/mt6620/inc \ + -I$(src)/../wmt/include \ + -I$(src)/../wmt/linux/include \ + -I$(src)/cust/mt6620 \ + -I$(src)/private/inc \ + -DMT6620_FM + + obj-$(CONFIG_MTK_COMBO_FM) += mtk_fm_drv.o + mtk_fm_drv-objs += core/fm_module.o \ + core/fm_main.o \ + core/fm_config.o \ + core/fm_rds_parser.o \ + core/fm_patch.o \ + core/fm_utils.o \ + core/fm_link.o \ + core/fm_eint.o \ + mt6620/pub/mt6620_fm_lib.o \ + mt6620/pub/mt6620_fm_rds.o \ + mt6620/pub/mt6620_fm_cmd.o \ + mt6620/pub/mt6620_fm_config.o + +# MT6626 FM driver +ifeq ($(CONFIG_MTK_COMBO_CHIP_MT6626), y) +FM_CHIP = mt6626 +FM_CHIP_PATH = $(FM_CHIP)/pub/$(FM_CHIP) +ccflags-y := -I$(src)/inc \ + -I$(src)/$(FM_CHIP)/inc \ + -I$(src)/cust/$(FM_CHIP) \ + -I$(src)/private/inc \ + -DMT6626_FM + +obj-$(CONFIG_MTK_COMBO_FM) += mtk_fm_drv.o +mtk_fm_drv-objs := core/fm_module.o \ + core/fm_main.o \ + core/fm_config.o \ + core/fm_patch.o \ + core/fm_rds_parser.o \ + core/fm_utils.o \ + core/fm_link.o \ + $(FM_CHIP_PATH)_fm_lib.o \ + $(FM_CHIP_PATH)_fm_rds.o \ + $(FM_CHIP_PATH)_fm_link.o \ + $(FM_CHIP_PATH)_fm_eint.o +endif + + diff --git a/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/fm/private/Makefile b/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/fm/private/Makefile new file mode 100755 index 00000000..1a8e7960 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/fm/private/Makefile @@ -0,0 +1,44 @@ +# Makefile generated by Mediatek + +# fm support +ifeq ($(MTK_FM_SUPPORT), yes) + +ifeq ($(CUSTOM_KERNEL_FM), mt6628) +PRIV_CHIP = mt6628 +PRIV_SRC_PATH = private/src/$(PRIV_CHIP) +PRIV_CONFIG = $(CONFIG_MTK_FM) + +ccflags-y := \ + -I$(src)/inc \ + -I$(src)/$(PRIV_SRC_PATH) \ + -I$(src)/../inc \ + -I$(src)/../cust/$(PRIV_CHIP) \ + -I$(src)/../../combo/common_mt6628/include \ + -I$(src)/../../combo/common_mt6628/linux/include + + +obj-$(PRIV_CONFIG) += mtk_fm_priv.o +mtk_fm_priv-objs := \ + src/$(PRIV_CHIP)/$(PRIV_CHIP)_fm_private.o +endif + +ifeq ($(CUSTOM_KERNEL_FM), mt6620) +PRIV_CHIP = mt6620 +PRIV_SRC_PATH = private/src/$(PRIV_CHIP) +PRIV_CONFIG = $(CONFIG_MTK_FM) + +ccflags-y := \ + -I$(src)/inc \ + -I$(src)/$(PRIV_SRC_PATH) \ + -I$(src)/../inc \ + -I$(src)/../cust/$(PRIV_CHIP) \ + -I$(src)/../../combo/common/include \ + -I$(src)/../../combo/common/linux/include + + +obj-$(PRIV_CONFIG) += mtk_fm_priv.o +mtk_fm_priv-objs := \ + src/$(PRIV_CHIP)/$(PRIV_CHIP)_fm_private.o +endif + +endif diff --git a/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/gps/Makefile b/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/gps/Makefile new file mode 100755 index 00000000..19d0d43a --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/gps/Makefile @@ -0,0 +1,50 @@ +# Copyright Statement: +# +# This software/firmware and related documentation ("MediaTek Software") are +# protected under relevant copyright laws. The information contained herein +# is confidential and proprietary to MediaTek Inc. and/or its licensors. +# Without the prior written permission of MediaTek inc. and/or its licensors, +# any reproduction, modification, use or disclosure of MediaTek Software, +# and information contained herein, in whole or in part, shall be strictly prohibited. + +# MediaTek Inc. (C) 2010. All rights reserved. +# +# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES +# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") +# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON +# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. +# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE +# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR +# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH +# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES +# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES +# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK +# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR +# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND +# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, +# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, +# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO +# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +# +# The following software/firmware and/or related documentation ("MediaTek Software") +# have been modified by MediaTek Inc. All revisions are subject to any receiver's +# applicable license agreements with MediaTek Inc. + + +# drivers/barcelona/gps/Makefile +# +# Makefile for the Barcelona GPS driver. +# +# Copyright (C) 2004,2005 TomTom BV <http://www.tomtom.com/> +# Author: Dimitry Andric <dimitry.andric@tomtom.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. + +obj-y += gps.o + + +# EOF diff --git a/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/wmt/Makefile b/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/wmt/Makefile new file mode 100755 index 00000000..64e0b362 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/mediatek/combo_mt66xx/wmt/Makefile @@ -0,0 +1,78 @@ +MTK_WCN_CMB_SDIO_EINT := y +CONFIG_MTK_COMBO_WMT:=m +CONFIG_MTK_COMBO_BT:=m +CONFIG_MTK_COMBO_GPS:=m + +ccflags-y += -I$(src)/linux/include -I$(src)/core/include -I$(src)/include -I$(src)/ +ccflags-y += -DWMT_PLAT_APEX=1 +ccflags-y += -DWMT_PLAT_ALPS=0 +ccflags-y += -DWMT_UART_RX_MODE_WORK=1 # 1. work thread 0. tasklet +ccflags-y += -DREMOVE_MK_NODE=1 +ifeq ($(strip $(MTK_WCN_CMB_SDIO_EINT)), y) +ccflags-y += -DMTK_CMB_SDIO_EINT +endif + +#stub to build-in +obj-y += platform/vendor/mtk_wcn_cmb_stub.o + +#Common SDIO driver for WIFI and STP(mtk_hif_sdio.ko) +obj-$(CONFIG_MTK_COMBO_WMT) += mtk_hif_sdio.o +mtk_hif_sdio-objs := linux/hif_sdio.o \ + linux/hif_sdio_chrdev.o \ + linux/osal.o + +ifeq ($(MTK_WCN_CMB_SDIO_EINT), y) +mtk_hif_sdio-objs += linux/hif_sdio_eint.o +endif + +# WMT/STP DRIVER(mtk_stp_wmt.ko) +obj-$(CONFIG_MTK_COMBO_WMT) += mtk_stp_wmt.o +mtk_stp_wmt-objs := core/wmt_core.o \ + core/wmt_ctrl.o \ + core/wmt_func.o \ + core/wmt_ic_6620.o \ + core/wmt_lib.o \ + core/wmt_conf.o \ + core/wmt_dbg.o \ + core/wmt_exp.o \ + core/wmt_ic_6628.o \ + linux/wmt_dev.o \ + linux/wmt_tm.o \ + platform/vendor/wmt_plat.o \ + platform/vendor/wmt_plat_stub.o \ + platform/vendor/mtk_wcn_cmb_hw.o \ + core/stp_exp.o \ + core/stp_core.o \ + core/psm_core.o \ + core/btm_core.o \ + linux/stp_dbg.o +ifeq ($(CONFIG_MTK_COMBO_WMT), m) +mtk_stp_wmt-objs += linux/osal.o +endif + +#WMT/STP use UART interface(mtk_stp_uart.ko) +obj-$(CONFIG_MTK_COMBO_WMT) += mtk_stp_uart.o +mtk_stp_uart-objs := linux/stp_uart.o + +#WMT/STP use SDIO interface(mtk_stp_sdio.ko) +obj-$(CONFIG_MTK_COMBO_WMT) += mtk_stp_sdio.o +mtk_stp_sdio-objs := linux/stp_sdio.o \ + +ifeq ($(CONFIG_MTK_COMBO_WMT), m) +mtk_stp_sdio-objs += linux/osal.o +endif + +#BT character device driver +obj-$(CONFIG_MTK_COMBO_BT) += mtk_stp_bt.o +mtk_stp_bt-objs := linux/stp_chrdev_bt.o + +#GPS character device driver +obj-$(CONFIG_MTK_COMBO_GPS) += mtk_stp_gps.o +mtk_stp_gps-objs := linux/stp_chrdev_gps.o + +#WIFI character device driver +obj-$(CONFIG_MTK_COMBO_WIFI) += mtk_wmt_wifi.o +mtk_wmt_wifi-objs := linux/wmt_chrdev_wifi.o + +#FM don't need such character device + diff --git a/ANDROID_3.4.5/drivers/misc/mediatek/dummy.c b/ANDROID_3.4.5/drivers/misc/mediatek/dummy.c new file mode 100755 index 00000000..e69de29b --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/mediatek/dummy.c diff --git a/ANDROID_3.4.5/drivers/misc/pn547.c b/ANDROID_3.4.5/drivers/misc/pn547.c new file mode 100755 index 00000000..ff819341 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/pn547.c @@ -0,0 +1,1180 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/i2c.h> +#include <linux/irq.h> +#include <linux/jiffies.h> +#include <linux/uaccess.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/miscdevice.h> +#include <linux/spinlock.h> +#include <linux/nfc/pn544.h> + +#include <mach/wmt_iomux.h> + +#include <mach/hardware.h> +//#include <plat/gpio-core.h> +//#include <plat/gpio-cfg.h> +//#include <plat/gpio-cfg-helpers.h> + + +#undef pr_err +#define pr_err printk +//#define pr_debug printk +//#define pr_warning printk + +#define DRIVER_DESC "NFC driver for PN544" + +#define CLIENT_ADDR 0x28 //0x2b mod 2014-7-10 +#define WMT_PN544_I2C_CHANNEL 0 + +struct i2c_client *pn544_client; +static int g_chip_nr = 7; + +#define MAX_BUFFER_SIZE 512 + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + +struct pn544_dev { + wait_queue_head_t read_wq; + struct mutex read_mutex; + struct i2c_client *client; + struct miscdevice pn544_device; + + + int ven_gpio; + int ven_active; + int ven_on_off; + + int firm_gpio; + int firm_active; + + int irq_gpio; + int irq_active; + + + bool irq_enabled; + spinlock_t irq_enabled_lock; +}; + +//**********************add 2014-7-16 +static int irq_gpio = 0; + +void wmt_clr_int(void) +{ + int num = irq_gpio; + + int reg_shift = 20; + if (num > /*11*/42) + { + return; + } + + if (num < 20) + { + REG32_VAL(__GPIO_BASE+0x0360) = 1<<num; + } + else + { + switch (num) + { + case WMT_PIN_GP5_VDOUT11: + REG32_VAL(__GPIO_BASE+0x0360) = 1<<reg_shift; + break; + case WMT_PIN_GP5_VDOUT12: + REG32_VAL(__GPIO_BASE+0x0360) = 1<<(reg_shift+1); + break; + case WMT_PIN_GP6_VDOUT18: + REG32_VAL(__GPIO_BASE+0x0360) = 1<<(reg_shift+2); + break; + case WMT_PIN_GP6_VDOUT19: + REG32_VAL(__GPIO_BASE+0x0360) = 1<<(reg_shift+3); + break; + case WMT_PIN_GP6_VDOUT20: + REG32_VAL(__GPIO_BASE+0x0360) = 1<<(reg_shift+4); + break; + case WMT_PIN_GP6_VDOUT21: + REG32_VAL(__GPIO_BASE+0x0360) = 1<<(reg_shift+5); + break; + + } + } + //gpio 0-19 vdout11 12 18:21 + //REG32_VAL(__GPIO_BASE+0x0360) = 1<<num; //interrupt status register ,1:active 0:inactive + // write 1:to clear +} + +void wmt_set_irqinput(void) +{ + int num = irq_gpio; + + if (num > /*19*/42) + return; + if (num < 20) + { + REG32_VAL(__GPIO_BASE+0x0040) |= (1<<num); //enable gpio + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<num); //set input + } + + //GPIO GP5 Enable Register for VDOUT[15:8] + //GPIO GP6 Enable Register for VDOUT[23:16] + + switch (num) //gpio 0-19 vdout11 12 18:21 -->gpio 31 32 38:41 + { + case WMT_PIN_GP5_VDOUT11: + REG32_VAL(__GPIO_BASE+0x0044) |= (1<<(num-20)); //enable gpio + REG32_VAL(__GPIO_BASE+0x0084) &= ~(1<<(num-20)); //set input + break; + case WMT_PIN_GP5_VDOUT12: + REG32_VAL(__GPIO_BASE+0x0044) |= (1<<(num-20)); //enable gpio + REG32_VAL(__GPIO_BASE+0x0084) &= ~(1<<(num-20)); //set input + break; + case WMT_PIN_GP6_VDOUT18: + REG32_VAL(__GPIO_BASE+0x0044) |= (1<<(num-20)); //enable gpio + REG32_VAL(__GPIO_BASE+0x0084) &= ~(1<<(num-20)); //set input + break; + case WMT_PIN_GP6_VDOUT19: + REG32_VAL(__GPIO_BASE+0x0044) |= (1<<(num-20)); //enable gpio + REG32_VAL(__GPIO_BASE+0x0084) &= ~(1<<(num-20)); //set input + break; + case WMT_PIN_GP6_VDOUT20: + REG32_VAL(__GPIO_BASE+0x0044) |= (1<<(num-20)); //enable gpio + REG32_VAL(__GPIO_BASE+0x0084) &= ~(1<<(num-20)); //set input + break; + case WMT_PIN_GP6_VDOUT21: + REG32_VAL(__GPIO_BASE+0x0044) |= (1<<(num-20)); //enable gpio + REG32_VAL(__GPIO_BASE+0x0084) &= ~(1<<(num-20)); //set input + break; + + } +} + +static void wmt_disable_irqinput(void) +{ + int num = irq_gpio; + + if (num > /*19*/42) + return; + if (num < 20) + { + REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<<num); //enable gpio + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<num); //set input + } + + //GPIO GP5 Enable Register for VDOUT[15:8] + //GPIO GP6 Enable Register for VDOUT[23:16] + + switch (num) //gpio 0-19 vdout11 12 18:21 -->gpio 31 32 38:41 + { + case WMT_PIN_GP5_VDOUT11: + REG32_VAL(__GPIO_BASE+0x0044) &= ~(1<<(num-20)); //disable gpio + REG32_VAL(__GPIO_BASE+0x0084) &= ~(1<<(num-20)); //set input + break; + case WMT_PIN_GP5_VDOUT12: + REG32_VAL(__GPIO_BASE+0x0044) &= ~(1<<(num-20)); //enable gpio + REG32_VAL(__GPIO_BASE+0x0084) &= ~(1<<(num-20)); //set input + break; + case WMT_PIN_GP6_VDOUT18: + REG32_VAL(__GPIO_BASE+0x0044) &= ~(1<<(num-20)); //enable gpio + REG32_VAL(__GPIO_BASE+0x0084) &= ~(1<<(num-20)); //set input + break; + case WMT_PIN_GP6_VDOUT19: + REG32_VAL(__GPIO_BASE+0x0044) &= ~(1<<(num-20)); //enable gpio + REG32_VAL(__GPIO_BASE+0x0084) &= ~(1<<(num-20)); //set input + break; + case WMT_PIN_GP6_VDOUT20: + REG32_VAL(__GPIO_BASE+0x0044) &= ~(1<<(num-20)); //enable gpio + REG32_VAL(__GPIO_BASE+0x0084) &= ~(1<<(num-20)); //set input + break; + case WMT_PIN_GP6_VDOUT21: + REG32_VAL(__GPIO_BASE+0x0044) &= ~(1<<(num-20)); //enable gpio + REG32_VAL(__GPIO_BASE+0x0084) &= ~(1<<(num-20)); //set input + break; + + } +} + +static void wmt_pullup(void) +{ + int num = irq_gpio; + + if(num >/*11*//*19*/42) + return; + if (num < 20) + { + REG32_VAL(__GPIO_BASE+0x04c0) |= (1<<num); //pull up! + REG32_VAL(__GPIO_BASE+0x0480) |= (1<<num); //enable pull up/down + } + switch (num) + { //vdout11 12 18:21-->gpio 31 32 38:41 + case WMT_PIN_GP5_VDOUT11: + REG32_VAL(__GPIO_BASE+0x04c4) |= (1<<(num-20)); //pull up! + REG32_VAL(__GPIO_BASE+0x0484) |= (1<<(num-20)); //enable pull up/down + break; + case WMT_PIN_GP5_VDOUT12: + REG32_VAL(__GPIO_BASE+0x04c4) |= (1<<(num-20)); //pull up! + REG32_VAL(__GPIO_BASE+0x0484) |= (1<<(num-20)); //enable pull up/down + break; + case WMT_PIN_GP6_VDOUT18: + REG32_VAL(__GPIO_BASE+0x04c4) |= (1<<(num-20)); //pull up! + REG32_VAL(__GPIO_BASE+0x0484) |= (1<<(num-20)); //enable pull up/down + break; + case WMT_PIN_GP6_VDOUT19: + REG32_VAL(__GPIO_BASE+0x04c4) |= (1<<(num-20)); //pull up! + REG32_VAL(__GPIO_BASE+0x0484) |= (1<<(num-20)); //enable pull up/down + break; + case WMT_PIN_GP6_VDOUT20: + REG32_VAL(__GPIO_BASE+0x04c4) |= (1<<(num-20)); //pull up! + REG32_VAL(__GPIO_BASE+0x0484) |= (1<<(num-20)); //enable pull up/down + break; + case WMT_PIN_GP6_VDOUT21: + REG32_VAL(__GPIO_BASE+0x04c4) |= (1<<(num-20)); //pull up! + REG32_VAL(__GPIO_BASE+0x0484) |= (1<<(num-20)); //enable pull up/down + break; + + } +} + +int wmt_set_gpirq(int type) +{ + int shift; + int offset; + unsigned long reg; + int num = irq_gpio; + + if(num >/*11*//*19*/42) + return -1; + //if (num > 9) + //GPIO_PIN_SHARING_SEL_4BYTE_VAL &= ~BIT4; // gpio10,11 as gpio +#if 0 + REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<<num); // gpio disable + REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<num); //set input +#endif + wmt_disable_irqinput();//replace 2014-8-22 +#if 0 + REG32_VAL(__GPIO_BASE+0x04c0) |= (1<<num); //pull up! + REG32_VAL(__GPIO_BASE+0x0480) |= (1<<num); //enable pull up/down +#endif + wmt_pullup();//replace 2014-8-22 + + //set gpio irq triger type + if(num < 4){//[0,3] + shift = num; + offset = 0x0300; + }else if(num >= 4 && num < 8){//[4,7] + shift = num-4; + offset = 0x0304; + }else if (num >= 8 && num <12){// [8,11] + shift = num-8; + offset = 0x0308; + } + else if (num>=12 && num < 16) + { + shift = num -12; + offset = 0x030c; + } + else if (num>=16 && num <20) + { + shift = num -16; + offset = 0x0310; + } + else ////vdout11 12 18:21-->gpio 31 32 38:41 + { // 0x0314----0x0319 + switch (num) + { + case WMT_PIN_GP5_VDOUT11: + shift = 0; + offset = 0x0314; + break; + case WMT_PIN_GP5_VDOUT12: + shift = 1; + offset = 0x0314; + break; + + case WMT_PIN_GP6_VDOUT18: + shift = 2; + offset = 0x0314; + break; + + case WMT_PIN_GP6_VDOUT19: + shift = 3; + offset = 0x0314; + break; + case WMT_PIN_GP6_VDOUT20: + shift = 0; + offset = 0x0318; + break; + + case WMT_PIN_GP6_VDOUT21: + + shift = 1; + offset = 0x0318; + break; + } + #if 0 + else if (num>=20 && num<24) //videoOut11 12 18 19 + { + shift = num -20; + offset = 0x0314; + } + else if (num>=24 && num<28) //videoOut20 21 + { + shift = num -24; + offset = 0x0318; + } + #endif + } + + reg = REG32_VAL(__GPIO_BASE + offset); + + switch(type){ + case IRQ_TYPE_LEVEL_LOW: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_LEVEL_HIGH: + reg &= ~(1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_FALLING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + case IRQ_TYPE_EDGE_RISING: + reg &= ~(1<<(shift*8+2)); + reg |= (1<<(shift*8+1)); + reg |= (1<<(shift*8)); + break; + default://both edge + reg |= (1<<(shift*8+2)); + reg &= ~(1<<(shift*8+1)); + reg &= ~(1<<(shift*8)); + break; + + } + //reg |= 1<<(shift*8+7);//enable interrupt + reg &= ~(1<<(shift*8+7)); //disable int + + REG32_VAL(__GPIO_BASE + offset) = reg; + wmt_clr_int(); //replace 2014-8-22 + //REG32_VAL(__GPIO_BASE+0x0360) = 1<<num; //clear interrupt status// 1 bit per int + msleep(5); + return 0; +} + +int wmt_enable_gpirq(void) +{ + int num = irq_gpio; + + if(num > /*11*/ /*19*/42) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) |= 1<<(num*8+7); //enable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) |= 1<<((num-4)*8+7); //enable interrupt + else if (num >= 8 && num < 12) + REG32_VAL(__GPIO_BASE+0x0308) |= 1<<((num-8)*8+7); //enable interrupt + else if (num >= 12 && num < 16) + REG32_VAL(__GPIO_BASE+0x030c) |= 1<<((num-12)*8+7); //enable interrupt + else if (num >= 16 && num < 20) + REG32_VAL(__GPIO_BASE+0x0310) |= 1<<((num-16)*8+7); //enable interrupt + else ////vdout11 12 18:21-->gpio 31 32 38:41 + { // 0x0314----0x0319 + switch (num) + { + case WMT_PIN_GP5_VDOUT11: + REG32_VAL(__GPIO_BASE+0x0314) |= 1<<(0*8+7); //enable interrupt + + break; + case WMT_PIN_GP5_VDOUT12: + REG32_VAL(__GPIO_BASE+0x0314) |= 1<<(1*8+7); //enable interrupt + break; + + case WMT_PIN_GP6_VDOUT18: + REG32_VAL(__GPIO_BASE+0x0314) |= 1<<(2*8+7); //enable interrupt + break; + + case WMT_PIN_GP6_VDOUT19: + REG32_VAL(__GPIO_BASE+0x0314) |= 1<<(3*8+7); //enable interrupt + break; + case WMT_PIN_GP6_VDOUT20: + REG32_VAL(__GPIO_BASE+0x0318) |= 1<<(0*8+7); //enable interrupt + + break; + + case WMT_PIN_GP6_VDOUT21: + + REG32_VAL(__GPIO_BASE+0x0318) |= 1<<(1*8+7); //enable interrupt + break; + } + + } + + return 0; +} + +int wmt_disable_gpirq(void) +{ + int num = irq_gpio; + + if(num > /*11*//*19*/42) + return -1; + + if(num<4) + REG32_VAL(__GPIO_BASE+0x0300) &= ~(1<<(num*8+7)); //disable interrupt + else if(num >= 4 && num < 8) + REG32_VAL(__GPIO_BASE+0x0304) &= ~(1<<((num-4)*8+7)); //enable interrupt + else if (num >= 8 && num <12) + REG32_VAL(__GPIO_BASE+0x0308) &= ~(1<<((num-8)*8+7)); //enable interrupt + else if (num >= 12 && num <16) + REG32_VAL(__GPIO_BASE+0x030c) &= ~(1<<((num-8)*8+7)); //enable interrupt + else if (num >= 16 && num <20) + REG32_VAL(__GPIO_BASE+0x0310) &= ~(1<<((num-8)*8+7)); //enable interrupt + else ////vdout11 12 18:21-->gpio 31 32 38:41 + { // 0x0314----0x0319 + switch (num) + { + case WMT_PIN_GP5_VDOUT11: + REG32_VAL(__GPIO_BASE+0x0314) &= ~(1<<(0*8+7)); //enable interrupt + + break; + case WMT_PIN_GP5_VDOUT12: + REG32_VAL(__GPIO_BASE+0x0314) &= ~(1<<(1*8+7)); //enable interrupt + break; + + case WMT_PIN_GP6_VDOUT18: + REG32_VAL(__GPIO_BASE+0x0314) &= ~(1<<(2*8+7)); //enable interrupt + break; + + case WMT_PIN_GP6_VDOUT19: + REG32_VAL(__GPIO_BASE+0x0314) &= ~(1<<(3*8+7)); //enable interrupt + break; + case WMT_PIN_GP6_VDOUT20: + REG32_VAL(__GPIO_BASE+0x0318) &= ~(1<<(0*8+7)); //enable interrupt + + break; + + case WMT_PIN_GP6_VDOUT21: + + REG32_VAL(__GPIO_BASE+0x0318) &= ~(1<<(1*8+7)); //enable interrupt + break; + } + + } + + return 0; +} + +static int pn544_wmt_is_int(int num) +{ + if (num > 42) + { + return 0; + } + if (num < 20) + { + return REG32_VAL(__GPIO_BASE+0x0360) & (1<<num) ? 1 : 0; + } + else + { + switch (num) + { + case WMT_PIN_GP5_VDOUT11: + return REG32_VAL(__GPIO_BASE+0x0360) & (1<<20) ? 1 : 0; + break; + case WMT_PIN_GP5_VDOUT12: + return REG32_VAL(__GPIO_BASE+0x0360) & (1<<21) ? 1 : 0; + break; + case WMT_PIN_GP6_VDOUT18: + return REG32_VAL(__GPIO_BASE+0x0360) & (1<<22) ? 1 : 0; + break; + case WMT_PIN_GP6_VDOUT19: + return REG32_VAL(__GPIO_BASE+0x0360) & (1<<23) ? 1 : 0; + break; + case WMT_PIN_GP6_VDOUT20: + return REG32_VAL(__GPIO_BASE+0x0360) & (1<<24) ? 1 : 0; + break; + case WMT_PIN_GP6_VDOUT21: + return REG32_VAL(__GPIO_BASE+0x0360) & (1<<25) ? 1 : 0; + break; + + } + + } + //return (REG32_VAL(__GPIO_BASE+0x0360) & (1<<num)) ? 1: 0; +} +//*************add end + + +static void pn544_disable_irq(struct pn544_dev *pn544_dev) +{ + unsigned long flags; + + spin_lock_irqsave(&pn544_dev->irq_enabled_lock, flags); + if (pn544_dev->irq_enabled) { + wmt_disable_gpirq(); + //disable_irq_nosync(pn544_dev->client->irq); + pn544_dev->irq_enabled = false; + } + spin_unlock_irqrestore(&pn544_dev->irq_enabled_lock, flags); +} + +static irqreturn_t pn544_dev_irq_handler(int irq, void *dev_id) +{ + struct pn544_dev *pn544_dev = dev_id; + //printk("<<<<<<<%s!\n", __func__); +#if 0 + if (!gpio_get_value(pn544_dev->irq_gpio)) { + + return IRQ_NONE; + //return IRQ_HANDLED;//??? + } +#endif + if (pn544_wmt_is_int(pn544_dev->irq_gpio)) + { + wmt_clr_int(); + pn544_disable_irq(pn544_dev); + + //printk("<<<<<<<%s! wakeup reader!\n", __func__); + /* Wake up waiting readers */ + wake_up(&pn544_dev->read_wq); + return IRQ_HANDLED; + } + else + { + return IRQ_NONE; + } +} + +static ssize_t pn544_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_dev *pn544_dev = filp->private_data; + char tmp[MAX_BUFFER_SIZE]; + int ret,i; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + printk("%s : reading %zu bytes.\n", __func__, count); + + mutex_lock(&pn544_dev->read_mutex); + + printk("%s irq gpio %d val %d\n", __func__, pn544_dev->irq_gpio, gpio_get_value(pn544_dev->irq_gpio)); + if (/*!gpio_get_value(pn544_dev->irq_gpio)*/gpio_get_value(pn544_dev->irq_gpio)!=pn544_dev->irq_active) { + printk("%s &&& waitting for interrupt!\n", __func__); + if (filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto fail; + } + + while (1) { + pn544_dev->irq_enabled = true; + wmt_enable_gpirq(); + //enable_irq(pn544_dev->client->irq); + + printk("%s &&& enter waitting for interrupt!\n", __func__); + + ret = wait_event_interruptible( + pn544_dev->read_wq, + !pn544_dev->irq_enabled/*false??*/); + + /*ret = wait_event_interruptible(pn544_dev->read_wq, + gpio_get_value(pn544_dev->irq_gpio)); + */ + + pn544_disable_irq(pn544_dev); + + if (ret) + goto fail; + if (gpio_get_value(pn544_dev->irq_gpio)==pn544_dev->irq_active) + break; + + pr_warning("%s: spurious interrupt detected\n", __func__); + } + } + + /* Read data */ + ret = i2c_master_recv(pn544_dev->client, tmp, count); + mutex_unlock(&pn544_dev->read_mutex); + /* pn544 seems to be slow in handling I2C read requests + * so add 1ms delay after recv operation */ + udelay(1000); + + if (ret < 0) { + pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); + return ret; + } + if (ret > count) { + pr_err("%s: received too many bytes from i2c (%d)\n", + __func__, ret); + return -EIO; + } + if (copy_to_user(buf, tmp, ret)) { + pr_warning("%s : failed to copy to user space\n", __func__); + return -EFAULT; + } + + printk("IFD->PC:"); + for(i = 0; i < ret; i++){ + printk(" %02X", tmp[i]); + } + printk("\n"); + + return ret; + +fail: + printk("%s fail end! ret :%x\n", __func__, ret); + mutex_unlock(&pn544_dev->read_mutex); + return ret; +} + +static ssize_t pn544_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_dev *pn544_dev; + char tmp[MAX_BUFFER_SIZE]; + int ret,i; + + pn544_dev = filp->private_data; + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + if (copy_from_user(tmp, buf, count)) { + pr_err("%s : failed to copy from user space\n", __func__); + return -EFAULT; + } + + printk("%s : writing %zu bytes.\n", __func__, count); + /* Write data */ + ret = i2c_master_send(pn544_dev->client, tmp, count); + if (ret != count) { + pr_err("%s : i2c_master_send returned %d\n", __func__, ret); + ret = -EIO; + } + printk("PC->IFD:"); + for(i = 0; i < count; i++){ + printk(" %02X", tmp[i]); + } + /* pn544 seems to be slow in handling I2C write requests + * so add 1ms delay after I2C send oparation */ + udelay(1000); + + return ret; +} + +static int pn544_dev_open(struct inode *inode, struct file *filp) +{ + struct pn544_dev *pn544_dev = container_of(filp->private_data, + struct pn544_dev, + pn544_device); + + filp->private_data = pn544_dev; + + pr_debug("%s : %d,%d\n", __func__, imajor(inode), iminor(inode)); + + return 0; +} + +static /*int*/long pn544_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct pn544_dev *pn544_dev = filp->private_data; + + switch (cmd) { + case PN544_SET_PWR: + if (arg == 2) { + /* power on with firmware download (requires hw reset) + */ + printk("%s power on with firmware\n", __func__); + gpio_set_value(pn544_dev->ven_gpio, /*1*/pn544_dev->ven_active); + msleep(20); + if (pn544_dev->firm_gpio >= 0) + gpio_set_value(pn544_dev->firm_gpio, /*1*/pn544_dev->firm_active); + msleep(20); + gpio_set_value(pn544_dev->ven_gpio, /*0*/!pn544_dev->ven_active); + msleep(100); + gpio_set_value(pn544_dev->ven_gpio, /*1*/pn544_dev->ven_active); + msleep(20); + pn544_dev->ven_on_off = 1; + } else if (arg == 1) { + /* power on */ + printk("%s power on\n", __func__); + if (pn544_dev->firm_gpio >= 0) + gpio_set_value(pn544_dev->firm_gpio, /*0*/!pn544_dev->firm_active); + gpio_set_value(pn544_dev->ven_gpio, /*1*/pn544_dev->ven_active); + msleep(100); + pn544_dev->ven_on_off = 1; + } else if (arg == 0) { + /* power off */ + printk("%s power off ven %d \n", __func__, !pn544_dev->ven_active); + if (pn544_dev->firm_gpio >= 0) + gpio_set_value(pn544_dev->firm_gpio, /*0*/!pn544_dev->firm_active); + gpio_set_value(pn544_dev->ven_gpio, /*0*/!pn544_dev->ven_active); + + pn544_dev->ven_on_off = 0; + //gpio_set_value(pn544_dev->ven_gpio, 0); + msleep(100); + } else { + printk("%s bad arg %u\n", __func__, arg); + return -EINVAL; + } + break; + default: + printk("%s bad ioctl %u\n", __func__, cmd); + return -EINVAL; + } + + return 0; +} + +static const struct file_operations pn544_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = pn544_dev_read, + .write = pn544_dev_write, + .open = pn544_dev_open, + .unlocked_ioctl = pn544_dev_ioctl, +}; + + +static int pn544_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct pn544_nfc_platform_data *platform_data; + struct pn544_dev *pn544_dev; + + platform_data = client->dev.platform_data; + + if (platform_data == NULL) { + pr_err("%s : nfc probe fail\n", __func__); + return -ENODEV; + } + + printk("nfc probe step01 is ok\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s : need I2C_FUNC_I2C\n", __func__); + return -ENODEV; + } + + printk("nfc probe step02 is ok\n"); + + ret = gpio_request(platform_data->irq_gpio, "nfc_int"); + if (ret) + return -ENODEV; + + + + ret = gpio_request(platform_data->ven_gpio, "nfc_ven"); + if (ret) + goto err_ven; + + + if (platform_data->firm_gpio >= 0) + { + + ret = gpio_request(platform_data->firm_gpio, "nfc_firm"); + if (ret) + goto err_firm; + + } + + pn544_dev = kzalloc(sizeof(*pn544_dev), GFP_KERNEL); + if (pn544_dev == NULL) { + dev_err(&client->dev, + "failed to allocate memory for module data\n"); + ret = -ENOMEM; + goto err_exit; + } + + printk("nfc probe step04 is ok\n"); + + //pn544_dev->irq_enable = platform_data->irq_enable; + pn544_dev->irq_gpio = platform_data->irq_gpio; + pn544_dev->irq_active = platform_data->irq_active; + + //pn544_dev->ven_enable = platform_data->ven_enable; + pn544_dev->ven_gpio = platform_data->ven_gpio; + pn544_dev->ven_active = platform_data->ven_active; + pn544_dev->ven_on_off = 0; + //pn544_dev->firm_enable = platform_data->firm_enable; + pn544_dev->firm_gpio = platform_data->firm_gpio; + pn544_dev->firm_active = platform_data->firm_active; + + pn544_dev->client = client; + + irq_gpio = pn544_dev->irq_gpio; + /* init mutex and queues */ + init_waitqueue_head(&pn544_dev->read_wq); + mutex_init(&pn544_dev->read_mutex); + spin_lock_init(&pn544_dev->irq_enabled_lock); + + pn544_dev->pn544_device.minor = MISC_DYNAMIC_MINOR; + switch (g_chip_nr) + { + case 7: + pn544_dev->pn544_device.name = "pn547"; //"pn544" modify 2014-7-21 + break; + case 4: + pn544_dev->pn544_device.name = "pn544"; //"pn544" modify 2014-8-22 + break; + } + pn544_dev->pn544_device.fops = &pn544_dev_fops; + + ret = misc_register(&pn544_dev->pn544_device); + if (ret) { + pr_err("%s : misc_register failed\n", __FILE__); + goto err_misc_register; + } + printk("nfc probe step05 is ok\n"); + + /* request irq. the irq is set whenever the chip has data available + * for reading. it is cleared when all data has been read. + */ + + + gpio_direction_output(platform_data->ven_gpio,/*0*/ !platform_data->ven_active); + + if (platform_data->firm_gpio >= 0) + gpio_direction_output(platform_data->firm_gpio,/*0*/!platform_data->firm_active); + //s3c_gpio_setpull(platform_data->ven_gpio, S3C_GPIO_PULL_UP); + //s3c_gpio_setpull(platform_data->firm_gpio, S3C_GPIO_PULL_DOWN); + + //eint16 setting + + gpio_direction_input(platform_data->irq_gpio); + //wmt_gpio_setpull(platform_data->irq_gpio, WMT_GPIO_PULL_UP); + if (platform_data->irq_active) + { + printk("%s irq pull down!\n", __func__); + wmt_gpio_setpull(platform_data->irq_gpio, WMT_GPIO_PULL_DOWN); //modify 2014-7-16 + } + else + { + printk("%s irq pull up!\n", __func__); + wmt_gpio_setpull(platform_data->irq_gpio, WMT_GPIO_PULL_UP); + } + //s3c_gpio_setpull(platform_data->irq_gpio, S3C_GPIO_PULL_UP); + + + pr_info("%s : requesting IRQ %d\n", __func__, client->irq); + pn544_dev->irq_enabled = true; + + ret = request_irq(client->irq, pn544_dev_irq_handler, + /*platform_data->irq_active?IRQF_TRIGGER_HIGH:IRQF_TRIGGER_LOW*/IRQF_SHARED, \ + client->name, pn544_dev);//IRQF_TRIGGER_RISING IRQF_TRIGGER_HIGH + if (ret) { + printk(/*&client->dev, */"request_irq failed\n"); + goto err_request_irq_failed; + } + printk("nfc probe step06 is ok\n"); + //add 2014-7-16 for gpio irq config + wmt_set_irqinput(); + wmt_set_gpirq(platform_data->irq_active?IRQF_TRIGGER_HIGH:IRQF_TRIGGER_LOW); //IRQF_TRIGGER_HIGH + //wmt_enable_gpirq(); + //add end + + pn544_disable_irq(pn544_dev); + i2c_set_clientdata(client, pn544_dev); + + //add debug 2014-7-10 +#if 0 + printk("%s power on\n", __func__); + gpio_set_value(pn544_dev->firm_gpio, 0); + gpio_set_value(pn544_dev->ven_gpio, 1); + msleep(10); + + int maddr = 1; + char mbuf[2] = {0}; + for (maddr=1; maddr<0x7f; maddr++) + { + mbuf[0] = maddr; + /* Write data */ + //pn544_dev->client->addr = maddr; + ret = i2c_master_send(pn544_dev->client, mbuf, 1); + if (ret != 1) { + pr_err("%s : reg 0x%x i2c_master_send returned %d\n", __func__, maddr, ret); + //ret = -EIO; + } + else + { + pr_err("%s ok!!!: reg 0x%x i2c_master_send returned %d\n", __func__, maddr, ret); + //break; + } + + struct i2c_msg msg[2] = { + {.addr = client->addr, + .flags = 0|I2C_M_NOSTART, + .len = 1, + .buf = &mbuf[0], + }, + { .addr = client->addr, + .flags = I2C_M_RD, + .len = 1, + .buf = &mbuf[1], + }, + }; + + ret = i2c_transfer(client->adapter, msg, 2); + + //ret = i2c_master_recv(pn544_dev->client, mbuf, 1); + if (ret != 2) { + pr_err("%s : addr 0x%x i2c_master_recv %d returned %d\n", __func__, maddr, mbuf[1], ret); + //ret = -EIO; + } + else + { + pr_err("%s ok!!!: addr 0x%x i2c_master_recv %d returned %d\n", __func__, maddr, mbuf[1], ret); + //break; + } + + } +#endif + //add end + + printk("nfc probe step07 is ok\n"); + + return 0; + +err_request_irq_failed: + misc_deregister(&pn544_dev->pn544_device); +err_misc_register: + mutex_destroy(&pn544_dev->read_mutex); + kfree(pn544_dev); +err_exit: + if (platform_data->firm_gpio >= 0) + gpio_free(platform_data->firm_gpio); +err_firm: + + gpio_free(platform_data->ven_gpio); +err_ven: + + gpio_free(platform_data->irq_gpio); + return ret; +} + +static int pn544_remove(struct i2c_client *client) +{ + struct pn544_dev *pn544_dev; + + pn544_dev = i2c_get_clientdata(client); + free_irq(client->irq, pn544_dev); + misc_deregister(&pn544_dev->pn544_device); + mutex_destroy(&pn544_dev->read_mutex); + gpio_free(pn544_dev->irq_gpio); + gpio_free(pn544_dev->ven_gpio); + gpio_free(pn544_dev->firm_gpio); + kfree(pn544_dev); + + return 0; +} + +static const struct i2c_device_id pn544_id[] = { + { "pn544", 0 }, + { } +}; + +static int pn544_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct pn544_dev *pn544_dev; + + pn544_dev = i2c_get_clientdata(client); + printk("\n%s on_off %d\n", __func__, pn544_dev->ven_on_off); + return 0; +} + +static int pn544_resume(struct i2c_client *client) +{ + struct pn544_dev *pn544_dev; + + pn544_dev = i2c_get_clientdata(client); + + printk("%s on_off %d\n", __func__, pn544_dev->ven_on_off); + + gpio_direction_input(pn544_dev->irq_gpio); + //wmt_gpio_setpull(platform_data->irq_gpio, WMT_GPIO_PULL_UP); + if (pn544_dev->irq_active) + wmt_gpio_setpull(pn544_dev->irq_gpio, WMT_GPIO_PULL_DOWN); //modify 2014-7-16 + else + wmt_gpio_setpull(pn544_dev->irq_gpio, WMT_GPIO_PULL_UP); + + //add 2014-7-16 for gpio irq config + wmt_set_irqinput(); + wmt_set_gpirq(pn544_dev->irq_active?IRQF_TRIGGER_HIGH:IRQF_TRIGGER_LOW); //IRQF_TRIGGER_HIGH + //wmt_enable_gpirq(); + //add end + + pn544_disable_irq(pn544_dev); + + printk("%s active %d, !active %d\n", __func__, pn544_dev->ven_active, !pn544_dev->ven_active); + if (pn544_dev->ven_on_off) + gpio_set_value(pn544_dev->ven_gpio, pn544_dev->ven_active); + else + gpio_set_value(pn544_dev->ven_gpio, !pn544_dev->ven_active); + + //gpio_set_value(pn544_dev->ven_gpio, 0); + + return 0; +} +static struct i2c_driver pn544_driver = { + .id_table = pn544_id, + .probe = pn544_probe, + .remove = pn544_remove, + .suspend = pn544_suspend, + .resume = pn544_resume, + .driver = { + .owner = THIS_MODULE, + .name = "pn544", + }, +}; + +/* + * module load/unload record keeping + */ + +static struct pn544_nfc_platform_data pn544_pdata = { + //.irq_enable = 1, + .irq_gpio = WMT_PIN_GP0_GPIO0, + .irq_active = 1, + //.ven_enable = 1, + .ven_gpio= WMT_PIN_GP18_UART0RTS, // WMT_PIN_GP18_UART0RTS WMT_PIN_GP0_GPIO1 + .ven_active = 1, + //.firm_enable = 1, + .firm_gpio=WMT_PIN_GP0_GPIO1, //WMT_PIN_GP0_GPIO2, + .firm_active = 1, +}; +static int g_i2c_adapter = 0; +static int g_i2c_addr = 0x28; +static int get_board_info(void) +{ + int ret; + char buf[100] = {0}; + int len = sizeof(buf); + + char *pbuf = "wmt.nfc.pn54x"; // wmt.nfc.pn547 + printk("%s\n", __func__); + //wmt.nfc.pn54x 4:43:0:39:1:1:1:132:1 2b-->43 wmt.nfc.pn54x 4:43:0:39:1:1:0:132:1 + ret = wmt_getsyspara(pbuf, buf, &len); + if (!ret) + { + printk("%s %s:%s\n", __func__, pbuf, buf);//irq ven firm + + ret = sscanf(buf, "%d:%d:%d:%d:%d:%d:%d:%d:%d", \ + &g_chip_nr, &g_i2c_addr, &g_i2c_adapter, \ + &pn544_pdata.irq_gpio, &pn544_pdata.irq_active, \ + &pn544_pdata.ven_gpio, &pn544_pdata.ven_active, \ + &pn544_pdata.firm_gpio, &pn544_pdata.firm_active); + + printk("chip nr %d,i2c addr %d adapter %d, irq gpio %d active %d, ven %d %d, firm %d %d\n", \ + g_chip_nr, g_i2c_addr, g_i2c_adapter, \ + pn544_pdata.irq_gpio, pn544_pdata.irq_active, \ + pn544_pdata.ven_gpio, pn544_pdata.ven_active, \ + pn544_pdata.firm_gpio, pn544_pdata.firm_active); + + return 0; + } + else + { + printk("%s not get %s, use default\n", __func__, pbuf); + return -1; + } + + return 0; +} + +static int __init pn544_dev_init(void) +{ + //pr_info("Loading pn544 driver\n"); + + int r; + struct i2c_adapter *adapter; + + + + struct i2c_board_info wmt_pn544_bi = { + .type = PN544_DRIVER_NAME, + .flags = 0x00, + .addr = CLIENT_ADDR, + .platform_data = &pn544_pdata, //custom 2014-7-25 + .archdata = NULL, + .irq = IRQ_GPIO, + }; + //wmt_pn544_bi.addr = g_i2c_addr; + + pr_debug(DRIVER_DESC ": %s\n", __func__); + r = get_board_info(); + if (r < 0) + { + printk("%s no env!!\n", __func__); + return r; + } + wmt_pn544_bi.addr = g_i2c_addr; + adapter = i2c_get_adapter(/*WMT_PN544_I2C_CHANNEL*/g_i2c_adapter); + if (adapter == NULL) { + printk("can not get i2c adapter, client address error"); + return -ENODEV; + } + + pn544_client = i2c_new_device(adapter, &wmt_pn544_bi); + if ( pn544_client == NULL) { + printk("allocate i2c client failed"); + return -ENOMEM; + } + + i2c_put_adapter(adapter); + + r = i2c_add_driver(&pn544_driver); + if (r) { + pr_err(PN544_DRIVER_NAME ": driver registration failed\n"); + return r; + } + + return 0; + //return i2c_add_driver(&pn544_driver); +} +module_init(pn544_dev_init); + +static void __exit pn544_dev_exit(void) +{ + pr_info("Unloading pn544 driver\n"); + i2c_del_driver(&pn544_driver); + + i2c_unregister_device(pn544_client); +} +module_exit(pn544_dev_exit); + +MODULE_AUTHOR("Sylvain Fonteneau"); +MODULE_DESCRIPTION("NFC PN544 driver"); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/misc/rsa/Kconfig b/ANDROID_3.4.5/drivers/misc/rsa/Kconfig new file mode 100755 index 00000000..30039d81 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/rsa/Kconfig @@ -0,0 +1,6 @@ +menu "WMT RSA " +config WMT_RSA + tristate "RSA" + help + This enables the RSA decode/encode +endmenu diff --git a/ANDROID_3.4.5/drivers/misc/rsa/Makefile b/ANDROID_3.4.5/drivers/misc/rsa/Makefile new file mode 100755 index 00000000..be017d93 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/rsa/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for rsa drivers. +# + +#obj-$(CONFIG_WMT_RSA) += bignum.o rsa_verify.o + +obj-y += bignum.o rsa_verify.o + diff --git a/ANDROID_3.4.5/drivers/misc/rsa/asn1.h b/ANDROID_3.4.5/drivers/misc/rsa/asn1.h new file mode 100755 index 00000000..20ced912 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/rsa/asn1.h @@ -0,0 +1,244 @@ +/** + * \file asn1.h + * + * \brief Generic ASN.1 parsing + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org> + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_ASN1_H +#define POLARSSL_ASN1_H + +//#include "config.h" + +//#if defined(POLARSSL_BIGNUM_C) +#include "bignum.h" +//#endif + +//#include <string.h> + +/** + * \addtogroup asn1_module + * \{ + */ + +/** + * \name ASN1 Error codes + * These error codes are OR'ed to X509 error codes for + * higher error granularity. + * ASN1 is a standard to specify data structures. + * \{ + */ +#define POLARSSL_ERR_ASN1_OUT_OF_DATA -0x0014 /**< Out of data when parsing an ASN1 data structure. */ +#define POLARSSL_ERR_ASN1_UNEXPECTED_TAG -0x0016 /**< ASN1 tag was of an unexpected value. */ +#define POLARSSL_ERR_ASN1_INVALID_LENGTH -0x0018 /**< Error when trying to determine the length or invalid length. */ +#define POLARSSL_ERR_ASN1_LENGTH_MISMATCH -0x001A /**< Actual length differs from expected length. */ +#define POLARSSL_ERR_ASN1_INVALID_DATA -0x001C /**< Data is invalid. (not used) */ +#define POLARSSL_ERR_ASN1_MALLOC_FAILED -0x001E /**< Memory allocation failed */ +/* \} name */ + +/** + * \name DER constants + * These constants comply with DER encoded the ANS1 type tags. + * DER encoding uses hexadecimal representation. + * An example DER sequence is:\n + * - 0x02 -- tag indicating INTEGER + * - 0x01 -- length in octets + * - 0x05 -- value + * Such sequences are typically read into \c ::x509_buf. + * \{ + */ +#define ASN1_BOOLEAN 0x01 +#define ASN1_INTEGER 0x02 +#define ASN1_BIT_STRING 0x03 +#define ASN1_OCTET_STRING 0x04 +#define ASN1_NULL 0x05 +#define ASN1_OID 0x06 +#define ASN1_UTF8_STRING 0x0C +#define ASN1_SEQUENCE 0x10 +#define ASN1_SET 0x11 +#define ASN1_PRINTABLE_STRING 0x13 +#define ASN1_T61_STRING 0x14 +#define ASN1_IA5_STRING 0x16 +#define ASN1_UTC_TIME 0x17 +#define ASN1_GENERALIZED_TIME 0x18 +#define ASN1_UNIVERSAL_STRING 0x1C +#define ASN1_BMP_STRING 0x1E +#define ASN1_PRIMITIVE 0x00 +#define ASN1_CONSTRUCTED 0x20 +#define ASN1_CONTEXT_SPECIFIC 0x80 +/* \} name */ +/* \} addtogroup asn1_module */ + +/** Returns the size of the binary string, without the trailing \\0 */ +#define OID_SIZE(x) (sizeof(x) - 1) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name Functions to parse ASN.1 data structures + * \{ + */ + +/** + * Type-length-value structure that allows for ASN1 using DER. + */ +typedef struct _asn1_buf +{ + int tag; /**< ASN1 type, e.g. ASN1_UTF8_STRING. */ + size_t len; /**< ASN1 length, e.g. in octets. */ + unsigned char *p; /**< ASN1 data, e.g. in ASCII. */ +} +asn1_buf; + +/** + * Container for ASN1 bit strings. + */ +typedef struct _asn1_bitstring +{ + size_t len; /**< ASN1 length, e.g. in octets. */ + unsigned char unused_bits; /**< Number of unused bits at the end of the string */ + unsigned char *p; /**< Raw ASN1 data for the bit string */ +} +asn1_bitstring; + +/** + * Container for a sequence of ASN.1 items + */ +typedef struct _asn1_sequence +{ + asn1_buf buf; /**< Buffer containing the given ASN.1 item. */ + struct _asn1_sequence *next; /**< The next entry in the sequence. */ +} +asn1_sequence; + +/** + * Get the length of an ASN.1 element. + * Updates the pointer to immediately behind the length. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param len The variable that will receive the value + * + * \return 0 if successful, POLARSSL_ERR_ASN1_OUT_OF_DATA on reaching + * end of data, POLARSSL_ERR_ASN1_INVALID_LENGTH if length is + * unparseable. + */ +int asn1_get_len( unsigned char **p, + const unsigned char *end, + size_t *len ); + +/** + * Get the tag and length of the tag. Check for the requested tag. + * Updates the pointer to immediately behind the tag and length. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param len The variable that will receive the length + * \param tag The expected tag + * + * \return 0 if successful, POLARSSL_ERR_ASN1_UNEXPECTED_TAG if tag did + * not match requested tag, or another specific ASN.1 error code. + */ +int asn1_get_tag( unsigned char **p, + const unsigned char *end, + size_t *len, int tag ); + +/** + * Retrieve a boolean ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param val The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int asn1_get_bool( unsigned char **p, + const unsigned char *end, + int *val ); + +/** + * Retrieve an integer ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param val The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int asn1_get_int( unsigned char **p, + const unsigned char *end, + int *val ); + +/** + * Retrieve a bitstring ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param bs The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int asn1_get_bitstring( unsigned char **p, const unsigned char *end, + asn1_bitstring *bs); + +/** + * Parses and splits an ASN.1 "SEQUENCE OF <tag>" + * Updated the pointer to immediately behind the full sequence tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param cur First variable in the chain to fill + * \param tag Type of sequence + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int asn1_get_sequence_of( unsigned char **p, + const unsigned char *end, + asn1_sequence *cur, + int tag); + +#if defined(POLARSSL_BIGNUM_C) +/** + * Retrieve a MPI value from an integer ASN.1 tag. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param X The MPI that will receive the value + * + * \return 0 if successful or a specific ASN.1 or MPI error code. + */ +int asn1_get_mpi( unsigned char **p, + const unsigned char *end, + mpi *X ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* asn1.h */ diff --git a/ANDROID_3.4.5/drivers/misc/rsa/base64.h b/ANDROID_3.4.5/drivers/misc/rsa/base64.h new file mode 100755 index 00000000..355116d7 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/rsa/base64.h @@ -0,0 +1,87 @@ +/** + * \file base64.h + * + * \brief RFC 1521 base64 encoding/decoding + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org> + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_BASE64_H +#define POLARSSL_BASE64_H + +//#include <string.h> + +#define POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL -0x002A /**< Output buffer too small. */ +#define POLARSSL_ERR_BASE64_INVALID_CHARACTER -0x002C /**< Invalid character in input. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encode a buffer into base64 format + * + * \param dst destination buffer + * \param dlen size of the buffer + * \param src source buffer + * \param slen amount of data to be encoded + * + * \return 0 if successful, or POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL. + * *dlen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with *dlen = 0 to obtain the + * required buffer size in *dlen + */ +int base64_encode( unsigned char *dst, size_t *dlen, + const unsigned char *src, size_t slen ); + +/** + * \brief Decode a base64-formatted buffer + * + * \param dst destination buffer + * \param dlen size of the buffer + * \param src source buffer + * \param slen amount of data to be decoded + * + * \return 0 if successful, POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL, or + * POLARSSL_ERR_BASE64_INVALID_DATA if the input data is not + * correct. *dlen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with *dlen = 0 to obtain the + * required buffer size in *dlen + */ +int base64_decode( unsigned char *dst, size_t *dlen, + const unsigned char *src, size_t slen ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int base64_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* base64.h */ diff --git a/ANDROID_3.4.5/drivers/misc/rsa/bignum.c b/ANDROID_3.4.5/drivers/misc/rsa/bignum.c new file mode 100755 index 00000000..01809e11 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/rsa/bignum.c @@ -0,0 +1,2132 @@ +/* + * Multi-precision integer library + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org> + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * This MPI implementation is based on: + * + * http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf + * http://www.stillhq.com/extracted/gnupg-api/mpi/ + * http://math.libtomcrypt.com/files/tommath.pdf + */ + +//#include "polarssl/config.h" + +#if 1 + +//#include "polarssl/bn_mul.h" +#include "bignum.h" +#include "dhm.h" +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/mutex.h> +#include <linux/backing-dev.h> +#include <linux/compat.h> +#include <linux/mount.h> +#include <linux/blkpg.h> + +#include <linux/vmalloc.h> +#include <asm/uaccess.h> + +#include <linux/types.h> +#include <linux/moduleparam.h> +#include <linux/delay.h> +#include <mach/hardware.h> + +#define ciL (sizeof(t_uint)) /* chars in limb */ +#define biL (ciL << 3) /* bits in limb */ +#define biH (ciL << 2) /* half limb size */ + +/* + * Convert between bits/chars and number of limbs + */ +#define BITS_TO_LIMBS(i) (((i) + biL - 1) / biL) +#define CHARS_TO_LIMBS(i) (((i) + ciL - 1) / ciL) + +/* + * Initialize one MPI + */ +void mpi_init( mpi *X ) +{ + if( X == NULL ) + return; + + X->s = 1; + X->n = 0; + X->p = NULL; +} + +/* + * Unallocate one MPI + */ +void mpi_free( mpi *X ) +{ + if( X == NULL ) + return; + + if( X->p != NULL ) + { + memset( X->p, 0, X->n * ciL ); + vfree( X->p ); + } + + X->s = 1; + X->n = 0; + X->p = NULL; +} + +/* + * Enlarge to the specified number of limbs + */ +int mpi_grow( mpi *X, size_t nblimbs ) +{ + t_uint *p; + + if( nblimbs > POLARSSL_MPI_MAX_LIMBS ) + return( POLARSSL_ERR_MPI_MALLOC_FAILED ); + + if( X->n < nblimbs ) + { + if( ( p = (t_uint *) vmalloc( nblimbs * ciL ) ) == NULL ) + return( POLARSSL_ERR_MPI_MALLOC_FAILED ); + + memset( p, 0, nblimbs * ciL ); + + if( X->p != NULL ) + { + memcpy( p, X->p, X->n * ciL ); + memset( X->p, 0, X->n * ciL ); + vfree( X->p ); + } + + X->n = nblimbs; + X->p = p; + } + + return( 0 ); +} + +/* + * Copy the contents of Y into X + */ +int mpi_copy( mpi *X, const mpi *Y ) +{ + int ret; + size_t i; + + if( X == Y ) + return( 0 ); + + for( i = Y->n - 1; i > 0; i-- ) + if( Y->p[i] != 0 ) + break; + i++; + + X->s = Y->s; + + MPI_CHK( mpi_grow( X, i ) ); + + memset( X->p, 0, X->n * ciL ); + memcpy( X->p, Y->p, i * ciL ); + +cleanup: + + return( ret ); +} + +/* + * Swap the contents of X and Y + */ +void mpi_swap( mpi *X, mpi *Y ) +{ + mpi T; + + memcpy( &T, X, sizeof( mpi ) ); + memcpy( X, Y, sizeof( mpi ) ); + memcpy( Y, &T, sizeof( mpi ) ); +} + +/* + * Set value from integer + */ +int mpi_lset( mpi *X, t_sint z ) +{ + int ret; + + MPI_CHK( mpi_grow( X, 1 ) ); + memset( X->p, 0, X->n * ciL ); + + X->p[0] = ( z < 0 ) ? -z : z; + X->s = ( z < 0 ) ? -1 : 1; + +cleanup: + + return( ret ); +} + +/* + * Get a specific bit + */ +int mpi_get_bit( mpi *X, size_t pos ) +{ + if( X->n * biL <= pos ) + return( 0 ); + + return ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01; +} + +/* + * Set a bit to a specific value of 0 or 1 + */ +int mpi_set_bit( mpi *X, size_t pos, unsigned char val ) +{ + int ret = 0; + size_t off = pos / biL; + size_t idx = pos % biL; + + if( val != 0 && val != 1 ) + return POLARSSL_ERR_MPI_BAD_INPUT_DATA; + + if( X->n * biL <= pos ) + { + if( val == 0 ) + return ( 0 ); + + MPI_CHK( mpi_grow( X, off + 1 ) ); + } + + X->p[off] = ( X->p[off] & ~( 0x01 << idx ) ) | ( val << idx ); + +cleanup: + + return( ret ); +} + +/* + * Return the number of least significant bits + */ +size_t mpi_lsb( const mpi *X ) +{ + size_t i, j, count = 0; + + for( i = 0; i < X->n; i++ ) + for( j = 0; j < biL; j++, count++ ) + if( ( ( X->p[i] >> j ) & 1 ) != 0 ) + return( count ); + + return( 0 ); +} + +/* + * Return the number of most significant bits + */ +size_t mpi_msb( const mpi *X ) +{ + size_t i, j; + + for( i = X->n - 1; i > 0; i-- ) + if( X->p[i] != 0 ) + break; + + for( j = biL; j > 0; j-- ) + if( ( ( X->p[i] >> ( j - 1 ) ) & 1 ) != 0 ) + break; + + return( ( i * biL ) + j ); +} + +/* + * Return the total size in bytes + */ +size_t mpi_size( const mpi *X ) +{ + return( ( mpi_msb( X ) + 7 ) >> 3 ); +} + +/* + * Convert an ASCII character to digit value + */ +static int mpi_get_digit( t_uint *d, int radix, char c ) +{ + *d = 255; + + if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30; + if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37; + if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57; + + if( *d >= (t_uint) radix ) + return( POLARSSL_ERR_MPI_INVALID_CHARACTER ); + + return( 0 ); +} + +/* + * Import from an ASCII string + */ +int mpi_read_string( mpi *X, int radix, const char *s ) +{ + int ret; + size_t i, j, slen, n; + t_uint d; + mpi T; + + if( radix < 2 || radix > 16 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + mpi_init( &T ); + + slen = strlen( s ); + + if( radix == 16 ) + { + n = BITS_TO_LIMBS( slen << 2 ); + + MPI_CHK( mpi_grow( X, n ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i = slen, j = 0; i > 0; i--, j++ ) + { + if( i == 1 && s[i - 1] == '-' ) + { + X->s = -1; + break; + } + + MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) ); + X->p[j / (2 * ciL)] |= d << ( (j % (2 * ciL)) << 2 ); + } + } + else + { + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i = 0; i < slen; i++ ) + { + if( i == 0 && s[i] == '-' ) + { + X->s = -1; + continue; + } + + MPI_CHK( mpi_get_digit( &d, radix, s[i] ) ); + MPI_CHK( mpi_mul_int( &T, X, radix ) ); + + if( X->s == 1 ) + { + MPI_CHK( mpi_add_int( X, &T, d ) ); + } + else + { + MPI_CHK( mpi_sub_int( X, &T, d ) ); + } + } + } + +cleanup: + + mpi_free( &T ); + + return( ret ); +} + +/* + * Helper to write the digits high-order first + */ +static int mpi_write_hlp( mpi *X, int radix, char **p ) +{ + int ret; + t_uint r; + + if( radix < 2 || radix > 16 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + MPI_CHK( mpi_mod_int( &r, X, radix ) ); + MPI_CHK( mpi_div_int( X, NULL, X, radix ) ); + + if( mpi_cmp_int( X, 0 ) != 0 ) + MPI_CHK( mpi_write_hlp( X, radix, p ) ); + + if( r < 10 ) + *(*p)++ = (char)( r + 0x30 ); + else + *(*p)++ = (char)( r + 0x37 ); + +cleanup: + + return( ret ); +} + +/* + * Export into an ASCII string + */ +int mpi_write_string( const mpi *X, int radix, char *s, size_t *slen ) +{ + int ret = 0; + size_t n; + char *p; + mpi T; + + if( radix < 2 || radix > 16 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + n = mpi_msb( X ); + if( radix >= 4 ) n >>= 1; + if( radix >= 16 ) n >>= 1; + n += 3; + + if( *slen < n ) + { + *slen = n; + return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL ); + } + + p = s; + mpi_init( &T ); + + if( X->s == -1 ) + *p++ = '-'; + + if( radix == 16 ) + { + int c; + size_t i, j, k; + + for( i = X->n, k = 0; i > 0; i-- ) + { + for( j = ciL; j > 0; j-- ) + { + c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF; + + if( c == 0 && k == 0 && ( i + j + 3 ) != 0 ) + continue; + + p += sprintf( p, "%02X", c ); + k = 1; + } + } + } + else + { + MPI_CHK( mpi_copy( &T, X ) ); + + if( T.s == -1 ) + T.s = 1; + + MPI_CHK( mpi_write_hlp( &T, radix, &p ) ); + } + + *p++ = '\0'; + *slen = p - s; + +cleanup: + + mpi_free( &T ); + + return( ret ); +} + +#if defined(POLARSSL_FS_IO) +/* + * Read X from an opened file + */ +int mpi_read_file( mpi *X, int radix, FILE *fin ) +{ + t_uint d; + size_t slen; + char *p; + /* + * Buffer should have space for (short) label and decimal formatted MPI, + * newline characters and '\0' + */ + char s[ POLARSSL_MPI_READ_BUFFER_SIZE ]; + + memset( s, 0, sizeof( s ) ); + if( fgets( s, sizeof( s ) - 1, fin ) == NULL ) + return( POLARSSL_ERR_MPI_FILE_IO_ERROR ); + + slen = strlen( s ); + if( slen == sizeof( s ) - 2 ) + return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL ); + + if( s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; } + if( s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; } + + p = s + slen; + while( --p >= s ) + if( mpi_get_digit( &d, radix, *p ) != 0 ) + break; + + return( mpi_read_string( X, radix, p + 1 ) ); +} + +/* + * Write X into an opened file (or stdout if fout == NULL) + */ +int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout ) +{ + int ret; + size_t n, slen, plen; + /* + * Buffer should have space for minus sign, hexified MPI and '\0' + */ + char s[ 2 * POLARSSL_MPI_MAX_SIZE + 2 ]; + + n = sizeof( s ); + memset( s, 0, n ); + n -= 2; + + MPI_CHK( mpi_write_string( X, radix, s, (size_t *) &n ) ); + + if( p == NULL ) p = ""; + + plen = strlen( p ); + slen = strlen( s ); + s[slen++] = '\r'; + s[slen++] = '\n'; + + if( fout != NULL ) + { + if( fwrite( p, 1, plen, fout ) != plen || + fwrite( s, 1, slen, fout ) != slen ) + return( POLARSSL_ERR_MPI_FILE_IO_ERROR ); + } + else + printf( "%s%s", p, s ); + +cleanup: + + return( ret ); +} +#endif /* POLARSSL_FS_IO */ + +/* + * Import X from unsigned binary data, big endian + */ +int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t i, j, n; + + for( n = 0; n < buflen; n++ ) + if( buf[n] != 0 ) + break; + + MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i = buflen, j = 0; i > n; i--, j++ ) + X->p[j / ciL] |= ((t_uint) buf[i - 1]) << ((j % ciL) << 3); + +cleanup: + + return( ret ); +} + +/* + * Export X into unsigned binary data, big endian + */ +int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen ) +{ + size_t i, j, n; + + n = mpi_size( X ); + + if( buflen < n ) + return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL ); + + memset( buf, 0, buflen ); + + for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- ) + buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) ); + + return( 0 ); +} + +/* + * Left-shift: X <<= count + */ +int mpi_shift_l( mpi *X, size_t count ) +{ + int ret; + size_t i, v0, t1; + t_uint r0 = 0, r1; + + v0 = count / (biL ); + t1 = count & (biL - 1); + + i = mpi_msb( X ) + count; + + if( X->n * biL < i ) + MPI_CHK( mpi_grow( X, BITS_TO_LIMBS( i ) ) ); + + ret = 0; + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = X->n; i > v0; i-- ) + X->p[i - 1] = X->p[i - v0 - 1]; + + for( ; i > 0; i-- ) + X->p[i - 1] = 0; + } + + /* + * shift by count % limb_size + */ + if( t1 > 0 ) + { + for( i = v0; i < X->n; i++ ) + { + r1 = X->p[i] >> (biL - t1); + X->p[i] <<= t1; + X->p[i] |= r0; + r0 = r1; + } + } + +cleanup: + + return( ret ); +} + +/* + * Right-shift: X >>= count + */ +int mpi_shift_r( mpi *X, size_t count ) +{ + size_t i, v0, v1; + t_uint r0 = 0, r1; + + v0 = count / biL; + v1 = count & (biL - 1); + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = 0; i < X->n - v0; i++ ) + X->p[i] = X->p[i + v0]; + + for( ; i < X->n; i++ ) + X->p[i] = 0; + } + + /* + * shift by count % limb_size + */ + if( v1 > 0 ) + { + for( i = X->n; i > 0; i-- ) + { + r1 = X->p[i - 1] << (biL - v1); + X->p[i - 1] >>= v1; + X->p[i - 1] |= r0; + r0 = r1; + } + } + + return( 0 ); +} + +/* + * Compare unsigned values + */ +int mpi_cmp_abs( const mpi *X, const mpi *Y ) +{ + size_t i, j; + + for( i = X->n; i > 0; i-- ) + if( X->p[i - 1] != 0 ) + break; + + for( j = Y->n; j > 0; j-- ) + if( Y->p[j - 1] != 0 ) + break; + + if( i == 0 && j == 0 ) + return( 0 ); + + if( i > j ) return( 1 ); + if( j > i ) return( -1 ); + + for( ; i > 0; i-- ) + { + if( X->p[i - 1] > Y->p[i - 1] ) return( 1 ); + if( X->p[i - 1] < Y->p[i - 1] ) return( -1 ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mpi_cmp_mpi( const mpi *X, const mpi *Y ) +{ + size_t i, j; + + for( i = X->n; i > 0; i-- ) + if( X->p[i - 1] != 0 ) + break; + + for( j = Y->n; j > 0; j-- ) + if( Y->p[j - 1] != 0 ) + break; + + if( i == 0 && j == 0 ) + return( 0 ); + + if( i > j ) return( X->s ); + if( j > i ) return( -Y->s ); + + if( X->s > 0 && Y->s < 0 ) return( 1 ); + if( Y->s > 0 && X->s < 0 ) return( -1 ); + + for( ; i > 0; i-- ) + { + if( X->p[i - 1] > Y->p[i - 1] ) return( X->s ); + if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mpi_cmp_int( const mpi *X, t_sint z ) +{ + mpi Y; + t_uint p[1]; + + *p = ( z < 0 ) ? -z : z; + Y.s = ( z < 0 ) ? -1 : 1; + Y.n = 1; + Y.p = p; + + return( mpi_cmp_mpi( X, &Y ) ); +} + +/* + * Unsigned addition: X = |A| + |B| (HAC 14.7) + */ +int mpi_add_abs( mpi *X, const mpi *A, const mpi *B ) +{ + int ret; + size_t i, j; + t_uint *o, *p, c; + + if( X == B ) + { + const mpi *T = A; A = X; B = T; + } + + if( X != A ) + MPI_CHK( mpi_copy( X, A ) ); + + /* + * X should always be positive as a result of unsigned additions. + */ + X->s = 1; + + for( j = B->n; j > 0; j-- ) + if( B->p[j - 1] != 0 ) + break; + + MPI_CHK( mpi_grow( X, j ) ); + + o = B->p; p = X->p; c = 0; + + for( i = 0; i < j; i++, o++, p++ ) + { + *p += c; c = ( *p < c ); + *p += *o; c += ( *p < *o ); + } + + while( c != 0 ) + { + if( i >= X->n ) + { + MPI_CHK( mpi_grow( X, i + 1 ) ); + p = X->p + i; + } + + *p += c; c = ( *p < c ); i++; + } + +cleanup: + + return( ret ); +} + +/* + * Helper for mpi substraction + */ +static void mpi_sub_hlp( size_t n, t_uint *s, t_uint *d ) +{ + size_t i; + t_uint c, z; + + for( i = c = 0; i < n; i++, s++, d++ ) + { + z = ( *d < c ); *d -= c; + c = ( *d < *s ) + z; *d -= *s; + } + + while( c != 0 ) + { + z = ( *d < c ); *d -= c; + c = z; i++; d++; + } +} + +/* + * Unsigned substraction: X = |A| - |B| (HAC 14.9) + */ +int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B ) +{ + mpi TB; + int ret; + size_t n; + + if( mpi_cmp_abs( A, B ) < 0 ) + return( POLARSSL_ERR_MPI_NEGATIVE_VALUE ); + + mpi_init( &TB ); + + if( X == B ) + { + MPI_CHK( mpi_copy( &TB, B ) ); + B = &TB; + } + + if( X != A ) + MPI_CHK( mpi_copy( X, A ) ); + + /* + * X should always be positive as a result of unsigned substractions. + */ + X->s = 1; + + ret = 0; + + for( n = B->n; n > 0; n-- ) + if( B->p[n - 1] != 0 ) + break; + + mpi_sub_hlp( n, B->p, X->p ); + +cleanup: + + mpi_free( &TB ); + + return( ret ); +} + +/* + * Signed addition: X = A + B + */ +int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s < 0 ) + { + if( mpi_cmp_abs( A, B ) >= 0 ) + { + MPI_CHK( mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MPI_CHK( mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MPI_CHK( mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed substraction: X = A - B + */ +int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s > 0 ) + { + if( mpi_cmp_abs( A, B ) >= 0 ) + { + MPI_CHK( mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MPI_CHK( mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MPI_CHK( mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed addition: X = A + b + */ +int mpi_add_int( mpi *X, const mpi *A, t_sint b ) +{ + mpi _B; + t_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_add_mpi( X, A, &_B ) ); +} + +/* + * Signed substraction: X = A - b + */ +int mpi_sub_int( mpi *X, const mpi *A, t_sint b ) +{ + mpi _B; + t_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_sub_mpi( X, A, &_B ) ); +} + +/* + * Helper for mpi multiplication + */ +static void mpi_mul_hlp( size_t i, t_uint *s, t_uint *d, t_uint b ) +{ + t_uint c = 0, t = 0; + +#if defined(MULADDC_HUIT) + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_HUIT + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } +#else + for( ; i >= 16; i -= 16 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } +#endif + + t++; + + do { + *d += c; c = ( *d < c ); d++; + } + while( c != 0 ); +} +//mpi TA, TB; +/* + * Baseline multiplication: X = A * B (HAC 14.12) + */ +int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B ) +{ + int ret; + size_t i, j; + mpi TDA, TB; + + mpi_init( &TDA ); mpi_init( &TB ); + + if( X == A ) { MPI_CHK( mpi_copy( &TDA, A ) ); A = &TDA; } + if( X == B ) { MPI_CHK( mpi_copy( &TB, B ) ); B = &TB; } + + for( i = A->n; i > 0; i-- ) + if( A->p[i - 1] != 0 ) + break; + + for( j = B->n; j > 0; j-- ) + if( B->p[j - 1] != 0 ) + break; + + MPI_CHK( mpi_grow( X, i + j ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i++; j > 0; j-- ) + mpi_mul_hlp( i - 1, A->p, X->p + j - 1, B->p[j - 1] ); + + X->s = A->s * B->s; + +cleanup: + + mpi_free( &TB ); mpi_free( &TDA ); + + return( ret ); +} + +/* + * Baseline multiplication: X = A * b + */ +int mpi_mul_int( mpi *X, const mpi *A, t_sint b ) +{ + mpi _B; + t_uint p[1]; + + _B.s = 1; + _B.n = 1; + _B.p = p; + p[0] = b; + + return( mpi_mul_mpi( X, A, &_B ) ); +} + +/* + * Division by mpi: A = Q * B + R (HAC 14.20) + */ +int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B ) +{ + int ret; + size_t i, n, t, k; + mpi X, Y, Z, T1, T2; + + if( mpi_cmp_int( B, 0 ) == 0 ) + return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO ); + + mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z ); + mpi_init( &T1 ); mpi_init( &T2 ); + + if( mpi_cmp_abs( A, B ) < 0 ) + { + if( Q != NULL ) MPI_CHK( mpi_lset( Q, 0 ) ); + if( R != NULL ) MPI_CHK( mpi_copy( R, A ) ); + return( 0 ); + } + + MPI_CHK( mpi_copy( &X, A ) ); + MPI_CHK( mpi_copy( &Y, B ) ); + X.s = Y.s = 1; + + MPI_CHK( mpi_grow( &Z, A->n + 2 ) ); + MPI_CHK( mpi_lset( &Z, 0 ) ); + MPI_CHK( mpi_grow( &T1, 2 ) ); + MPI_CHK( mpi_grow( &T2, 3 ) ); + + k = mpi_msb( &Y ) % biL; + if( k < biL - 1 ) + { + k = biL - 1 - k; + MPI_CHK( mpi_shift_l( &X, k ) ); + MPI_CHK( mpi_shift_l( &Y, k ) ); + } + else k = 0; + + n = X.n - 1; + t = Y.n - 1; + mpi_shift_l( &Y, biL * (n - t) ); + + while( mpi_cmp_mpi( &X, &Y ) >= 0 ) + { + Z.p[n - t]++; + mpi_sub_mpi( &X, &X, &Y ); + } + mpi_shift_r( &Y, biL * (n - t) ); + + for( i = n; i > t ; i-- ) + { + if( X.p[i] >= Y.p[t] ) + Z.p[i - t - 1] = ~0; + else + { +#if defined(POLARSSL_HAVE_LONGLONG) + t_udbl r; + + r = (t_udbl) X.p[i] << biL; + r |= (t_udbl) X.p[i - 1]; + r /= Y.p[t]; + if( r > ((t_udbl) 1 << biL) - 1) + r = ((t_udbl) 1 << biL) - 1; + + Z.p[i - t - 1] = (t_uint) r; +#else + /* + * __udiv_qrnnd_c, from gmp/longlong.h + */ + t_uint q0, q1, r0, r1; + t_uint d0, d1, d, m; + + d = Y.p[t]; + d0 = ( d << biH ) >> biH; + d1 = ( d >> biH ); + + q1 = X.p[i] / d1; + r1 = X.p[i] - d1 * q1; + r1 <<= biH; + r1 |= ( X.p[i - 1] >> biH ); + + m = q1 * d0; + if( r1 < m ) + { + q1--, r1 += d; + while( r1 >= d && r1 < m ) + q1--, r1 += d; + } + r1 -= m; + + q0 = r1 / d1; + r0 = r1 - d1 * q0; + r0 <<= biH; + r0 |= ( X.p[i - 1] << biH ) >> biH; + + m = q0 * d0; + if( r0 < m ) + { + q0--, r0 += d; + while( r0 >= d && r0 < m ) + q0--, r0 += d; + } + r0 -= m; + + Z.p[i - t - 1] = ( q1 << biH ) | q0; +#endif + } + + Z.p[i - t - 1]++; + do + { + Z.p[i - t - 1]--; + + MPI_CHK( mpi_lset( &T1, 0 ) ); + T1.p[0] = (t < 1) ? 0 : Y.p[t - 1]; + T1.p[1] = Y.p[t]; + MPI_CHK( mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) ); + + MPI_CHK( mpi_lset( &T2, 0 ) ); + T2.p[0] = (i < 2) ? 0 : X.p[i - 2]; + T2.p[1] = (i < 1) ? 0 : X.p[i - 1]; + T2.p[2] = X.p[i]; + } + while( mpi_cmp_mpi( &T1, &T2 ) > 0 ); + + MPI_CHK( mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) ); + MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); + MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); + + if( mpi_cmp_int( &X, 0 ) < 0 ) + { + MPI_CHK( mpi_copy( &T1, &Y ) ); + MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); + MPI_CHK( mpi_add_mpi( &X, &X, &T1 ) ); + Z.p[i - t - 1]--; + } + } + + if( Q != NULL ) + { + mpi_copy( Q, &Z ); + Q->s = A->s * B->s; + } + + if( R != NULL ) + { + mpi_shift_r( &X, k ); + mpi_copy( R, &X ); + + R->s = A->s; + if( mpi_cmp_int( R, 0 ) == 0 ) + R->s = 1; + } + +cleanup: + + mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z ); + mpi_free( &T1 ); mpi_free( &T2 ); + + return( ret ); +} + +/* + * Division by int: A = Q * b + R + * + * Returns 0 if successful + * 1 if memory allocation failed + * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0 + */ +int mpi_div_int( mpi *Q, mpi *R, const mpi *A, t_sint b ) +{ + mpi _B; + t_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_div_mpi( Q, R, A, &_B ) ); +} + +/* + * Modulo: R = A mod B + */ +int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B ) +{ + int ret; + + if( mpi_cmp_int( B, 0 ) < 0 ) + return POLARSSL_ERR_MPI_NEGATIVE_VALUE; + + MPI_CHK( mpi_div_mpi( NULL, R, A, B ) ); + + while( mpi_cmp_int( R, 0 ) < 0 ) + MPI_CHK( mpi_add_mpi( R, R, B ) ); + + while( mpi_cmp_mpi( R, B ) >= 0 ) + MPI_CHK( mpi_sub_mpi( R, R, B ) ); + +cleanup: + + return( ret ); +} + +/* + * Modulo: r = A mod b + */ +int mpi_mod_int( t_uint *r, const mpi *A, t_sint b ) +{ + size_t i; + t_uint x, y, z; + + if( b == 0 ) + return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO ); + + if( b < 0 ) + return POLARSSL_ERR_MPI_NEGATIVE_VALUE; + + /* + * handle trivial cases + */ + if( b == 1 ) + { + *r = 0; + return( 0 ); + } + + if( b == 2 ) + { + *r = A->p[0] & 1; + return( 0 ); + } + + /* + * general case + */ + for( i = A->n, y = 0; i > 0; i-- ) + { + x = A->p[i - 1]; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + + x <<= biH; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + } + + /* + * If A is negative, then the current y represents a negative value. + * Flipping it to the positive side. + */ + if( A->s < 0 && y != 0 ) + y = b - y; + + *r = y; + + return( 0 ); +} + +/* + * Fast Montgomery initialization (thanks to Tom St Denis) + */ +static void mpi_montg_init( t_uint *mm, const mpi *N ) +{ + t_uint x, m0 = N->p[0]; + + x = m0; + x += ( ( m0 + 2 ) & 4 ) << 1; + x *= ( 2 - ( m0 * x ) ); + + if( biL >= 16 ) x *= ( 2 - ( m0 * x ) ); + if( biL >= 32 ) x *= ( 2 - ( m0 * x ) ); + if( biL >= 64 ) x *= ( 2 - ( m0 * x ) ); + + *mm = ~x + 1; +} + +/* + * Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36) + */ +static void mpi_montmul( mpi *A, const mpi *B, const mpi *N, t_uint mm, const mpi *T ) +{ + size_t i, n, m; + t_uint u0, u1, *d; + + memset( T->p, 0, T->n * ciL ); + + d = T->p; + n = N->n; + m = ( B->n < n ) ? B->n : n; + + for( i = 0; i < n; i++ ) + { + /* + * T = (T + u0*B + u1*N) / 2^biL + */ + u0 = A->p[i]; + u1 = ( d[0] + u0 * B->p[0] ) * mm; + + mpi_mul_hlp( m, B->p, d, u0 ); + mpi_mul_hlp( n, N->p, d, u1 ); + + *d++ = u0; d[n + 1] = 0; + } + + memcpy( A->p, d, (n + 1) * ciL ); + + if( mpi_cmp_abs( A, N ) >= 0 ) + mpi_sub_hlp( n, N->p, A->p ); + else + /* prevent timing attacks */ + mpi_sub_hlp( n, A->p, T->p ); +} + +/* + * Montgomery reduction: A = A * R^-1 mod N + */ +static void mpi_montred( mpi *A, const mpi *N, t_uint mm, const mpi *T ) +{ + t_uint z = 1; + mpi U; + + U.n = U.s = z; + U.p = &z; + + mpi_montmul( A, &U, N, mm, T ); +} + +/* + * Sliding-window exponentiation: X = A^E mod N (HAC 14.85) + */ +int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR ) +{ + int ret; + size_t wbits, wsize, one = 1; + size_t i, j, nblimbs; + size_t bufsize, nbits; + t_uint ei, mm, state; + mpi RR, T, W[ 2 << POLARSSL_MPI_WINDOW_SIZE ]; + + if( mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + /* + * Init temps and window size + */ + mpi_montg_init( &mm, N ); + mpi_init( &RR ); mpi_init( &T ); + memset( W, 0, sizeof( W ) ); + + i = mpi_msb( E ); + + wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 : + ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1; + + if( wsize > POLARSSL_MPI_WINDOW_SIZE ) + wsize = POLARSSL_MPI_WINDOW_SIZE; + + j = N->n + 1; + MPI_CHK( mpi_grow( X, j ) ); + MPI_CHK( mpi_grow( &W[1], j ) ); + MPI_CHK( mpi_grow( &T, j * 2 ) ); + + /* + * If 1st call, pre-compute R^2 mod N + */ + if( _RR == NULL || _RR->p == NULL ) + { + MPI_CHK( mpi_lset( &RR, 1 ) ); + MPI_CHK( mpi_shift_l( &RR, N->n * 2 * biL ) ); + MPI_CHK( mpi_mod_mpi( &RR, &RR, N ) ); + + if( _RR != NULL ) + memcpy( _RR, &RR, sizeof( mpi ) ); + } + else + memcpy( &RR, _RR, sizeof( mpi ) ); + + /* + * W[1] = A * R^2 * R^-1 mod N = A * R mod N + */ + if( mpi_cmp_mpi( A, N ) >= 0 ) + mpi_mod_mpi( &W[1], A, N ); + else mpi_copy( &W[1], A ); + + mpi_montmul( &W[1], &RR, N, mm, &T ); + + /* + * X = R^2 * R^-1 mod N = R mod N + */ + MPI_CHK( mpi_copy( X, &RR ) ); + mpi_montred( X, N, mm, &T ); + + if( wsize > 1 ) + { + /* + * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1) + */ + j = one << (wsize - 1); + + MPI_CHK( mpi_grow( &W[j], N->n + 1 ) ); + MPI_CHK( mpi_copy( &W[j], &W[1] ) ); + + for( i = 0; i < wsize - 1; i++ ) + mpi_montmul( &W[j], &W[j], N, mm, &T ); + + /* + * W[i] = W[i - 1] * W[1] + */ + for( i = j + 1; i < (one << wsize); i++ ) + { + MPI_CHK( mpi_grow( &W[i], N->n + 1 ) ); + MPI_CHK( mpi_copy( &W[i], &W[i - 1] ) ); + + mpi_montmul( &W[i], &W[1], N, mm, &T ); + } + } + + nblimbs = E->n; + bufsize = 0; + nbits = 0; + wbits = 0; + state = 0; + + while( 1 ) + { + if( bufsize == 0 ) + { + if( nblimbs-- == 0 ) + break; + + bufsize = sizeof( t_uint ) << 3; + } + + bufsize--; + + ei = (E->p[nblimbs] >> bufsize) & 1; + + /* + * skip leading 0s + */ + if( ei == 0 && state == 0 ) + continue; + + if( ei == 0 && state == 1 ) + { + /* + * out of window, square X + */ + mpi_montmul( X, X, N, mm, &T ); + continue; + } + + /* + * add ei to current window + */ + state = 2; + + nbits++; + wbits |= (ei << (wsize - nbits)); + + if( nbits == wsize ) + { + /* + * X = X^wsize R^-1 mod N + */ + for( i = 0; i < wsize; i++ ) + mpi_montmul( X, X, N, mm, &T ); + + /* + * X = X * W[wbits] R^-1 mod N + */ + mpi_montmul( X, &W[wbits], N, mm, &T ); + + state--; + nbits = 0; + wbits = 0; + } + } + + /* + * process the remaining bits + */ + for( i = 0; i < nbits; i++ ) + { + mpi_montmul( X, X, N, mm, &T ); + + wbits <<= 1; + + if( (wbits & (one << wsize)) != 0 ) + mpi_montmul( X, &W[1], N, mm, &T ); + } + + /* + * X = A^E * R * R^-1 mod N = A^E mod N + */ + mpi_montred( X, N, mm, &T ); + +cleanup: + + for( i = (one << (wsize - 1)); i < (one << wsize); i++ ) + mpi_free( &W[i] ); + + mpi_free( &W[1] ); mpi_free( &T ); + + if( _RR == NULL ) + mpi_free( &RR ); + + return( ret ); +} + +/* + * Greatest common divisor: G = gcd(A, B) (HAC 14.54) + */ +int mpi_gcd( mpi *G, const mpi *A, const mpi *B ) +{ + int ret; + size_t lz, lzt; + mpi TG, TDA, TB; + + mpi_init( &TG ); mpi_init( &TDA ); mpi_init( &TB ); + + MPI_CHK( mpi_copy( &TDA, A ) ); + MPI_CHK( mpi_copy( &TB, B ) ); + + lz = mpi_lsb( &TDA ); + lzt = mpi_lsb( &TB ); + + if ( lzt < lz ) + lz = lzt; + + MPI_CHK( mpi_shift_r( &TDA, lz ) ); + MPI_CHK( mpi_shift_r( &TB, lz ) ); + + TDA.s = TB.s = 1; + + while( mpi_cmp_int( &TDA, 0 ) != 0 ) + { + MPI_CHK( mpi_shift_r( &TDA, mpi_lsb( &TDA ) ) ); + MPI_CHK( mpi_shift_r( &TB, mpi_lsb( &TB ) ) ); + + if( mpi_cmp_mpi( &TDA, &TB ) >= 0 ) + { + MPI_CHK( mpi_sub_abs( &TDA, &TDA, &TB ) ); + MPI_CHK( mpi_shift_r( &TDA, 1 ) ); + } + else + { + MPI_CHK( mpi_sub_abs( &TB, &TB, &TDA ) ); + MPI_CHK( mpi_shift_r( &TB, 1 ) ); + } + } + + MPI_CHK( mpi_shift_l( &TB, lz ) ); + MPI_CHK( mpi_copy( G, &TB ) ); + +cleanup: + + mpi_free( &TG ); mpi_free( &TDA ); mpi_free( &TB ); + + return ret; +} + +int mpi_fill_random( mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + + MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( size ) ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + MPI_CHK( f_rng( p_rng, (unsigned char *) X->p, size ) ); + +cleanup: + return( ret ); +} + +#if defined(POLARSSL_GENPRIME) + +/* + * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64) + */ +int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N ) +{ + int ret; + mpi G, TDA, TU, U1, U2, TB, TV, V1, V2; + + if( mpi_cmp_int( N, 0 ) <= 0 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + mpi_init( &TDA ); mpi_init( &TU ); mpi_init( &U1 ); mpi_init( &U2 ); + mpi_init( &G ); mpi_init( &TB ); mpi_init( &TV ); + mpi_init( &V1 ); mpi_init( &V2 ); + + MPI_CHK( mpi_gcd( &G, A, N ) ); + + if( mpi_cmp_int( &G, 1 ) != 0 ) + { + ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE; + goto cleanup; + } + + MPI_CHK( mpi_mod_mpi( &TDA, A, N ) ); + MPI_CHK( mpi_copy( &TU, &TDA ) ); + MPI_CHK( mpi_copy( &TB, N ) ); + MPI_CHK( mpi_copy( &TV, N ) ); + + MPI_CHK( mpi_lset( &U1, 1 ) ); + MPI_CHK( mpi_lset( &U2, 0 ) ); + MPI_CHK( mpi_lset( &V1, 0 ) ); + MPI_CHK( mpi_lset( &V2, 1 ) ); + + do + { + while( ( TU.p[0] & 1 ) == 0 ) + { + MPI_CHK( mpi_shift_r( &TU, 1 ) ); + + if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 ) + { + MPI_CHK( mpi_add_mpi( &U1, &U1, &TB ) ); + MPI_CHK( mpi_sub_mpi( &U2, &U2, &TDA ) ); + } + + MPI_CHK( mpi_shift_r( &U1, 1 ) ); + MPI_CHK( mpi_shift_r( &U2, 1 ) ); + } + + while( ( TV.p[0] & 1 ) == 0 ) + { + MPI_CHK( mpi_shift_r( &TV, 1 ) ); + + if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 ) + { + MPI_CHK( mpi_add_mpi( &V1, &V1, &TB ) ); + MPI_CHK( mpi_sub_mpi( &V2, &V2, &TDA ) ); + } + + MPI_CHK( mpi_shift_r( &V1, 1 ) ); + MPI_CHK( mpi_shift_r( &V2, 1 ) ); + } + + if( mpi_cmp_mpi( &TU, &TV ) >= 0 ) + { + MPI_CHK( mpi_sub_mpi( &TU, &TU, &TV ) ); + MPI_CHK( mpi_sub_mpi( &U1, &U1, &V1 ) ); + MPI_CHK( mpi_sub_mpi( &U2, &U2, &V2 ) ); + } + else + { + MPI_CHK( mpi_sub_mpi( &TV, &TV, &TU ) ); + MPI_CHK( mpi_sub_mpi( &V1, &V1, &U1 ) ); + MPI_CHK( mpi_sub_mpi( &V2, &V2, &U2 ) ); + } + } + while( mpi_cmp_int( &TU, 0 ) != 0 ); + + while( mpi_cmp_int( &V1, 0 ) < 0 ) + MPI_CHK( mpi_add_mpi( &V1, &V1, N ) ); + + while( mpi_cmp_mpi( &V1, N ) >= 0 ) + MPI_CHK( mpi_sub_mpi( &V1, &V1, N ) ); + + MPI_CHK( mpi_copy( X, &V1 ) ); + +cleanup: + + mpi_free( &TDA ); mpi_free( &TU ); mpi_free( &U1 ); mpi_free( &U2 ); + mpi_free( &G ); mpi_free( &TB ); mpi_free( &TV ); + mpi_free( &V1 ); mpi_free( &V2 ); + + return( ret ); +} + +static const int small_prime[] = +{ + 3, 5, 7, 11, 13, 17, 19, 23, + 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773, + 787, 797, 809, 811, 821, 823, 827, 829, + 839, 853, 857, 859, 863, 877, 881, 883, + 887, 907, 911, 919, 929, 937, 941, 947, + 953, 967, 971, 977, 983, 991, 997, -103 +}; + +/* + * Miller-Rabin primality test (HAC 4.24) + */ +int mpi_is_prime( mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret, xs; + size_t i, j, n, s; + mpi W, R, T, A, RR; + + if( mpi_cmp_int( X, 0 ) == 0 || + mpi_cmp_int( X, 1 ) == 0 ) + return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); + + if( mpi_cmp_int( X, 2 ) == 0 ) + return( 0 ); + + mpi_init( &W ); mpi_init( &R ); mpi_init( &T ); mpi_init( &A ); + mpi_init( &RR ); + + xs = X->s; X->s = 1; + + /* + * test trivial factors first + */ + if( ( X->p[0] & 1 ) == 0 ) + return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); + + for( i = 0; small_prime[i] > 0; i++ ) + { + t_uint r; + + if( mpi_cmp_int( X, small_prime[i] ) <= 0 ) + return( 0 ); + + MPI_CHK( mpi_mod_int( &r, X, small_prime[i] ) ); + + if( r == 0 ) + return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); + } + + /* + * W = |X| - 1 + * R = W >> lsb( W ) + */ + MPI_CHK( mpi_sub_int( &W, X, 1 ) ); + s = mpi_lsb( &W ); + MPI_CHK( mpi_copy( &R, &W ) ); + MPI_CHK( mpi_shift_r( &R, s ) ); + + i = mpi_msb( X ); + /* + * HAC, table 4.4 + */ + n = ( ( i >= 1300 ) ? 2 : ( i >= 850 ) ? 3 : + ( i >= 650 ) ? 4 : ( i >= 350 ) ? 8 : + ( i >= 250 ) ? 12 : ( i >= 150 ) ? 18 : 27 ); + + for( i = 0; i < n; i++ ) + { + /* + * pick a random A, 1 < A < |X| - 1 + */ + MPI_CHK( mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) ); + + if( mpi_cmp_mpi( &A, &W ) >= 0 ) + { + j = mpi_msb( &A ) - mpi_msb( &W ); + MPI_CHK( mpi_shift_r( &A, j + 1 ) ); + } + A.p[0] |= 3; + + /* + * A = A^R mod |X| + */ + MPI_CHK( mpi_exp_mod( &A, &A, &R, X, &RR ) ); + + if( mpi_cmp_mpi( &A, &W ) == 0 || + mpi_cmp_int( &A, 1 ) == 0 ) + continue; + + j = 1; + while( j < s && mpi_cmp_mpi( &A, &W ) != 0 ) + { + /* + * A = A * A mod |X| + */ + MPI_CHK( mpi_mul_mpi( &T, &A, &A ) ); + MPI_CHK( mpi_mod_mpi( &A, &T, X ) ); + + if( mpi_cmp_int( &A, 1 ) == 0 ) + break; + + j++; + } + + /* + * not prime if A != |X| - 1 or A == 1 + */ + if( mpi_cmp_mpi( &A, &W ) != 0 || + mpi_cmp_int( &A, 1 ) == 0 ) + { + ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE; + break; + } + } + +cleanup: + + X->s = xs; + + mpi_free( &W ); mpi_free( &R ); mpi_free( &T ); mpi_free( &A ); + mpi_free( &RR ); + + return( ret ); +} + +/* + * Prime number generation + */ +int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t k, n; + mpi Y; + + if( nbits < 3 || nbits > POLARSSL_MPI_MAX_BITS ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + mpi_init( &Y ); + + n = BITS_TO_LIMBS( nbits ); + + MPI_CHK( mpi_fill_random( X, n * ciL, f_rng, p_rng ) ); + + k = mpi_msb( X ); + if( k < nbits ) MPI_CHK( mpi_shift_l( X, nbits - k ) ); + if( k > nbits ) MPI_CHK( mpi_shift_r( X, k - nbits ) ); + + X->p[0] |= 3; + + if( dh_flag == 0 ) + { + while( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) != 0 ) + { + if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + MPI_CHK( mpi_add_int( X, X, 2 ) ); + } + } + else + { + MPI_CHK( mpi_sub_int( &Y, X, 1 ) ); + MPI_CHK( mpi_shift_r( &Y, 1 ) ); + + while( 1 ) + { + if( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) == 0 ) + { + if( ( ret = mpi_is_prime( &Y, f_rng, p_rng ) ) == 0 ) + break; + + if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + } + + if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + MPI_CHK( mpi_add_int( &Y, X, 1 ) ); + MPI_CHK( mpi_add_int( X, X, 2 ) ); + MPI_CHK( mpi_shift_r( &Y, 1 ) ); + } + } + +cleanup: + + mpi_free( &Y ); + + return( ret ); +} + +#endif + +#if defined(POLARSSL_SELF_TEST) + +#define GCD_PAIR_COUNT 3 + +static const int gcd_pairs[GCD_PAIR_COUNT][3] = +{ + { 693, 609, 21 }, + { 1764, 868, 28 }, + { 768454923, 542167814, 1 } +}; + +/* + * Checkup routine + */ +int mpi_self_test( int verbose ) +{ + int ret, i; + mpi A, E, N, X, Y, U, V; + + mpi_init( &A ); mpi_init( &E ); mpi_init( &N ); mpi_init( &X ); + mpi_init( &Y ); mpi_init( &U ); mpi_init( &V ); + + MPI_CHK( mpi_read_string( &A, 16, + "EFE021C2645FD1DC586E69184AF4A31E" \ + "D5F53E93B5F123FA41680867BA110131" \ + "944FE7952E2517337780CB0DB80E61AA" \ + "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) ); + + MPI_CHK( mpi_read_string( &E, 16, + "B2E7EFD37075B9F03FF989C7C5051C20" \ + "34D2A323810251127E7BF8625A4F49A5" \ + "F3E27F4DA8BD59C47D6DAABA4C8127BD" \ + "5B5C25763222FEFCCFC38B832366C29E" ) ); + + MPI_CHK( mpi_read_string( &N, 16, + "0066A198186C18C10B2F5ED9B522752A" \ + "9830B69916E535C8F047518A889A43A5" \ + "94B6BED27A168D31D4A52F88925AA8F5" ) ); + + MPI_CHK( mpi_mul_mpi( &X, &A, &N ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "602AB7ECA597A3D6B56FF9829A5E8B85" \ + "9E857EA95A03512E2BAE7391688D264A" \ + "A5663B0341DB9CCFD2C4C5F421FEC814" \ + "8001B72E848A38CAE1C65F78E56ABDEF" \ + "E12D3C039B8A02D6BE593F0BBBDA56F1" \ + "ECF677152EF804370C1A305CAF3B5BF1" \ + "30879B56C61DE584A0F53A2447A51E" ) ); + + if( verbose != 0 ) + printf( " MPI test #1 (mul_mpi): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + + MPI_CHK( mpi_div_mpi( &X, &Y, &A, &N ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "256567336059E52CAE22925474705F39A94" ) ); + + MPI_CHK( mpi_read_string( &V, 16, + "6613F26162223DF488E9CD48CC132C7A" \ + "0AC93C701B001B092E4E5B9F73BCD27B" \ + "9EE50D0657C77F374E903CDFA4C642" ) ); + + if( verbose != 0 ) + printf( " MPI test #2 (div_mpi): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 || + mpi_cmp_mpi( &Y, &V ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + + MPI_CHK( mpi_exp_mod( &X, &A, &E, &N, NULL ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "36E139AEA55215609D2816998ED020BB" \ + "BD96C37890F65171D948E9BC7CBAA4D9" \ + "325D24D6A3C12710F10A09FA08AB87" ) ); + + if( verbose != 0 ) + printf( " MPI test #3 (exp_mod): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + +#if defined(POLARSSL_GENPRIME) + MPI_CHK( mpi_inv_mod( &X, &A, &N ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \ + "C3DBA76456363A10869622EAC2DD84EC" \ + "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) ); + + if( verbose != 0 ) + printf( " MPI test #4 (inv_mod): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); +#endif + + if( verbose != 0 ) + printf( " MPI test #5 (simple gcd): " ); + + for ( i = 0; i < GCD_PAIR_COUNT; i++) + { + MPI_CHK( mpi_lset( &X, gcd_pairs[i][0] ) ); + MPI_CHK( mpi_lset( &Y, gcd_pairs[i][1] ) ); + + MPI_CHK( mpi_gcd( &A, &X, &Y ) ); + + if( mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 ) + { + if( verbose != 0 ) + printf( "failed at %d\n", i ); + + return( 1 ); + } + } + + if( verbose != 0 ) + printf( "passed\n" ); + +cleanup: + + if( ret != 0 && verbose != 0 ) + printf( "Unexpected error, return code = %08X\n", ret ); + + mpi_free( &A ); mpi_free( &E ); mpi_free( &N ); mpi_free( &X ); + mpi_free( &Y ); mpi_free( &U ); mpi_free( &V ); + + if( verbose != 0 ) + printf( "\n" ); + + return( ret ); +} + +#endif + +#endif diff --git a/ANDROID_3.4.5/drivers/misc/rsa/bignum.h b/ANDROID_3.4.5/drivers/misc/rsa/bignum.h new file mode 100755 index 00000000..3b4d19c4 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/rsa/bignum.h @@ -0,0 +1,763 @@ +/** + * \file bignum.h + * + * \brief Multi-precision integer library + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org> + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_BIGNUM_H +#define POLARSSL_BIGNUM_H + +//#include <common.h> +//#include <command.h> +#include <asm/io.h> + +//#include <stdio.h> +//#include <string.h> + +//#include "config.h" + +#define POLARSSL_ERR_MPI_FILE_IO_ERROR -0x0002 /**< An error occurred while reading from or writing to a file. */ +#define POLARSSL_ERR_MPI_BAD_INPUT_DATA -0x0004 /**< Bad input parameters to function. */ +#define POLARSSL_ERR_MPI_INVALID_CHARACTER -0x0006 /**< There is an invalid character in the digit string. */ +#define POLARSSL_ERR_MPI_BUFFER_TOO_SMALL -0x0008 /**< The buffer is too small to write to. */ +#define POLARSSL_ERR_MPI_NEGATIVE_VALUE -0x000A /**< The input arguments are negative or result in illegal output. */ +#define POLARSSL_ERR_MPI_DIVISION_BY_ZERO -0x000C /**< The input argument for division is zero, which is not allowed. */ +#define POLARSSL_ERR_MPI_NOT_ACCEPTABLE -0x000E /**< The input arguments are not acceptable. */ +#define POLARSSL_ERR_MPI_MALLOC_FAILED -0x0010 /**< Memory allocation failed. */ + +#define MPI_CHK(f) if( ( ret = f ) != 0 ) goto cleanup + +/* + * Maximum size MPIs are allowed to grow to in number of limbs. + */ +#define POLARSSL_MPI_MAX_LIMBS 10000 + +/* + * Maximum window size used for modular exponentiation. Default: 6 + * Minimum value: 1. Maximum value: 6. + * + * Result is an array of ( 2 << POLARSSL_MPI_WINDOW_SIZE ) MPIs used + * for the sliding window calculation. (So 64 by default) + * + * Reduction in size, reduces speed. + */ +#define POLARSSL_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ + +/* + * Maximum size of MPIs allowed in bits and bytes for user-MPIs. + * ( Default: 512 bytes => 4096 bits ) + * + * Note: Calculations can results temporarily in larger MPIs. So the number + * of limbs required (POLARSSL_MPI_MAX_LIMBS) is higher. + */ +#define POLARSSL_MPI_MAX_SIZE 512 /**< Maximum number of bytes for usable MPIs. */ +#define POLARSSL_MPI_MAX_BITS ( 8 * POLARSSL_MPI_MAX_SIZE ) /**< Maximum number of bits for usable MPIs. */ + +/* + * When reading from files with mpi_read_file() the buffer should have space + * for a (short) label, the MPI (in the provided radix), the newline + * characters and the '\0'. + * + * By default we assume at least a 10 char label, a minimum radix of 10 + * (decimal) and a maximum of 4096 bit numbers (1234 decimal chars). + */ +#define POLARSSL_MPI_READ_BUFFER_SIZE 1250 + +/* + * Define the base integer type, architecture-wise + */ +#if defined(POLARSSL_HAVE_INT8) +typedef signed char t_sint; +typedef unsigned char t_uint; +typedef unsigned short t_udbl; +#else +#if defined(POLARSSL_HAVE_INT16) +typedef signed short t_sint; +typedef unsigned short t_uint; +typedef unsigned long t_udbl; +#else + typedef signed long t_sint; + typedef unsigned long t_uint; + #if defined(_MSC_VER) && defined(_M_IX86) + typedef unsigned __int64 t_udbl; + #else + #if defined(__GNUC__) && ( \ + defined(__amd64__) || defined(__x86_64__) || \ + defined(__ppc64__) || defined(__powerpc64__) || \ + defined(__ia64__) || defined(__alpha__) || \ + (defined(__sparc__) && defined(__arch64__)) || \ + defined(__s390x__) ) + typedef unsigned int t_udbl __attribute__((mode(TI))); + #define POLARSSL_HAVE_LONGLONG + #else + #if defined(POLARSSL_HAVE_LONGLONG) + typedef unsigned long long t_udbl; + #endif + #endif + #endif +#endif +#endif + +/** + * \brief MPI structure + */ +typedef struct +{ + int s; /*!< integer sign */ + size_t n; /*!< total # of limbs */ + t_uint *p; /*!< pointer to limbs */ +} +mpi; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initialize one MPI + * + * \param X One MPI to initialize. + */ +void mpi_init( mpi *X ); + +/** + * \brief Unallocate one MPI + * + * \param X One MPI to unallocate. + */ +void mpi_free( mpi *X ); + +/** + * \brief Enlarge to the specified number of limbs + * + * \param X MPI to grow + * \param nblimbs The target number of limbs + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_grow( mpi *X, size_t nblimbs ); + +/** + * \brief Copy the contents of Y into X + * + * \param X Destination MPI + * \param Y Source MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_copy( mpi *X, const mpi *Y ); + +/** + * \brief Swap the contents of X and Y + * + * \param X First MPI value + * \param Y Second MPI value + */ +void mpi_swap( mpi *X, mpi *Y ); + +/** + * \brief Set value from integer + * + * \param X MPI to set + * \param z Value to use + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_lset( mpi *X, t_sint z ); + +/* + * \brief Get a specific bit from X + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * + * \return Either a 0 or a 1 + */ +int mpi_get_bit( mpi *X, size_t pos ); + +/* + * \brief Set a bit of X to a specific value of 0 or 1 + * + * \note Will grow X if necessary to set a bit to 1 in a not yet + * existing limb. Will not grow if bit should be set to 0 + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * \param val The value to set the bit to (0 or 1) + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_BAD_INPUT_DATA if val is not 0 or 1 + */ +int mpi_set_bit( mpi *X, size_t pos, unsigned char val ); + +/** + * \brief Return the number of least significant bits + * + * \param X MPI to use + */ +size_t mpi_lsb( const mpi *X ); + +/** + * \brief Return the number of most significant bits + * + * \param X MPI to use + */ +size_t mpi_msb( const mpi *X ); + +/** + * \brief Return the total size in bytes + * + * \param X MPI to use + */ +size_t mpi_size( const mpi *X ); + +/** + * \brief Import from an ASCII string + * + * \param X Destination MPI + * \param radix Input numeric base + * \param s Null-terminated string buffer + * + * \return 0 if successful, or a POLARSSL_ERR_MPI_XXX error code + */ +int mpi_read_string( mpi *X, int radix, const char *s ); + +/** + * \brief Export into an ASCII string + * + * \param X Source MPI + * \param radix Output numeric base + * \param s String buffer + * \param slen String buffer size + * + * \return 0 if successful, or a POLARSSL_ERR_MPI_XXX error code. + * *slen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with *slen = 0 to obtain the + * minimum required buffer size in *slen. + */ +int mpi_write_string( const mpi *X, int radix, char *s, size_t *slen ); + +/** + * \brief Read X from an opened file + * + * \param X Destination MPI + * \param radix Input numeric base + * \param fin Input file handle + * + * \return 0 if successful, POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if + * the file read buffer is too small or a + * POLARSSL_ERR_MPI_XXX error code + */ +//int mpi_read_file( mpi *X, int radix, FILE *fin ); + +/** + * \brief Write X into an opened file, or stdout if fout is NULL + * + * \param p Prefix, can be NULL + * \param X Source MPI + * \param radix Output numeric base + * \param fout Output file handle (can be NULL) + * + * \return 0 if successful, or a POLARSSL_ERR_MPI_XXX error code + * + * \note Set fout == NULL to print X on the console. + */ +//int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout ); + +/** + * \brief Import X from unsigned binary data, big endian + * + * \param X Destination MPI + * \param buf Input buffer + * \param buflen Input buffer size + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen ); + +/** + * \brief Export X into unsigned binary data, big endian + * + * \param X Source MPI + * \param buf Output buffer + * \param buflen Output buffer size + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough + */ +int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen ); + +/** + * \brief Left-shift: X <<= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_shift_l( mpi *X, size_t count ); + +/** + * \brief Right-shift: X >>= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_shift_r( mpi *X, size_t count ); + +/** + * \brief Compare unsigned values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if |X| is greater than |Y|, + * -1 if |X| is lesser than |Y| or + * 0 if |X| is equal to |Y| + */ +int mpi_cmp_abs( const mpi *X, const mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if X is greater than Y, + * -1 if X is lesser than Y or + * 0 if X is equal to Y + */ +int mpi_cmp_mpi( const mpi *X, const mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param z The integer value to compare to + * + * \return 1 if X is greater than z, + * -1 if X is lesser than z or + * 0 if X is equal to z + */ +int mpi_cmp_int( const mpi *X, t_sint z ); + +/** + * \brief Unsigned addition: X = |A| + |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_add_abs( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Unsigned substraction: X = |A| - |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_NEGATIVE_VALUE if B is greater than A + */ +int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Signed addition: X = A + B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Signed substraction: X = A - B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Signed addition: X = A + b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to add + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_add_int( mpi *X, const mpi *A, t_sint b ); + +/** + * \brief Signed substraction: X = A - b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to subtract + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_sub_int( mpi *X, const mpi *A, t_sint b ); + +/** + * \brief Baseline multiplication: X = A * B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Baseline multiplication: X = A * b + * Note: b is an unsigned integer type, thus + * Negative values of b are ignored. + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to multiply with + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_mul_int( mpi *X, const mpi *A, t_sint b ); + +/** + * \brief Division by mpi: A = Q * B + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0 + * + * \note Either Q or R can be NULL. + */ +int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B ); + +/** + * \brief Division by int: A = Q * b + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0 + * + * \note Either Q or R can be NULL. + */ +int mpi_div_int( mpi *Q, mpi *R, const mpi *A, t_sint b ); + +/** + * \brief Modulo: R = A mod B + * + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0, + * POLARSSL_ERR_MPI_NEGATIVE_VALUE if B < 0 + */ +int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B ); + +/** + * \brief Modulo: r = A mod b + * + * \param r Destination t_uint + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0, + * POLARSSL_ERR_MPI_NEGATIVE_VALUE if b < 0 + */ +int mpi_mod_int( t_uint *r, const mpi *A, t_sint b ); + +/** + * \brief Sliding-window exponentiation: X = A^E mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param E Exponent MPI + * \param N Modular MPI + * \param _RR Speed-up MPI used for recalculations + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or even + * + * \note _RR is used to avoid re-computing R*R mod N across + * multiple calls, which speeds up things a bit. It can + * be set to NULL if the extra performance is unneeded. + */ +int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR ); + +/** + * \brief Fill an MPI X with size bytes of random + * + * \param X Destination MPI + * \param size Size in bytes + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_fill_random( mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Greatest common divisor: G = gcd(A, B) + * + * \param G Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_gcd( mpi *G, const mpi *A, const mpi *B ); + +/** + * \brief Modular inverse: X = A^-1 mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param N Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or nil + POLARSSL_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N + */ +int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N ); + +/** + * \brief Miller-Rabin primality test + * + * \param X MPI to check + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime + */ +int mpi_is_prime( mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Prime number generation + * + * \param X Destination MPI + * \param nbits Required size of X in bits ( 3 <= nbits <= POLARSSL_MPI_MAX_BITS ) + * \param dh_flag If 1, then (X-1)/2 will be prime too + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_BAD_INPUT_DATA if nbits is < 3 + */ +int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mpi_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#define __ARM__ 1 +#ifdef __ARM__ +#define MULADDC_INIT \ + asm( "ldr r0, %0 " :: "m" (s)); \ + asm( "ldr r1, %0 " :: "m" (d)); \ + asm( "ldr r2, %0 " :: "m" (c)); \ + asm( "ldr r3, %0 " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "ldr r4, [r0], #4 " ); \ + asm( "mov r5, #0 " ); \ + asm( "ldr r6, [r1] " ); \ + asm( "umlal r2, r5, r3, r4 " ); \ + asm( "adds r7, r6, r2 " ); \ + asm( "adc r2, r5, #0 " ); \ + asm( "str r7, [r1], #4 " ); + +#define MULADDC_STOP \ + asm( "str r2, %0 " : "=m" (c)); \ + asm( "str r1, %0 " : "=m" (d)); \ + asm( "str r0, %0 " : "=m" (s) :: \ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" ); + +#endif + +#ifdef __i386__ +#define MULADDC_INIT \ + asm( " \ + movl %%ebx, %0; \ + movl %5, %%esi; \ + movl %6, %%edi; \ + movl %7, %%ecx; \ + movl %8, %%ebx; \ + " + +#define MULADDC_CORE \ + " \ + lodsl; \ + mull %%ebx; \ + addl %%ecx, %%eax; \ + adcl $0, %%edx; \ + addl (%%edi), %%eax; \ + adcl $0, %%edx; \ + movl %%edx, %%ecx; \ + stosl; \ + " + + +#define MULADDC_HUIT \ + " \ + movd %%ecx, %%mm1; \ + movd %%ebx, %%mm0; \ + movd (%%edi), %%mm3; \ + paddq %%mm3, %%mm1; \ + movd (%%esi), %%mm2; \ + pmuludq %%mm0, %%mm2; \ + movd 4(%%esi), %%mm4; \ + pmuludq %%mm0, %%mm4; \ + movd 8(%%esi), %%mm6; \ + pmuludq %%mm0, %%mm6; \ + movd 12(%%esi), %%mm7; \ + pmuludq %%mm0, %%mm7; \ + paddq %%mm2, %%mm1; \ + movd 4(%%edi), %%mm3; \ + paddq %%mm4, %%mm3; \ + movd 8(%%edi), %%mm5; \ + paddq %%mm6, %%mm5; \ + movd 12(%%edi), %%mm4; \ + paddq %%mm4, %%mm7; \ + movd %%mm1, (%%edi); \ + movd 16(%%esi), %%mm2; \ + pmuludq %%mm0, %%mm2; \ + psrlq $32, %%mm1; \ + movd 20(%%esi), %%mm4; \ + pmuludq %%mm0, %%mm4; \ + paddq %%mm3, %%mm1; \ + movd 24(%%esi), %%mm6; \ + pmuludq %%mm0, %%mm6; \ + movd %%mm1, 4(%%edi); \ + psrlq $32, %%mm1; \ + movd 28(%%esi), %%mm3; \ + pmuludq %%mm0, %%mm3; \ + paddq %%mm5, %%mm1; \ + movd 16(%%edi), %%mm5; \ + paddq %%mm5, %%mm2; \ + movd %%mm1, 8(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm7, %%mm1; \ + movd 20(%%edi), %%mm5; \ + paddq %%mm5, %%mm4; \ + movd %%mm1, 12(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm2, %%mm1; \ + movd 24(%%edi), %%mm5; \ + paddq %%mm5, %%mm6; \ + movd %%mm1, 16(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm4, %%mm1; \ + movd 28(%%edi), %%mm5; \ + paddq %%mm5, %%mm3; \ + movd %%mm1, 20(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm6, %%mm1; \ + movd %%mm1, 24(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm3, %%mm1; \ + movd %%mm1, 28(%%edi); \ + addl $32, %%edi; \ + addl $32, %%esi; \ + psrlq $32, %%mm1; \ + movd %%mm1, %%ecx; \ + " + +#define MULADDC_STOP \ + " \ + emms; \ + movl %4, %%ebx; \ + movl %%ecx, %1; \ + movl %%edi, %2; \ + movl %%esi, %3; \ + " \ + : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ + : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ + : "eax", "ecx", "edx", "esi", "edi" \ + ); + +#endif +#endif /* bignum.h */ diff --git a/ANDROID_3.4.5/drivers/misc/rsa/dhm.h b/ANDROID_3.4.5/drivers/misc/rsa/dhm.h new file mode 100755 index 00000000..0c8dd55e --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/rsa/dhm.h @@ -0,0 +1,153 @@ +/** + * \file dhm.h + * + * \brief Diffie-Hellman-Merkle key exchange + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org> + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_DHM_H +#define POLARSSL_DHM_H + +#include "bignum.h" + +/* + * DHM Error codes + */ +#define POLARSSL_ERR_DHM_BAD_INPUT_DATA -0x3080 /**< Bad input parameters to function. */ +#define POLARSSL_ERR_DHM_READ_PARAMS_FAILED -0x3100 /**< Reading of the DHM parameters failed. */ +#define POLARSSL_ERR_DHM_MAKE_PARAMS_FAILED -0x3180 /**< Making of the DHM parameters failed. */ +#define POLARSSL_ERR_DHM_READ_PUBLIC_FAILED -0x3200 /**< Reading of the public values failed. */ +#define POLARSSL_ERR_DHM_MAKE_PUBLIC_FAILED -0x3280 /**< Making of the public value failed. */ +#define POLARSSL_ERR_DHM_CALC_SECRET_FAILED -0x3300 /**< Calculation of the DHM secret failed. */ + +/** + * \brief DHM context structure + */ +typedef struct +{ + size_t len; /*!< size(P) in chars */ + mpi P; /*!< prime modulus */ + mpi G; /*!< generator */ + mpi X; /*!< secret value */ + mpi GX; /*!< self = G^X mod P */ + mpi GY; /*!< peer = G^Y mod P */ + mpi K; /*!< key = GY^X mod P */ + mpi RP; /*!< cached R^2 mod P */ +} +dhm_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Parse the ServerKeyExchange parameters + * + * \param ctx DHM context + * \param p &(start of input buffer) + * \param end end of buffer + * + * \return 0 if successful, or an POLARSSL_ERR_DHM_XXX error code + */ +int dhm_read_params( dhm_context *ctx, + unsigned char **p, + const unsigned char *end ); + +/** + * \brief Setup and write the ServerKeyExchange parameters + * + * \param ctx DHM context + * \param x_size private value size in bytes + * \param output destination buffer + * \param olen number of chars written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note This function assumes that ctx->P and ctx->G + * have already been properly set (for example + * using mpi_read_string or mpi_read_binary). + * + * \return 0 if successful, or an POLARSSL_ERR_DHM_XXX error code + */ +int dhm_make_params( dhm_context *ctx, int x_size, + unsigned char *output, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Import the peer's public value G^Y + * + * \param ctx DHM context + * \param input input buffer + * \param ilen size of buffer + * + * \return 0 if successful, or an POLARSSL_ERR_DHM_XXX error code + */ +int dhm_read_public( dhm_context *ctx, + const unsigned char *input, size_t ilen ); + +/** + * \brief Create own private value X and export G^X + * + * \param ctx DHM context + * \param x_size private value size in bytes + * \param output destination buffer + * \param olen must be equal to ctx->P.len + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, or an POLARSSL_ERR_DHM_XXX error code + */ +int dhm_make_public( dhm_context *ctx, int x_size, + unsigned char *output, size_t olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Derive and export the shared secret (G^Y)^X mod P + * + * \param ctx DHM context + * \param output destination buffer + * \param olen number of chars written + * + * \return 0 if successful, or an POLARSSL_ERR_DHM_XXX error code + */ +int dhm_calc_secret( dhm_context *ctx, + unsigned char *output, size_t *olen ); + +/* + * \brief Free the components of a DHM key + */ +void dhm_free( dhm_context *ctx ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int dhm_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ANDROID_3.4.5/drivers/misc/rsa/pem.h b/ANDROID_3.4.5/drivers/misc/rsa/pem.h new file mode 100755 index 00000000..fbae8c55 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/rsa/pem.h @@ -0,0 +1,100 @@ +/** + * \file pem.h + * + * \brief Privacy Enhanced Mail (PEM) decoding + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org> + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_PEM_H +#define POLARSSL_PEM_H + +//#include <string.h> + +/** + * \name PEM Error codes + * These error codes are returned in case of errors reading the + * PEM data. + * \{ + */ +#define POLARSSL_ERR_PEM_NO_HEADER_PRESENT -0x1080 /**< No PEM header found. */ +#define POLARSSL_ERR_PEM_INVALID_DATA -0x1100 /**< PEM string is not as expected. */ +#define POLARSSL_ERR_PEM_MALLOC_FAILED -0x1180 /**< Failed to allocate memory. */ +#define POLARSSL_ERR_PEM_INVALID_ENC_IV -0x1200 /**< RSA IV is not in hex-format. */ +#define POLARSSL_ERR_PEM_UNKNOWN_ENC_ALG -0x1280 /**< Unsupported key encryption algorithm. */ +#define POLARSSL_ERR_PEM_PASSWORD_REQUIRED -0x1300 /**< Private key password can't be empty. */ +#define POLARSSL_ERR_PEM_PASSWORD_MISMATCH -0x1380 /**< Given private key password does not allow for correct decryption. */ +#define POLARSSL_ERR_PEM_FEATURE_UNAVAILABLE -0x1400 /**< Unavailable feature, e.g. hashing/encryption combination. */ +/* \} name */ + +/** + * \brief PEM context structure + */ +typedef struct +{ + unsigned char *buf; /*!< buffer for decoded data */ + size_t buflen; /*!< length of the buffer */ + unsigned char *info; /*!< buffer for extra header information */ +} +pem_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief PEM context setup + * + * \param ctx context to be initialized + */ +void pem_init( pem_context *ctx ); + +/** + * \brief Read a buffer for PEM information and store the resulting + * data into the specified context buffers. + * + * \param ctx context to use + * \param header header string to seek and expect + * \param footer footer string to seek and expect + * \param data source data to look in + * \param pwd password for decryption (can be NULL) + * \param pwdlen length of password + * \param use_len destination for total length used + * + * \return 0 on success, ior a specific PEM error code + */ +int pem_read_buffer( pem_context *ctx, + const unsigned char *data, + const unsigned char *pwd, + size_t pwdlen, size_t *use_len ); + +/** + * \brief PEM context memory freeing + * + * \param ctx context to be freed + */ +void pem_free( pem_context *ctx ); + +#ifdef __cplusplus +} +#endif + +#endif /* pem.h */ diff --git a/ANDROID_3.4.5/drivers/misc/rsa/rsa.h b/ANDROID_3.4.5/drivers/misc/rsa/rsa.h new file mode 100755 index 00000000..41691ae1 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/rsa/rsa.h @@ -0,0 +1,373 @@ +/** + * \file rsa.h + * + * \brief The RSA public-key cryptosystem + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org> + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_RSA_H +#define POLARSSL_RSA_H + +#include "bignum.h" +#include <stddef.h> +/* + * RSA Error codes + */ +#define POLARSSL_ERR_RSA_BAD_INPUT_DATA -0x4080 /**< Bad input parameters to function. */ +#define POLARSSL_ERR_RSA_INVALID_PADDING -0x4100 /**< Input data contains invalid padding and is rejected. */ +#define POLARSSL_ERR_RSA_KEY_GEN_FAILED -0x4180 /**< Something failed during generation of a key. */ +#define POLARSSL_ERR_RSA_KEY_CHECK_FAILED -0x4200 /**< Key failed to pass the libraries validity check. */ +#define POLARSSL_ERR_RSA_PUBLIC_FAILED -0x4280 /**< The public key operation failed. */ +#define POLARSSL_ERR_RSA_PRIVATE_FAILED -0x4300 /**< The private key operation failed. */ +#define POLARSSL_ERR_RSA_VERIFY_FAILED -0x4380 /**< The PKCS#1 verification failed. */ +#define POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE -0x4400 /**< The output buffer for decryption is not large enough. */ +#define POLARSSL_ERR_RSA_RNG_FAILED -0x4480 /**< The random generator failed to generate non-zeros. */ + +/* + * PKCS#1 constants + */ +#define SIG_RSA_RAW 0 +#define SIG_RSA_MD2 2 +#define SIG_RSA_MD4 3 +#define SIG_RSA_MD5 4 +#define SIG_RSA_SHA1 5 +#define SIG_RSA_SHA224 14 +#define SIG_RSA_SHA256 11 +#define SIG_RSA_SHA384 12 +#define SIG_RSA_SHA512 13 + +#define RSA_PUBLIC 0 +#define RSA_PRIVATE 1 + +#define RSA_PKCS_V15 0 +#define RSA_PKCS_V21 1 + +#define RSA_SIGN 1 +#define RSA_CRYPT 2 + +#define ASN1_STR_CONSTRUCTED_SEQUENCE "\x30" +#define ASN1_STR_NULL "\x05" +#define ASN1_STR_OID "\x06" +#define ASN1_STR_OCTET_STRING "\x04" + +#define OID_DIGEST_ALG_MDX "\x2A\x86\x48\x86\xF7\x0D\x02\x00" +#define OID_HASH_ALG_SHA1 "\x2b\x0e\x03\x02\x1a" +#define OID_HASH_ALG_SHA2X "\x60\x86\x48\x01\x65\x03\x04\x02\x00" + +#define OID_ISO_MEMBER_BODIES "\x2a" +#define OID_ISO_IDENTIFIED_ORG "\x2b" + +/* + * ISO Member bodies OID parts + */ +#define OID_COUNTRY_US "\x86\x48" +#define OID_RSA_DATA_SECURITY "\x86\xf7\x0d" + +/* + * ISO Identified organization OID parts + */ +#define OID_OIW_SECSIG_SHA1 "\x0e\x03\x02\x1a" + +/* + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * Digest ::= OCTET STRING + */ +#define ASN1_HASH_MDX \ +( \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x20" \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x0C" \ + ASN1_STR_OID "\x08" \ + OID_DIGEST_ALG_MDX \ + ASN1_STR_NULL "\x00" \ + ASN1_STR_OCTET_STRING "\x10" \ +) + +#define ASN1_HASH_SHA1 \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x21" \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x09" \ + ASN1_STR_OID "\x05" \ + OID_HASH_ALG_SHA1 \ + ASN1_STR_NULL "\x00" \ + ASN1_STR_OCTET_STRING "\x14" + +#define ASN1_HASH_SHA2X \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x11" \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x0d" \ + ASN1_STR_OID "\x09" \ + OID_HASH_ALG_SHA2X \ + ASN1_STR_NULL "\x00" \ + ASN1_STR_OCTET_STRING "\x00" + + +/** + * \brief RSA context structure + */ +typedef struct +{ + int ver; /*!< always 0 */ + size_t len; /*!< size(N) in chars */ + + mpi N; /*!< public modulus */ + mpi E; /*!< public exponent */ + + mpi D; /*!< private exponent */ + mpi P; /*!< 1st prime factor */ + mpi Q; /*!< 2nd prime factor */ + mpi DP; /*!< D % (P - 1) */ + mpi DQ; /*!< D % (Q - 1) */ + mpi QP; /*!< 1 / (Q % P) */ + + mpi RN; /*!< cached R^2 mod N */ + mpi RP; /*!< cached R^2 mod P */ + mpi RQ; /*!< cached R^2 mod Q */ + + int padding; /*!< RSA_PKCS_V15 for 1.5 padding and + RSA_PKCS_v21 for OAEP/PSS */ + int hash_id; /*!< Hash identifier of md_type_t as + specified in the md.h header file + for the EME-OAEP and EMSA-PSS + encoding */ +} +rsa_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initialize an RSA context + * + * \param ctx RSA context to be initialized + * \param padding RSA_PKCS_V15 or RSA_PKCS_V21 + * \param hash_id RSA_PKCS_V21 hash identifier + * + * \note The hash_id parameter is actually ignored + * when using RSA_PKCS_V15 padding. + */ +void rsa_init( rsa_context *ctx, + int padding, + int hash_id); + +/** + * \brief Generate an RSA keypair + * + * \param ctx RSA context that will hold the key + * \param f_rng RNG function + * \param p_rng RNG parameter + * \param nbits size of the public key in bits + * \param exponent public exponent (e.g., 65537) + * + * \note rsa_init() must be called beforehand to setup + * the RSA context. + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + */ +int rsa_gen_key( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + unsigned int nbits, int exponent ); + +/** + * \brief Check a public RSA key + * + * \param ctx RSA context to be checked + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + */ +int rsa_check_pubkey( const rsa_context *ctx ); + +/** + * \brief Check a private RSA key + * + * \param ctx RSA context to be checked + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + */ +int rsa_check_privkey( const rsa_context *ctx ); + +/** + * \brief Do an RSA public key operation + * + * \param ctx RSA context + * \param input input buffer + * \param output output buffer + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + * + * \note This function does NOT take care of message + * padding. Also, be sure to set input[0] = 0 or assure that + * input is smaller than N. + * + * \note The input and output buffers must be large + * enough (eg. 128 bytes if RSA-1024 is used). + */ +int rsa_public( rsa_context *ctx, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Do an RSA private key operation + * + * \param ctx RSA context + * \param input input buffer + * \param output output buffer + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + * + * \note The input and output buffers must be large + * enough (eg. 128 bytes if RSA-1024 is used). + */ +int rsa_private( rsa_context *ctx, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Add the message padding, then do an RSA operation + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for padding and PKCS#1 v2.1 encoding) + * \param p_rng RNG parameter + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param ilen contains the plaintext length + * \param input buffer holding the data to be encrypted + * \param output buffer that will hold the ciphertext + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int rsa_pkcs1_encrypt( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Do an RSA operation, then remove the message padding + * + * \param ctx RSA context + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param olen will contain the plaintext length + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \param output_max_len maximum length of the output buffer + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise + * an error is thrown. + */ +int rsa_pkcs1_decrypt( rsa_context *ctx, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief Do a private RSA to sign a message digest + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for PKCS#1 v2.1 encoding) + * \param p_rng RNG parameter + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} + * \param hashlen message digest length (for SIG_RSA_RAW only) + * \param hash buffer holding the message digest + * \param sig buffer that will hold the ciphertext + * + * \return 0 if the signing operation was successful, + * or an POLARSSL_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + * + * \note In case of PKCS#1 v2.1 encoding keep in mind that + * the hash_id in the RSA context is the one used for the + * encoding. hash_id in the function call is the type of hash + * that is encoded. According to RFC 3447 it is advised to + * keep both hashes the same. + */ +int rsa_pkcs1_sign( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief Do a public RSA and check the message digest + * + * \param ctx points to an RSA public key + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} + * \param hashlen message digest length (for SIG_RSA_RAW only) + * \param hash buffer holding the message digest + * \param sig buffer holding the ciphertext + * + * \return 0 if the verify operation was successful, + * or an POLARSSL_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + * + * \note In case of PKCS#1 v2.1 encoding keep in mind that + * the hash_id in the RSA context is the one used for the + * verification. hash_id in the function call is the type of hash + * that is verified. According to RFC 3447 it is advised to + * keep both hashes the same. + */ +int rsa_pkcs1_verify( rsa_context *ctx, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief Free the components of an RSA key + * + * \param ctx RSA Context to free + */ +void rsa_free( rsa_context *ctx ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int rsa_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* rsa.h */ diff --git a/ANDROID_3.4.5/drivers/misc/rsa/rsa_verify.c b/ANDROID_3.4.5/drivers/misc/rsa/rsa_verify.c new file mode 100755 index 00000000..7d864016 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/rsa/rsa_verify.c @@ -0,0 +1,572 @@ +/* + * The RSA public-key cryptosystem + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org> + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * RSA was designed by Ron Rivest, Adi Shamir and Len Adleman. + * + * http://theory.lcs.mit.edu/~rivest/rsapaper.pdf + * http://www.cacr.math.uwaterloo.ca/hac/about/chap8.pdf + */ + +#include "rsa.h" +#include "base64.h" +#include "pem.h" +#include "asn1.h" +#include "x509.h" +//#include <stdlib.h> +//#include <stdio.h> +#include <linux/vmalloc.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <asm/io.h> +#include <linux/mtd/partitions.h> +#include <linux/platform_device.h> +#include <mach/hardware.h> +#include <linux/delay.h> + + + +static const unsigned char base64_dec_map[128] = +{ + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 62, 127, 127, 127, 63, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, + 127, 64, 127, 127, 127, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 127, 127, 127, 127, 127 +}; + +/* + * Decode a base64-formatted buffer + */ +int base64_decode( unsigned char *dst, size_t *dlen, + const unsigned char *src, size_t slen ) +{ + size_t i, j, n; + unsigned long x; + unsigned char *p; + + for( i = j = n = 0; i < slen; i++ ) + { + if( ( slen - i ) >= 2 && + src[i] == '\r' && src[i + 1] == '\n' ) + continue; + + if( src[i] == '\n' ) + continue; + + if( src[i] == '=' && ++j > 2 ) + return( POLARSSL_ERR_BASE64_INVALID_CHARACTER ); + + if( src[i] > 127 || base64_dec_map[src[i]] == 127 ) + return( POLARSSL_ERR_BASE64_INVALID_CHARACTER ); + + if( base64_dec_map[src[i]] < 64 && j != 0 ) + return( POLARSSL_ERR_BASE64_INVALID_CHARACTER ); + + n++; + } + + if( n == 0 ) + return( 0 ); + + n = ((n * 6) + 7) >> 3; + + if( *dlen < n ) + { + *dlen = n; + return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ ) + { + if( *src == '\r' || *src == '\n' ) + continue; + + j -= ( base64_dec_map[*src] == 64 ); + x = (x << 6) | ( base64_dec_map[*src] & 0x3F ); + + if( ++n == 4 ) + { + n = 0; + if( j > 0 ) *p++ = (unsigned char)( x >> 16 ); + if( j > 1 ) *p++ = (unsigned char)( x >> 8 ); + if( j > 2 ) *p++ = (unsigned char)( x ); + } + } + + *dlen = p - dst; + + return( 0 ); +} + +int pem_read_buffer( pem_context *ctx, const unsigned char *data, const unsigned char *pwd, size_t pwdlen, size_t *use_len ) +{ + int ret; + size_t len; + unsigned char *buf; + + ((void) pwd); + ((void) pwdlen); + + if( ctx == NULL ) + return( POLARSSL_ERR_PEM_INVALID_DATA ); + + + + len = 0; + ret = base64_decode( NULL, &len, data, strlen((char *)data) ); + + if( ret == POLARSSL_ERR_BASE64_INVALID_CHARACTER ) + return( POLARSSL_ERR_PEM_INVALID_DATA + ret ); + + if( ( buf = (unsigned char *) vmalloc( len ) ) == NULL ) + return( POLARSSL_ERR_PEM_MALLOC_FAILED ); + + if( ( ret = base64_decode( buf, &len, data, strlen((char *)data) ) ) != 0 ) + { + vfree( buf ); + return( POLARSSL_ERR_PEM_INVALID_DATA + ret ); + } + + + ctx->buf = buf; + ctx->buflen = len; + //*use_len = s2 - data; + + return( 0 ); +} + +int asn1_get_len( unsigned char **p, + const unsigned char *end, + size_t *len ) +{ + if( ( end - *p ) < 1 ) + return( POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + if( ( **p & 0x80 ) == 0 ) + *len = *(*p)++; + else + { + switch( **p & 0x7F ) + { + case 1: + if( ( end - *p ) < 2 ) + return( POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + *len = (*p)[1]; + (*p) += 2; + break; + + case 2: + if( ( end - *p ) < 3 ) + return( POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (*p)[1] << 8 ) | (*p)[2]; + (*p) += 3; + break; + + case 3: + if( ( end - *p ) < 4 ) + return( POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (*p)[1] << 16 ) | ( (*p)[2] << 8 ) | (*p)[3]; + (*p) += 4; + break; + + case 4: + if( ( end - *p ) < 5 ) + return( POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (*p)[1] << 24 ) | ( (*p)[2] << 16 ) | ( (*p)[3] << 8 ) | (*p)[4]; + (*p) += 5; + break; + + default: + return( POLARSSL_ERR_ASN1_INVALID_LENGTH ); + } + } + + if( *len > (size_t) ( end - *p ) ) + return( POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + return( 0 ); +} + +int asn1_get_tag( unsigned char **p, + const unsigned char *end, + size_t *len, int tag ) +{ + if( ( end - *p ) < 1 ) + return( POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + if( **p != tag ) + return( POLARSSL_ERR_ASN1_UNEXPECTED_TAG ); + + (*p)++; + + return( asn1_get_len( p, end, len ) ); +} + +int asn1_get_mpi( unsigned char **p, + const unsigned char *end, + mpi *X ) +{ + int ret; + size_t len; + + if( ( ret = asn1_get_tag( p, end, &len, ASN1_INTEGER ) ) != 0 ) + return( ret ); + + ret = mpi_read_binary( X, *p, len ); + + *p += len; + + return( ret ); +} + +static int x509_get_alg( unsigned char **p, + const unsigned char *end, + x509_buf *alg ) +{ + int ret; + size_t len; + + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_ALG + ret ); + + end = *p + len; + alg->tag = **p; + + if( ( ret = asn1_get_tag( p, end, &alg->len, ASN1_OID ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_ALG + ret ); + + alg->p = *p; + *p += alg->len; + + if( *p == end ) + return( 0 ); + + /* + * assume the algorithm parameters must be NULL + */ + if( ( ret = asn1_get_tag( p, end, &len, ASN1_NULL ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_ALG + ret ); + + if( *p != end ) + return( POLARSSL_ERR_X509_CERT_INVALID_ALG + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +static int x509_get_pubkey( unsigned char **p, + const unsigned char *end, + x509_buf *pk_alg_oid, + mpi *N, mpi *E ) +{ + int ret, can_handle; + size_t len; + unsigned char *end2; + + if( ( ret = x509_get_alg( p, end, pk_alg_oid ) ) != 0 ) + return( ret ); + + /* + * only RSA public keys handled at this time + */ + can_handle = 0; + + if( pk_alg_oid->len == 9 && + memcmp( pk_alg_oid->p, OID_PKCS1_RSA, 9 ) == 0 ) + can_handle = 1; + + if( pk_alg_oid->len == 9 && + memcmp( pk_alg_oid->p, OID_PKCS1, 8 ) == 0 ) + { + if( pk_alg_oid->p[8] >= 2 && pk_alg_oid->p[8] <= 5 ) + can_handle = 1; + + if ( pk_alg_oid->p[8] >= 11 && pk_alg_oid->p[8] <= 14 ) + can_handle = 1; + } + + if( pk_alg_oid->len == 5 && + memcmp( pk_alg_oid->p, OID_RSA_SHA_OBS, 5 ) == 0 ) + can_handle = 1; + + if( can_handle == 0 ) + return( POLARSSL_ERR_X509_UNKNOWN_PK_ALG ); + + if( ( ret = asn1_get_tag( p, end, &len, ASN1_BIT_STRING ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_PUBKEY + ret ); + + if( ( end - *p ) < 1 ) + return( POLARSSL_ERR_X509_CERT_INVALID_PUBKEY + + POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + end2 = *p + len; + + if( *(*p)++ != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_PUBKEY ); + + /* + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + */ + if( ( ret = asn1_get_tag( p, end2, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_PUBKEY + ret ); + + if( *p + len != end2 ) + return( POLARSSL_ERR_X509_CERT_INVALID_PUBKEY + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + if( ( ret = asn1_get_mpi( p, end2, N ) ) != 0 || + ( ret = asn1_get_mpi( p, end2, E ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_PUBKEY + ret ); + + if( *p != end ) + return( POLARSSL_ERR_X509_CERT_INVALID_PUBKEY + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + + +void pem_free( pem_context *ctx ) +{ + if( ctx->buf ) + vfree( ctx->buf ); + + if( ctx->info ) + vfree( ctx->info ); + + memset(ctx, 0, sizeof(pem_context)); +} + +int x509parse_public_key( rsa_context *rsa, const unsigned char *key, size_t keylen ) +{ + int ret; + size_t len; + unsigned char *p, *end; + x509_buf alg_oid; + pem_context pem; + + memset( &pem, 0, sizeof( pem_context ) ); + ret = pem_read_buffer( &pem, + key, NULL, 0, &len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + keylen = pem.buflen; + + } + else if( ret != POLARSSL_ERR_PEM_NO_HEADER_PRESENT ) + { + pem_free( &pem ); + return( ret ); + } + + p = ( ret == 0 ) ? pem.buf : (unsigned char *) key; + end = p + keylen; + + /* + * PublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * PublicKey BIT STRING + * } + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + * + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + */ + + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + pem_free( &pem ); + rsa_free( rsa ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret ); + } + + if( ( ret = x509_get_pubkey( &p, end, &alg_oid, &rsa->N, &rsa->E ) ) != 0 ) + { + pem_free( &pem ); + rsa_free( rsa ); + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + } + +#if 0 + if( ( ret = rsa_check_pubkey( rsa ) ) != 0 ) + { +#if defined(POLARSSL_PEM_C) + pem_free( &pem ); +#endif + rsa_free( rsa ); + return( ret ); + } +#endif + rsa->len = mpi_size( &rsa->N ); + + + + pem_free( &pem ); + + return( 0 ); +} +/* + * Initialize an RSA context + */ +void rsa_init( rsa_context *ctx, int padding, int hash_id) +{ + memset( ctx, 0, sizeof(rsa_context)); + + ctx->padding = padding; + ctx->hash_id = hash_id; +} + + +/* + * Do an RSA public key operation + */ + +int rsa_public( rsa_context *ctx, const unsigned char *input, unsigned char *output) +{ + int ret; + size_t olen; + mpi T; + + mpi_init( &T ); + + MPI_CHK( mpi_read_binary( &T, input, ctx->len ) ); + + if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) { + mpi_free( &T ); + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + } + + olen = ctx->len; + MPI_CHK( mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) ); + MPI_CHK( mpi_write_binary( &T, output, olen ) ); + +cleanup: + + mpi_free( &T ); + + if( ret != 0 ) + return( POLARSSL_ERR_RSA_PUBLIC_FAILED + ret ); + + return( 0 ); +} + + + +/* + * Free the components of an RSA key + */ +void rsa_free( rsa_context *ctx ) +{ + mpi_free( &ctx->RQ ); mpi_free( &ctx->RP ); mpi_free( &ctx->RN ); + mpi_free( &ctx->QP ); mpi_free( &ctx->DQ ); mpi_free( &ctx->DP ); + mpi_free( &ctx->Q ); mpi_free( &ctx->P ); mpi_free( &ctx->D ); + mpi_free( &ctx->E ); mpi_free( &ctx->N ); +} + +int rsa_check(unsigned int pub_key_addr, unsigned int pub_key_size, unsigned int sig_addr, unsigned int sig_size, u8 *out_buf) +{ + + size_t len; + rsa_context rsa; + unsigned char key[1024]; + unsigned char signature[1024]; + unsigned char verified[1024]; + int i; + unsigned char *tmp; + int ret, siglen; + + rsa_init(&rsa, RSA_PKCS_V15, 0); + + memcpy((void *)key, (void *)pub_key_addr, pub_key_size); + key[pub_key_size] = '\0'; + len = pub_key_size; + + x509parse_public_key(&rsa, key, len); + + tmp = (unsigned char *) rsa.N.p; + + memcpy(signature, (void *)sig_addr, sig_size); + signature[sig_size]='\0'; + + ret = rsa_public(&rsa, signature, verified); + + if (ret){ + printk("Signature verify failed!!!\n"); + return -2; + } + + + if ((verified[0] != 0) && (verified[1] != RSA_SIGN)) { + printk("Signature verify failed!!!\n"); + return -1; + } + + tmp = &verified[2]; + while (*tmp == 0xff) // skip padding + tmp++; + tmp++; // skip a terminator + + siglen = rsa.len -( tmp - verified); + + for (i = 0; i < siglen; i++) { + out_buf[i] = tmp[i]; + } + + rsa_free(&rsa); + return 0; +} +EXPORT_SYMBOL(rsa_check);
\ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/misc/rsa/x509.h b/ANDROID_3.4.5/drivers/misc/rsa/x509.h new file mode 100755 index 00000000..cd0dc84a --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/rsa/x509.h @@ -0,0 +1,726 @@ +/** + * \file x509.h + * + * \brief X.509 certificate and private key decoding + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org> + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_X509_H +#define POLARSSL_X509_H + +#include "asn1.h" +#include "rsa.h" +#include "dhm.h" + +/** + * \addtogroup x509_module + * \{ + */ + +/** + * \name X509 Error codes + * \{ + */ +#define POLARSSL_ERR_X509_FEATURE_UNAVAILABLE -0x2080 /**< Unavailable feature, e.g. RSA hashing/encryption combination. */ +#define POLARSSL_ERR_X509_CERT_INVALID_PEM -0x2100 /**< The PEM-encoded certificate contains invalid elements, e.g. invalid character. */ +#define POLARSSL_ERR_X509_CERT_INVALID_FORMAT -0x2180 /**< The certificate format is invalid, e.g. different type expected. */ +#define POLARSSL_ERR_X509_CERT_INVALID_VERSION -0x2200 /**< The certificate version element is invalid. */ +#define POLARSSL_ERR_X509_CERT_INVALID_SERIAL -0x2280 /**< The serial tag or value is invalid. */ +#define POLARSSL_ERR_X509_CERT_INVALID_ALG -0x2300 /**< The algorithm tag or value is invalid. */ +#define POLARSSL_ERR_X509_CERT_INVALID_NAME -0x2380 /**< The name tag or value is invalid. */ +#define POLARSSL_ERR_X509_CERT_INVALID_DATE -0x2400 /**< The date tag or value is invalid. */ +#define POLARSSL_ERR_X509_CERT_INVALID_PUBKEY -0x2480 /**< The pubkey tag or value is invalid (only RSA is supported). */ +#define POLARSSL_ERR_X509_CERT_INVALID_SIGNATURE -0x2500 /**< The signature tag or value invalid. */ +#define POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS -0x2580 /**< The extension tag or value is invalid. */ +#define POLARSSL_ERR_X509_CERT_UNKNOWN_VERSION -0x2600 /**< Certificate or CRL has an unsupported version number. */ +#define POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG -0x2680 /**< Signature algorithm (oid) is unsupported. */ +#define POLARSSL_ERR_X509_UNKNOWN_PK_ALG -0x2700 /**< Key algorithm is unsupported (only RSA is supported). */ +#define POLARSSL_ERR_X509_CERT_SIG_MISMATCH -0x2780 /**< Certificate signature algorithms do not match. (see \c ::x509_cert sig_oid) */ +#define POLARSSL_ERR_X509_CERT_VERIFY_FAILED -0x2800 /**< Certificate verification failed, e.g. CRL, CA or signature check failed. */ +#define POLARSSL_ERR_X509_KEY_INVALID_VERSION -0x2880 /**< Unsupported RSA key version */ +#define POLARSSL_ERR_X509_KEY_INVALID_FORMAT -0x2900 /**< Invalid RSA key tag or value. */ +#define POLARSSL_ERR_X509_CERT_UNKNOWN_FORMAT -0x2980 /**< Format not recognized as DER or PEM. */ +#define POLARSSL_ERR_X509_INVALID_INPUT -0x2A00 /**< Input invalid. */ +#define POLARSSL_ERR_X509_MALLOC_FAILED -0x2A80 /**< Allocation of memory failed. */ +#define POLARSSL_ERR_X509_FILE_IO_ERROR -0x2B00 /**< Read/write of file failed. */ +/* \} name */ + + +/** + * \name X509 Verify codes + * \{ + */ +#define BADCERT_EXPIRED 0x01 /**< The certificate validity has expired. */ +#define BADCERT_REVOKED 0x02 /**< The certificate has been revoked (is on a CRL). */ +#define BADCERT_CN_MISMATCH 0x04 /**< The certificate Common Name (CN) does not match with the expected CN. */ +#define BADCERT_NOT_TRUSTED 0x08 /**< The certificate is not correctly signed by the trusted CA. */ +#define BADCRL_NOT_TRUSTED 0x10 /**< CRL is not correctly signed by the trusted CA. */ +#define BADCRL_EXPIRED 0x20 /**< CRL is expired. */ +#define BADCERT_MISSING 0x40 /**< Certificate was missing. */ +#define BADCERT_SKIP_VERIFY 0x80 /**< Certificate verification was skipped. */ +/* \} name */ +/* \} addtogroup x509_module */ + +/* + * various object identifiers + */ +#define X520_COMMON_NAME 3 +#define X520_COUNTRY 6 +#define X520_LOCALITY 7 +#define X520_STATE 8 +#define X520_ORGANIZATION 10 +#define X520_ORG_UNIT 11 +#define PKCS9_EMAIL 1 + +#define X509_OUTPUT_DER 0x01 +#define X509_OUTPUT_PEM 0x02 +#define PEM_LINE_LENGTH 72 +#define X509_ISSUER 0x01 +#define X509_SUBJECT 0x02 + +#define OID_X520 "\x55\x04" +#define OID_CN OID_X520 "\x03" + +#define OID_PKCS1 "\x2A\x86\x48\x86\xF7\x0D\x01\x01" +#define OID_PKCS1_RSA OID_PKCS1 "\x01" + +#define OID_RSA_SHA_OBS "\x2B\x0E\x03\x02\x1D" + +#define OID_PKCS9 "\x2A\x86\x48\x86\xF7\x0D\x01\x09" +#define OID_PKCS9_EMAIL OID_PKCS9 "\x01" + +/** ISO arc for standard certificate and CRL extensions */ +#define OID_ID_CE "\x55\x1D" /**< id-ce OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 29} */ + +/** + * Private Internet Extensions + * { iso(1) identified-organization(3) dod(6) internet(1) + * security(5) mechanisms(5) pkix(7) } + */ +#define OID_PKIX "\x2B\x06\x01\x05\x05\x07" + +/* + * OIDs for standard certificate extensions + */ +#define OID_AUTHORITY_KEY_IDENTIFIER OID_ID_CE "\x23" /**< id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 } */ +#define OID_SUBJECT_KEY_IDENTIFIER OID_ID_CE "\x0E" /**< id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 14 } */ +#define OID_KEY_USAGE OID_ID_CE "\x0F" /**< id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } */ +#define OID_CERTIFICATE_POLICIES OID_ID_CE "\x20" /**< id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } */ +#define OID_POLICY_MAPPINGS OID_ID_CE "\x21" /**< id-ce-policyMappings OBJECT IDENTIFIER ::= { id-ce 33 } */ +#define OID_SUBJECT_ALT_NAME OID_ID_CE "\x11" /**< id-ce-subjectAltName OBJECT IDENTIFIER ::= { id-ce 17 } */ +#define OID_ISSUER_ALT_NAME OID_ID_CE "\x12" /**< id-ce-issuerAltName OBJECT IDENTIFIER ::= { id-ce 18 } */ +#define OID_SUBJECT_DIRECTORY_ATTRS OID_ID_CE "\x09" /**< id-ce-subjectDirectoryAttributes OBJECT IDENTIFIER ::= { id-ce 9 } */ +#define OID_BASIC_CONSTRAINTS OID_ID_CE "\x13" /**< id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 } */ +#define OID_NAME_CONSTRAINTS OID_ID_CE "\x1E" /**< id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 } */ +#define OID_POLICY_CONSTRAINTS OID_ID_CE "\x24" /**< id-ce-policyConstraints OBJECT IDENTIFIER ::= { id-ce 36 } */ +#define OID_EXTENDED_KEY_USAGE OID_ID_CE "\x25" /**< id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 } */ +#define OID_CRL_DISTRIBUTION_POINTS OID_ID_CE "\x1F" /**< id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= { id-ce 31 } */ +#define OID_INIHIBIT_ANYPOLICY OID_ID_CE "\x36" /**< id-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::= { id-ce 54 } */ +#define OID_FRESHEST_CRL OID_ID_CE "\x2E" /**< id-ce-freshestCRL OBJECT IDENTIFIER ::= { id-ce 46 } */ + +/* + * X.509 v3 Key Usage Extension flags + */ +#define KU_DIGITAL_SIGNATURE (0x80) /* bit 0 */ +#define KU_NON_REPUDIATION (0x40) /* bit 1 */ +#define KU_KEY_ENCIPHERMENT (0x20) /* bit 2 */ +#define KU_DATA_ENCIPHERMENT (0x10) /* bit 3 */ +#define KU_KEY_AGREEMENT (0x08) /* bit 4 */ +#define KU_KEY_CERT_SIGN (0x04) /* bit 5 */ +#define KU_CRL_SIGN (0x02) /* bit 6 */ + +/* + * X.509 v3 Extended key usage OIDs + */ +#define OID_ANY_EXTENDED_KEY_USAGE OID_EXTENDED_KEY_USAGE "\x00" /**< anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 } */ + +#define OID_KP OID_PKIX "\x03" /**< id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } */ +#define OID_SERVER_AUTH OID_KP "\x01" /**< id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } */ +#define OID_CLIENT_AUTH OID_KP "\x02" /**< id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } */ +#define OID_CODE_SIGNING OID_KP "\x03" /**< id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 } */ +#define OID_EMAIL_PROTECTION OID_KP "\x04" /**< id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 } */ +#define OID_TIME_STAMPING OID_KP "\x08" /**< id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } */ +#define OID_OCSP_SIGNING OID_KP "\x09" /**< id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } */ + +#define STRING_SERVER_AUTH "TLS Web Server Authentication" +#define STRING_CLIENT_AUTH "TLS Web Client Authentication" +#define STRING_CODE_SIGNING "Code Signing" +#define STRING_EMAIL_PROTECTION "E-mail Protection" +#define STRING_TIME_STAMPING "Time Stamping" +#define STRING_OCSP_SIGNING "OCSP Signing" + +/* + * OIDs for CRL extensions + */ +#define OID_PRIVATE_KEY_USAGE_PERIOD OID_ID_CE "\x10" +#define OID_CRL_NUMBER OID_ID_CE "\x14" /**< id-ce-cRLNumber OBJECT IDENTIFIER ::= { id-ce 20 } */ + +/* + * Netscape certificate extensions + */ +#define OID_NETSCAPE "\x60\x86\x48\x01\x86\xF8\x42" /**< Netscape OID */ +#define OID_NS_CERT OID_NETSCAPE "\x01" +#define OID_NS_CERT_TYPE OID_NS_CERT "\x01" +#define OID_NS_BASE_URL OID_NS_CERT "\x02" +#define OID_NS_REVOCATION_URL OID_NS_CERT "\x03" +#define OID_NS_CA_REVOCATION_URL OID_NS_CERT "\x04" +#define OID_NS_RENEWAL_URL OID_NS_CERT "\x07" +#define OID_NS_CA_POLICY_URL OID_NS_CERT "\x08" +#define OID_NS_SSL_SERVER_NAME OID_NS_CERT "\x0C" +#define OID_NS_COMMENT OID_NS_CERT "\x0D" +#define OID_NS_DATA_TYPE OID_NETSCAPE "\x02" +#define OID_NS_CERT_SEQUENCE OID_NS_DATA_TYPE "\x05" + +/* + * Netscape certificate types + * (http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn3.html) + */ + +#define NS_CERT_TYPE_SSL_CLIENT (0x80) /* bit 0 */ +#define NS_CERT_TYPE_SSL_SERVER (0x40) /* bit 1 */ +#define NS_CERT_TYPE_EMAIL (0x20) /* bit 2 */ +#define NS_CERT_TYPE_OBJECT_SIGNING (0x10) /* bit 3 */ +#define NS_CERT_TYPE_RESERVED (0x08) /* bit 4 */ +#define NS_CERT_TYPE_SSL_CA (0x04) /* bit 5 */ +#define NS_CERT_TYPE_EMAIL_CA (0x02) /* bit 6 */ +#define NS_CERT_TYPE_OBJECT_SIGNING_CA (0x01) /* bit 7 */ + +#define EXT_AUTHORITY_KEY_IDENTIFIER (1 << 0) +#define EXT_SUBJECT_KEY_IDENTIFIER (1 << 1) +#define EXT_KEY_USAGE (1 << 2) +#define EXT_CERTIFICATE_POLICIES (1 << 3) +#define EXT_POLICY_MAPPINGS (1 << 4) +#define EXT_SUBJECT_ALT_NAME (1 << 5) +#define EXT_ISSUER_ALT_NAME (1 << 6) +#define EXT_SUBJECT_DIRECTORY_ATTRS (1 << 7) +#define EXT_BASIC_CONSTRAINTS (1 << 8) +#define EXT_NAME_CONSTRAINTS (1 << 9) +#define EXT_POLICY_CONSTRAINTS (1 << 10) +#define EXT_EXTENDED_KEY_USAGE (1 << 11) +#define EXT_CRL_DISTRIBUTION_POINTS (1 << 12) +#define EXT_INIHIBIT_ANYPOLICY (1 << 13) +#define EXT_FRESHEST_CRL (1 << 14) + +#define EXT_NS_CERT_TYPE (1 << 16) + +/* + * Storage format identifiers + * Recognized formats: PEM and DER + */ +#define X509_FORMAT_DER 1 +#define X509_FORMAT_PEM 2 + +/** + * \addtogroup x509_module + * \{ */ + +/** + * \name Structures for parsing X.509 certificates and CRLs + * \{ + */ + +/** + * Type-length-value structure that allows for ASN1 using DER. + */ +typedef asn1_buf x509_buf; + +/** + * Container for ASN1 bit strings. + */ +typedef asn1_bitstring x509_bitstring; + +/** + * Container for ASN1 named information objects. + * It allows for Relative Distinguished Names (e.g. cn=polarssl,ou=code,etc.). + */ +typedef struct _x509_name +{ + x509_buf oid; /**< The object identifier. */ + x509_buf val; /**< The named value. */ + struct _x509_name *next; /**< The next named information object. */ +} +x509_name; + +/** + * Container for a sequence of ASN.1 items + */ +typedef asn1_sequence x509_sequence; + +/** Container for date and time (precision in seconds). */ +typedef struct _x509_time +{ + int year, mon, day; /**< Date. */ + int hour, min, sec; /**< Time. */ +} +x509_time; + +/** + * Container for an X.509 certificate. The certificate may be chained. + */ +typedef struct _x509_cert +{ + x509_buf raw; /**< The raw certificate data (DER). */ + x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */ + + int version; /**< The X.509 version. (0=v1, 1=v2, 2=v3) */ + x509_buf serial; /**< Unique id for certificate issued by a specific CA. */ + x509_buf sig_oid1; /**< Signature algorithm, e.g. sha1RSA */ + + x509_buf issuer_raw; /**< The raw issuer data (DER). Used for quick comparison. */ + x509_buf subject_raw; /**< The raw subject data (DER). Used for quick comparison. */ + + x509_name issuer; /**< The parsed issuer data (named information object). */ + x509_name subject; /**< The parsed subject data (named information object). */ + + x509_time valid_from; /**< Start time of certificate validity. */ + x509_time valid_to; /**< End time of certificate validity. */ + + x509_buf pk_oid; /**< Subject public key info. Includes the public key algorithm and the key itself. */ + rsa_context rsa; /**< Container for the RSA context. Only RSA is supported for public keys at this time. */ + + x509_buf issuer_id; /**< Optional X.509 v2/v3 issuer unique identifier. */ + x509_buf subject_id; /**< Optional X.509 v2/v3 subject unique identifier. */ + x509_buf v3_ext; /**< Optional X.509 v3 extensions. Only Basic Contraints are supported at this time. */ + + int ext_types; /**< Bit string containing detected and parsed extensions */ + int ca_istrue; /**< Optional Basic Constraint extension value: 1 if this certificate belongs to a CA, 0 otherwise. */ + int max_pathlen; /**< Optional Basic Constraint extension value: The maximum path length to the root certificate. */ + + unsigned char key_usage; /**< Optional key usage extension value: See the values below */ + + x509_sequence ext_key_usage; /**< Optional list of extended key usage OIDs. */ + + unsigned char ns_cert_type; /**< Optional Netscape certificate type extension value: See the values below */ + + x509_buf sig_oid2; /**< Signature algorithm. Must match sig_oid1. */ + x509_buf sig; /**< Signature: hash of the tbs part signed with the private key. */ + int sig_alg; /**< Internal representation of the signature algorithm, e.g. SIG_RSA_MD2 */ + + struct _x509_cert *next; /**< Next certificate in the CA-chain. */ +} +x509_cert; + +/** + * Certificate revocation list entry. + * Contains the CA-specific serial numbers and revocation dates. + */ +typedef struct _x509_crl_entry +{ + x509_buf raw; + + x509_buf serial; + + x509_time revocation_date; + + x509_buf entry_ext; + + struct _x509_crl_entry *next; +} +x509_crl_entry; + +/** + * Certificate revocation list structure. + * Every CRL may have multiple entries. + */ +typedef struct _x509_crl +{ + x509_buf raw; /**< The raw certificate data (DER). */ + x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */ + + int version; + x509_buf sig_oid1; + + x509_buf issuer_raw; /**< The raw issuer data (DER). */ + + x509_name issuer; /**< The parsed issuer data (named information object). */ + + x509_time this_update; + x509_time next_update; + + x509_crl_entry entry; /**< The CRL entries containing the certificate revocation times for this CA. */ + + x509_buf crl_ext; + + x509_buf sig_oid2; + x509_buf sig; + int sig_alg; + + struct _x509_crl *next; +} +x509_crl; +/** \} name Structures for parsing X.509 certificates and CRLs */ +/** \} addtogroup x509_module */ + +/** + * \name Structures for writing X.509 certificates. + * XvP: commented out as they are not used. + * - <tt>typedef struct _x509_node x509_node;</tt> + * - <tt>typedef struct _x509_raw x509_raw;</tt> + */ +/* +typedef struct _x509_node +{ + unsigned char *data; + unsigned char *p; + unsigned char *end; + + size_t len; +} +x509_node; + +typedef struct _x509_raw +{ + x509_node raw; + x509_node tbs; + + x509_node version; + x509_node serial; + x509_node tbs_signalg; + x509_node issuer; + x509_node validity; + x509_node subject; + x509_node subpubkey; + + x509_node signalg; + x509_node sign; +} +x509_raw; +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name Functions to read in DHM parameters, a certificate, CRL or private RSA key + * \{ + */ + +/** \ingroup x509_module */ +/** + * \brief Parse one or more certificates and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param buf buffer holding the certificate data + * \param buflen size of the buffer + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int x509parse_crt( x509_cert *chain, const unsigned char *buf, size_t buflen ); + +/** \ingroup x509_module */ +/** + * \brief Load one or more certificates and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param path filename to read the certificates from + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int x509parse_crtfile( x509_cert *chain, const char *path ); + +/** \ingroup x509_module */ +/** + * \brief Parse one or more CRLs and add them + * to the chained list + * + * \param chain points to the start of the chain + * \param buf buffer holding the CRL data + * \param buflen size of the buffer + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_crl( x509_crl *chain, const unsigned char *buf, size_t buflen ); + +/** \ingroup x509_module */ +/** + * \brief Load one or more CRLs and add them + * to the chained list + * + * \param chain points to the start of the chain + * \param path filename to read the CRLs from + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_crlfile( x509_crl *chain, const char *path ); + +/** \ingroup x509_module */ +/** + * \brief Parse a private RSA key + * + * \param rsa RSA context to be initialized + * \param key input buffer + * \param keylen size of the buffer + * \param pwd password for decryption (optional) + * \param pwdlen size of the password + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_key( rsa_context *rsa, + const unsigned char *key, size_t keylen, + const unsigned char *pwd, size_t pwdlen ); + +/** \ingroup x509_module */ +/** + * \brief Load and parse a private RSA key + * + * \param rsa RSA context to be initialized + * \param path filename to read the private key from + * \param password password to decrypt the file (can be NULL) + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_keyfile( rsa_context *rsa, const char *path, + const char *password ); + +/** \ingroup x509_module */ +/** + * \brief Parse a public RSA key + * + * \param rsa RSA context to be initialized + * \param key input buffer + * \param keylen size of the buffer + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_public_key( rsa_context *rsa, + const unsigned char *key, size_t keylen ); + +/** \ingroup x509_module */ +/** + * \brief Load and parse a public RSA key + * + * \param rsa RSA context to be initialized + * \param path filename to read the private key from + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_public_keyfile( rsa_context *rsa, const char *path ); + +/** \ingroup x509_module */ +/** + * \brief Parse DHM parameters + * + * \param dhm DHM context to be initialized + * \param dhmin input buffer + * \param dhminlen size of the buffer + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_dhm( dhm_context *dhm, const unsigned char *dhmin, size_t dhminlen ); + +/** \ingroup x509_module */ +/** + * \brief Load and parse DHM parameters + * + * \param dhm DHM context to be initialized + * \param path filename to read the DHM Parameters from + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_dhmfile( dhm_context *dhm, const char *path ); + +/** \} name Functions to read in DHM parameters, a certificate, CRL or private RSA key */ + +/** + * \brief Store the certificate DN in printable form into buf; + * no more than size characters will be written. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param dn The X509 name to represent + * + * \return The amount of data written to the buffer, or -1 in + * case of an error. + */ +int x509parse_dn_gets( char *buf, size_t size, const x509_name *dn ); + +/** + * \brief Store the certificate serial in printable form into buf; + * no more than size characters will be written. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param serial The X509 serial to represent + * + * \return The amount of data written to the buffer, or -1 in + * case of an error. + */ +int x509parse_serial_gets( char *buf, size_t size, const x509_buf *serial ); + +/** + * \brief Returns an informational string about the + * certificate. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param crt The X509 certificate to represent + * + * \return The amount of data written to the buffer, or -1 in + * case of an error. + */ +int x509parse_cert_info( char *buf, size_t size, const char *prefix, + const x509_cert *crt ); + +/** + * \brief Returns an informational string about the + * CRL. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param crl The X509 CRL to represent + * + * \return The amount of data written to the buffer, or -1 in + * case of an error. + */ +int x509parse_crl_info( char *buf, size_t size, const char *prefix, + const x509_crl *crl ); + +/** + * \brief Give an known OID, return its descriptive string. + * + * \param oid buffer containing the oid + * + * \return Return a string if the OID is known, + * or NULL otherwise. + */ +const char *x509_oid_get_description( x509_buf *oid ); + +/* + * \brief Give an OID, return a string version of its OID number. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param oid Buffer containing the OID + * + * \return The amount of data written to the buffer, or -1 in + * case of an error. + */ +int x509_oid_get_numeric_string( char *buf, size_t size, x509_buf *oid ); + +/** + * \brief Check a given x509_time against the system time and check + * if it is valid. + * + * \param time x509_time to check + * + * \return Return 0 if the x509_time is still valid, + * or 1 otherwise. + */ +int x509parse_time_expired( const x509_time *time ); + +/** + * \name Functions to verify a certificate + * \{ + */ +/** \ingroup x509_module */ +/** + * \brief Verify the certificate signature + * + * \param crt a certificate to be verified + * \param trust_ca the trusted CA chain + * \param ca_crl the CRL chain for trusted CA's + * \param cn expected Common Name (can be set to + * NULL if the CN must not be verified) + * \param flags result of the verification + * \param f_vrfy verification function + * \param p_vrfy verification parameter + * + * \return 0 if successful or POLARSSL_ERR_X509_SIG_VERIFY_FAILED, + * in which case *flags will have one or more of + * the following values set: + * BADCERT_EXPIRED -- + * BADCERT_REVOKED -- + * BADCERT_CN_MISMATCH -- + * BADCERT_NOT_TRUSTED + * + * \note TODO: add two arguments, depth and crl + */ +int x509parse_verify( x509_cert *crt, + x509_cert *trust_ca, + x509_crl *ca_crl, + const char *cn, int *flags, + int (*f_vrfy)(void *, x509_cert *, int, int), + void *p_vrfy ); + +/** + * \brief Verify the certificate signature + * + * \param crt a certificate to be verified + * \param crl the CRL to verify against + * + * \return 1 if the certificate is revoked, 0 otherwise + * + */ +int x509parse_revoked( const x509_cert *crt, const x509_crl *crl ); + +/** \} name Functions to verify a certificate */ + + + +/** + * \name Functions to clear a certificate, CRL or private RSA key + * \{ + */ +/** \ingroup x509_module */ +/** + * \brief Unallocate all certificate data + * + * \param crt Certificate chain to free + */ +void x509_free( x509_cert *crt ); + +/** \ingroup x509_module */ +/** + * \brief Unallocate all CRL data + * + * \param crl CRL chain to free + */ +void x509_crl_free( x509_crl *crl ); + +/** \} name Functions to clear a certificate, CRL or private RSA key */ + + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int x509_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* x509.h */ diff --git a/ANDROID_3.4.5/drivers/misc/viatel/Kconfig b/ANDROID_3.4.5/drivers/misc/viatel/Kconfig new file mode 100755 index 00000000..a341da3f --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/viatel/Kconfig @@ -0,0 +1,14 @@ +menu "Viatelecom OEM funtion support" + +config VIATELECOM_SYNC_CBP + bool "Ap Sync Cbp" + help + The synchronous mechanism for the data exchage between Ap and Cbp. + +config VIATELECOM_POWER_CBP + bool "AP Power Cbp" + help + Enable this driver to support to control funtion such as reset, power + between AP and Cbp. + +endmenu diff --git a/ANDROID_3.4.5/drivers/misc/viatel/Makefile b/ANDROID_3.4.5/drivers/misc/viatel/Makefile new file mode 100755 index 00000000..fe30dd44 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/viatel/Makefile @@ -0,0 +1,3 @@ +obj-y += core.o oem.o sync.o # cp_reset.o +obj-$(CONFIG_VIATELECOM_SYNC_CBP) += sync.o +obj-$(CONFIG_VIATELECOM_POWER_CBP) += power.o diff --git a/ANDROID_3.4.5/drivers/misc/viatel/core.c b/ANDROID_3.4.5/drivers/misc/viatel/core.c new file mode 100755 index 00000000..d06d7a48 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/viatel/core.c @@ -0,0 +1,49 @@ +/* + * core.c + * + * VIA CBP driver for Linux + * + * Copyright (C) 2011 VIA TELECOM Corporation, Inc. + * Author: VIA TELECOM Corporation, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/wait.h> +#include <linux/platform_device.h> + +static struct kobject *viatel_kobj; + +struct kobject *viatel_kobject_add(const char *name) +{ + struct kobject *kobj = NULL; + if(viatel_kobj){ + kobj = kobject_create_and_add(name, viatel_kobj); + } + + return kobj; +} + +static int __init viatel_core_init(void) +{ + int ret = 0; + viatel_kobj = kobject_create_and_add("viatel", NULL); + if (!viatel_kobj){ + ret = -ENOMEM; + goto err_create_kobj; + } +err_create_kobj: + return ret; +} + +arch_initcall(viatel_core_init); diff --git a/ANDROID_3.4.5/drivers/misc/viatel/core.h b/ANDROID_3.4.5/drivers/misc/viatel/core.h new file mode 100755 index 00000000..d6d323cc --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/viatel/core.h @@ -0,0 +1,21 @@ +/* + * core.h + * + * VIA CBP driver for Linux + * + * Copyright (C) 2011 VIA TELECOM Corporation, Inc. + * Author: VIA TELECOM Corporation, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#ifndef VIATEL_CORE_H +#define VIATEL_CORE_H + +extern struct kobject *viatel_kobject_add(const char *name); +#endif diff --git a/ANDROID_3.4.5/drivers/misc/viatel/oem.c b/ANDROID_3.4.5/drivers/misc/viatel/oem.c new file mode 100755 index 00000000..105c4d7d --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/viatel/oem.c @@ -0,0 +1,752 @@ +/* + * viatel_cbp_oem.c + * + * VIA CBP driver for Linux + * + * Copyright (C) 2011 VIA TELECOM Corporation, Inc. + * Author: VIA TELECOM Corporation, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include <linux/interrupt.h> +#include <mach/viatel.h> +#include <linux/gpio.h> +#include <mach/wmt_iomux.h> +#include <mach/hardware.h> +#include "linux/delay.h" + +#if 1 + +//#define VIATEL_DEBUG +#ifdef VIATEL_DEBUG +#define wmt_dbg(fmt, arg...) printk(fmt, ##arg) +#else +#define wmt_dbg(fmt, arg...) +#endif + +int isviatelcom = 0; +int wk1_high_active = 0; +int gpio_viatel_4wire[4]; +int ap_ready_always = 0; +unsigned int wakeup_reg_val; +unsigned int wakeup_shift_bit; +int wakeup_type_mask; + +extern int wmt_getsyspara(char *varname, char *varval, int *varlen); + +int oem_gpio_convert_init(void){ + char buf[256]; + int varlen = 256; + if( wmt_getsyspara("wmt.modem.viatel.4wire",buf,&varlen) == 0) + { + sscanf(buf,"%d:%d:%d:%d",&gpio_viatel_4wire[GPIO_VIATEL_USB_AP_RDY], + &gpio_viatel_4wire[GPIO_VIATEL_USB_MDM_RDY], + &gpio_viatel_4wire[GPIO_VIATEL_USB_AP_WAKE_MDM], + &gpio_viatel_4wire[GPIO_VIATEL_USB_MDM_WAKE_AP]); + + printk("4wire %d:%d:%d:%d\n",gpio_viatel_4wire[GPIO_VIATEL_USB_AP_RDY], + gpio_viatel_4wire[GPIO_VIATEL_USB_MDM_RDY], + gpio_viatel_4wire[GPIO_VIATEL_USB_AP_WAKE_MDM], + gpio_viatel_4wire[GPIO_VIATEL_USB_MDM_WAKE_AP]); + + isviatelcom = 1; + printk("disable wakeup1 %s %d\n",__FUNCTION__,__LINE__); + + + if(gpio_viatel_4wire[GPIO_VIATEL_USB_MDM_WAKE_AP]==149){ + wakeup_reg_val=0x1L; + wakeup_shift_bit = 0; + wakeup_type_mask = 0xfffffff8; + }else{ + wakeup_reg_val=0x4L; + wakeup_shift_bit = 8; + wakeup_type_mask = 0xfffff8ff; + } + + + PMCIE_VAL &=(~wakeup_reg_val); + INT_TRG_EN_VAL&=(~wakeup_reg_val); + + if(wmt_getsyspara("wmt.modem.viatel.aprdy",buf,&varlen) == 0){ + sscanf(buf,"%d",&ap_ready_always); + }else{ + ap_ready_always = 0;/* default value */ + } + + return 0; + } + + return -1; +} + +int oem_gpio_request(int gpio, const char *label) +{ + wmt_dbg("%s index=%d gpio=%d\n",__FUNCTION__,gpio,gpio_viatel_4wire[gpio]); + gpio_request(gpio_viatel_4wire[gpio], label); + return 0; +} + +void oem_gpio_free(int gpio) +{ + wmt_dbg("%s index=%d gpio=%d\n",__FUNCTION__,gpio,gpio_viatel_4wire[gpio]); + gpio_free(gpio_viatel_4wire[gpio]); + return ; +} + +/*config the gpio to be input for irq if the SOC need*/ +int oem_gpio_direction_input_for_irq(int gpio) +{ + if(!isviatelcom) + return 0; + wmt_dbg("%s index=%d gpio=%d\n",__FUNCTION__,gpio,gpio_viatel_4wire[gpio]); + + wmt_gpio_setpull(gpio_viatel_4wire[gpio], WMT_GPIO_PULL_DOWN); + gpio_direction_input(gpio_viatel_4wire[gpio]); + gpio_re_enabled(gpio_viatel_4wire[gpio]); + + return 0; +} + +int oem_gpio_direction_output(int gpio, int value) +{ + if(!isviatelcom) + return 0; + wmt_dbg("%s index=%d gpio=%d\n",__FUNCTION__,gpio,gpio_viatel_4wire[gpio]); + if(ap_ready_always&&(gpio == GPIO_VIATEL_USB_AP_RDY)) + return 0; + + + gpio_re_enabled(gpio_viatel_4wire[gpio]); + gpio_direction_output(gpio_viatel_4wire[gpio], value); + + return 0; +} + +int oem_gpio_output(int gpio, int value) +{ + if(!isviatelcom) + return 0; + wmt_dbg("%s index=%d gpio=%d\n",__FUNCTION__,gpio,gpio_viatel_4wire[gpio]); + + gpio_re_enabled(gpio_viatel_4wire[gpio]); + gpio_direction_output(gpio_viatel_4wire[gpio], value); + + return 0; +} + +int oem_gpio_is_wakeup(int gpio) +{ + if(gpio==149||gpio==152) //wekup0 gpio index WMT_PIN_GP62_WAKEUP0 + return 1; + else + return 0; +} + + +/* + * Get the output level if the gpio is output type; + * Get the input level if the gpio is input type + */ +int oem_gpio_get_value(int gpio) +{ + int rtn; + if(!isviatelcom) + return 0; + wmt_gpio_setpull(gpio_viatel_4wire[gpio], WMT_GPIO_PULL_DOWN); + gpio_direction_input(gpio_viatel_4wire[gpio]); + gpio_re_enabled(gpio_viatel_4wire[gpio]); + rtn = __gpio_get_value(gpio_viatel_4wire[gpio]); + wmt_dbg("%s index=%d gpio=%d,rtn=%d\n",__FUNCTION__,gpio,gpio_viatel_4wire[gpio],rtn); + if(oem_gpio_is_wakeup(gpio_viatel_4wire[gpio])&&(!wk1_high_active)) + return !rtn; + else + return rtn; +} + + + + +int oem_gpio_to_irq(int gpio) +{ + wmt_dbg("%s index=%d gpio=%d\n",__FUNCTION__,gpio,gpio_viatel_4wire[gpio]); + return IRQ_GPIO; +} + +/* + * Set the irq type of the pin. + * Get the pin level and set the correct edge if the type is both edge and + * the SOC do not support both edge detection at one time + */ +int oem_gpio_set_irq_type(int gpio, unsigned int type) +{ + if(!isviatelcom) + return 0; + + wmt_dbg("%s index=%d gpio=%d\n",__FUNCTION__,gpio,gpio_viatel_4wire[gpio]); + if(oem_gpio_is_wakeup(gpio_viatel_4wire[gpio])){ + int wakeup_type; + if(type==IRQF_TRIGGER_RISING){ + if(wk1_high_active) + wakeup_type=(0x3<<wakeup_shift_bit); + else + wakeup_type=(0x2<<wakeup_shift_bit); + } + else if(type==(IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) + wakeup_type=(0x4<<wakeup_shift_bit); + else{ + printk("\n\n\n\n\n=======oem_gpio_set_irq_type error\n\n\n\n\n\n"); + return 0; + } + + INT_TYPE0_VAL = (INT_TYPE0_VAL&wakeup_type_mask)|wakeup_type; + return 0; + } + + if(type < IRQF_TRIGGER_NONE ||type >=IRQF_TRIGGER_HIGH) + printk("error %s %d gpio %d type 0x%x\n",__FUNCTION__,__LINE__,gpio_viatel_4wire[gpio],type); + return wmt_gpio_set_irq_type(gpio_viatel_4wire[gpio], type); +} + + +int oem_gpio_request_irq(int gpio, irq_handler_t handler, unsigned long flags, + const char *name, void *dev) +{ + if(!isviatelcom) + return 0; + wmt_dbg("%s index=%d gpio=%d\n",__FUNCTION__,gpio,gpio_viatel_4wire[gpio]); + if(oem_gpio_is_wakeup(gpio_viatel_4wire[gpio])) + return 0; + + return request_irq(oem_gpio_to_irq(gpio), handler, flags, name, dev); +} + +void oem_gpio_irq_mask(int gpio) +{ + if(!isviatelcom) + return ; + + wmt_dbg("%s index=%d gpio=%d\n",__FUNCTION__,gpio,gpio_viatel_4wire[gpio]); + if(oem_gpio_is_wakeup(gpio_viatel_4wire[gpio])){ + PMCIE_VAL &=(~wakeup_reg_val); + INT_TRG_EN_VAL&=(~wakeup_reg_val); + return ; + } + + wmt_gpio_mask_irq(gpio_viatel_4wire[gpio]); + + return ; +} +void oem_gpio_irq_unmask(int gpio) +{ + if(!isviatelcom) + return; + + wmt_dbg("%s index=%d gpio=%d\n",__FUNCTION__,gpio,gpio_viatel_4wire[gpio]); + if(oem_gpio_is_wakeup(gpio_viatel_4wire[gpio])){ + int i; + for(i=0;i<100;i++){ + PMCIE_VAL |=wakeup_reg_val; + INT_TRG_EN_VAL|=wakeup_reg_val; + if(PMCIE_VAL&wakeup_reg_val){ + break; + } + printk("PMCIE_VAL set error %x,retry %d\n", PMCIE_VAL,i); + mdelay(10); + } + return ; + } + + wmt_gpio_unmask_irq(gpio_viatel_4wire[gpio]); + + return ; +} + +int oem_gpio_irq_isenable(int gpio){ + if(!isviatelcom) + return 0; + + if(oem_gpio_is_wakeup(gpio_viatel_4wire[gpio])) + return 1; + + return is_gpio_irqenable(gpio_viatel_4wire[gpio]); +} + +int oem_gpio_irq_isint(int gpio){ + if(!isviatelcom) + return 0; + + if(oem_gpio_is_wakeup(gpio_viatel_4wire[gpio])) + return 1; + + return gpio_irqstatus(gpio_viatel_4wire[gpio]); + +} +int oem_gpio_irq_clear(int gpio){ + if(!isviatelcom) + return 1; + + if(oem_gpio_is_wakeup(gpio_viatel_4wire[gpio])) + return 0; + + wmt_gpio_ack_irq(gpio_viatel_4wire[gpio]); + + return 0; +} + +#endif +#if 0 + +#if defined(CONFIG_MACH_OMAP_KUNLUN) +int oem_gpio_request(int gpio, const char *label) +{ + return gpio_request(gpio, label); +} + +void oem_gpio_free(int gpio) +{ + gpio_free(gpio); +} + +/*config the gpio to be input for irq if the SOC need*/ +int oem_gpio_direction_input_for_irq(int gpio) +{ + return gpio_direction_input(gpio); +} + +int oem_gpio_direction_output(int gpio, int value) +{ + return gpio_direction_output(gpio, value); +} + +/* + * Get the output level if the gpio is output type; + * Get the input level if the gpio is input type + */ +int oem_gpio_get_value(int gpio) +{ + return gpio_get_value(gpio); +} + +int oem_gpio_to_irq(int gpio) +{ + return gpio_to_irq(gpio); +} + +/* + * Set the irq type of the pin. + * Get the pin level and set the correct edge if the type is both edge and + * the SOC do not support both edge detection at one time + */ +int oem_gpio_set_irq_type(unsigned gpio, unsigned int type) +{ + return set_irq_type(oem_gpio_to_irq(gpio), type); +} + + +int oem_gpio_request_irq(int gpio, irq_handler_t handler, unsigned long flags, + const char *name, void *dev) +{ + return request_irq(oem_gpio_to_irq(gpio), handler, flags, name, dev); +} + +void oem_gpio_irq_mask(int gpio) +{ + return ; +} + +void oem_gpio_irq_unmask(int gpio) +{ + return ; +} + + + +#endif + +#if defined(CONFIG_SOC_JZ4770) +int oem_gpio_request(int gpio, const char *label) +{ + return gpio_request(gpio, label); +} + +void oem_gpio_free(int gpio) +{ + gpio_free(gpio); +} + +/*config the gpio to be input for irq if the SOC need*/ +int oem_gpio_direction_input_for_irq(int gpio) +{ + return 0; +} + +int oem_gpio_direction_output(int gpio, int value) +{ + return gpio_direction_output(gpio, value); +} + +/* + * Get the output level if the gpio is output type; + * Get the input level if the gpio is input type + */ +int oem_gpio_get_value(int gpio) +{ + return gpio_get_value(gpio); +} + +int oem_gpio_to_irq(int gpio) +{ + return gpio_to_irq(gpio); +} + +#define GPIO_DEBOUNCE (3) +int read_gpio_pin(int pin) +{ + int t, v; + int i; + + i = GPIO_DEBOUNCE; + + v = t = 0; + + while (i--) { + t = __gpio_get_pin(pin); + if (v != t) + i = GPIO_DEBOUNCE; + + v = t; + ndelay(100); + } + + return v; +} + +int oem_gpio_set_irq_type(int gpio, unsigned int type) +{ + if(type == IRQ_TYPE_EDGE_BOTH){ + if(read_gpio_pin(gpio)){ + type = IRQ_TYPE_EDGE_FALLING; + }else{ + type = IRQ_TYPE_EDGE_RISING; + } + } + + if(type == IRQ_TYPE_LEVEL_MASK){ + if(read_gpio_pin(gpio)){ + type = IRQ_TYPE_LEVEL_LOW; + }else{ + type = IRQ_TYPE_LEVEL_HIGH; + } + } + + switch(type){ + case IRQ_TYPE_EDGE_RISING: + __gpio_as_irq_rise_edge(gpio); + break; + case IRQ_TYPE_EDGE_FALLING: + __gpio_as_irq_fall_edge(gpio); + break; + case IRQ_TYPE_LEVEL_HIGH: + __gpio_as_irq_high_level(gpio); + break; + case IRQ_TYPE_LEVEL_LOW: + __gpio_as_irq_low_level(gpio); + break; + default: + return -EINVAL; + } + + return 0; +} + +int oem_gpio_request_irq(int gpio, irq_handler_t handler, unsigned long flags, + const char *name, void *dev) +{ + int ret = request_irq(oem_gpio_to_irq(gpio), handler, flags, name, dev); + enable_irq_wake(oem_gpio_to_irq(gpio)); + return ret; +} + +void oem_gpio_irq_mask(int gpio) +{ + return ; +} + +void oem_gpio_irq_unmask(int gpio) +{ + return ; +} +#endif + +#if defined(EVDO_DT_SUPPORT) +#include <linux/interrupt.h> +int oem_gpio_request(int gpio, const char *label) +{ + return 0; +} + +void oem_gpio_free(int gpio) +{ + return ; +} + +/*config the gpio to be input for irq if the SOC need*/ +int oem_gpio_direction_input_for_irq(int gpio) +{ + mt_set_gpio_mode(gpio, GPIO_MODE_02); + mt_set_gpio_dir(gpio, GPIO_DIR_IN); + return 0; +} + +int oem_gpio_direction_output(int gpio, int value) +{ + mt_set_gpio_mode(gpio, GPIO_MODE_GPIO); + mt_set_gpio_dir(gpio, GPIO_DIR_OUT); + mt_set_gpio_out(gpio, !!value); + return 0; +} + +int oem_gpio_get_value(int gpio) +{ + if(GPIO_DIR_IN == mt_get_gpio_dir(gpio)){ + return mt_get_gpio_in(gpio); + }else{ + return mt_get_gpio_out(gpio); + } +} + +typedef struct mtk_oem_gpio_des{ + int gpio; + int irq; + void (*redirect)(void); + irq_handler_t handle; + void *data; +}mtk_oem_gpio_des; + +static void gpio_irq_handle_usb_mdm_rdy(void); +static void gpio_irq_handle_usb_mdm_wake_ap(void); +static void gpio_irq_handle_uart_mdm_wake_ap(void); +static void gpio_irq_handle_rst_ind(void); +static void gpio_irq_handle_pwr_ind(void); + +mtk_oem_gpio_des oem_gpio_list[] = { + {GPIO_VIATEL_USB_MDM_RDY, 4, gpio_irq_handle_usb_mdm_rdy, NULL, NULL}, + {GPIO_VIATEL_USB_MDM_WAKE_AP, 29, gpio_irq_handle_usb_mdm_wake_ap, NULL, NULL}, + {GPIO_VIATEL_MDM_RST_IND, 28, gpio_irq_handle_rst_ind, NULL, NULL}, + {GPIO_VIATEL_UART_MDM_WAKE_AP, 27, gpio_irq_handle_uart_mdm_wake_ap, NULL, NULL}, + {GPIO_VIATEL_MDM_PWR_IND, 27, gpio_irq_handle_pwr_ind, NULL, NULL}, +}; + +static mtk_oem_gpio_des* gpio_des_find_by_gpio(int gpio) +{ + int i = 0; + mtk_oem_gpio_des *des = NULL; + + if(gpio < 0){ + return NULL; + } + + for(i=0; i < sizeof(oem_gpio_list) / sizeof(mtk_oem_gpio_des); i++){ + des = oem_gpio_list + i; + if(des->gpio == gpio){ + return des; + } + } + + return NULL; +} + +static mtk_oem_gpio_des* gpio_des_find_by_irq(int irq) +{ + int i = 0; + mtk_oem_gpio_des *des = NULL; + + for(i=0; i < sizeof(oem_gpio_list) / sizeof(mtk_oem_gpio_des); i++){ + des = oem_gpio_list + i; + if(des->irq == irq){ + return des; + } + } + + return NULL; +} +static void gpio_irq_handle_usb_mdm_rdy(void) +{ + int irq = 0; + mtk_oem_gpio_des *des = NULL; + + des = gpio_des_find_by_gpio(GPIO_VIATEL_USB_MDM_RDY); + if(des && des->handle){ + des->handle(des->irq, des->data); + } +} +static void gpio_irq_handle_usb_mdm_wake_ap(void) +{ + int irq = 0; + mtk_oem_gpio_des *des = NULL; + + des = gpio_des_find_by_gpio(GPIO_VIATEL_USB_MDM_WAKE_AP); + if(des && des->handle){ + des->handle(des->irq, des->data); + } +} + +static void gpio_irq_handle_uart_mdm_wake_ap(void) +{ + int irq = 0; + mtk_oem_gpio_des *des = NULL; + + des = gpio_des_find_by_gpio(GPIO_VIATEL_UART_MDM_WAKE_AP); + if(des && des->handle){ + des->handle(des->irq, des->data); + } +} + +static void gpio_irq_handle_rst_ind(void) +{ + int irq = 0; + mtk_oem_gpio_des *des = NULL; + + des = gpio_des_find_by_gpio(GPIO_VIATEL_MDM_RST_IND); + if(des && des->handle){ + des->handle(des->irq, des->data); + } +} +static void gpio_irq_handle_pwr_ind(void) +{ + int irq = 0; + mtk_oem_gpio_des *des = NULL; + + des = gpio_des_find_by_gpio(GPIO_VIATEL_MDM_PWR_IND); + if(des && des->handle){ + des->handle(des->irq, des->data); + } +} + +int oem_gpio_to_irq(int gpio) +{ + mtk_oem_gpio_des *des = NULL; + + des = gpio_des_find_by_gpio(gpio); + if(NULL == des){ + printk("%s: no irq for gpio %d\n", __FUNCTION__, gpio); + return -1; + }else{ + return des->irq; + } +} + +int oem_irq_to_gpio(int irq) +{ + mtk_oem_gpio_des *des = NULL; + + des = gpio_des_find_by_irq(irq); + if(NULL == des){ + printk("%s: no gpio for irq %d\n", __FUNCTION__, irq); + return -1; + }else{ + return des->gpio; + } +} + +int oem_gpio_set_irq_type(int gpio, unsigned int type) +{ + int irq, level; + + irq = oem_gpio_to_irq(gpio); + if(irq < 0){ + return irq; + } + + level = oem_gpio_get_value(gpio); + + if(type == IRQ_TYPE_EDGE_BOTH){ + if(level){ + type = IRQ_TYPE_EDGE_FALLING; + }else{ + type = IRQ_TYPE_EDGE_RISING; + } + } + + if(type == IRQ_TYPE_LEVEL_MASK){ + if(level){ + type = IRQ_TYPE_LEVEL_LOW; + }else{ + type = IRQ_TYPE_LEVEL_HIGH; + } + } + + mt65xx_eint_set_hw_debounce(irq, 3); + switch(type){ + case IRQ_TYPE_EDGE_RISING: + mt65xx_eint_set_sens(irq, MT65xx_EDGE_SENSITIVE); + mt65xx_eint_set_polarity(irq, MT65xx_POLARITY_HIGH); + break; + case IRQ_TYPE_EDGE_FALLING: + mt65xx_eint_set_sens(irq, MT65xx_EDGE_SENSITIVE); + mt65xx_eint_set_polarity(irq, MT65xx_POLARITY_LOW); + break; + case IRQ_TYPE_LEVEL_HIGH: + mt65xx_eint_set_sens(irq, MT65xx_LEVEL_SENSITIVE); + mt65xx_eint_set_polarity(irq, MT65xx_POLARITY_HIGH); + break; + case IRQ_TYPE_LEVEL_LOW: + mt65xx_eint_set_sens(irq, MT65xx_LEVEL_SENSITIVE); + mt65xx_eint_set_polarity(irq, MT65xx_POLARITY_LOW); + break; + default: + return -EINVAL; + } + + return 0; +} + +int oem_gpio_request_irq(int gpio, irq_handler_t handler, unsigned long flags, + const char *name, void *dev) +{ + mtk_oem_gpio_des *des = NULL; + + des = gpio_des_find_by_gpio(gpio); + if(des == NULL){ + return -1; + } + des->data = dev; + des->handle = handler; + + mt65xx_eint_registration(des->irq, 1, 1, des->redirect, 0); + + return 0; +} + +void oem_gpio_irq_mask(int gpio) +{ + int irq; + + irq = oem_gpio_to_irq(gpio); + if(irq < 0){ + return ; + } + + mt65xx_eint_mask(irq); +} + +void oem_gpio_irq_unmask(int gpio) +{ + int irq; + + irq = oem_gpio_to_irq(gpio); + if(irq < 0){ + return ; + } + + mt65xx_eint_unmask(irq); +} +#endif +#endif diff --git a/ANDROID_3.4.5/drivers/misc/viatel/power.c b/ANDROID_3.4.5/drivers/misc/viatel/power.c new file mode 100755 index 00000000..0fc22cb3 --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/viatel/power.c @@ -0,0 +1,340 @@ +/* + * viatel_cbp_power.c + * + * VIA CBP driver for Linux + * + * Copyright (C) 2009 VIA TELECOM Corporation, Inc. + * Author: VIA TELECOM Corporation, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include <linux/ctype.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/irq.h> +#include <linux/wakelock.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <mach/viatel.h> +#include "core.h" + +#define MDM_RST_LOCK_TIME (120) +#define MDM_RST_HOLD_DELAY (100) //ms +#define MDM_PWR_HOLD_DELAY (500) //ms + +//#define VIA_AP_MODEM_DEBU +#ifdef VIA_AP_MODEM_DEBUG +#undef dbg +#define dbg(format, arg...) printk("[CBP_POWER]: " format "\n" , ## arg) +#else +#undef dbg +#define dbg(format, arg...) do {} while (0) +#endif + +static struct wake_lock reset_lock; + +void oem_power_off_modem(void) +{ + if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_PWR_EN)){ + oem_gpio_direction_output(GPIO_VIATEL_MDM_PWR_EN, 0); + } + + if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_RST)){ + oem_gpio_direction_output(GPIO_VIATEL_MDM_RST, 1); + /*just hold the reset pin if no power enable pin*/ + if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_PWR_EN)){ + mdelay(MDM_RST_HOLD_DELAY); + oem_gpio_direction_output(GPIO_VIATEL_MDM_RST, 0); + } + } +} +EXPORT_SYMBOL(oem_power_off_modem); + +ssize_t modem_power_show( + struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + int power = 0; + int ret = 0; + + if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_PWR_IND)){ + power = !!oem_gpio_get_value(GPIO_VIATEL_MDM_PWR_IND); + }else if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_PWR_EN)){ + printk("No MDM_PWR_IND, just detect MDM_PWR_EN\n"); + power = !!oem_gpio_get_value(GPIO_VIATEL_MDM_PWR_EN); + }else if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_RST)){ + printk("No MDM_PWR_IND, just detect MDM_PWR_RST\n"); + power = !!oem_gpio_get_value(GPIO_VIATEL_MDM_RST); + } + if(power){ + ret += sprintf(buf + ret, "on\n"); + }else{ + ret += sprintf(buf + ret, "off\n"); + } + + return ret; +} + +ssize_t modem_power_store( + struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) +{ + int power; + + /* power the modem */ + if ( !strncmp(buf, "on", strlen("on"))) { + power = 1; + }else if(!strncmp(buf, "off", strlen("off"))){ + power = 0; + }else{ + printk("%s: input %s is invalid.\n", __FUNCTION__, buf); + return n; + } + + printk("Warnning: Power %s modem\n", power ? "on" : "off"); + if(power){ +#if 0 + if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_RST)){ + oem_gpio_direction_output(GPIO_VIATEL_MDM_RST, 1); + mdelay(MDM_RST_HOLD_DELAY); + } + if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_PWR_EN)){ + oem_gpio_direction_output(GPIO_VIATEL_MDM_PWR_EN, 0); + mdelay(MDM_PWR_HOLD_DELAY); + } + + if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_PWR_EN)){ + oem_gpio_direction_output(GPIO_VIATEL_MDM_PWR_EN, 1); + mdelay(MDM_PWR_HOLD_DELAY); + } + + if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_RST)){ + oem_gpio_direction_output(GPIO_VIATEL_MDM_RST, 0); + mdelay(MDM_RST_HOLD_DELAY); + } + + if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_PWR_EN)){ + oem_gpio_direction_output(GPIO_VIATEL_MDM_PWR_EN, 0); + } +#endif + + if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_PWR_EN)){ + if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_RST)){ + oem_gpio_direction_output(GPIO_VIATEL_MDM_RST, 0); + mdelay(MDM_RST_HOLD_DELAY); + } + oem_gpio_direction_output(GPIO_VIATEL_MDM_PWR_EN, 1); + mdelay(MDM_PWR_HOLD_DELAY); + } + }else{ + oem_power_off_modem(); + } + return n; +} + +ssize_t modem_reset_show( + struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + int reset = 0; + int ret = 0; + if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_RST_IND)){ + reset = !!oem_gpio_get_value(GPIO_VIATEL_MDM_RST_IND); + }else if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_RST)){ + reset = !!oem_gpio_get_value(GPIO_VIATEL_MDM_RST); + } + + if(reset){ + ret += sprintf(buf + ret, "reset\n"); + }else{ + ret += sprintf(buf + ret, "work\n"); + } + + return ret; +} + +ssize_t modem_reset_store( + struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) +{ + /* reset the modem */ + if ( !strncmp(buf, "reset", strlen("reset"))) { + wake_lock_timeout(&reset_lock, MDM_RST_LOCK_TIME * HZ); + if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_RST)){ + oem_gpio_direction_output(GPIO_VIATEL_MDM_RST, 1); + mdelay(MDM_RST_HOLD_DELAY); + oem_gpio_direction_output(GPIO_VIATEL_MDM_RST, 0); + mdelay(MDM_RST_HOLD_DELAY); + } + printk("Warnning: reset modem\n"); + } + + return n; +} + +ssize_t modem_ets_select_show( + struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + int level = 0; + int ret = 0; + + if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_ETS_SEL)){ + level = !!oem_gpio_get_value(GPIO_VIATEL_MDM_ETS_SEL); + } + + ret += sprintf(buf, "%d\n", level); + return ret; +} + +ssize_t modem_ets_select_store( + struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) +{ + if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_ETS_SEL)){ + if ( !strncmp(buf, "1", strlen("1"))) { + oem_gpio_direction_output(GPIO_VIATEL_MDM_ETS_SEL, 1); + }else if( !strncmp(buf, "0", strlen("0"))){ + oem_gpio_direction_output(GPIO_VIATEL_MDM_ETS_SEL, 0); + }else{ + dbg("Unknow command.\n"); + } + } + + return n; +} + +ssize_t modem_boot_select_show( + struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + int ret = 0; + int level = 0; + + if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_BOOT_SEL)){ + level = !!oem_gpio_get_value(GPIO_VIATEL_MDM_BOOT_SEL); + } + + ret += sprintf(buf, "%d\n", level); + return ret; +} + +ssize_t modem_boot_select_store( + struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) +{ + if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_BOOT_SEL)){ + if ( !strncmp(buf, "1", strlen("1"))) { + oem_gpio_direction_output(GPIO_VIATEL_MDM_BOOT_SEL, 1); + }else if( !strncmp(buf, "0", strlen("0"))){ + oem_gpio_direction_output(GPIO_VIATEL_MDM_BOOT_SEL, 0); + }else{ + dbg("Unknow command.\n"); + } + } + + return n; +} + +#define modem_attr(_name) \ +static struct kobj_attribute _name##_attr = { \ + .attr = { \ + .name = __stringify(_name), \ + .mode = 0644, \ + }, \ + .show = modem_##_name##_show, \ + .store = modem_##_name##_store, \ +} + +modem_attr(power); +modem_attr(reset); +modem_attr(ets_select); +modem_attr(boot_select); + +static struct attribute *g_attr[] = { + &power_attr.attr, + &reset_attr.attr, + &ets_select_attr.attr, + &boot_select_attr.attr, + NULL +}; + +static struct attribute_group g_attr_group = { + .attrs = g_attr, +}; + + +static void modem_shutdown(struct platform_device *dev) +{ + oem_power_off_modem(); +} + +static struct platform_driver power_driver = { + .driver.name = "modem_power", + .shutdown = modem_shutdown, +}; + +static struct platform_device power_device = { + .name = "modem_power", +}; + +static struct kobject *modem_kobj; +static int __init viatel_power_init(void) +{ + int ret = 0; + + modem_kobj = viatel_kobject_add("modem"); + if(!modem_kobj){ + ret = -ENOMEM; + goto err_create_kobj; + } + + ret = platform_device_register(&power_device); + if (ret) { + printk("platform_device_register failed\n"); + goto err_platform_device_register; + } + ret = platform_driver_register(&power_driver); + if (ret) { + printk("platform_driver_register failed\n"); + goto err_platform_driver_register; + } + + wake_lock_init(&reset_lock, WAKE_LOCK_SUSPEND, "cbp_rst"); + if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_PWR_IND)){ + oem_gpio_direction_input_for_irq(GPIO_VIATEL_MDM_PWR_IND); + } + if(GPIO_OEM_VALID(GPIO_VIATEL_MDM_RST_IND)){ + oem_gpio_direction_input_for_irq(GPIO_VIATEL_MDM_RST_IND); + } + + //oem_gpio_direction_output(GPIO_VIATEL_MDM_RST, 0); + //oem_gpio_direction_output(GPIO_VIATEL_MDM_PWR_EN, 1); + ret = sysfs_create_group(modem_kobj, &g_attr_group); + + if(ret){ + printk("sysfs_create_group failed\n"); + goto err_sysfs_create_group; + } + + return 0; +err_sysfs_create_group: + platform_driver_unregister(&power_driver); +err_platform_driver_register: + platform_device_unregister(&power_device); +err_platform_device_register: +err_create_kobj: + return ret; +} + +static void __exit viatel_power_exit(void) +{ + wake_lock_destroy(&reset_lock); +} + +late_initcall_sync(viatel_power_init); +module_exit(viatel_power_exit); diff --git a/ANDROID_3.4.5/drivers/misc/viatel/sync.c b/ANDROID_3.4.5/drivers/misc/viatel/sync.c new file mode 100755 index 00000000..08ddf8ba --- /dev/null +++ b/ANDROID_3.4.5/drivers/misc/viatel/sync.c @@ -0,0 +1,2445 @@ +/* + * viatel_cbp_sync.c + * + * VIA CBP driver for Linux + * + * Copyright (C) 2011 VIA TELECOM Corporation, Inc. + * Author: VIA TELECOM Corporation, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/time.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/irq.h> +#include <linux/sched.h> +#include <linux/wakelock.h> +#include <linux/delay.h> +#include <linux/wait.h> +#include <linux/platform_device.h> +#include <mach/viatel.h> +#include "core.h" + +//define in oem.c +extern int isviatelcom; +extern int ap_ready_always; + +static int asc_debug = 0; +#define ASCDPRT(fmt, arg...) do{ \ + if(asc_debug) \ + printk("[ASC] " fmt, ##arg); \ + }while(0) +#define ASCPRT(fmt, arg...) printk("[ASC] " fmt, ##arg) + +/*mS*/ +#define ASC_RX_WAIT_IDLE_TIME (1000) +#define ASC_TX_WAIT_READY_TIME (1000) +#define ASC_TX_WAIT_IDLE_TIME (2000) +#define ASC_TX_AUTO_DELAY_TIME (2000) +#define ASC_TX_WAIT_SLEEP_TIME (500) +#define ASC_TX_TRY_TIMES (3) +#define ASC_TX_DEBOUNCE_TIME (10) + +#define ASC_TX_SYSFS_USER "AscApp" +#define ASC_TX_AUTO_USER "AscAuto" + +/* asc_list contains all registered struct struct asc_handle*/ +static DEFINE_SPINLOCK(hdlock); +static LIST_HEAD(asc_tx_handle_list); +static LIST_HEAD(asc_rx_handle_list); +static struct workqueue_struct *asc_work_queue; +static struct kobject *asc_kobj; + +typedef enum{ + ASC_TX_HD = 0, + ASC_RX_HD +}asc_handle_type; + +#define ASC_EVENT_POOL_MAX (60) +typedef enum{ + ASC_EVENT_UNUSE = 0, + ASC_EVENT_STATIC, + ASC_EVENT_DYNAMIC +}asc_event_type; + +struct asc_event{ + int id; + struct list_head list; + char usage; +}; + +static struct asc_event event_pool[ASC_EVENT_POOL_MAX]; + +struct asc_user{ + struct asc_infor infor; + atomic_t count; + struct list_head node; +}; + +struct asc_state_dsp{ + char name[ASC_NAME_LEN]; + /*state callback handle for events*/ + int (*handle)(void * hd, int event); +}; + +/* TX STATUS and TX EVENT*/ +typedef enum{ + AP_TX_EVENT_REQUEST = 0, /*internal*/ + AP_TX_EVENT_CP_READY, + AP_TX_EVENT_CP_UNREADY, + AP_TX_EVENT_WAIT_TIMEOUT, + AP_TX_EVENT_IDLE_TIMEOUT, + AP_TX_EVENT_STOP, + AP_TX_EVENT_RESET, + AP_TX_EVENT_NUM +} ap_tx_event; + +typedef enum{ + AP_TX_ST_SLEEP = 0, + AP_TX_ST_WAIT_READY, + AP_TX_ST_READY, /*wait All Tx channel finished*/ + AP_TX_ST_IDLE, + AP_TX_ST_NUM +} ap_tx_state; + +struct asc_tx_handle{ + struct asc_config cfg; + atomic_t state; + atomic_t count; + struct list_head user_list; + struct asc_state_dsp *table; + /*process the event to switch different states*/ + struct task_struct *thread; + int ntf; + int wait_try; + int auto_delay; + spinlock_t slock; + wait_queue_head_t wait; + wait_queue_head_t wait_tx_state; + struct mutex mlock; + struct wake_lock wlock; + struct timer_list timer_wait_ready; + struct timer_list timer_wait_idle; + struct timer_list timer_wait_sleep; + struct work_struct ntf_work; + struct list_head event_q; + struct list_head node; + struct kobject *kobj; +}; + +static int asc_tx_handle_sleep(void *, int ); +static int asc_tx_handle_wait_ready(void *, int ); +static int asc_tx_handle_ready(void *, int ); +static int asc_tx_handle_idle(void *, int ); + +/*the table used to discribe all tx states*/ +static struct asc_state_dsp asc_tx_table[AP_TX_ST_NUM] = { + [AP_TX_ST_SLEEP] = { + .name = "AP_TX_ST_SLEEP", + .handle = asc_tx_handle_sleep, + }, + [AP_TX_ST_WAIT_READY] = { + .name = "AP_TX_ST_WAIT_READY", + .handle = asc_tx_handle_wait_ready, + }, + [AP_TX_ST_READY] = { + .name = "AP_TX_ST_READY", + .handle = asc_tx_handle_ready, + }, + [AP_TX_ST_IDLE] = { + .name = "AP_TX_ST_IDLE", + .handle = asc_tx_handle_idle, + }, +}; + +/* RX STATUS and RX EVENT*/ +typedef enum{ + AP_RX_EVENT_REQUEST = 0, + AP_RX_EVENT_AP_READY, + AP_RX_EVENT_AP_UNREADY, + AP_RX_EVENT_STOP, + AP_RX_EVENT_IDLE_TIMEOUT, + AP_RX_EVENT_RESET, + AP_RX_EVENT_NUM +} ap_rx_event; + +typedef enum{ + AP_RX_ST_SLEEP = 0, + AP_RX_ST_WAIT_READY, + AP_RX_ST_READY, + AP_RX_ST_IDLE, + AP_RX_ST_NUM +} ap_rx_state; + +struct asc_rx_handle{ + struct asc_config cfg; + atomic_t state; + struct list_head user_list; + struct asc_state_dsp *table; + int ntf; + /*process the event to switch different states*/ + struct task_struct *thread; + spinlock_t slock; + wait_queue_head_t wait; + struct mutex mlock; + struct wake_lock wlock; + struct timer_list timer; + struct list_head event_q; + struct list_head node; + struct work_struct ntf_work; +}; + +static struct asc_config tx_cfg,rx_cfg; +static int asc_rx_handle_sleep(void *, int ); +static int asc_rx_handle_wait_ready(void *, int ); +static int asc_rx_handle_ready(void *, int ); +static int asc_rx_handle_idle(void *, int ); + +/*the table used to discribe all rx states*/ +static struct asc_state_dsp asc_rx_table[AP_RX_ST_NUM] = { + [AP_RX_ST_SLEEP] = { + .name = "AP_RX_ST_SLEEP", + .handle = asc_rx_handle_sleep, + }, + [AP_RX_ST_WAIT_READY] = { + .name = "AP_RX_ST_WAIT_READY", + .handle = asc_rx_handle_wait_ready, + }, + [AP_RX_ST_READY] = { + .name = "AP_RX_ST_READY", + .handle = asc_rx_handle_ready, + }, + [AP_RX_ST_IDLE] = { + .name = "AP_RX_ST_IDLE", + .handle = asc_rx_handle_idle, + }, +}; + +static int asc_tx_event_send(struct asc_tx_handle *tx, int id); +static void asc_tx_handle_reset(struct asc_tx_handle *tx); +static int asc_rx_event_send(struct asc_rx_handle *rx, int id); +static void asc_rx_handle_reset(struct asc_rx_handle *rx); + +static struct asc_event * asc_event_malloc(void) +{ + int i = 0; + unsigned long flags = 0; + struct asc_event *event = NULL; + + spin_lock_irqsave(&hdlock, flags); + for(i = 0; i < ASC_EVENT_POOL_MAX; i++){ + if(ASC_EVENT_UNUSE == event_pool[i].usage){ + event = &(event_pool[i]); + event->usage = ASC_EVENT_STATIC; + } + } + + if(NULL == event){ + event = kmalloc(sizeof(struct asc_event), GFP_ATOMIC); + if(event){ + event->usage = ASC_EVENT_DYNAMIC; + } + } + spin_unlock_irqrestore(&hdlock, flags); + return event; +} + +static void asc_event_free(struct asc_event * event) +{ + unsigned long flags = 0; + + if(!event) + return ; + spin_lock_irqsave(&hdlock, flags); + if(ASC_EVENT_STATIC == event->usage){ + memset(event, 0, sizeof(struct asc_event)); + }else{ + kfree(event); + } + spin_unlock_irqrestore(&hdlock, flags); +} +static irqreturn_t asc_irq_cp_indicate_state(int irq, void *data) +{ + int level; + struct asc_tx_handle *tx = (struct asc_tx_handle *)data; + struct asc_config *cfg = &tx->cfg; + + if (!oem_gpio_irq_isenable(cfg->gpio_ready) || + !oem_gpio_irq_isint(cfg->gpio_ready)){ + + return IRQ_NONE; + + } + oem_gpio_irq_clear(cfg->gpio_ready); + level = !!oem_gpio_get_value(cfg->gpio_ready); + oem_gpio_set_irq_type(cfg->gpio_ready, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING); + ASCDPRT("Irq %s cp_indicate_ap %s.\n", cfg->name, (level == cfg->polar)?"WAKEN":"SLEEP"); + if(level == cfg->polar){ + asc_tx_event_send(tx, AP_TX_EVENT_CP_READY); + }else{ + /*do not care*/ + //asc_tx_event_send(tx, AP_TX_EVENT_CP_UNREADY); + } + oem_gpio_irq_unmask(cfg->gpio_ready); + return IRQ_HANDLED; +} + + + +static irqreturn_t asc_irq_cp_wake_ap(int irq, void *data) +{ + int level; + struct asc_rx_handle *rx = (struct asc_rx_handle *)data; + struct asc_config *cfg = &rx->cfg; + + if(!cfg||cfg->gpio_wake<=0){ + return IRQ_NONE; + } + + if (!oem_gpio_irq_isenable(cfg->gpio_wake) || + !oem_gpio_irq_isint(cfg->gpio_wake)){ + return IRQ_NONE; + } + + oem_gpio_irq_clear(cfg->gpio_wake); + + level = !!oem_gpio_get_value(cfg->gpio_wake); + oem_gpio_set_irq_type(cfg->gpio_wake, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING); + ASCDPRT("Irq %s cp_wake_ap, requset ap to be %s.\n", cfg->name, (level == cfg->polar)?"WAKEN":"SLEEP"); + + if(level == cfg->polar){ + /*Cp requset Ap wake*/ + wake_lock(&rx->wlock); + /*FIXME: jump to ready as soon as possible to avoid the AP_READY error indication to CBP */ + if(AP_RX_ST_IDLE == atomic_read(&rx->state)){ + ASCDPRT("Rx(%s): process event(%d) in state(%s).\n", cfg->name, AP_RX_EVENT_REQUEST, rx->table[AP_RX_ST_IDLE].name); + asc_rx_handle_idle(rx, AP_RX_EVENT_REQUEST); + ASCDPRT("Rx(%s): go into state(%s).\n", cfg->name, rx->table[atomic_read(&rx->state)].name); + }else{ + asc_rx_event_send(rx, AP_RX_EVENT_REQUEST); + } + }else{ + /*Cp allow Ap sleep*/ + asc_rx_event_send(rx, AP_RX_EVENT_STOP); + } + + oem_gpio_irq_unmask(cfg->gpio_wake); + return IRQ_HANDLED; +} + + + + +static struct asc_tx_handle *asc_tx_handle_lookup(const char *name) +{ + unsigned long flags; + struct asc_tx_handle *hd, *tmp, *t; + + if (!name) + return NULL; + + hd = NULL; + + spin_lock_irqsave(&hdlock, flags); + list_for_each_entry_safe(tmp, t, &asc_tx_handle_list, node) { + if (!strncmp(name, tmp->cfg.name, ASC_NAME_LEN - 1)) { + hd = tmp; + break; + } + } + spin_unlock_irqrestore(&hdlock, flags); + return hd; +} + +static struct asc_rx_handle *asc_rx_handle_lookup(const char *name) +{ + unsigned long flags; + struct asc_rx_handle *hd, *tmp, *t; + + if (!name) + return NULL; + + hd = NULL; + spin_lock_irqsave(&hdlock, flags); + list_for_each_entry_safe(tmp, t, &asc_rx_handle_list, node) { + if (!strncmp(name, tmp->cfg.name, ASC_NAME_LEN - 1)) { + hd = tmp; + break; + } + } + spin_unlock_irqrestore(&hdlock, flags); + return hd; +} + +irqreturn_t viatelcom_irq_cp_wake_ap(int irq, void *data){ + struct asc_rx_handle *rx; + if(!isviatelcom||ap_ready_always) + return IRQ_HANDLED; + rx = asc_rx_handle_lookup(USB_RX_HD_NAME); + return asc_irq_cp_wake_ap(irq,rx); +} + +static struct asc_user *asc_tx_user_lookup(struct asc_tx_handle *tx, const char *name) +{ + unsigned long flags = 0; + struct asc_user *user = NULL, *tmp = NULL, *t = NULL; + + if (!name) + return NULL; + + spin_lock_irqsave(&tx->slock, flags); + list_for_each_entry_safe(tmp, t, &tx->user_list, node) { + if (!strncmp(name, tmp->infor.name, ASC_NAME_LEN - 1)) { + user = tmp; + break; + } + } + spin_unlock_irqrestore(&tx->slock, flags); + + return user; +} + +static struct asc_user *asc_rx_user_lookup(struct asc_rx_handle *rx, const char *name) +{ + unsigned long flags = 0; + struct asc_user *user = NULL, *tmp = NULL, *t = NULL; + + if (!name) + return NULL; + + spin_lock_irqsave(&rx->slock, flags); + list_for_each_entry_safe(tmp, t, &rx->user_list, node) { + if (!strncmp(name, tmp->infor.name, ASC_NAME_LEN - 1)) { + user = tmp; + break; + } + } + spin_unlock_irqrestore(&rx->slock, flags); + + return user; +} + +static inline void asc_rx_indicate_wake(struct asc_rx_handle *rx) +{ + if(rx->cfg.gpio_ready >= 0) + oem_gpio_direction_output(rx->cfg.gpio_ready, rx->cfg.polar); +} + +static inline void asc_rx_indicate_sleep(struct asc_rx_handle *rx) +{ + if(rx->cfg.gpio_ready >= 0) + oem_gpio_direction_output(rx->cfg.gpio_ready, !rx->cfg.polar); +} + +static int asc_rx_event_send(struct asc_rx_handle *rx, int id) +{ + unsigned long flags = 0; + struct asc_event *event = NULL; + int ret = -ENODEV; + + if(rx->thread == NULL){ + ASCPRT("%s:no thread for event\n", __FUNCTION__); + return ret; + } + + /*check whether the event is cared by current charge state*/ + if(id >= 0){ + event = asc_event_malloc(); + if(!event){ + ASCPRT("No memory to create new event.\n"); + ret = -ENOMEM; + goto send_event_error; + } + /*insert a new event to the list tail and wakeup the process thread*/ + //ASCDPRT("Rx(%s):send event(%d) to state(%s).\n", rx->name, id, rx->table[atomic_read(&rx->state)].name); + event->id = id; + spin_lock_irqsave(&rx->slock, flags); + if(AP_RX_EVENT_RESET == id){ + list_add(&event->list, &rx->event_q); + }else{ + list_add_tail(&event->list, &rx->event_q); + } + spin_unlock_irqrestore(&rx->slock, flags); + wake_up(&rx->wait); + } + ret = 0; +send_event_error: + return ret; +} + +static int asc_rx_event_recv(struct asc_rx_handle *rx) +{ + unsigned long flags = 0; + struct asc_event *event = NULL; + int ret = -ENODEV; + + if(rx->thread == NULL){ + ASCPRT("%s:no thread for event\n", __FUNCTION__); + return ret; + } + + spin_lock_irqsave(&rx->slock, flags); + if(!list_empty(&rx->event_q)){ + event = list_first_entry(&rx->event_q, struct asc_event, list); + list_del(&event->list); + } + spin_unlock_irqrestore(&rx->slock, flags); + + if(event){ + ret = event->id; + asc_event_free(event); + } + return ret; +} + +static int asc_rx_event_thread(void *data) +{ + struct asc_rx_handle *rx = (struct asc_rx_handle *)data; + int id = 0, index; + char name[ASC_NAME_LEN] = {0}; + struct asc_state_dsp *dsp = NULL; + + rx->thread = current; + snprintf(name, ASC_NAME_LEN, "asc_rx_%s", rx->cfg.name); + daemonize(name); + ASCDPRT("%s thread start now.\n", name); + + while(1){ + /*sleep until receive an evnet or thread exist*/ + wait_event(rx->wait, ((id=asc_rx_event_recv(rx)) >= 0) || (!rx->thread)); + /*thread is existed*/ + if(!rx->thread){ + break; + } + + mutex_lock(&rx->mlock); + if(AP_RX_EVENT_RESET == id){ + asc_rx_handle_reset(rx); + }else{ + index = atomic_read(&rx->state); + dsp = rx->table + index; + if(dsp->handle){ + ASCDPRT("Rx(%s): process event(%d) in state(%s).\n", rx->cfg.name, id, dsp->name); + dsp->handle(rx, id); + ASCDPRT("Rx(%s): go into state(%s).\n", rx->cfg.name, rx->table[atomic_read(&rx->state)].name); + } + } + mutex_unlock(&rx->mlock); + } + + ASCDPRT("%s thread exit.\n", name); + kfree(rx); + return 0; +} + +static void asc_rx_event_timer(unsigned long data) +{ + struct asc_rx_handle *rx = (struct asc_rx_handle *)data; + //ASCDPRT("%s timer is time out.\n", rx->name); + asc_rx_event_send(rx, AP_RX_EVENT_IDLE_TIMEOUT); +} + +static void asc_tx_notifier_work(struct work_struct *work) +{ + struct asc_infor *infor; + struct asc_user *user = NULL, *t = NULL; + struct asc_tx_handle *tx = container_of(work, struct asc_tx_handle, + ntf_work); + + list_for_each_entry_safe(user, t, &tx->user_list, node){ + infor = &user->infor; + if(infor->notifier){ + infor->notifier(tx->ntf, infor->data); + } + } +} + +static void asc_rx_notifier_work(struct work_struct *work) +{ + struct asc_infor *infor; + struct asc_user *user = NULL, *t = NULL; + struct asc_rx_handle *rx = container_of(work, struct asc_rx_handle, + ntf_work); + + list_for_each_entry_safe(user, t, &rx->user_list, node){ + infor = &user->infor; + if(infor->notifier){ + infor->notifier(rx->ntf, infor->data); + } + } +} + +static void asc_tx_notifier(struct asc_tx_handle *tx, int ntf) +{ + tx->ntf = ntf; + queue_work(asc_work_queue, &tx->ntf_work); +} + +static void asc_rx_notifier(struct asc_rx_handle *rx, int ntf) +{ + rx->ntf = ntf; + queue_work(asc_work_queue, &rx->ntf_work); +} + +static int asc_rx_handle_init(struct asc_rx_handle *rx) +{ + int ret = 0; + char *name = NULL; + struct asc_config *cfg = &rx->cfg; + + if(cfg->gpio_ready >= 0){ + ret = oem_gpio_request(cfg->gpio_ready, "ap_ready"); + if(ret < 0){ + ASCPRT("Fail to requset ap_ready gpio %d for %s.\n", cfg->gpio_ready, cfg->name); + goto err_request_gpio_ap_ready; + } + if(ap_ready_always) + oem_gpio_output(cfg->gpio_ready, cfg->polar); + else + asc_rx_indicate_sleep(rx); + } + + if(cfg->gpio_wake >= 0){ + ret = oem_gpio_request(cfg->gpio_wake, "cp_wake_ap"); + if(ret < 0){ + ASCPRT("Fail to requset cp_wake_ap gpio %d for %s.\n", cfg->gpio_wake, cfg->name); + goto err_request_gpio_cp_wake_ap; + } + + oem_gpio_irq_mask(cfg->gpio_wake); + oem_gpio_direction_input_for_irq(cfg->gpio_wake); + oem_gpio_set_irq_type(cfg->gpio_wake, IRQF_TRIGGER_RISING); + ret = oem_gpio_request_irq(cfg->gpio_wake, asc_irq_cp_wake_ap, IRQF_SHARED | IRQF_NO_SUSPEND, "cp_wake_ap", rx); + printk("asc_rx_handle_init call oem_gpio_irq_unmask %d\n",cfg->gpio_wake); + oem_gpio_irq_unmask(cfg->gpio_wake); + if (ret < 0) { + ASCPRT("fail to request cp_wake_ap irq for %s\n", cfg->name); + goto err_req_irq_cp_wake_ap; + } + } + + rx->table = asc_rx_table; + mutex_init(&rx->mlock); + INIT_LIST_HEAD(&rx->event_q); + INIT_LIST_HEAD(&rx->user_list); + spin_lock_init(&rx->slock); + setup_timer(&rx->timer, asc_rx_event_timer, (unsigned long)rx); + name = kzalloc(ASC_NAME_LEN, GFP_KERNEL); + if(!name){ + ret = -ENOMEM; + ASCPRT("%s: no memory to malloc for wake lock name\n", __FUNCTION__); + goto err_malloc_name; + } + snprintf(name, ASC_NAME_LEN, "asc_rx_%s", rx->cfg.name); + wake_lock_init(&rx->wlock, WAKE_LOCK_SUSPEND, name); + init_waitqueue_head(&rx->wait); + INIT_WORK(&rx->ntf_work, asc_rx_notifier_work); + if(ap_ready_always) + atomic_set(&rx->state, AP_RX_ST_READY); + else + atomic_set(&rx->state, AP_RX_ST_SLEEP); + ret = kernel_thread(asc_rx_event_thread, rx, 0); + if(ret < 0){ + ASCPRT("Fail to create %s rx thread.\n", rx->cfg.name); + goto err_create_rx_thread; + } + + if(!!oem_gpio_get_value(cfg->gpio_wake) == cfg->polar){ + asc_rx_event_send(rx, AP_RX_EVENT_REQUEST); + } + + return 0; + +err_create_rx_thread: + if(name) + kfree(name); +err_malloc_name: + if(cfg->gpio_wake >= 0) + free_irq(oem_gpio_to_irq(cfg->gpio_wake), rx); +err_req_irq_cp_wake_ap: + if(cfg->gpio_wake) + oem_gpio_free(cfg->gpio_wake); +err_request_gpio_cp_wake_ap: + if(cfg->gpio_ready >= 0) + oem_gpio_free(cfg->gpio_ready); +err_request_gpio_ap_ready: + return ret; +} + +static int asc_rx_handle_sleep(void *data, int event) +{ + int ret = 0; + struct asc_rx_handle *rx = (struct asc_rx_handle *)data; + + //ASCDPRT("Rx(%s): process event(%d) in state(%s).\n", rx->name, event, rx->table[atomic_read(&rx->state)].name); + + if(AP_RX_ST_SLEEP != atomic_read(&rx->state)){ + return 0; + } + + switch(event){ + case AP_RX_EVENT_REQUEST: + wake_lock(&rx->wlock); + atomic_set(&rx->state, AP_RX_ST_WAIT_READY); + asc_rx_notifier(rx, ASC_NTF_RX_PREPARE); + break; + default: + ASCDPRT("ignore the rx event %d in state(%s)", event, rx->table[atomic_read(&rx->state)].name); + } + + //ASCDPRT("Rx(%s): go into state(%s).\n", rx->name, rx->table[atomic_read(&rx->state)].name); + return ret; +} + +static int asc_rx_handle_wait_ready(void *data, int event) +{ + int ret = 0; + struct asc_rx_handle *rx = (struct asc_rx_handle *)data; + + //ASCDPRT("Rx(%s): process event(%d) in state(%s).\n", rx->name, event, rx->table[atomic_read(&rx->state)].name); + + if(AP_RX_ST_WAIT_READY != atomic_read(&rx->state)){ + return 0; + } + + switch(event){ + case AP_RX_EVENT_AP_READY: + /*need ack ready to cp, do nothing if no gpio for ap_ready*/ + asc_rx_indicate_wake(rx); + atomic_set(&rx->state, AP_RX_ST_READY); + break; + case AP_RX_EVENT_AP_UNREADY: + case AP_RX_EVENT_STOP: + atomic_set(&rx->state, AP_RX_ST_SLEEP); + asc_rx_notifier(rx, ASC_NTF_RX_POST); + /*need ack ready to cp, do nothing if no gpio for ap_ready*/ + asc_rx_indicate_sleep(rx); + wake_unlock(&rx->wlock); + break; + default: + ASCDPRT("ignore the rx event %d in state(%s)", event, rx->table[atomic_read(&rx->state)].name); + } + + //ASCDPRT("Rx(%s): go into state(%s).\n", rx->name, rx->table[atomic_read(&rx->state)].name); + return ret; +} + +static int asc_rx_handle_ready(void *data, int event) +{ + int ret = 0; + struct asc_rx_handle *rx = (struct asc_rx_handle *)data; + + //ASCDPRT("Rx(%s): process event(%d) in state(%s).\n", rx->name, event, rx->table[atomic_read(&rx->state)].name); + + if(AP_RX_ST_READY != atomic_read(&rx->state)){ + return 0; + } + + switch(event){ + case AP_RX_EVENT_STOP: + atomic_set(&rx->state, AP_RX_ST_IDLE); + mod_timer(&rx->timer, jiffies + msecs_to_jiffies(ASC_RX_WAIT_IDLE_TIME)); + break; + default: + ASCDPRT("ignore the rx event %d in state(%s)", event, rx->table[atomic_read(&rx->state)].name); + } + + //ASCDPRT("Rx(%s): go into state(%s).\n", rx->name, rx->table[atomic_read(&rx->state)].name); + return ret; +} + +static int asc_rx_handle_idle(void *data, int event) +{ + int ret = 0; + unsigned long flags = 0; + struct asc_rx_handle *rx = (struct asc_rx_handle *)data; + + //ASCDPRT("Rx(%s): process event(%d) in state(%s).\n", rx->name, event, rx->table[atomic_read(&rx->state)].name); + + if(AP_RX_ST_IDLE != atomic_read(&rx->state)){ + return 0; + } + + /*FIXME: prevent from scheduled and interrupted to avoid error indication to CBP*/ + spin_lock_irqsave(&rx->slock, flags); + + switch(event){ + case AP_RX_EVENT_REQUEST: + del_timer(&rx->timer); + atomic_set(&rx->state, AP_RX_ST_READY); + break; + + case AP_RX_EVENT_IDLE_TIMEOUT: + asc_rx_notifier(rx, ASC_NTF_RX_POST); + atomic_set(&rx->state, AP_RX_ST_SLEEP); + /*need ack ready to cp, do nothing if no gpio for ap_ready*/ + asc_rx_indicate_sleep(rx); + wake_unlock(&rx->wlock); + break; + + default: + ASCDPRT("ignore the rx event %d in state(%s)", event, rx->table[atomic_read(&rx->state)].name); + } + + spin_unlock_irqrestore(&rx->slock, flags); + + //ASCDPRT("Rx(%s): go into state(%s).\n", rx->name, rx->table[atomic_read(&rx->state)].name); + return ret; +} + +static void asc_tx_trig_busy(struct asc_tx_handle *tx) +{ + mod_timer(&tx->timer_wait_idle, jiffies + msecs_to_jiffies(tx->auto_delay)); +} + +static inline void asc_tx_wake_cp(struct asc_tx_handle *tx) +{ + if(tx->cfg.gpio_wake >= 0) + oem_gpio_direction_output(tx->cfg.gpio_wake, tx->cfg.polar); +} + +static inline void asc_tx_sleep_cp(struct asc_tx_handle *tx) +{ + if(tx->cfg.gpio_wake >= 0) + oem_gpio_direction_output(tx->cfg.gpio_wake, !tx->cfg.polar); +} + +static inline int asc_tx_cp_be_ready(struct asc_tx_handle *tx) +{ + int ret = 0; + + if(tx->cfg.gpio_ready >= 0) + ret = ((!!oem_gpio_get_value(tx->cfg.gpio_ready)) == (tx->cfg.polar)); + + return ret; +} + + +static int asc_tx_event_send(struct asc_tx_handle *tx, int id) +{ + unsigned long flags = 0; + struct asc_event *event = NULL; + int ret = -ENODEV; + + if(tx->thread == NULL){ + ASCPRT("%s:no thread for event\n", __FUNCTION__); + return ret; + } + + /*check whether the event is cared by current charge state*/ + if(id >= 0){ + event = asc_event_malloc(); + if(!event){ + ASCPRT("No memory to create new event.\n"); + ret = -ENOMEM; + goto send_event_error; + } + /*insert a new event to the list tail and wakeup the process thread*/ + //ASCDPRT("Send tx event(%d) to state(%s).\n", id, tx->table[atomic_read(&tx->state)].name); + event->id = id; + spin_lock_irqsave(&tx->slock, flags); + if(AP_TX_EVENT_RESET == id){ + list_add(&event->list, &tx->event_q); + }else{ + list_add_tail(&event->list, &tx->event_q); + } + spin_unlock_irqrestore(&tx->slock, flags); + wake_up(&tx->wait); + } +send_event_error: + return ret; +} + +static int asc_tx_event_recv(struct asc_tx_handle *tx) +{ + unsigned long flags = 0; + struct asc_event *event = NULL; + int ret = -ENODEV; + + if(tx->thread == NULL){ + ASCPRT("%s:no thread for event\n", __FUNCTION__); + return ret; + } + + spin_lock_irqsave(&tx->slock, flags); + if(!list_empty(&tx->event_q)){ + event = list_first_entry(&tx->event_q, struct asc_event, list); + list_del(&event->list); + } + spin_unlock_irqrestore(&tx->slock, flags); + + if(event){ + ret = event->id; + asc_event_free(event); + } + return ret; +} + +static int asc_tx_get_user(struct asc_tx_handle *tx, const char *name) +{ + int ret = 0; + struct asc_user *user = NULL; + + user = asc_tx_user_lookup(tx, name); + if(user){ + atomic_inc(&user->count); + }else{ + ret = -ENODEV; + } + + return ret; +} +static int asc_tx_put_user(struct asc_tx_handle *tx, const char *name) +{ + struct asc_user *user = NULL; + int ret = 0; + + user = asc_tx_user_lookup(tx, name); + + if(user){ + if(atomic_read(&user->count) >= 1){ + atomic_dec(&user->count); + } + }else{ + ret = -ENODEV; + } + + return ret; +} + +static int asc_tx_refer(struct asc_tx_handle *tx, const char *name) +{ + unsigned long flags = 0; + struct asc_user *user = NULL, *t = NULL; + int count = 0; + + if(name){ + /*get the reference count of the user*/ + user = asc_tx_user_lookup(tx, name); + if(user){ + count = atomic_read(&user->count); + } + }else{ + spin_lock_irqsave(&tx->slock, flags); + list_for_each_entry_safe(user, t, &tx->user_list, node) { + count += atomic_read(&user->count); + } + spin_unlock_irqrestore(&tx->slock, flags); + } + + return count; +} + +static int asc_rx_refer(struct asc_rx_handle *rx, const char *name) +{ + unsigned long flags = 0; + struct asc_user *user = NULL, *t = NULL; + int count = 0; + + if(name){ + /*get the reference count of the user*/ + user = asc_rx_user_lookup(rx, name); + if(user){ + count = atomic_read(&user->count); + } + }else{ + spin_lock_irqsave(&rx->slock, flags); + list_for_each_entry_safe(user, t, &rx->user_list, node) { + count += atomic_read(&user->count); + } + spin_unlock_irqrestore(&rx->slock, flags); + } + + return count; +} + +static void asc_tx_refer_clear(struct asc_tx_handle *tx) +{ + unsigned long flags = 0; + struct asc_user *user = NULL, *t = NULL; + + spin_lock_irqsave(&tx->slock, flags); + list_for_each_entry_safe(user, t, &tx->user_list, node) { + atomic_set(&user->count, 0); + } + spin_unlock_irqrestore(&tx->slock, flags); +} + +static int asc_tx_event_thread(void *data) +{ + struct asc_tx_handle *tx = (struct asc_tx_handle *)data; + int id = 0, index; + char name[ASC_NAME_LEN] = {0}; + struct asc_state_dsp *dsp = NULL; + + snprintf(name, ASC_NAME_LEN, "asc_tx_%s", tx->cfg.name); + tx->thread = current; + daemonize(name); + ASCDPRT("%s thread start now.\n", name); + + while(1){ + /*sleep until receive an evnet or thread exist*/ + wait_event(tx->wait, ((id=asc_tx_event_recv(tx)) >= 0) || (!tx->thread) ); + /*thread is existed*/ + if(!tx->thread){ + break; + } + + mutex_lock(&tx->mlock); + if(AP_TX_EVENT_RESET == id){ + asc_tx_handle_reset(tx); + }else{ + index = atomic_read(&tx->state); + dsp = tx->table + index; + if(dsp->handle){ + ASCDPRT("Tx(%s): process event(%d) in state(%s).\n", tx->cfg.name, id, dsp->name); + dsp->handle(tx, id); + ASCDPRT("Tx(%s): go into state(%s) .\n", tx->cfg.name, tx->table[atomic_read(&tx->state)].name); + } + } + mutex_unlock(&tx->mlock); + } + + ASCDPRT("%s thread exit.\n", name); + kfree(tx); + return 0; +} + +static void asc_tx_wait_ready_timer(unsigned long data) +{ + struct asc_tx_handle *tx = (struct asc_tx_handle *)data; + //ASCDPRT("%s tx wait ready timer is timeout.\n", tx->name); + asc_tx_event_send(tx, AP_TX_EVENT_WAIT_TIMEOUT); +} + +static void asc_tx_wait_idle_timer(unsigned long data) +{ + char path[ASC_NAME_LEN] = {0}; + struct asc_tx_handle *tx = (struct asc_tx_handle *)data; + //ASCDPRT("%s tx wait idle timer is timeout.\n", tx->name); + snprintf(path, ASC_NAME_LEN, "%s.%s", tx->cfg.name, ASC_TX_AUTO_USER); + asc_tx_put_ready(path, 0); +} + +static void asc_tx_wait_sleep_timer(unsigned long data) +{ + struct asc_tx_handle *tx = (struct asc_tx_handle *)data; + //ASCDPRT("%s tx wait sleep timer is timeout.\n", tx->name); + asc_tx_event_send(tx, AP_TX_EVENT_IDLE_TIMEOUT); +} + +static int asc_tx_handle_init(struct asc_tx_handle *tx) +{ + int ret = 0; + char *name = NULL; + struct asc_config *cfg = &tx->cfg; + + ret = oem_gpio_request(cfg->gpio_wake, "ap_wake_cp"); + if(ret < 0){ + ASCPRT("Fail to requset ap_wake_cp gpio %d for %s.\n", cfg->gpio_wake, cfg->name); + goto err_request_gpio_ap_wake_cp; + } + + if(cfg->gpio_ready >= 0){ + ret = oem_gpio_request(cfg->gpio_ready, "cp_ready"); + if(ret < 0){ + ASCPRT("Fail to requset cp_ready gpio %d for %s.\n", cfg->gpio_ready, cfg->name); + goto err_request_gpio_cp_ready; + } + + oem_gpio_irq_mask(cfg->gpio_ready); + oem_gpio_direction_input_for_irq(cfg->gpio_ready); + oem_gpio_set_irq_type(cfg->gpio_ready, IRQF_TRIGGER_RISING); + ret = oem_gpio_request_irq(cfg->gpio_ready, asc_irq_cp_indicate_state, + IRQF_SHARED, "cp_indicate_state", tx); + oem_gpio_irq_unmask(cfg->gpio_ready); + if (ret < 0) { + ASCPRT("fail to request irq for %s:cp_ready\n", cfg->name); + goto err_req_irq_cp_indicate_state; + } + } + asc_tx_sleep_cp(tx); + + tx->auto_delay = ASC_TX_AUTO_DELAY_TIME; + tx->table = asc_tx_table; + mutex_init(&tx->mlock); + INIT_LIST_HEAD(&tx->event_q); + INIT_LIST_HEAD(&tx->user_list); + spin_lock_init(&tx->slock); + name = kzalloc(ASC_NAME_LEN, GFP_KERNEL); + if(!name){ + ret = -ENOMEM; + ASCPRT("%s: no memory to malloc for wake lock name\n", __FUNCTION__); + goto err_malloc_name; + } + snprintf(name, ASC_NAME_LEN, "asc_tx_%s", tx->cfg.name); + wake_lock_init(&tx->wlock, WAKE_LOCK_SUSPEND, name); + init_waitqueue_head(&tx->wait); + init_waitqueue_head(&tx->wait_tx_state); + setup_timer(&tx->timer_wait_ready, asc_tx_wait_ready_timer, (unsigned long)tx); + setup_timer(&tx->timer_wait_idle, asc_tx_wait_idle_timer, (unsigned long)tx); + setup_timer(&tx->timer_wait_sleep, asc_tx_wait_sleep_timer, (unsigned long)tx); + atomic_set(&tx->state, AP_TX_ST_SLEEP); + atomic_set(&tx->count, 0); + INIT_WORK(&tx->ntf_work, asc_tx_notifier_work); + ret = kernel_thread(asc_tx_event_thread, tx, 0); + if(ret < 0){ + ASCPRT("Fail to create %s tx thread.\n", tx->cfg.name); + goto err_create_tx_event_thread; + } + + return 0; +err_create_tx_event_thread: + if(cfg->gpio_ready >= 0) + free_irq(oem_gpio_to_irq(cfg->gpio_ready), tx); +err_malloc_name: + if(name) + kfree(name); +err_req_irq_cp_indicate_state: + if(cfg->gpio_ready >= 0) + oem_gpio_free(cfg->gpio_ready); +err_request_gpio_cp_ready: + if(cfg->gpio_wake >= 0) + oem_gpio_free(cfg->gpio_wake); +err_request_gpio_ap_wake_cp: + return ret; +} + +static int asc_tx_handle_sleep(void *data, int event) +{ + int ret = 0; + struct asc_tx_handle *tx = (struct asc_tx_handle *)data; + + //ASCDPRT("Tx(%s): process event(%d) in state(%s).\n", tx->name, event, tx->table[atomic_read(&tx->state)].name); + + if(AP_TX_ST_SLEEP != atomic_read(&tx->state)){ + return 0; + } + + switch(event){ + case AP_TX_EVENT_REQUEST: + wake_lock(&tx->wlock); + asc_tx_wake_cp(tx); + if(tx->cfg.gpio_ready >= 0){ + mod_timer(&tx->timer_wait_ready, jiffies + msecs_to_jiffies(ASC_TX_WAIT_READY_TIME)); + atomic_set(&tx->state, AP_TX_ST_WAIT_READY); + if(asc_tx_cp_be_ready(tx)){ + mdelay(ASC_TX_DEBOUNCE_TIME);//debounce wait, make sure CBP has already be ready + if(asc_tx_cp_be_ready(tx)){ + ASCDPRT("Tx:cp %s was ready now.\n", tx->cfg.name); + asc_tx_handle_wait_ready(tx, AP_TX_EVENT_CP_READY); + } + } + }else{ + mdelay(ASC_TX_DEBOUNCE_TIME); + atomic_set(&tx->state, AP_TX_ST_WAIT_READY); + asc_tx_handle_wait_ready(tx, AP_TX_EVENT_CP_READY); + } + break; + default: + ASCDPRT("Tx: ignore event %d in state(%s)", event, tx->table[atomic_read(&tx->state)].name); + } + + //ASCDPRT("Tx(%s): go into state(%s).\n", tx->name, tx->table[atomic_read(&tx->state)].name); + return ret; +} + +static int asc_tx_handle_wait_ready(void *data, int event) +{ + int ret = 0; + struct asc_tx_handle *tx = (struct asc_tx_handle *)data; + + if(AP_TX_ST_WAIT_READY != atomic_read(&tx->state)){ + return 0; + } + //ASCDPRT("Tx(%s): process event(%d) in state(%s).\n", tx->name, event, tx->table[atomic_read(&tx->state)].name); + switch(event){ + case AP_TX_EVENT_CP_READY: + del_timer(&tx->timer_wait_ready); + tx->wait_try = 0; + atomic_set(&tx->state, AP_TX_ST_READY); + wake_up_interruptible_all(&tx->wait_tx_state); + if(asc_tx_refer(tx, ASC_TX_AUTO_USER) > 0){ + asc_tx_trig_busy(tx); + } + asc_tx_notifier(tx, ASC_NTF_TX_READY); + break; + case AP_TX_EVENT_WAIT_TIMEOUT: + ASCPRT("Tx: %s wait cp ready timeout, try=%d.\n", tx->cfg.name, tx->wait_try); + + { + //kevin add .i dont know who disable irq after resume,so i reeanble it + oem_gpio_direction_input_for_irq(GPIO_VIATEL_USB_MDM_RDY); + oem_gpio_set_irq_type(GPIO_VIATEL_USB_MDM_RDY,(IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)); + oem_gpio_irq_unmask(GPIO_VIATEL_USB_MDM_RDY); + + } + + asc_tx_sleep_cp(tx); + mdelay(ASC_TX_DEBOUNCE_TIME);//delay to create a implus + atomic_set(&tx->state, AP_TX_ST_SLEEP); + if(tx->wait_try++ <= ASC_TX_TRY_TIMES){ + asc_tx_event_send(tx, AP_TX_EVENT_REQUEST); + }else{ + tx->wait_try = 0; + atomic_set(&tx->state, AP_TX_ST_SLEEP); + asc_tx_refer_clear(tx); + wake_up_interruptible_all(&tx->wait_tx_state); + wake_unlock(&tx->wlock); + asc_tx_notifier(tx, ASC_NTF_TX_UNREADY); + ASCPRT("try out to wake %s.\n", tx->cfg.name); + } + break; + case AP_TX_EVENT_STOP: + asc_tx_sleep_cp(tx); + del_timer(&tx->timer_wait_ready); + tx->wait_try = 0; + atomic_set(&tx->state, AP_TX_ST_SLEEP); + wake_unlock(&tx->wlock); + wake_up_interruptible_all(&tx->wait_tx_state); + break; + default: + ASCDPRT("Tx: ignore event %d in state(%s)", event, tx->table[atomic_read(&tx->state)].name); + } + + //ASCDPRT("Tx(%s): go into state(%s).\n", tx->name, tx->table[atomic_read(&tx->state)].name); + return ret; +} + +static int asc_tx_handle_ready(void *data, int event) +{ + int ret = 0; + struct asc_tx_handle *tx = (struct asc_tx_handle *)data; + + if(AP_TX_ST_READY != atomic_read(&tx->state)){ + return 0; + } + //ASCDPRT("Tx(%s): process event(%d) in state(%s).\n", tx->name, event, tx->table[atomic_read(&tx->state)].name); + switch(event){ + case AP_TX_EVENT_STOP: + del_timer(&tx->timer_wait_idle); + asc_tx_sleep_cp(tx); + atomic_set(&tx->state, AP_TX_ST_SLEEP); + wake_unlock(&tx->wlock); + //mod_timer(&tx->timer_wait_sleep, jiffies + msecs_to_jiffies(ASC_TX_WAIT_IDLE_TIME)); + break; + default: + ASCDPRT("Tx: ignore event %d in state(%s)", event, tx->table[atomic_read(&tx->state)].name); + } + + //ASCDPRT("Tx(%s): go into state(%s).\n", tx->name, tx->table[atomic_read(&tx->state)].name); + return ret; +} + +/*Ignore the idle state, wait for a while to let CBP go to sleep*/ +static int asc_tx_handle_idle(void *data, int event) +{ + int ret = 0; + struct asc_tx_handle *tx = (struct asc_tx_handle *)data; + + if(AP_TX_ST_IDLE != atomic_read(&tx->state)){ + return 0; + } + + //ASCDPRT("Tx(%s): process event(%d) in state(%s).\n", tx->name, event, tx->table[atomic_read(&tx->state)].name); + switch(event){ + case AP_TX_EVENT_IDLE_TIMEOUT: + atomic_set(&tx->state, AP_TX_ST_SLEEP); + wake_unlock(&tx->wlock); + break; + case AP_TX_EVENT_REQUEST: + del_timer(&tx->timer_wait_sleep); + atomic_set(&tx->state, AP_TX_ST_SLEEP); + /*loop back to SLEEP handle*/ + asc_tx_event_send(tx, AP_TX_EVENT_REQUEST); + break; + default: + ASCDPRT("Tx: ignore event %d in state(%s)", event, tx->table[atomic_read(&tx->state)].name); + } + + //ASCDPRT("Tx(%s): go into state(%s).\n", tx->name, tx->table[atomic_read(&tx->state)].name); + return ret; +} + +static void asc_tx_handle_reset(struct asc_tx_handle *tx) +{ + unsigned long flags; + + ASCDPRT("%s %s\n", __FUNCTION__, tx->cfg.name); + del_timer(&tx->timer_wait_ready); + del_timer(&tx->timer_wait_idle); + del_timer(&tx->timer_wait_sleep); + spin_lock_irqsave(&tx->slock, flags); + INIT_LIST_HEAD(&tx->event_q); + spin_unlock_irqrestore(&tx->slock, flags); + asc_tx_sleep_cp(tx); + atomic_set(&tx->state, AP_TX_ST_SLEEP); + wake_unlock(&tx->wlock); +} + +/** + * asc_tx_reset - reset the tx handle + * @name: the config name for the handle + * + * return 0 ok, others be error + */ +void asc_tx_reset(const char *name) +{ + struct asc_tx_handle *tx = NULL; + + tx = asc_tx_handle_lookup(name); + if(tx){ + asc_tx_event_send(tx, AP_TX_EVENT_RESET); + } +} +EXPORT_SYMBOL(asc_tx_reset); + +/** + * asc_tx_set_auto_delay - change the delay time for auto ready + * @name: the config name for the handle + * @delay: the time for auto ready which is valid while more than default value + * return 0 ok,others be error + */ +int asc_tx_set_auto_delay(const char *name, int delay) +{ + int ret = 0; + unsigned long flags; + struct asc_tx_handle *tx; + + tx = asc_tx_handle_lookup(name); + if(!tx){ + ret = -ENODEV; + goto end; + } + if(delay > 0){ + spin_lock_irqsave(&tx->slock, flags); + tx->auto_delay = delay; + spin_unlock_irqrestore(&tx->slock, flags); + } + +end: + return ret; +} +EXPORT_SYMBOL(asc_tx_set_auto_delay); + +/** + * asc_tx_check_ready - check whether tx tanslation has alreay be ready + * @name: the config name for the handle + * + * return 1 waken, 0 not, others be error + */ +int asc_tx_check_ready(const char *name) +{ + int ret = 0; + struct asc_tx_handle *tx; + + tx = asc_tx_handle_lookup(name); + if(NULL == tx) + return -ENODEV; + + ret = atomic_read(&tx->state); + + if(ret == AP_TX_ST_READY){ + ret = 1; + }else{ + ret = 0; + } + + return ret; +} +EXPORT_SYMBOL(asc_tx_check_ready); + +/** + * asc_tx_user_counts - get the refernce count of the user or the handle + * @path: (handle name).[user name] + * If user name is NULL, return the count of tx handle. + * others return the count of the tx user + */ +int asc_tx_user_count(const char *path) +{ + const char *name; + char hname[ASC_NAME_LEN] = {0}; + struct asc_tx_handle *tx = NULL; + + name = strchr(path, '.'); + if (name){ + memcpy(hname, path, min(name - path, ASC_NAME_LEN - 1)); + name++; + }else { + strncpy(hname, path, ASC_NAME_LEN - 1); + } + + tx = asc_tx_handle_lookup(hname); + + if(NULL == tx) + return -ENODEV; + + return asc_tx_refer(tx, name); +} +EXPORT_SYMBOL(asc_tx_user_count); + +/** + * asc_tx_add_user - add a user for tx handle + * @name: the config name for the handle + * @infor: the user information + * + * return 0, others be error + */ +int asc_tx_add_user(const char *name, struct asc_infor *infor) +{ + int ret = 0; + unsigned long flags = 0; + struct asc_tx_handle *tx; + struct asc_user *user; + + tx = asc_tx_handle_lookup(name); + if(NULL == tx) + return -ENODEV; + + user = asc_tx_user_lookup(tx, infor->name); + if(NULL == user){ + user = kzalloc(sizeof(*user), GFP_KERNEL); + if(!user){ + ASCPRT("No memory to create new user reference.\n"); + ret = -ENOMEM; + goto error; + } + user->infor.data = infor->data; + user->infor.notifier = infor->notifier; + strncpy(user->infor.name, infor->name, ASC_NAME_LEN - 1); + atomic_set(&user->count, 0); + spin_lock_irqsave(&tx->slock, flags); + list_add_tail(&user->node, &tx->user_list); + spin_unlock_irqrestore(&tx->slock, flags); + }else{ + ASCPRT("%s error: user %s already exist!!\n", __FUNCTION__, infor->name); + ret = -EINVAL; + } +error: + return ret; +} +EXPORT_SYMBOL(asc_tx_add_user); + +/** + * asc_tx_del_user - delete a user for tx handle + * @path: (handle name).(user name) + * + * no return + */ +void asc_tx_del_user(const char *path) +{ + unsigned long flags = 0; + char hname[ASC_NAME_LEN] = {0}; + const char *name; + struct asc_user *user = NULL; + struct asc_tx_handle *tx = NULL; + + name = strchr(path, '.'); + if (name) { + memcpy(hname, path, min(name - path, ASC_NAME_LEN - 1)); + name++; + }else{ + ASCPRT("%s: invalid path %s\n", __FUNCTION__, path); + return ; + } + + /*if reserve user, do nothing*/ + if (!strncmp(name, ASC_TX_SYSFS_USER, ASC_NAME_LEN - 1) || \ + !strncmp(name, ASC_TX_AUTO_USER, ASC_NAME_LEN - 1) ) { + ASCPRT("Can not delete reserve user %s\n", path); + return ; + } + + tx = asc_tx_handle_lookup(hname); + + if(NULL == tx) + return ; + + user = asc_tx_user_lookup(tx, name); + if(user){ + /*put ready if the user had operated Tx handle*/ + if(atomic_read(&user->count) > 0){ + atomic_set(&user->count, 1); + asc_tx_put_ready(path, 0); + } + spin_lock_irqsave(&tx->slock, flags); + list_del(&user->node); + spin_unlock_irqrestore(&tx->slock, flags); + kfree(user); + } + + return ; +} +EXPORT_SYMBOL(asc_tx_del_user); + +/** + * asc_tx_get_ready - lock CBP to work + * @path: (handle name).(user name) + * @block: whether block wait for CBP has already waken + * + * This function try to wake the CBP and add the reference count. + * It will block wait for CBP has already be waken if set sync parameter, + * otherwise it just trig the action to wake CBP, which can not make sure + * that CBP has be waken after return. + * return 0 is ok, otherwise something error + */ +int asc_tx_get_ready(const char *path, int sync) +{ + int ret = 0; + char hname[ASC_NAME_LEN] = {0}; + const char *name; + struct asc_tx_handle *tx = NULL; + + name = strchr(path, '.'); + if (name) { + memcpy(hname, path, min(name - path, ASC_NAME_LEN - 1)); + name++; + } else { + ASCPRT("Invalid path %s\n", path); + return -EINVAL; + } + tx = asc_tx_handle_lookup(hname); + if(NULL == tx) + return -ENODEV; + + if(asc_tx_get_user(tx, name) < 0){ + ASCPRT("%s:tx user name %s is unknow\n", __FUNCTION__, name); + return -ENODEV; + } + ASCDPRT("%s: %s=%d, %s=%d\n", __FUNCTION__,\ + tx->cfg.name, asc_tx_refer(tx, NULL), path, asc_tx_refer(tx, name)); + switch(atomic_read(&tx->state)){ + case AP_TX_ST_SLEEP: + //To make CP wake ASAP,call the funtion directly + if(!list_empty(&tx->event_q)){ + asc_tx_handle_sleep(tx, AP_TX_EVENT_REQUEST); + }else{ + asc_tx_event_send(tx, AP_TX_EVENT_REQUEST); + } + break; + case AP_TX_ST_IDLE: + asc_tx_event_send(tx, AP_TX_EVENT_REQUEST); + break; + case AP_TX_ST_WAIT_READY: + case AP_TX_ST_READY: + if(!strncmp(name, ASC_TX_AUTO_USER, strlen(ASC_TX_AUTO_USER))){ + asc_tx_trig_busy(tx); + } + break; + default: + ASCPRT("Unknow tx state %d\n", atomic_read(&tx->state)); + return -EINVAL; + } + + if(sync){ + if(AP_TX_ST_READY != atomic_read(&tx->state)){ + interruptible_sleep_on(&tx->wait_tx_state); + if(AP_TX_ST_READY != atomic_read(&tx->state)){ + ret = -EBUSY; + } + } + } + + return ret; +} +EXPORT_SYMBOL(asc_tx_get_ready); + +/** + * asc_tx_put_ready - lock CBP to work if not set auto sleep + * @path: (config name).[user name] + * @block: whether block wait for CBP has already waken + * + * This function try to wake the CBP. It will block wait for CBP + * has already be sleep if set sync parameter, otherwise it just + * trig the action to sleep CBP, which can not make sure that + * CBP has be sleep after return. If the reference count is not 1. it + * do nothing but sub one. + * return 0 is ok, otherwise something error + */ +int asc_tx_put_ready(const char *path, int sync) +{ + int ret = 0; + char hname[ASC_NAME_LEN] = {0}; + const char *name; + struct asc_tx_handle *tx = NULL; + + name = strchr(path, '.'); + if (name) { + memcpy(hname, path, min(name - path, ASC_NAME_LEN - 1)); + name++; + } else { + ASCPRT("Invalid path %s\n", path); + return -EINVAL; + } + + tx = asc_tx_handle_lookup(hname); + if(NULL == tx) + return -ENODEV; + + if(asc_tx_put_user(tx, name) < 0){ + ASCPRT("%s:tx user name %s is unknow\n", __FUNCTION__, name); + return -ENODEV; + } + ASCDPRT("%s: %s=%d, %s=%d\n", __FUNCTION__,\ + tx->cfg.name, asc_tx_refer(tx, NULL), path, asc_tx_refer(tx, name)); + /*count is not 0, so do nothing*/ + if(asc_tx_refer(tx, NULL) != 0){ + return 0; + } + + switch(atomic_read(&tx->state)){ + case AP_TX_ST_SLEEP: + break; + case AP_TX_ST_WAIT_READY: + case AP_TX_ST_READY: + asc_tx_event_send(tx, AP_TX_EVENT_STOP); + break; + case AP_TX_ST_IDLE: + asc_tx_event_send(tx, AP_TX_EVENT_IDLE_TIMEOUT); + break; + default: + ASCPRT("Unknow tx state %d\n", atomic_read(&tx->state)); + return -EINVAL; + } + + if(sync){ + if(AP_TX_ST_SLEEP != atomic_read(&tx->state)){ + interruptible_sleep_on(&tx->wait_tx_state); + if(AP_TX_ST_SLEEP != atomic_read(&tx->state)){ + ret = -EBUSY; + } + } + } + + return ret; +} +EXPORT_SYMBOL(asc_tx_put_ready); + +/** + * asc_tx_auto_ready - call each time before operate for CBP if set auto sleep + * @name: the cofnig name for the handle + * @sync: whether block wait for CBP has already waken + * + * This function try to wake the CBP and trig the tx state. It will + * block wait for CBP has already be waken if set sync parameter, + * otherwise it just trig the action to wake CBP, which can not make + * sure that CBP has be waken after return. + * return 0 is ok, otherwise something error + */ +int asc_tx_auto_ready(const char *name, int sync) +{ + int ret = 0; + struct asc_user *user; + struct asc_tx_handle *tx; + + if (!name) { + ASCPRT("%s:Invalid name\n", __FUNCTION__); + return -EINVAL; + } + + tx = asc_tx_handle_lookup(name); + if(NULL == tx) + return -ENODEV; + + user = asc_tx_user_lookup(tx, ASC_TX_AUTO_USER); + if(!user){ + return -ENODEV; + } + + if(atomic_read(&user->count) == 0){ + ASCDPRT("%s: %s=%d, %s=%d\n", __FUNCTION__,\ + tx->cfg.name, asc_tx_refer(tx, NULL), ASC_TX_AUTO_USER, asc_tx_refer(tx, ASC_TX_AUTO_USER)); + atomic_inc(&user->count); + } + + switch(atomic_read(&tx->state)){ + case AP_TX_ST_SLEEP: + //To make CP wake ASAP,call the funtion directly + if(!list_empty(&tx->event_q)){ + asc_tx_handle_sleep(tx, AP_TX_EVENT_REQUEST); + }else{ + asc_tx_event_send(tx, AP_TX_EVENT_REQUEST); + } + break; + case AP_TX_ST_IDLE: + asc_tx_event_send(tx, AP_TX_EVENT_REQUEST); + break; + case AP_TX_ST_WAIT_READY: + case AP_TX_ST_READY: + asc_tx_trig_busy(tx); + break; + default: + ASCPRT("Unknow tx state %d\n", atomic_read(&tx->state)); + return -EINVAL; + } + + if(sync){ + if(AP_TX_ST_READY != atomic_read(&tx->state)){ + interruptible_sleep_on(&tx->wait_tx_state); + if(AP_TX_ST_READY != atomic_read(&tx->state)){ + ret = -EBUSY; + } + } + } + + return ret; + +} +EXPORT_SYMBOL(asc_tx_auto_ready); + +static void asc_rx_handle_reset(struct asc_rx_handle *rx) +{ + unsigned long flags; + + ASCDPRT("%s %s\n", __FUNCTION__, rx->cfg.name); + del_timer(&rx->timer); + wake_unlock(&rx->wlock); + asc_rx_indicate_sleep(rx); + atomic_set(&rx->state, AP_RX_ST_SLEEP); + spin_lock_irqsave(&rx->slock, flags); + INIT_LIST_HEAD(&rx->event_q); + spin_unlock_irqrestore(&rx->slock, flags); + +} + +/** + * asc_rx_reset - reset the rx handle + * @name: the config name for the handle + * + * return 0 ok, others be error + */ +void asc_rx_reset(const char *name) +{ + struct asc_rx_handle *rx = NULL; + + rx = asc_rx_handle_lookup(name); + if(rx){ + asc_rx_event_send(rx, AP_RX_EVENT_RESET); + } +} +EXPORT_SYMBOL(asc_rx_reset); + +/** + * asc_rx_add_user - add a user for rx handle + * @name: the config name for the handle + * @infor: the user information + * + * return 0, others be error + */ +int asc_rx_add_user(const char *name, struct asc_infor *infor) +{ + int ret = 0; + unsigned long flags = 0; + struct asc_rx_handle *rx; + struct asc_user *user; + + rx = asc_rx_handle_lookup(name); + if(NULL == rx) + return -ENODEV; + + user = asc_rx_user_lookup(rx, infor->name); + if(NULL == user){ + user = kzalloc(sizeof(*user), GFP_KERNEL); + if(!user){ + ASCPRT("No memory to create new user reference.\n"); + ret = -ENOMEM; + goto error; + } + user->infor.data = infor->data; + user->infor.notifier = infor->notifier; + strncpy(user->infor.name, infor->name, ASC_NAME_LEN - 1); + atomic_set(&user->count, 0); + spin_lock_irqsave(&rx->slock, flags); + list_add_tail(&user->node, &rx->user_list); + spin_unlock_irqrestore(&rx->slock, flags); + if(AP_RX_ST_WAIT_READY == atomic_read(&rx->state)){ + if(infor->notifier){ + infor->notifier(ASC_NTF_RX_PREPARE, infor->data); + } + } + }else{ + ASCPRT("%s error: user %s already exist!!\n", __FUNCTION__, infor->name); + ret = -EINVAL; + } +error: + return ret; +} +EXPORT_SYMBOL(asc_rx_add_user); + +/** + * asc_rx_del_user - add a user for rx handle + * @path: (config name).[user name] + * + * no return + */ +void asc_rx_del_user(const char *path) +{ + unsigned long flags = 0; + const char *name; + char hname[ASC_NAME_LEN] = {0}; + struct asc_user *user; + struct asc_rx_handle *rx; + + + name = strchr(path, '.'); + if (name) { + memcpy(hname, path, min(name - path, ASC_NAME_LEN - 1)); + name++; + }else{ + ASCPRT("%s: Invalid path %s\n",__FUNCTION__, path); + return ; + } + + rx = asc_rx_handle_lookup(hname); + if(NULL == rx) + return ; + + user = asc_rx_user_lookup(rx, name); + if(user){ + atomic_set(&user->count, 0); + spin_lock_irqsave(&rx->slock, flags); + list_del(&user->node); + spin_unlock_irqrestore(&rx->slock, flags); + kfree(user); + if(list_empty(&rx->user_list)){ + asc_rx_handle_reset(rx); + } + } + return ; +} +EXPORT_SYMBOL(asc_rx_del_user); + +/** + * asc_rx_confirm_ready - echo AP state to rx CBP data + * @name: the config name to rx handle + * @ready: whether AP has been ready to rx data + * + * After CBP request AP to rx data, the function can be used to + * tell CBP whether AP has been ready to receive. + * return 0 is ok, otherwise something error + */ +int asc_rx_confirm_ready(const char *name, int ready) +{ + struct asc_rx_handle *rx = NULL; + + rx = asc_rx_handle_lookup(name); + if(!rx){ + ASCDPRT("%s: name %s is unknow\n", __FUNCTION__, name); + return -ENODEV; + } + + ASCDPRT("Rx(%s) cnofirm ready=%d\n", rx->cfg.name, ready); + return asc_rx_event_send(rx, ready ? AP_RX_EVENT_AP_READY : AP_RX_EVENT_AP_UNREADY); +} +EXPORT_SYMBOL(asc_rx_confirm_ready); + +/** + * check_on_start - prevent from missing cp waking + * @name: the name of rx handle + * + * Before the rx user is registed,CP may wake up AP.Usually AP will ignore + * the waking.Because the interrupt don't be register at that time.So the + * signal will be missed.When opening the tty device, we should check whether CP + * has waken up AP or not.If CP did that,we should send the signal "AP READY" + * to CP. + */ + +int asc_rx_check_on_start(const char *name) +{ + int level; + struct asc_config *cfg = NULL; + struct asc_rx_handle *rx = NULL; + int ret = 1; + + rx = asc_rx_handle_lookup(name); + if(!rx){ + ASCPRT("config %s has not already exist.\n", name); + return -EINVAL; + } + + cfg = &(rx->cfg); + level = !!oem_gpio_get_value(cfg->gpio_wake); + if(level == cfg->polar){ + /*Cp has requested Ap wake*/ + if(AP_RX_ST_SLEEP == atomic_read(&rx->state)){ + ASCDPRT("Rx(%s):check_on_start--send event AP_RX_EVENT_REQUEST.\n", cfg->name); + ret = asc_rx_event_send(rx, AP_RX_EVENT_REQUEST); + }else{ + ASCDPRT("Rx(%s): check_on_start--send event AP_RX_EVENT_AP_READY.\n", cfg->name); + ret = asc_rx_event_send(rx, AP_RX_EVENT_AP_READY); + } + } + + return ret; +} +EXPORT_SYMBOL(asc_rx_check_on_start); + +static ssize_t asc_debug_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + char *s = buf; + s += sprintf(s, "%d\n", asc_debug); + + return (s - buf); +} + +static ssize_t asc_debug_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned long val; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + + if (val < 0) + return -EINVAL; + + asc_debug = val; + + return n; +} + + + +static ssize_t asc_infor_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + char *s = buf; + int val1, val2; + struct asc_config *cfg; + struct asc_infor *infor; + struct asc_user *user = NULL, *tuser = NULL; + struct asc_tx_handle *tx = NULL, *ttmp = NULL; + struct asc_rx_handle *rx = NULL, *rtmp = NULL; + + list_for_each_entry_safe(tx, ttmp, &asc_tx_handle_list, node){ + cfg = &tx->cfg; + val1 = val2 = -1; + if(cfg->gpio_wake >= 0) + val1 = !!oem_gpio_get_value(cfg->gpio_wake); + if(cfg->gpio_ready >= 0) + val2 = !!oem_gpio_get_value(cfg->gpio_ready); + + s += sprintf(s, "Tx %s: ref=%d, ap_wake_cp(%d)=%d, cp_ready(%d)=%d, polar=%d, auto_delay=%d mS\n", + cfg->name, asc_tx_refer(tx, NULL), cfg->gpio_wake, val1, cfg->gpio_ready, val2, cfg->polar, tx->auto_delay); + + list_for_each_entry_safe(user, tuser, &tx->user_list, node) { + infor = &user->infor; + s += sprintf(s, " user %s: ref=%d\n", infor->name, atomic_read(&user->count)); + } + } + + s += sprintf(s, "\n"); + + list_for_each_entry_safe(rx, rtmp, &asc_rx_handle_list, node){ + cfg = &rx->cfg; + val1 = val2 = -1; + if(cfg->gpio_wake >= 0) + val1 = !!oem_gpio_get_value(cfg->gpio_wake); + if(cfg->gpio_ready >= 0) + val2 = !!oem_gpio_get_value(cfg->gpio_ready); + + s += sprintf(s, "Rx %s: ref=%d, cp_wake_ap(%d)=%d, ap_ready(%d)=%d, polar=%d\n", \ + cfg->name, asc_rx_refer(rx, NULL), cfg->gpio_wake, val1, cfg->gpio_ready, val2, cfg->polar); + list_for_each_entry_safe(user, tuser, &rx->user_list, node) { + infor = &user->infor; + s += sprintf(s, " user %s: ref=%d\n", infor->name, atomic_read(&user->count)); + } + } + + return (s - buf); +} +static ssize_t asc_infor_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) +{ + return n; +} + +static ssize_t asc_refer_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + unsigned long flags; + char *s = buf; + struct asc_tx_handle *tx, *tmp, *t; + + tx = tmp = NULL; + spin_lock_irqsave(&hdlock, flags); + list_for_each_entry_safe(tmp, t, &asc_tx_handle_list, node){ + if(tmp->kobj == kobj){ + tx = tmp; + break; + } + } + spin_unlock_irqrestore(&hdlock, flags); + + if(tx){ + s += sprintf(s, "%d\n", asc_tx_refer(tx, ASC_TX_SYSFS_USER)); + return s - buf; + }else{ + ASCPRT("%s read error\n", __FUNCTION__); + return -EINVAL; + } + +} + + +static ssize_t asc_setcpmode_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + char *s = buf; + s += sprintf(s, "nothing\n"); + + return (s - buf); +} + +static ssize_t asc_setcpmode_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned long val; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + + if (val < 0) + return -EINVAL; + + if(val>0) + oem_gpio_output(GPIO_VIATEL_USB_AP_WAKE_MDM,1); + else + oem_gpio_output(GPIO_VIATEL_USB_AP_WAKE_MDM,0); + + + //asc_debug = val; + + return n; +} + + +static ssize_t asc_refer_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned long flags; + char *p; + int error = 0, len; + char path[ASC_NAME_LEN] = {0}; + struct asc_tx_handle *tx, *tmp, *t; + + tx = tmp = NULL; + spin_lock_irqsave(&hdlock, flags); + list_for_each_entry_safe(tmp, t, &asc_tx_handle_list, node){ + if(tmp->kobj == kobj){ + tx = tmp; + break; + } + } + spin_unlock_irqrestore(&hdlock, flags); + + if(tx){ + p = memchr(buf, '\n', n); + len = p ? p - buf : n; + snprintf(path, ASC_NAME_LEN, "%s.%s", tx->cfg.name, ASC_TX_SYSFS_USER); + + if (len == 3 && !strncmp(buf, "get", len)) { + error = asc_tx_get_ready(path, 1); + }else if (len == 3 && !strncmp(buf, "put", len)) { + error= asc_tx_put_ready(path, 1); + } + } + + return error ? error : n; +} + +static ssize_t asc_state_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + unsigned long flags; + char *s = buf; + struct asc_tx_handle *tx, *tmp, *t; + + tx = tmp = NULL; + spin_lock_irqsave(&hdlock, flags); + list_for_each_entry_safe(tmp, t, &asc_tx_handle_list, node){ + if(tmp->kobj == kobj){ + tx = tmp; + break; + } + } + spin_unlock_irqrestore(&hdlock, flags); + + if(tx){ + s += sprintf(s, "%s\n", tx->table[atomic_read(&tx->state)].name); + return s - buf; + }else{ + ASCPRT("%s read error\n", __FUNCTION__); + return -EINVAL; + } + +} + +static ssize_t asc_state_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) +{ + return n; +} + +static ssize_t asc_auto_ready_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + unsigned long flags; + char *s = buf; + struct asc_tx_handle *tx, *tmp, *t; + + tx = tmp = NULL; + spin_lock_irqsave(&hdlock, flags); + list_for_each_entry_safe(tmp, t, &asc_tx_handle_list, node){ + if(tmp->kobj == kobj){ + tx = tmp; + break; + } + } + spin_unlock_irqrestore(&hdlock, flags); + + if(tx){ + s += sprintf(s, "%d\n", tx->auto_delay); + return s - buf; + }else{ + ASCPRT("%s read error\n", __FUNCTION__); + return -EINVAL; + } + +} + +static ssize_t asc_auto_ready_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) +{ + int error = 0; + long val; + unsigned long flags; + struct asc_tx_handle *tx, *tmp, *t; + + tx = tmp = NULL; + spin_lock_irqsave(&hdlock, flags); + list_for_each_entry_safe(tmp, t, &asc_tx_handle_list, node){ + if(tmp->kobj == kobj){ + tx = tmp; + break; + } + } + spin_unlock_irqrestore(&hdlock, flags); + + if(tx){ + error = strict_strtol(buf, 10, &val); + if(error || (val < 0)){ + error = -EINVAL; + goto end; + } + + if(val > 0){ + spin_lock_irqsave(&tx->slock, flags); + tx->auto_delay = val; + spin_unlock_irqrestore(&tx->slock, flags); + } + error = asc_tx_auto_ready(tx->cfg.name, 1); + }else{ + ASCPRT("%s read error\n", __FUNCTION__); + error = -EINVAL; + } + +end: + return error ? error : n; +} + +#define asc_attr(_name) \ +static struct kobj_attribute _name##_attr = { \ + .attr = { \ + .name = __stringify(_name), \ + .mode = 0644, \ + }, \ + .show = asc_##_name##_show, \ + .store = asc_##_name##_store, \ +} + +asc_attr(debug); +asc_attr(infor); +asc_attr(setcpmode); + +static struct attribute * g_attr[] = { + &debug_attr.attr, + &infor_attr.attr, + &setcpmode_attr.attr, + NULL, +}; + +static struct attribute_group g_attr_group = { + .attrs = g_attr, +}; + +asc_attr(refer); +asc_attr(state); +asc_attr(auto_ready); + +static struct attribute * tx_hd_attr[] = { + &refer_attr.attr, + &state_attr.attr, + &auto_ready_attr.attr, + NULL, +}; + +int asc_suspend(struct platform_device *pdev, pm_message_t state) +{ + oem_gpio_irq_mask(tx_cfg.gpio_ready); + oem_gpio_irq_mask(rx_cfg.gpio_wake); + if(ap_ready_always) + oem_gpio_output(rx_cfg.gpio_ready,!rx_cfg.polar); + + return 0; +} + + +int asc_resume(struct platform_device *pdev) +{ + + msleep(500); + printk("asc_resume\n"); + oem_gpio_direction_output(tx_cfg.gpio_wake, tx_cfg.polar); + oem_gpio_direction_input_for_irq(tx_cfg.gpio_ready); + oem_gpio_set_irq_type(tx_cfg.gpio_ready, IRQF_TRIGGER_RISING); + oem_gpio_irq_unmask(tx_cfg.gpio_ready); + + oem_gpio_output(rx_cfg.gpio_ready, rx_cfg.polar); + oem_gpio_direction_input_for_irq(rx_cfg.gpio_wake); + oem_gpio_set_irq_type(rx_cfg.gpio_wake, IRQF_TRIGGER_RISING); + oem_gpio_irq_unmask(rx_cfg.gpio_wake); + + return 0; +} + +static struct attribute_group tx_hd_attr_group = { + .attrs = tx_hd_attr, +}; + + +static struct platform_driver asc_driver = { + .driver.name = "asc", + .suspend = asc_suspend, + .resume = asc_resume, +}; + +static struct platform_device asc_device = { + .name = "asc", +}; + + +/** + * asc_rx_register_handle - register the rx handle + * @cfg: the config for the handle + * + * the device which receive data from CBP can register a notifier to + * listen the event according to the changes from CBP. + * ASC_PREPARE_RX_DATA event will be send when CBP start tx data + * to the device which must be ready to work; + * ASC_POST_RX_DATA event will be send when CBP stop tx data to + * the device which can go to sleep. + * The gpio for ap_ready can be -1 which be ignored when the device + * can receive the data from CBP correctly any time. + * return index according to the notifier in handle, otherwise something error + */ +int asc_rx_register_handle(struct asc_config *cfg) +{ + int ret = 0; + unsigned long flags; + struct asc_rx_handle *rx = NULL; + + if(NULL == asc_work_queue){ + ASCPRT("%s: error Asc has not been init\n", __FUNCTION__); + return -EINVAL; + } + + if(NULL == cfg){ + return -EINVAL; + } + + if(cfg->gpio_wake < 0){ + ASCPRT("%s: config %s gpio is invalid.\n", __FUNCTION__, cfg->name); + return -EINVAL; + } + + rx = asc_rx_handle_lookup(cfg->name); + if(rx){ + ASCPRT("config %s has already exist.\n", cfg->name); + return -EINVAL; + } + + rx = kzalloc(sizeof(struct asc_rx_handle), GFP_KERNEL); + if(NULL == rx){ + ASCPRT("No memory to alloc rx handle.\n"); + return -ENOMEM; + } + + rx->cfg.gpio_ready = cfg->gpio_ready; + rx->cfg.gpio_wake = cfg->gpio_wake; + rx->cfg.polar = !!cfg->polar; + strncpy(rx->cfg.name, cfg->name, ASC_NAME_LEN - 1); + memcpy(&rx_cfg, &rx->cfg, sizeof(struct asc_config)); + + ret = asc_rx_handle_init(rx); + if(ret < 0){ + kfree(rx); + ASCPRT("fail to init rx handle %s\n", rx->cfg.name); + return -EINVAL; + } + + /* Add the handle to the asc list */ + spin_lock_irqsave(&hdlock, flags); + list_add(&rx->node, &asc_rx_handle_list); + spin_unlock_irqrestore(&hdlock, flags); + ASCDPRT("Register rx handle %s\n", rx->cfg.name); + return ret; +} +EXPORT_SYMBOL(asc_rx_register_handle); + +/** + * asc_tx_register_handle - register the tx handle for state change + * @cfg: the config for the handle + * + * the chip which exchanged data with CBP must create a handle. + * There is only one tx state handle between the AP and CBP because + * all devices in CBP will be ready to receive data after CBP has been + * waken. But servial rx state handles can be exist because different + * devices in AP maybe waken indivially. Each rx state handle must be + * registed a notifier to listen the evnets. + * return 0 is ok, otherwise something error + */ +int asc_tx_register_handle(struct asc_config *cfg) +{ + int ret=0; + unsigned long flags; + struct asc_infor infor; + struct asc_tx_handle *tx = NULL; + + if(NULL == asc_work_queue){ + ASCPRT("%s: error Asc has not been init\n", __FUNCTION__); + return -EINVAL; + } + + if(NULL == cfg){ + return -EINVAL; + } + + if(cfg->gpio_wake < 0){ + ASCPRT("%s: config %s gpio is invalid.\n", __FUNCTION__, cfg->name); + return -EINVAL; + } + + tx = asc_tx_handle_lookup(cfg->name); + if(tx){ + ASCPRT("config %s has already exist.\n", cfg->name); + return -EINVAL; + } + + tx = kzalloc(sizeof(struct asc_tx_handle), GFP_KERNEL); + if(NULL == tx){ + ASCPRT("Fail to alloc memory for tx handle.\n"); + return -ENOMEM; + } + + tx->cfg.gpio_ready = cfg->gpio_ready; + tx->cfg.gpio_wake = cfg->gpio_wake; + tx->cfg.polar = !!cfg->polar; + strncpy(tx->cfg.name, cfg->name, ASC_NAME_LEN - 1); + memcpy(&tx_cfg, &tx->cfg, sizeof(struct asc_config)); + ret = asc_tx_handle_init(tx); + if(ret < 0){ + ASCPRT("Fail to init tx handle %s.\n", tx->cfg.name); + goto err_tx_handle_init; + } + + /* Add the handle to the asc list */ + spin_lock_irqsave(&hdlock, flags); + list_add(&tx->node, &asc_tx_handle_list); + spin_unlock_irqrestore(&hdlock, flags); + ASCDPRT("Register tx handle %s.\n", tx->cfg.name); + + tx->kobj = kobject_create_and_add(cfg->name, asc_kobj); + if(!tx->kobj){ + ret = -ENOMEM; + goto err_create_kobj; + } + + /*add default user for application*/ + memset(&infor, 0, sizeof(infor)); + strncpy(infor.name, ASC_TX_SYSFS_USER, ASC_NAME_LEN); + asc_tx_add_user(tx->cfg.name, &infor); + memset(&infor, 0, sizeof(infor)); + strncpy(infor.name, ASC_TX_AUTO_USER, ASC_NAME_LEN); + asc_tx_add_user(tx->cfg.name, &infor); + return sysfs_create_group(tx->kobj, &tx_hd_attr_group); + +err_create_kobj: + list_del(&tx->node); +err_tx_handle_init: + if(tx){ + kfree(tx); + } + + return ret; +} +EXPORT_SYMBOL(asc_tx_register_handle); + +static int __init asc_init(void) +{ + int ret; + ret = oem_gpio_convert_init(); + if(ret){ + printk("Warnning:viatel gpio not set.\n"); + return -EIO; + } + + ret = platform_device_register(&asc_device); + if (ret) { + ASCPRT("platform_device_register failed\n"); + goto err_platform_device_register; + } + ret = platform_driver_register(&asc_driver); + if (ret) { + ASCPRT("platform_driver_register failed\n"); + goto err_platform_driver_register; + } + + asc_work_queue = create_singlethread_workqueue("asc_work"); + if (asc_work_queue == NULL) { + ret = -ENOMEM; + goto err_create_work_queue; + } + + asc_kobj = viatel_kobject_add("asc"); + if (!asc_kobj){ + ret = -ENOMEM; + goto err_create_kobj; + } + + return sysfs_create_group(asc_kobj, &g_attr_group); + +err_create_kobj: + destroy_workqueue(asc_work_queue); +err_create_work_queue: + platform_driver_unregister(&asc_driver); +err_platform_driver_register: + platform_device_unregister(&asc_device); +err_platform_device_register: + return ret; +} + +device_initcall(asc_init); + |