From 2489007e7d740ccbc3e0a202914e243ad5178787 Mon Sep 17 00:00:00 2001 From: codeworkx Date: Sat, 22 Sep 2012 09:48:20 +0200 Subject: merge opensource jb u5 Change-Id: I1aaec157aa196f3448eff8636134fce89a814cf2 --- drivers/felica/felica.c | 2219 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2219 insertions(+) create mode 100644 drivers/felica/felica.c (limited to 'drivers/felica/felica.c') diff --git a/drivers/felica/felica.c b/drivers/felica/felica.c new file mode 100644 index 0000000..cdb61c7 --- /dev/null +++ b/drivers/felica/felica.c @@ -0,0 +1,2219 @@ +/* +* 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. +* +* 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. +*/ + +#ifdef CONFIG_FELICA + +#include "felica.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/****************************************************************************** + * log + ******************************************************************************/ + +#ifdef FELICA_DEBUG +#define FELICA_LOG_DEBUG(fmt, args...) printk(KERN_INFO fmt, ## args) +#else +#define FELICA_LOG_DEBUG(fmt, args...) +#endif +#define FELICA_LOG_ERR(fmt, args...) printk(KERN_ERR fmt, ## args) + +/****************************************************************************** + * global variable + ******************************************************************************/ + +static struct class *felica_class; + +/* storages for communicate to netlink */ +static int gfa_open_cnt; +static int gfa_pid; +static int gfa_connect_flag; +static struct sock *gfanl_sk; +static char gfa_send_str[FELICA_NL_MSG_SIZE]; +static char gfa_rcv_str[FELICA_NL_MSG_SIZE]; +static int gfa_wait_flag; + +/* R/W functions availability information storage */ +static char gfelica_rw_status; + +/* IRQ data storage for INT terminal monitoring */ +struct felica_int_irqdata { + struct delayed_work work; + wait_queue_head_t read_wait; + int irq_done; + int open_flag; +}; +static struct felica_int_irqdata gint_irq; +static struct felica_int_irqdata *pgint_irq = &gint_irq; + +/* storages for access restriction */ +static uid_t gmfc_uid = -1; +static uid_t gmfl_uid = -1; +static uid_t grwm_uid = -1; +static uid_t gdiag_uid = -1; +/* package name's storage for access restriction */ +static char gdiag_name[DIAG_NAME_MAXSIZE + 1]; +static uid_t gant_uid = -1; +static int gi2c_address; +static char gi2c_antaddress; +static char gi2c_lockaddress; +static struct i2c_msg gread_msgs[] = { + { + .addr = 0, + .flags = 0, + .len = 0, + .buf = NULL, + }, + { + .addr = 0, + .flags = 0, + .len = 0, + .buf = NULL, + }, +}; + +static struct i2c_msg gwrite_msgs[] = { + { + .addr = 0, + .flags = 0, + .len = 0, + .buf = NULL, + }, +}; +#define FELICA_UART1RX EXYNOS4_GPA0(4) +#define FELICA_UART3RX EXYNOS4_GPA1(4) + + +/****************************************************************************** + * /dev/felica + ******************************************************************************/ + +/* character device definition */ +static int felica_uart_port; + +static dev_t devid_felica_uart; +static struct cdev cdev_felica_uart; +static const struct file_operations fops_felica_uart = { + .owner = THIS_MODULE, + .open = felica_uart_open, + .release = felica_uart_close, + .read = felica_uart_read, + .write = felica_uart_write, + .fsync = felica_uart_sync, + .unlocked_ioctl = felica_uart_ioctl, +}; +struct felica_sem_data { + struct semaphore felica_sem; +}; +static struct felica_sem_data *dev_sem; + +/* + * initialize device + */ +static void felica_uart_init(void) +{ + int ret; + struct device *device_felica_uart; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + devid_felica_uart = MKDEV(FELICA_MAJOR, FELICA_MINOR); + ret = + alloc_chrdev_region(&devid_felica_uart, FELICA_BASEMINOR, + FELICA_MINOR_COUNT, FELICA_UART_NAME); + if (ret < 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(alloc_chrdev_region), ret=[%d]", + __func__, ret); + return; + } + + cdev_init(&cdev_felica_uart, &fops_felica_uart); + ret = + cdev_add(&cdev_felica_uart, devid_felica_uart, FELICA_MINOR_COUNT); + if (ret < 0) { + unregister_chrdev_region(devid_felica_uart, FELICA_MINOR_COUNT); + FELICA_LOG_ERR("[MFDD] %s ERROR(cdev_add), ret=[%d]", __func__, + ret); + return; + } + + device_felica_uart = + device_create(felica_class, NULL, devid_felica_uart, NULL, + FELICA_UART_NAME); + if (IS_ERR(device_felica_uart)) { + cdev_del(&cdev_felica_uart); + unregister_chrdev_region(devid_felica_uart, FELICA_MINOR_COUNT); + FELICA_LOG_ERR("[MFDD] %s ERROR(device_create)", __func__); + return; + } + + dev_sem = kmalloc(sizeof(struct felica_sem_data), GFP_KERNEL); + if (!dev_sem) { + cdev_del(&cdev_felica_uart); + unregister_chrdev_region(devid_felica_uart, FELICA_MINOR_COUNT); + FELICA_LOG_ERR("[MFDD] %s ERROR(dev_sem malloc)", __func__); + return; + } + sema_init(&dev_sem->felica_sem, 1); + + FELICA_LOG_DEBUG("[MFDD] %s END, major=[%d], minor=[%d]", __func__, + MAJOR(devid_felica_uart), MINOR(devid_felica_uart)); +} + +/* + * finalize device + */ +static void felica_uart_exit(void) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + kfree(dev_sem); + device_destroy(felica_class, devid_felica_uart); + cdev_del(&cdev_felica_uart); + unregister_chrdev_region(devid_felica_uart, FELICA_MINOR_COUNT); + + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); +} + +/* + * open device + */ +static int felica_uart_open(struct inode *inode, struct file *file) +{ + uid_t uid; + int ret; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + + FELICA_LOG_DEBUG("[MFDD] %s system_rev: 0x%x uart port: %d ", + __func__, system_rev, felica_uart_port); + + uid = __task_cred(current)->uid; + if ((uid != gmfc_uid) && (uid != gdiag_uid) + && (uid != gant_uid)) { + FELICA_LOG_DEBUG + ("[MFDD] %s END, uid=[%d], gmfc_uid=[%d], gdiag_uid=[%d]", + __func__, uid, gmfc_uid, gdiag_uid); + return -EACCES; + } + + if (down_interruptible(&dev_sem->felica_sem)) { + FELICA_LOG_ERR("[MFDD] %s ERROR(down_interruptible)", \ + __func__); + return -ERESTARTSYS; + } + + if (gfa_open_cnt == 0) { + memset(gfa_send_str, 0, FELICA_NL_MSG_SIZE); + memset(gfa_rcv_str, 0, FELICA_NL_MSG_SIZE); + gfa_send_str[0] = FELICA_NL_REQ_OPEN; + gfa_send_str[1] = felica_uart_port; + + ret = felica_nl_send_msg(2); + + if (ret == 0) { + felica_nl_wait_ret_msg(); + if (gfa_rcv_str[1] == FELICA_NL_EFAILED) { + FELICA_LOG_ERR("[MFDD] %s Open Fail", __func__); + up(&dev_sem->felica_sem); + return -EFAULT; + } + } else { + FELICA_LOG_ERR("[MFDD] %s felica_nl_send_msg Fail", \ + __func__); + up(&dev_sem->felica_sem); + return -EFAULT; + } + } + gfa_open_cnt++; + + up(&dev_sem->felica_sem); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * close device + */ +static int felica_uart_close(struct inode *inode, struct file *file) +{ + int ret; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + if (down_interruptible(&dev_sem->felica_sem)) { + FELICA_LOG_ERR("[MFDD] %s ERROR(down_interruptible)", \ + __func__); + return -ERESTARTSYS; + } + + gfa_open_cnt--; + if (gfa_open_cnt == 0) { + memset(gfa_send_str, 0, FELICA_NL_MSG_SIZE); + memset(gfa_rcv_str, 0, FELICA_NL_MSG_SIZE); + gfa_send_str[0] = FELICA_NL_REQ_CLOSE; + ret = felica_nl_send_msg(1); + if (ret == 0) { + felica_nl_wait_ret_msg(); + if (gfa_rcv_str[1] == FELICA_NL_EFAILED) { + FELICA_LOG_ERR("[MFDD] %s Close Fail",\ + __func__); + gfa_open_cnt++; + up(&dev_sem->felica_sem); + return -EFAULT; + } + } else { + FELICA_LOG_ERR("[MFDD] %s felica_nl_send_msg Fail", \ + __func__); + gfa_open_cnt++; + up(&dev_sem->felica_sem); + return -EFAULT; + } + } + + up(&dev_sem->felica_sem); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * read operation + */ +static ssize_t felica_uart_read(struct file *file, char __user *buf, + size_t len, loff_t *ppos) +{ + int ret = 0; + int nlret; + size_t wk_len = 0; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + if (down_interruptible(&dev_sem->felica_sem)) { + FELICA_LOG_ERR("[MFDD] %s ERROR(down_interruptible)", \ + __func__); + return -ERESTARTSYS; + } + + memset(gfa_send_str, 0, FELICA_NL_MSG_SIZE); + memset(gfa_rcv_str, 0, FELICA_NL_MSG_SIZE); + + wk_len = len; + if (FELICA_NL_MSG_DATA_SIZE < wk_len) { + FELICA_LOG_DEBUG("[MFDD] %s read max size over [%d]", __func__, + wk_len); + wk_len = FELICA_NL_MSG_DATA_SIZE; + } + gfa_send_str[0] = FELICA_NL_REQ_READ; + gfa_send_str[1] = (char)(wk_len >> 8); + gfa_send_str[2] = (char)wk_len; + nlret = felica_nl_send_msg(3); + + wk_len = 0; + if (nlret == 0) { + felica_nl_wait_ret_msg(); + if (gfa_rcv_str[1] == FELICA_NL_SUCCESS) { + wk_len = + (((int)gfa_rcv_str[2] << 8) & 0xFF00) | \ + (int)gfa_rcv_str[3]; + ret = copy_to_user(buf, &gfa_rcv_str[4], wk_len); + if (ret != 0) { + FELICA_LOG_ERR + ("[MFDD]%s ERROR(copy_from_user), ret=[%d]", + __func__, ret); + up(&dev_sem->felica_sem); + return -EFAULT; + } + *ppos = *ppos + wk_len; + } else { + FELICA_LOG_DEBUG(" %s FAIL", __func__); + up(&dev_sem->felica_sem); + return -EFAULT; + } + } else { + FELICA_LOG_DEBUG(" %s FAIL", __func__); + up(&dev_sem->felica_sem); + return -EFAULT; + } + + up(&dev_sem->felica_sem); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return (ssize_t) wk_len; +} + +/* + * write operation + */ +static ssize_t felica_uart_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + int ret = 0; + int nlret; + size_t wk_len = 0; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + if (down_interruptible(&dev_sem->felica_sem)) { + FELICA_LOG_ERR("[MFDD] %s ERROR(down_interruptible)", \ + __func__); + return -ERESTARTSYS; + } + + memset(gfa_send_str, 0, FELICA_NL_MSG_SIZE); + memset(gfa_rcv_str, 0, FELICA_NL_MSG_SIZE); + + wk_len = len; + if (FELICA_NL_MSG_DATA_SIZE < wk_len) { + FELICA_LOG_DEBUG("[MFDD] %s read max size over [%d]", __func__, + wk_len); + wk_len = FELICA_NL_MSG_DATA_SIZE; + } + gfa_send_str[0] = FELICA_NL_REQ_WRITE; + gfa_send_str[1] = (char)(wk_len >> 8); + gfa_send_str[2] = (char)wk_len; + ret = copy_from_user(&gfa_send_str[3], data, wk_len); + if (ret != 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(copy_from_user), ret=[%d]", + __func__, ret); + up(&dev_sem->felica_sem); + return -EFAULT; + } + nlret = felica_nl_send_msg(3 + len); + if (nlret == 0) { + wk_len = 0; + felica_nl_wait_ret_msg(); + wk_len = (((int)gfa_rcv_str[2] << 8) & 0xFF00) | \ + (int)gfa_rcv_str[3]; + if (gfa_rcv_str[1] == FELICA_NL_EFAILED) { + FELICA_LOG_ERR("[MFDD] %s Write Fail", __func__); + up(&dev_sem->felica_sem); + return -EINVAL; + } + } else { + FELICA_LOG_ERR("[MFDD] %s felica_nl_send_msg Fail", __func__); + up(&dev_sem->felica_sem); + return -EINVAL; + } + up(&dev_sem->felica_sem); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return wk_len; +} + +/* + * sync operation + */ +static int felica_uart_sync(struct file *file, int datasync) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * available operation + */ +static long felica_uart_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + unsigned int ret_str = 0; + int ret; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + if (down_interruptible(&dev_sem->felica_sem)) { + FELICA_LOG_ERR("[MFDD] %s ERROR(down_interruptible)", \ + __func__); + return -ERESTARTSYS; + } + + memset(gfa_send_str, 0, FELICA_NL_MSG_SIZE); + memset(gfa_rcv_str, 0, FELICA_NL_MSG_SIZE); + + gfa_send_str[0] = FELICA_NL_REQ_AVAIABLE; + ret = felica_nl_send_msg(1); + + if (ret == 0) { + felica_nl_wait_ret_msg(); + if (gfa_rcv_str[1] == FELICA_NL_SUCCESS) { + /* create response data */ + ret_str = + (((unsigned int)gfa_rcv_str[2] << 8) & 0xFF00) | \ + (unsigned int)gfa_rcv_str[3]; + FELICA_LOG_DEBUG("Available Success data size [%d]", \ + ret_str); + } else { + FELICA_LOG_ERR("[MFDD] %s Available Fail", __func__); + up(&dev_sem->felica_sem); + return -EINVAL; + } + } else { + FELICA_LOG_ERR("[MFDD] %s felica_nl_send_msg Fail", __func__); + up(&dev_sem->felica_sem); + return -EINVAL; + } + + up(&dev_sem->felica_sem); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return put_user(ret_str, (unsigned int __user *)arg); + +} + +/* + * create netlink socket + */ +static void felica_nl_init(void) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + gfa_connect_flag = 0; + gfa_pid = 0; + gfa_wait_flag = 0; + memset(gfa_send_str, 0, FELICA_NL_MSG_SIZE); + memset(gfa_rcv_str, 0, FELICA_NL_MSG_SIZE); + + gfanl_sk = + netlink_kernel_create(&init_net, FELICA_NL_NETLINK_USER, 0, + felica_nl_recv_msg, NULL, THIS_MODULE); + if (!gfanl_sk) + FELICA_LOG_ERR("Error creating socket. %s\n", __func__); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); +} + +/* + * release netlink socket + */ +static void felica_nl_exit(void) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + netlink_kernel_release(gfanl_sk); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); +} + +/* + * send message to FeliCa-Serial-Connector + */ +static int felica_nl_send_msg(int len) +{ + struct nlmsghdr *nlh; + struct sk_buff *skb_out; + int msg_size = 0; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + if (!gfanl_sk) { + FELICA_LOG_ERR("[MFDD]Error Not creating socket. %s\n", + __func__); + return 1; + } + if (gfa_pid == 0) { + FELICA_LOG_ERR("[MFDD]Error Not Rcv Connect Msg %s\n", + __func__); + return 1; + } + + msg_size = len; + skb_out = nlmsg_new(msg_size, 0); + + if (!skb_out) { + FELICA_LOG_ERR("Failed to allocate new skb_out %s\n", __func__); + return 1; + } + nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0); + NETLINK_CB(skb_out).dst_group = 0; + memcpy(NLMSG_DATA(nlh), gfa_send_str, msg_size); + + /* "skb_out" will release by netlink.*/ + nlmsg_unicast(gfanl_sk, skb_out, gfa_pid); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * receive message from FeliCa-Serial-Connector + */ +static void felica_nl_recv_msg(struct sk_buff *skb) +{ + + struct nlmsghdr *nlh; + struct sk_buff *wskb; + int port_threshold = 0; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + if (!skb) { + FELICA_LOG_ERR("[MFDD] %s ERROR(skb NULL)", __func__); + return; + } + + wskb = skb_get(skb); + if (wskb && (wskb->len > NLMSG_SPACE(0))) { + nlh = nlmsg_hdr(wskb); + memcpy(gfa_rcv_str, NLMSG_DATA(nlh), sizeof(gfa_rcv_str)); + if ((gfa_rcv_str[0] == FELICA_NL_CONNECT_MSG) + && (gfa_connect_flag == 0)) { + /* pid of sending process */ + gfa_pid = nlh->nlmsg_pid; + +#if defined(CONFIG_MACH_T0) + port_threshold = 0x09; +#elif defined(CONFIG_MACH_M3) + port_threshold = 0x02; +#endif + if (felica_get_tamper_fuse_cmd() != 1) { + if (system_rev >= port_threshold) { + s3c_gpio_cfgall_range(FELICA_UART1RX, 4,\ + S3C_GPIO_SFN(2), S3C_GPIO_PULL_DOWN); + felica_uart_port = 1; + } else { + s3c_gpio_cfgall_range(FELICA_UART3RX, 2,\ + S3C_GPIO_SFN(2), S3C_GPIO_PULL_DOWN); + felica_uart_port = 3; + } + felica_set_felica_info(); + felica_uart_init(); + felica_pon_init(); + felica_cen_init(); + felica_rfs_init(); + felica_rws_init(); + felica_ant_init(); + if (gdiag_name[0] != 0x00) + felica_uid_init(); + } + + gfa_connect_flag = 1; + } else if ((gfa_rcv_str[0] == FELICA_NL_RESPONCE) + && (gfa_pid == nlh->nlmsg_pid)) { + /* wake up */ + gfa_wait_flag = 1; + } else { + FELICA_LOG_ERR("[MFDD] %s ERROR(RCV Undefine MSG)", + __func__); + FELICA_LOG_ERR("RCV MSG [%d]", gfa_rcv_str[0]); + FELICA_LOG_ERR("rcv pid [%d]", nlh->nlmsg_pid); + FELICA_LOG_ERR("gfa_pid [%d]", gfa_pid); + } + } + kfree_skb(skb); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); +} +static void felica_set_felica_info(void) +{ + FELICA_LOG_DEBUG("[MFDD] %s START ", __func__); + memset(gdiag_name, 0x00, DIAG_NAME_MAXSIZE + 1); + + gread_msgs[0].flags = gfa_rcv_str[MSG_READ1_FLAGS_OFFSET]; + gread_msgs[0].len = gfa_rcv_str[MSG_READ1_LEN_OFFSET]; + gread_msgs[1].flags = gfa_rcv_str[MSG_READ2_FLAGS_OFFSET]; + gread_msgs[1].len = gfa_rcv_str[MSG_READ2_LEN_OFFSET]; + gwrite_msgs[0].flags = gfa_rcv_str[MSG_WRITE_FLAGS_OFFSET]; + gwrite_msgs[0].len = gfa_rcv_str[MSG_WRITE_LEN_OFFSET]; + gi2c_lockaddress = gfa_rcv_str[MSG_LOCK_ADDR_OFFSET]; + gi2c_address = gfa_rcv_str[MSG_I2C_ADDR_OFFSET]; + + memcpy(gdiag_name, &gfa_rcv_str[MSG_DIAG_NAME_OFFSET], + DIAG_NAME_MAXSIZE); + + gmfc_uid = + (((int)gfa_rcv_str[MSG_MFC_UID_FRONT_OFFSET] << 8) & 0xFF00) | + (int)gfa_rcv_str[MSG_MFC_UID_BACK_OFFSET]; + + gmfl_uid = + (((int)gfa_rcv_str[MSG_MFL_UID_FRONT_OFFSET] << 8) & 0xFF00) | + (int)gfa_rcv_str[MSG_MFL_UID_BACK_OFFSET]; + + gi2c_antaddress = gfa_rcv_str[MSG_ANT_ADDR_OFFSET]; + gant_uid = + (((int)gfa_rcv_str[MSG_ANT_UID_FRONT_OFFSET] << 8) & 0xFF00) | + (int)gfa_rcv_str[MSG_ANT_UID_BACK_OFFSET]; + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); +} + +/* + * waiting to receive messages from FeliCa-Serial-Connector + */ +static void felica_nl_wait_ret_msg(void) +{ + unsigned int cnt = 0; + FELICA_LOG_DEBUG("[MFDD] %s START ", __func__); + + while (1) { + if (gfa_wait_flag == 1) { + FELICA_LOG_DEBUG("[MFDD] %s sleep cnt [%d]", __func__, + cnt); + break; + } + mdelay(1); + cnt++; + } + gfa_wait_flag = 0; + + FELICA_LOG_DEBUG("[MFDD] %s END ", __func__); +} + + + +static int felica_smc_read_oemflag(u32 ctrl_word, u32 *val) +{ + register u32 reg0 __asm__("r0"); + register u32 reg1 __asm__("r1"); + register u32 reg2 __asm__("r2"); + register u32 reg3 __asm__("r3"); + u32 idx = 0; + + for (idx = 0; reg2 != ctrl_word; idx++) { + reg0 = -202; + reg1 = 1; + reg2 = idx; + + __asm__ volatile ("smc 0\n" : "+r" (reg0), "+r"(reg1), + "+r"(reg2), "+r"(reg3) + ); + if (reg1) + return -1; + } + + reg0 = -202; + reg1 = 1; + reg2 = idx; + + __asm__ volatile ("smc 0\n" : "+r" (reg0), "+r"(reg1), + "+r"(reg2), "+r"(reg3) + ); + if (reg1) + return -1; + + *val = reg2; + + return 0; +} + +static int felica_Cpu0(void) +{ + int ret = 0; + struct cpumask mask = CPU_MASK_CPU0; + + FELICA_LOG_DEBUG("System has %d CPU's, we are on CPU #%d\n" + "\tBinding this process to CPU #0.\n" + "\tactive mask is %lx, setting it to mask=%lx\n", + nr_cpu_ids, + raw_smp_processor_id(), cpu_active_mask->bits[0], mask.bits[0]); + + ret = set_cpus_allowed_ptr(current, &mask); + if (0 != ret) + FELICA_LOG_DEBUG("set_cpus_allowed_ptr=%d.\n", ret); + + FELICA_LOG_DEBUG("And now we are on CPU #%d", raw_smp_processor_id()); + + return ret; +} + +static int felica_CpuAll(void) +{ + int ret = 0; + struct cpumask mask = CPU_MASK_ALL; + + FELICA_LOG_DEBUG("System has %d CPU's, we are on CPU #%d\n" + "\tBinding this process to CPU #0.\n" + "\tactive mask is %lx, setting it to mask=%lx\n", + nr_cpu_ids, + raw_smp_processor_id(), cpu_active_mask->bits[0], mask.bits[0]); + + ret = set_cpus_allowed_ptr(current, &mask); + if (0 != ret) + FELICA_LOG_DEBUG("set_cpus_allowed_ptr=%d.\n", ret); + + FELICA_LOG_DEBUG("And now we are on CPU #%d", raw_smp_processor_id()); + + return ret; +} + + +static uint8_t felica_get_tamper_fuse_cmd(void) +{ + u32 fuse_id; + int ret; + + ret = felica_Cpu0(); + if (0 != ret) { + FELICA_LOG_DEBUG("changing core failed!"); + return -1; + } + + FELICA_LOG_DEBUG("get_fuse"); + + if (felica_smc_read_oemflag(0x80010001, (u32 *)&fuse_id) < 0) { + FELICA_LOG_ERR("[MFDD] %s read flag error", __func__); + return -1; + } + FELICA_LOG_DEBUG("[MFDD] Kernel Status[%x]", fuse_id); + felica_CpuAll(); + + return (uint8_t)fuse_id; +} + +/****************************************************************************** + * /dev/felica_pon + *****************************************************************************/ + +/* character device definition */ +static dev_t devid_felica_pon; +static struct cdev cdev_felica_pon; +static const struct file_operations fops_felica_pon = { + .owner = THIS_MODULE, + .open = felica_pon_open, + .release = felica_pon_close, + .read = felica_pon_read, + .write = felica_pon_write, +}; + +/* + * initialize device + */ +static void felica_pon_init(void) +{ + int ret; + struct device *device_felica_pon; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + devid_felica_pon = MKDEV(FELICA_MAJOR, FELICA_MINOR); + ret = + alloc_chrdev_region(&devid_felica_pon, FELICA_BASEMINOR, + FELICA_MINOR_COUNT, FELICA_PON_NAME); + if (ret < 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(alloc_chrdev_region), ret=[%d]", + __func__, ret); + return; + } + + cdev_init(&cdev_felica_pon, &fops_felica_pon); + ret = cdev_add(&cdev_felica_pon, devid_felica_pon, FELICA_MINOR_COUNT); + if (ret < 0) { + unregister_chrdev_region(devid_felica_pon, FELICA_MINOR_COUNT); + FELICA_LOG_ERR("[MFDD] %s ERROR(cdev_add), ret=[%d]", __func__, + ret); + return; + } + + device_felica_pon = + device_create(felica_class, NULL, devid_felica_pon, NULL, + FELICA_PON_NAME); + if (IS_ERR(device_felica_pon)) { + cdev_del(&cdev_felica_pon); + unregister_chrdev_region(devid_felica_pon, FELICA_MINOR_COUNT); + FELICA_LOG_ERR("[MFDD] %s ERROR(device_create)", __func__); + return; + } + + FELICA_LOG_DEBUG("[MFDD] %s END, major=[%d], minor=[%d]", __func__, + MAJOR(devid_felica_pon), MINOR(devid_felica_pon)); +} + +/* + * finalize device + */ +static void felica_pon_exit(void) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + device_destroy(felica_class, devid_felica_pon); + cdev_del(&cdev_felica_pon); + unregister_chrdev_region(devid_felica_pon, FELICA_MINOR_COUNT); + + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); +} + +/* + * open device + */ +static int felica_pon_open(struct inode *inode, struct file *file) +{ + uid_t uid; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + uid = __task_cred(current)->uid; + if ((uid != gmfc_uid) && (uid != gdiag_uid) + && (uid != gant_uid)) { + FELICA_LOG_DEBUG + ("[MFDD] %s END, uid=[%d], gmfc_uid=[%d], gdiag_uid=[%d]", + __func__, uid, gmfc_uid, gdiag_uid); + return -EACCES; + } + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * close device + */ +static int felica_pon_close(struct inode *inode, struct file *file) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + gpio_set_value(GPIO_PINID_FELICA_PON, GPIO_VALUE_LOW); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * read operation + */ +static ssize_t felica_pon_read(struct file *file, char __user *buf, size_t len, + loff_t *ppos) +{ + int ret; + char retparam; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + ret = gpio_get_value(GPIO_PINID_FELICA_PON); + if (ret == GPIO_VALUE_HIGH) { + retparam = FELICA_PON_WIRED; + FELICA_LOG_DEBUG("Wired interface Status is [%d][start]", + retparam); + } else if (ret == GPIO_VALUE_LOW) { + retparam = FELICA_PON_WIRELESS; + FELICA_LOG_DEBUG("Wired interface Status is [%d][standby]", + retparam); + } else { + FELICA_LOG_ERR("[MFDD] %s ERROR(gpio_get_value), ret=[%d]", + __func__, ret); + return -EIO; + } + + ret = copy_to_user(buf, &retparam, FELICA_PON_DATA_LEN); + if (ret != 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(copy_to_user), ret=[%d]", + __func__, ret); + return -EFAULT; + } + *ppos += 1; + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return FELICA_PON_DATA_LEN; +} + +/* + * write operation + */ +static ssize_t felica_pon_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + char pon; + int ret; + int setparam; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + ret = copy_from_user(&pon, data, FELICA_PON_DATA_LEN); + if (ret != 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(copy_from_user), ret=[%d]", + __func__, ret); + return -EFAULT; + } + + if (pon == FELICA_PON_WIRED) { + setparam = GPIO_VALUE_HIGH; + FELICA_LOG_DEBUG("Set wired interface to [%d][start]", + setparam); + } else if (pon == FELICA_PON_WIRELESS) { + setparam = GPIO_VALUE_LOW; + FELICA_LOG_DEBUG("Set wired interface to [%d][standby]", + setparam); + } else { + FELICA_LOG_ERR("[MFDD] %s ERROR(copy_from_user), pon=[%d]", + __func__, pon); + return -EINVAL; + } + + gpio_set_value(GPIO_PINID_FELICA_PON, setparam); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return FELICA_PON_DATA_LEN; +} + +/****************************************************************************** + * felica_i2c_driver + ******************************************************************************/ +static struct i2c_client *felica_i2c_client; +static const struct i2c_device_id felica_i2c_idtable[] = { + {FELICA_I2C_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, felica_i2c_idtable); + +static struct i2c_driver felica_i2c_driver = { + .probe = felica_i2c_probe, + .remove = felica_i2c_remove, + .driver = { + .name = FELICA_I2C_NAME, + .owner = THIS_MODULE, + }, + .id_table = felica_i2c_idtable, +}; + +/* + * felica_i2c_init + */ +static void felica_i2c_init(void) +{ + int ret; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + ret = i2c_add_driver(&felica_i2c_driver); + if (ret < 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(i2c_add_driver), ret=[%d]", + __func__, ret); + return; + } + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return; +} + +/* + * felica_i2c_exit + */ +static void felica_i2c_exit(void) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + i2c_del_driver(&felica_i2c_driver); + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return; +} + +/* + * probe device + */ +static int felica_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + felica_i2c_client = client; + if (!felica_i2c_client) { + FELICA_LOG_ERR("[MFDD] %s ERROR(felica_i2c_client==NULL)", \ + __func__); + return -EINVAL; + } + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * remove device + */ +static int felica_i2c_remove(struct i2c_client *client) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + /* no operation */ + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/****************************************************************************** + * /dev/felica_cen + ******************************************************************************/ + +/* character device definition */ +static dev_t devid_felica_cen; +static struct cdev cdev_felica_cen; +static const struct file_operations fops_felica_cen = { + .owner = THIS_MODULE, + .open = felica_cen_open, + .release = felica_cen_close, + .read = felica_cen_read, + .write = felica_cen_write, +}; + +/* + * felica_cen_init + */ +static void felica_cen_init(void) +{ + int ret; + struct device *device_felica_cen; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + devid_felica_cen = MKDEV(FELICA_MAJOR, FELICA_MINOR); + ret = + alloc_chrdev_region(&devid_felica_cen, FELICA_BASEMINOR, + FELICA_MINOR_COUNT, FELICA_CEN_NAME); + if (ret < 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(alloc_chrdev_region), ret=[%d]", + __func__, ret); + return; + } + + cdev_init(&cdev_felica_cen, &fops_felica_cen); + ret = cdev_add(&cdev_felica_cen, devid_felica_cen, FELICA_MINOR_COUNT); + if (ret < 0) { + unregister_chrdev_region(devid_felica_cen, FELICA_MINOR_COUNT); + FELICA_LOG_ERR("[MFDD] %s ERROR(cdev_add), ret=[%d]", __func__, + ret); + return; + } + + device_felica_cen = + device_create(felica_class, NULL, devid_felica_cen, NULL, + FELICA_CEN_NAME); + if (IS_ERR(device_felica_cen)) { + cdev_del(&cdev_felica_cen); + unregister_chrdev_region(devid_felica_cen, FELICA_MINOR_COUNT); + FELICA_LOG_ERR("[MFDD] %s ERROR(device_create)", __func__); + return; + } + + FELICA_LOG_DEBUG("[MFDD] %s END, major=[%d], minor=[%d]", __func__, + MAJOR(devid_felica_cen), MINOR(devid_felica_cen)); +} + +/* + * felica_cen_exit + */ +static void felica_cen_exit(void) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + device_destroy(felica_class, devid_felica_cen); + cdev_del(&cdev_felica_cen); + unregister_chrdev_region(devid_felica_cen, FELICA_MINOR_COUNT); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); +} + +/* + * open device + */ +static int felica_cen_open(struct inode *inode, struct file *file) +{ + uid_t uid; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + uid = __task_cred(current)->uid; + if (file->f_mode & FMODE_WRITE) { + if ((uid != gdiag_uid) && (uid != gmfl_uid)) { + FELICA_LOG_DEBUG(\ + "[MFDD] %s END, uid=[%d]\n", __func__, uid); + FELICA_LOG_DEBUG(\ + "[MFDD] %s END, gmfc_uid=[%d]\n", __func__, gmfc_uid); + FELICA_LOG_DEBUG(\ + "[MFDD] %s END, gdiag_uid=[%d]\n", __func__, gdiag_uid); + FELICA_LOG_DEBUG(\ + "[MFDD] %s END, gmfl_uid=[%d]\n", __func__, gmfl_uid); + return -EACCES; + } + } + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * close device + */ +static int felica_cen_close(struct inode *inode, struct file *file) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + /* no operation */ + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * read operation + */ +static ssize_t felica_cen_read(struct file *file, char __user *buf, \ + size_t len, loff_t *ppos) +{ + int ret; + unsigned char address = gi2c_lockaddress; + unsigned char read_buff = 0; + + gread_msgs[0].addr = gi2c_address; + gread_msgs[0].buf = &address; + gread_msgs[1].addr = gi2c_address; + gread_msgs[1].buf = &read_buff; + + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + if (felica_i2c_client == NULL) { + FELICA_LOG_DEBUG("felica_i2c_client is NULL"); + return -EIO; + } + + ret = i2c_transfer(felica_i2c_client->adapter, &gread_msgs[0], 1); + if (ret < 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(i2c_transfer[0]), ret=[%d]", + __func__, ret); + return -EIO; + } + ret = i2c_transfer(felica_i2c_client->adapter, &gread_msgs[1], 1); + if (ret < 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(i2c_transfer[1]), ret=[%d]", + __func__, ret); + return -EIO; + } + + FELICA_LOG_DEBUG("[MFDD] %s read_buff=[%d]", __func__, read_buff); + read_buff &= FELICA_CONTROL_LOCK_MASK; + FELICA_LOG_DEBUG("[MFDD] %s read_buff=[%d]", __func__, read_buff); + + ret = copy_to_user(buf, &read_buff, FELICA_CEN_DATA_LEN); + if (ret != 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(copy_to_user), ret=[%d]", + __func__, ret); + return -EFAULT; + } + *ppos += 1; + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return FELICA_CEN_DATA_LEN; +} + +/* + * write operation + */ +static ssize_t felica_cen_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + char cen; + int ret; + unsigned char write_buff[2]; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + if (felica_i2c_client == NULL) { + FELICA_LOG_DEBUG("felica_i2c_client is NULL"); + return -EIO; + } + + gwrite_msgs[0].buf = &write_buff[0]; + gwrite_msgs[0].addr = gi2c_address; + write_buff[0] = gi2c_lockaddress; + + ret = copy_from_user(&cen, data, FELICA_CEN_DATA_LEN); + if (ret != 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(copy_from_user), ret=[%d]", + __func__, ret); + return -EFAULT; + } + if (cen == FELICA_CEN_UNLOCK) { + write_buff[1] = FELICA_CEN_SET_UNLOCK; + FELICA_LOG_DEBUG("Set FeliCa-Lock status to [%d][UnLock]", + write_buff[1]); + } else if (cen == FELICA_CEN_LOCK) { + write_buff[1] = FELICA_CEN_SET_LOCK; + FELICA_LOG_DEBUG("Set FeliCa-Lock status to [%d][Lock]", + write_buff[1]); + } else { + FELICA_LOG_ERR("[MFDD] %s ERROR(copy_from_user), cen=[%d]", + __func__, cen); + return -EINVAL; + } + ret = i2c_transfer(felica_i2c_client->adapter, gwrite_msgs, 1); + if (ret < 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(i2c_transfer), ret=[%d]", + __func__, ret); + return -EIO; + } + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return FELICA_CEN_DATA_LEN; +} + +/****************************************************************************** + * /dev/felica_rfs + ******************************************************************************/ + +/* character device definition */ +static dev_t devid_felica_rfs; +static struct cdev cdev_felica_rfs; +static const struct file_operations fops_felica_rfs = { + .owner = THIS_MODULE, + .open = felica_rfs_open, + .release = felica_rfs_close, + .read = felica_rfs_read, +}; + +/* + * initialize device + */ +static void felica_rfs_init(void) +{ + int ret; + struct device *device_felica_rfs; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + devid_felica_rfs = MKDEV(FELICA_MAJOR, FELICA_MINOR); + ret = + alloc_chrdev_region(&devid_felica_rfs, FELICA_BASEMINOR, + FELICA_MINOR_COUNT, FELICA_RFS_NAME); + if (ret < 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(alloc_chrdev_region), ret=[%d]", + __func__, ret); + return; + } + + cdev_init(&cdev_felica_rfs, &fops_felica_rfs); + ret = cdev_add(&cdev_felica_rfs, devid_felica_rfs, FELICA_MINOR_COUNT); + if (ret < 0) { + unregister_chrdev_region(devid_felica_rfs, FELICA_MINOR_COUNT); + FELICA_LOG_ERR("[MFDD] %s ERROR(cdev_add), ret=[%d]", __func__, + ret); + return; + } + + device_felica_rfs = + device_create(felica_class, NULL, devid_felica_rfs, NULL, + FELICA_RFS_NAME); + if (IS_ERR(device_felica_rfs)) { + cdev_del(&cdev_felica_rfs); + unregister_chrdev_region(devid_felica_rfs, FELICA_MINOR_COUNT); + FELICA_LOG_ERR("[MFDD] %s ERROR(device_create)", __func__); + return; + } + + FELICA_LOG_DEBUG("[MFDD] %s END, major=[%d], minor=[%d]", __func__, + MAJOR(devid_felica_rfs), MINOR(devid_felica_rfs)); +} + +/* + * finalize device + */ +static void felica_rfs_exit(void) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + device_destroy(felica_class, devid_felica_rfs); + cdev_del(&cdev_felica_rfs); + unregister_chrdev_region(devid_felica_rfs, FELICA_MINOR_COUNT); + + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); +} + +/* + * open device + */ +static int felica_rfs_open(struct inode *inode, struct file *file) +{ + uid_t uid; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + uid = __task_cred(current)->uid; + + if ((uid != gmfc_uid) && (uid != gdiag_uid)) { + FELICA_LOG_DEBUG + ("[MFDD] %s END, uid=[%d], gmfc_uid=[%d], gdiag_uid=[%d]", + __func__, uid, gmfc_uid, gdiag_uid); + return -EACCES; + } + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * close device + */ +static int felica_rfs_close(struct inode *inode, struct file *file) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + /* no operation */ + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * read operation + */ +static ssize_t felica_rfs_read(struct file *file, char __user *buf, \ + size_t len, loff_t *ppos) +{ + int ret; + char retparam; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + ret = gpio_get_value(GPIO_PINID_FELICA_RFS); + if (ret == GPIO_VALUE_HIGH) { + retparam = FELICA_RFS_STANDBY; + FELICA_LOG_DEBUG("Carrier-Wave Status is [%d][standby]", + retparam); + } else if (ret == GPIO_VALUE_LOW) { + retparam = FELICA_RFS_DETECTED; + FELICA_LOG_DEBUG("Carrier-Wave Status is [%d][detected]", + retparam); + } else { + FELICA_LOG_ERR("[MFDD] %s ERROR(gpio_get_value), ret=[%d]", + __func__, ret); + return -EIO; + } + + ret = copy_to_user(buf, &retparam, FELICA_RFS_DATA_LEN); + if (ret != 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(copy_to_user), ret=[%d]", + __func__, ret); + return -EFAULT; + } + *ppos += 1; + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return FELICA_RFS_DATA_LEN; +} + +/****************************************************************************** + * /dev/felica_rws + ******************************************************************************/ + +/* character device definition */ +static dev_t devid_felica_rws; +static struct cdev cdev_felica_rws; +static const struct file_operations fops_felica_rws = { + .owner = THIS_MODULE, + .open = felica_rws_open, + .release = felica_rws_close, + .read = felica_rws_read, + .write = felica_rws_write, +}; + +/* + * initialize device + */ +static void felica_rws_init(void) +{ + int ret; + struct device *device_felica_rws; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + devid_felica_rws = MKDEV(FELICA_MAJOR, FELICA_MINOR); + ret = + alloc_chrdev_region(&devid_felica_rws, FELICA_BASEMINOR, + FELICA_MINOR_COUNT, FELICA_RWS_NAME); + if (ret < 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(alloc_chrdev_region), ret=[%d]", + __func__, ret); + return; + } + + cdev_init(&cdev_felica_rws, &fops_felica_rws); + ret = cdev_add(&cdev_felica_rws, devid_felica_rws, FELICA_MINOR_COUNT); + if (ret < 0) { + unregister_chrdev_region(devid_felica_rws, FELICA_MINOR_COUNT); + FELICA_LOG_ERR("[MFDD] %s ERROR(cdev_add), ret=[%d]", __func__, + ret); + return; + } + + device_felica_rws = + device_create(felica_class, NULL, devid_felica_rws, NULL, + FELICA_RWS_NAME); + if (IS_ERR(device_felica_rws)) { + cdev_del(&cdev_felica_rws); + unregister_chrdev_region(devid_felica_rws, FELICA_MINOR_COUNT); + FELICA_LOG_ERR("[MFDD] %s ERROR(device_create)", __func__); + return; + } + + gfelica_rw_status = FELICA_RW_STATUS_INIT; + + FELICA_LOG_DEBUG("[MFDD] %s END, major=[%d], minor=[%d]", __func__, + MAJOR(devid_felica_rws), MINOR(devid_felica_rws)); +} + +/* + * finalize device + */ +static void felica_rws_exit(void) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + device_destroy(felica_class, devid_felica_rws); + cdev_del(&cdev_felica_rws); + unregister_chrdev_region(devid_felica_rws, FELICA_MINOR_COUNT); + + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); +} + +/* + * open device + */ +static int felica_rws_open(struct inode *inode, struct file *file) +{ + uid_t uid; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + uid = __task_cred(current)->uid; + if (file->f_mode & FMODE_WRITE) { + if (uid != grwm_uid) { + FELICA_LOG_DEBUG(\ + "[MFDD] %s END, uid=[%d],gmfc_uid=[%d],gdiag_uid=[%d]", + __func__, uid, gmfc_uid, gdiag_uid); + return -EACCES; + } + } else { + if ((uid != gmfc_uid) && (uid != grwm_uid)) { + FELICA_LOG_DEBUG(\ + "[MFDD] %s END, uid=[%d],gmfc_uid=[%d],gdiag_uid=[%d]", + __func__, uid, gmfc_uid, gdiag_uid); + return -EACCES; + } + } + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * close device + */ +static int felica_rws_close(struct inode *inode, struct file *file) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + /* no operation */ + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * read operation + */ +static ssize_t felica_rws_read(struct file *file, char __user *buf, size_t len, + loff_t *ppos) +{ + int ret; + char retparam; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + if (gfelica_rw_status == FELICA_RW_STATUS_ENABLE) { + retparam = FELICA_RW_STATUS_ENABLE; + FELICA_LOG_DEBUG("ReaderWriterFunction status is [%d][enabled]", + retparam); + } else if (gfelica_rw_status == FELICA_RW_STATUS_DISABLE) { + retparam = FELICA_RW_STATUS_DISABLE; + FELICA_LOG_DEBUG + ("ReaderWriterFunction status is [%d][disabled]", retparam); + } else { + FELICA_LOG_ERR("[MFDD] %s ERROR(gfelica_rw_status), RWM=[%d]", + __func__, gfelica_rw_status); + return -EIO; + } + + ret = copy_to_user(buf, &retparam, FELICA_RWS_DATA_LEN); + if (ret != 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(copy_to_user), ret=[%d]", + __func__, ret); + return -EFAULT; + } + *ppos += 1; + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return FELICA_RWS_DATA_LEN; +} + +/* + * write operation + */ +static ssize_t felica_rws_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + char work; + int ret; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + ret = copy_from_user(&work, data, FELICA_RWS_DATA_LEN); + if (ret != 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(copy_from_user), ret=[%d]", + __func__, ret); + return -EFAULT; + } + + if (work == FELICA_RW_STATUS_ENABLE) { + FELICA_LOG_DEBUG + ("Set ReaderWriterFunction status to [%d][enable]", work); + } else if (work == FELICA_RW_STATUS_DISABLE) { + FELICA_LOG_DEBUG + ("Set ReaderWriterFunction status to s[%d][disable]", work); + } else { + FELICA_LOG_ERR("[MFDD] %s ERROR(copy_from_user), work=[%d]", + __func__, work); + return -EINVAL; + } + + gfelica_rw_status = work; + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return FELICA_RWS_DATA_LEN; +} + +/****************************************************************************** + * /dev/felica_int_poll + ******************************************************************************/ + +/* character device definition */ +static dev_t devid_felica_int_poll; +static struct cdev cdev_felica_int_poll; +static const struct file_operations fops_felica_int_poll = { + .owner = THIS_MODULE, + .open = felica_int_poll_open, + .release = felica_int_poll_close, + .read = felica_int_poll_read, + .poll = felica_int_poll_poll, +}; + +/* + * top half of irq_handler + */ +static irqreturn_t felica_int_irq_handler(int irq, void *dev_id) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + disable_irq_nosync(gpio_to_irq(GPIO_PINID_FELICA_INT)); + schedule_delayed_work(&pgint_irq->work, + msecs_to_jiffies(FELICA_INT_DELAY_TIME)); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return IRQ_HANDLED; +} + +/* + * bottom half of irq_handler + */ +static void felica_int_irq_work(struct work_struct *work) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + enable_irq(gpio_to_irq(GPIO_PINID_FELICA_INT)); + pgint_irq->irq_done = 1; + wake_up_interruptible(&pgint_irq->read_wait); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); +} + +/* + * initialize device + */ +static void felica_int_poll_init(void) +{ + int ret; + struct device *device_felica_int_poll; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + devid_felica_int_poll = MKDEV(FELICA_MAJOR, FELICA_MINOR); + ret = + alloc_chrdev_region(&devid_felica_int_poll, FELICA_BASEMINOR, + FELICA_MINOR_COUNT, FELICA_INT_POLL_NAME); + if (ret < 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(alloc_chrdev_region), ret=[%d]", + __func__, ret); + return; + } + + cdev_init(&cdev_felica_int_poll, &fops_felica_int_poll); + ret = + cdev_add(&cdev_felica_int_poll, devid_felica_int_poll, + FELICA_MINOR_COUNT); + if (ret < 0) { + unregister_chrdev_region(devid_felica_int_poll, + FELICA_MINOR_COUNT); + FELICA_LOG_ERR("[MFDD] %s ERROR(cdev_add), ret=[%d]", __func__, + ret); + return; + } + + device_felica_int_poll = + device_create(felica_class, NULL, devid_felica_int_poll, NULL, + FELICA_INT_POLL_NAME); + if (IS_ERR(device_felica_int_poll)) { + cdev_del(&cdev_felica_int_poll); + unregister_chrdev_region(devid_felica_int_poll, + FELICA_MINOR_COUNT); + FELICA_LOG_ERR("[MFDD] %s ERROR(device_create)", __func__); + return; + } + + memset(pgint_irq, 0x00, sizeof(struct felica_int_irqdata)); + INIT_DELAYED_WORK(&pgint_irq->work, felica_int_irq_work); + init_waitqueue_head(&pgint_irq->read_wait); + ret = request_irq(gpio_to_irq(GPIO_PINID_FELICA_INT), + felica_int_irq_handler, + IRQF_TRIGGER_FALLING, + FELICA_INT_POLL_NAME, (void *)pgint_irq); + if (ret != 0) { + device_destroy(felica_class, devid_felica_int_poll); + cdev_del(&cdev_felica_int_poll); + unregister_chrdev_region(devid_felica_int_poll, + FELICA_MINOR_COUNT); + FELICA_LOG_ERR("[MFDD] %s ERROR(request_irq), ret=[%d]", + __func__, ret); + return; + } + + ret = enable_irq_wake(gpio_to_irq(GPIO_PINID_FELICA_INT)); + if (ret < 0) { + free_irq(gpio_to_irq(GPIO_PINID_FELICA_INT), (void *)pgint_irq); + device_destroy(felica_class, devid_felica_int_poll); + cdev_del(&cdev_felica_int_poll); + unregister_chrdev_region(devid_felica_int_poll, + FELICA_MINOR_COUNT); + FELICA_LOG_ERR("[MFDD] %s ERROR(enable_irq_wake), ret=[%d]", + __func__, ret); + return; + } + + pgint_irq->irq_done = 0; + + FELICA_LOG_DEBUG("[MFDD] %s END, major=[%d], minor=[%d]", __func__, + MAJOR(devid_felica_int_poll), + MINOR(devid_felica_int_poll)); +} + +/* + * finalize device + */ +static void felica_int_poll_exit(void) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + disable_irq(gpio_to_irq(GPIO_PINID_FELICA_INT)); + free_irq(gpio_to_irq(GPIO_PINID_FELICA_INT), (void *)pgint_irq); + device_destroy(felica_class, devid_felica_int_poll); + cdev_del(&cdev_felica_int_poll); + unregister_chrdev_region(devid_felica_int_poll, FELICA_MINOR_COUNT); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); +} + +/* + * open device + */ +static int felica_int_poll_open(struct inode *inode, struct file *file) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + /* no operation */ + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * close device + */ +static int felica_int_poll_close(struct inode *inode, struct file *file) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + /* no operation */ + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * read operation + */ +static ssize_t felica_int_poll_read(struct file *file, char __user *buf, + size_t len, loff_t *ppos) +{ + int ret; + char retparam; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + if (!pgint_irq->irq_done) { + ret = + wait_event_interruptible(pgint_irq->read_wait, + pgint_irq->irq_done == 1); + if (ret < 0) { + FELICA_LOG_ERR + ("[MFDD] %s ERROR(wait_event_interruptible),ret=[%d]",\ + __func__, ret); + return -EINTR; + } + } + + ret = gpio_get_value(GPIO_PINID_FELICA_INT); + if (ret == GPIO_VALUE_HIGH) { + retparam = FELICA_INT_HIGH; + FELICA_LOG_DEBUG("INT-PIN value is [%d][HIGH]", retparam); + } else if (ret == GPIO_VALUE_LOW) { + retparam = FELICA_INT_LOW; + FELICA_LOG_DEBUG("INT-PIN value is [%d][LOW]", retparam); + } else { + FELICA_LOG_ERR("[MFDD] %s ERROR(gpio_get_value), ret=[%d]", + __func__, ret); + return -EIO; + } + + ret = copy_to_user(buf, &retparam, FELICA_INT_DATA_LEN); + if (ret != 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(copy_to_user), ret=[%d]", + __func__, ret); + return -EFAULT; + } + *ppos += 1; + + pgint_irq->irq_done = 0; + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return FELICA_INT_DATA_LEN; +} + +/* + * poll operation + */ +static unsigned int felica_int_poll_poll(struct file *file, poll_table *wait) +{ + unsigned int mask = 0; + FELICA_LOG_DEBUG("%s START", __func__); + + poll_wait(file, &pgint_irq->read_wait, wait); + if (pgint_irq->irq_done) + mask = POLLIN | POLLRDNORM; + + FELICA_LOG_DEBUG("%s END", __func__); + return mask; +} +/****************************************************************************** + * /dev/felica_uid + ******************************************************************************/ + +/* character device definition */ +static dev_t devid_felica_uid; +static struct cdev cdev_felica_uid; +static const struct file_operations fops_felica_uid = { + .owner = THIS_MODULE, + .open = felica_uid_open, + .release = felica_uid_close, + .unlocked_ioctl = felica_uid_ioctl, +}; + +/* + * initialize device + */ +static void felica_uid_init(void) +{ + int ret; + struct device *device_felica_uid; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + devid_felica_uid = MKDEV(FELICA_MAJOR, FELICA_MINOR); + ret = + alloc_chrdev_region(&devid_felica_uid, FELICA_BASEMINOR, + FELICA_MINOR_COUNT, FELICA_UID_NAME); + if (ret < 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(alloc_chrdev_region), ret=[%d]", + __func__, ret); + return; + } + + cdev_init(&cdev_felica_uid, &fops_felica_uid); + ret = cdev_add(&cdev_felica_uid, devid_felica_uid, FELICA_MINOR_COUNT); + if (ret < 0) { + unregister_chrdev_region(devid_felica_uid, FELICA_MINOR_COUNT); + FELICA_LOG_ERR("[MFDD] %s ERROR(cdev_add), ret=[%d]", __func__, + ret); + return; + } + + device_felica_uid = + device_create(felica_class, NULL, devid_felica_uid, NULL, + FELICA_UID_NAME); + if (IS_ERR(device_felica_uid)) { + cdev_del(&cdev_felica_uid); + unregister_chrdev_region(devid_felica_uid, FELICA_MINOR_COUNT); + FELICA_LOG_ERR("[MFDD] %s ERROR(device_create)", __func__); + return; + } + FELICA_LOG_DEBUG("[MFDD] %s END, major=[%d], minor=[%d]", __func__, + MAJOR(devid_felica_uid), MINOR(devid_felica_uid)); +} + +/* + * finalize device + */ +static void felica_uid_exit(void) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + if (gdiag_name[0] != 0x00) { + device_destroy(felica_class, devid_felica_uid); + cdev_del(&cdev_felica_uid); + unregister_chrdev_region(devid_felica_uid, \ + FELICA_MINOR_COUNT); + } + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); +} + +/* + * open device + */ +static int felica_uid_open(struct inode *inode, struct file *file) +{ + char *cmdpos; + static char cmdline[1025]; + static unsigned long start_adr, end_adr, leng; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + start_adr = current->mm->arg_start; + end_adr = current->mm->arg_end; + leng = end_adr - start_adr; + + if (1024 < leng) + leng = 1024; + + cmdpos = (char *)(current->mm->arg_start); + memcpy(cmdline, cmdpos, leng); + cmdline[leng] = '\0'; + + if (strncmp(cmdline, gdiag_name, leng) != 0) { + FELICA_LOG_DEBUG("[MFDD] %s ERROR, %s gdiag %s", \ + __func__, cmdline, gdiag_name); + return -EACCES; + } + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * close device + */ +static int felica_uid_close(struct inode *inode, struct file *file) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + /* no operation */ + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * uid registration + */ +static long felica_uid_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + FELICA_LOG_DEBUG("[MFDD] %s START, cmd=[%d]", __func__, cmd); + + switch (cmd) { + case SET_FELICA_UID_DIAG: + gdiag_uid = *((int *)arg); + FELICA_LOG_DEBUG("Set gdiag_uid to [%d]", gdiag_uid); + break; + default: + FELICA_LOG_ERR("[MFDD] %s ERROR(unknown command)", __func__); + break; + } + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/****************************************************************************** + * /dev/felica_ant + ******************************************************************************/ + +/* character device definition */ +static dev_t devid_felica_ant; +static struct cdev cdev_felica_ant; +static const struct file_operations fops_felica_ant = { + .owner = THIS_MODULE, + .open = felica_ant_open, + .release = felica_ant_close, + .read = felica_ant_read, + .write = felica_ant_write, +}; + +/* + * felica_ant_init + */ +static void felica_ant_init(void) +{ + int ret; + struct device *device_felica_ant; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + devid_felica_ant = MKDEV(FELICA_MAJOR, FELICA_MINOR); + ret = + alloc_chrdev_region(&devid_felica_ant, FELICA_BASEMINOR, + FELICA_MINOR_COUNT, FELICA_ANT_NAME); + if (ret < 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(alloc_chrdev_region), ret=[%d]", + __func__, ret); + return; + } + + cdev_init(&cdev_felica_ant, &fops_felica_ant); + ret = cdev_add(&cdev_felica_ant, devid_felica_ant, FELICA_MINOR_COUNT); + if (ret < 0) { + unregister_chrdev_region(devid_felica_ant, FELICA_MINOR_COUNT); + FELICA_LOG_ERR("[MFDD] %s ERROR(cdev_add), ret=[%d]", __func__, + ret); + return; + } + + device_felica_ant = + device_create(felica_class, NULL, devid_felica_ant, NULL, + FELICA_ANT_NAME); + if (IS_ERR(device_felica_ant)) { + cdev_del(&cdev_felica_ant); + unregister_chrdev_region(devid_felica_ant, FELICA_MINOR_COUNT); + FELICA_LOG_ERR("[MFDD] %s ERROR(device_create)", __func__); + return; + } + + FELICA_LOG_DEBUG("[MFDD] %s END, major=[%d], minor=[%d]", __func__, + MAJOR(devid_felica_ant), MINOR(devid_felica_ant)); +} + +/* + * felica_ant_exit + */ +static void felica_ant_exit(void) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + device_destroy(felica_class, devid_felica_ant); + cdev_del(&cdev_felica_ant); + unregister_chrdev_region(devid_felica_ant, FELICA_MINOR_COUNT); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); +} + +/* + * open device + */ +static int felica_ant_open(struct inode *inode, struct file *file) +{ + uid_t uid; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + uid = __task_cred(current)->uid; + if ((uid != gant_uid) && (uid != gdiag_uid)) { + FELICA_LOG_DEBUG(\ + "[MFDD] %s END, uid=[%d]\n", __func__, uid); + FELICA_LOG_DEBUG(\ + "[MFDD] %s END, gant_uid=[%d]\n", __func__, gant_uid); + return -EACCES; + } + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * close device + */ +static int felica_ant_close(struct inode *inode, struct file *file) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + /* no operation */ + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * read operation + */ +static ssize_t felica_ant_read(struct file *file, char __user *buf, \ + size_t len, loff_t *ppos) +{ + int ret; + unsigned char address = gi2c_antaddress; + unsigned char read_buff = 0; + + gread_msgs[0].addr = gi2c_address; + gread_msgs[0].buf = &address; + gread_msgs[1].addr = gi2c_address; + gread_msgs[1].buf = &read_buff; + + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + if (felica_i2c_client == NULL) { + FELICA_LOG_DEBUG("[MFDD] %s felica_i2c_client is NULL", \ + __func__); + return -EIO; + } + + ret = i2c_transfer(felica_i2c_client->adapter, &gread_msgs[0], 1); + if (ret < 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(i2c_transfer[0]), ret=[%d]", + __func__, ret); + return -EIO; + } + ret = i2c_transfer(felica_i2c_client->adapter, &gread_msgs[1], 1); + if (ret < 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(i2c_transfer[1]), ret=[%d]", + __func__, ret); + return -EIO; + } + FELICA_LOG_DEBUG("[MFDD] %s read_buff=[%d]", __func__, read_buff); + + ret = copy_to_user(buf, &read_buff, FELICA_ANT_DATA_LEN); + if (ret != 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(copy_to_user), ret=[%d]", + __func__, ret); + return -EFAULT; + } + *ppos += 1; + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return FELICA_ANT_DATA_LEN; +} + +/* + * write operation + */ +static ssize_t felica_ant_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + char ant; + int ret; + unsigned char write_buff[2]; + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + if (felica_i2c_client == NULL) { + FELICA_LOG_DEBUG("[MFDD] %s felica_i2c_client is NULL", \ + __func__); + return -EIO; + } + + gwrite_msgs[0].buf = &write_buff[0]; + gwrite_msgs[0].addr = gi2c_address; + write_buff[0] = gi2c_antaddress; + + + ret = copy_from_user(&ant, data, FELICA_ANT_DATA_LEN); + if (ret != 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(copy_from_user), ret=[%d]", + __func__, ret); + return -EFAULT; + } + write_buff[1] = ant; + + ret = i2c_transfer(felica_i2c_client->adapter, gwrite_msgs, 1); + if (ret < 0) { + FELICA_LOG_ERR("[MFDD] %s ERROR(i2c_transfer), ret=[%d]", + __func__, ret); + return -EIO; + } + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return FELICA_ANT_DATA_LEN; +} + +/****************************************************************************** + * Mobile FeliCa device driver initialization / termination function + ******************************************************************************/ + +/* + * to set initial value to each terminal + */ +static void felica_initialize_pin(void) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + gpio_set_value(GPIO_PINID_FELICA_PON, GPIO_VALUE_LOW); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); +} + +/* + * to set final value to each terminal + */ +static void felica_finalize_pin(void) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + gpio_set_value(GPIO_PINID_FELICA_PON, GPIO_VALUE_LOW); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); +} + +/* + * device driver registration + */ +static void felica_register_device(void) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + felica_int_poll_init(); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); +} + +/* + * device driver deregistration + */ +static void felica_deregister_device(void) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + felica_uid_exit(); + felica_int_poll_exit(); + felica_ant_exit(); + felica_rws_exit(); + felica_rfs_exit(); + felica_cen_exit(); + felica_pon_exit(); + felica_uart_exit(); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); +} + +/* + * The entry point for initialization module + */ +static int __init felica_init(void) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + felica_class = class_create(THIS_MODULE, "felica"); + if (IS_ERR(felica_class)) { + FELICA_LOG_ERR("[MFDD] %s ERROR(class_create)", __func__); + return PTR_ERR(felica_class); + } + felica_initialize_pin(); + felica_register_device(); + felica_nl_init(); + felica_i2c_init(); + /* MFC UID registration */ + schedule_delayed_work(&pgint_irq->work, msecs_to_jiffies(10)); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); + return 0; +} + +/* + * The entry point for the termination module + */ +static void __exit felica_exit(void) +{ + FELICA_LOG_DEBUG("[MFDD] %s START", __func__); + + felica_i2c_exit(); + felica_nl_exit(); + felica_deregister_device(); + felica_finalize_pin(); + class_destroy(felica_class); + + FELICA_LOG_DEBUG("[MFDD] %s END", __func__); +} + +module_init(felica_init); +module_exit(felica_exit); + +MODULE_DESCRIPTION("felica_dd"); +MODULE_LICENSE("GPL v2"); + +#endif /* CONFIG_FELICA */ -- cgit v1.1