| /* |
| * File - hsi_protocol_if.c |
| * |
| * Implements HSI protocol for Infineon Modem. |
| * |
| * Copyright (C) 2011 Samsung Electronics. |
| * |
| * Author: Rupesh Gujare <rupesh.g@samsung.com> |
| * |
| * 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/errno.h> |
| #include <linux/module.h> |
| #include <linux/init.h> |
| #include <linux/device.h> |
| #include <linux/err.h> |
| #include <linux/platform_device.h> |
| #include <asm/mach-types.h> |
| #include <linux/ioctl.h> |
| #include <linux/delay.h> |
| #include <linux/ktime.h> |
| #include <linux/bitmap.h> |
| #include <linux/poll.h> |
| #include <linux/kthread.h> |
| #include <linux/slab.h> |
| #include <linux/proc_fs.h> |
| |
| #include <linux/hsi_driver_if.h> |
| #include "hsi-protocol-if.h" |
| |
| //#define DEBUG 1 |
| //#define DEBUG_PHY_DATA 1 |
| |
| #define HSI_CHANNEL_STATE_UNAVAIL (1 << 0) |
| #define HSI_CHANNEL_STATE_READING (1 << 1) |
| #define HSI_CHANNEL_STATE_WRITING (1 << 2) |
| |
| |
| struct if_hsi_iface hsi_protocol_iface; |
| wait_queue_head_t ipc_read_wait, ipc_write_wait; |
| |
| |
| static void if_hsi_protocol_port_event(struct hsi_device *dev, unsigned int event, |
| void *arg); |
| static int __devinit hsi_protocol_probe(struct hsi_device *dev); |
| static int __devexit hsi_protocol_remove(struct hsi_device *dev); |
| |
| static struct hsi_device_driver if_hsi_protocol_driver = { |
| .ctrl_mask = ANY_HSI_CONTROLLER, |
| .probe = hsi_protocol_probe, |
| .remove = __devexit_p(hsi_protocol_remove), |
| .driver = { |
| .name = "hsi_protocol" |
| }, |
| }; |
| |
| struct if_hsi_cmd hsi_cmd_history; |
| int tx_cmd_history_p = 0; |
| int rx_cmd_history_p = 0; |
| |
| static int if_hsi_read_on(int ch, u32 *data, unsigned int count) |
| { |
| struct if_hsi_channel *channel; |
| int ret; |
| |
| channel = &hsi_protocol_iface.channels[ch]; |
| dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch); |
| |
| spin_lock(&channel->lock); |
| if (channel->state & HSI_CHANNEL_STATE_READING) { |
| pr_err("Read still pending on channel %d\n", ch); |
| spin_unlock(&channel->lock); |
| return -EBUSY; |
| } |
| channel->state |= HSI_CHANNEL_STATE_READING; |
| channel->rx_data = data; |
| channel->rx_count = count; |
| spin_unlock(&channel->lock); |
| |
| ret = hsi_read(channel->dev, data, count / 4); |
| dev_dbg(&channel->dev->device, "%s, ch = %d, ret = %d\n", __func__, ch, |
| ret); |
| |
| return ret; |
| } |
| |
| static void if_hsi_proto_read_done(struct hsi_device *dev, unsigned int size) |
| { |
| struct if_hsi_channel *channel; |
| struct hsi_event ev; |
| |
| #ifdef DEBUG_PHY_DATA |
| u32 *tmp; |
| u32 i; |
| #endif |
| |
| //printk(KERN_INFO "if_hsi_proto_read_done() is called for ch-> %d\n", dev->n_ch); |
| channel = &hsi_protocol_iface.channels[dev->n_ch]; |
| dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, dev->n_ch); |
| spin_lock(&channel->lock); |
| channel->state &= ~HSI_CHANNEL_STATE_READING; |
| ev.event = HSI_EV_IN; |
| ev.data = channel->rx_data; |
| ev.count = 4 * size; |
| spin_unlock(&channel->lock); |
| |
| #ifdef DEBUG_PHY_DATA |
| //Check received data -> Commented as it adds delay which causes MSG_BREAK |
| tmp = channel->rx_data; |
| printk(KERN_INFO "[%s](%d)(%d) RX = ", __func__, dev->n_ch, ev.count); |
| for (i = 0; i < ((size > 5) ? 5 : size); i++) { |
| printk(KERN_INFO "%08x ", *tmp); |
| tmp++; |
| } |
| printk(KERN_INFO "\n"); |
| #endif |
| |
| if_notify(dev->n_ch, &ev); |
| } |
| |
| int if_hsi_read(int ch, u32 *data, unsigned int count) |
| { |
| int ret = 0; |
| struct if_hsi_channel *channel; |
| channel = &hsi_protocol_iface.channels[ch]; |
| dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch); |
| ret = if_hsi_read_on(ch, data, count); |
| return ret; |
| } |
| |
| int if_hsi_poll(int ch) |
| { |
| struct if_hsi_channel *channel; |
| int ret = 0; |
| channel = &hsi_protocol_iface.channels[ch]; |
| dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch); |
| ret = hsi_poll(channel->dev); |
| return ret; |
| } |
| |
| static int if_hsi_write_on(int ch, u32 *address, unsigned int count) |
| { |
| struct if_hsi_channel *channel; |
| int ret; |
| |
| channel = &hsi_protocol_iface.channels[ch]; |
| |
| spin_lock(&channel->lock); |
| if (channel->state & HSI_CHANNEL_STATE_WRITING) { |
| pr_err("Write still pending on channel %d\n", ch); |
| printk(KERN_INFO "Write still pending on channel %d\n", ch); |
| spin_unlock(&channel->lock); |
| return -EBUSY; |
| } |
| |
| channel->tx_data = address; |
| channel->tx_count = count; |
| channel->state |= HSI_CHANNEL_STATE_WRITING; |
| spin_unlock(&channel->lock); |
| dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch); |
| ret = hsi_write(channel->dev, address, count / 4); |
| return ret; |
| } |
| |
| |
| static void if_hsi_proto_write_done(struct hsi_device *dev, unsigned int size) |
| { |
| struct if_hsi_channel *channel; |
| struct hsi_event ev; |
| |
| #ifdef DEBUG_PHY_DATA |
| u32 *tmp; |
| u32 i; |
| #endif |
| |
| //printk(KERN_INFO "if_hsi_proto_write_done() is called for ch-> %d\n", dev->n_ch); |
| channel = &hsi_protocol_iface.channels[dev->n_ch]; |
| dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, dev->n_ch); |
| |
| spin_lock(&channel->lock); |
| channel->state &= ~HSI_CHANNEL_STATE_WRITING; |
| ev.event = HSI_EV_OUT; |
| ev.data = channel->tx_data; |
| ev.count = 4 * size; |
| spin_unlock(&channel->lock); |
| |
| #ifdef DEBUG_PHY_DATA |
| //Check Outgoing data, Commented as it adds delay which causes MSG_BREAK |
| tmp = channel->tx_data; |
| printk(KERN_INFO "[%s](%d)(%d) TX = ", __func__, dev->n_ch, ev.count); |
| for (i = 0; i < ((size > 5) ? 5 : size); i++) { |
| printk(KERN_INFO "%08x ", *tmp); |
| tmp++; |
| } |
| printk(KERN_INFO "\n"); |
| #endif |
| |
| if_notify(dev->n_ch, &ev); |
| |
| } |
| |
| int if_hsi_write(int ch, u32 *data, unsigned int count) |
| { |
| int ret = 0; |
| struct if_hsi_channel *channel; |
| channel = &hsi_protocol_iface.channels[ch]; |
| dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch); |
| ret = if_hsi_write_on(ch, data, count); |
| return ret; |
| } |
| |
| void if_hsi_cancel_read(int ch) |
| { |
| struct if_hsi_channel *channel; |
| channel = &hsi_protocol_iface.channels[ch]; |
| dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch); |
| if (channel->state & HSI_CHANNEL_STATE_READING) |
| hsi_read_cancel(channel->dev); |
| spin_lock(&channel->lock); |
| channel->state &= ~HSI_CHANNEL_STATE_READING; |
| spin_unlock(&channel->lock); |
| } |
| |
| void if_hsi_set_wakeline(int ch, unsigned int state) |
| { |
| struct if_hsi_channel *channel; |
| channel = &hsi_protocol_iface.channels[ch]; |
| hsi_ioctl(channel->dev, |
| state ? HSI_IOCTL_ACWAKE_UP : HSI_IOCTL_ACWAKE_DOWN, NULL); |
| } |
| |
| |
| static void if_hsi_protocol_port_event(struct hsi_device *dev, unsigned int event, |
| void *arg) |
| { |
| struct hsi_event ev; |
| int i; |
| |
| ev.event = HSI_EV_EXCEP; |
| ev.data = (u32 *) 0; |
| ev.count = 0; |
| |
| |
| switch (event) { |
| case HSI_EVENT_BREAK_DETECTED: |
| pr_debug("%s, HWBREAK detected\n", __func__); |
| ev.data = (u32 *) HSI_HWBREAK; |
| for (i = 0; i < HSI_MAX_CHANNELS; i++) { |
| if (hsi_protocol_iface.channels[i].opened) |
| if_notify(i, &ev); |
| } |
| break; |
| case HSI_EVENT_HSR_DATAAVAILABLE: |
| i = (int)arg; |
| pr_debug("%s, HSI_EVENT_HSR_DATAAVAILABLE channel = %d\n", |
| __func__, i); |
| ev.event = HSI_EV_AVAIL; |
| if (hsi_protocol_iface.channels[i].opened) |
| if_notify(i, &ev); |
| break; |
| case HSI_EVENT_CAWAKE_UP: |
| pr_debug("%s, CAWAKE up\n", __func__); |
| break; |
| case HSI_EVENT_CAWAKE_DOWN: |
| pr_debug("%s, CAWAKE down\n", __func__); |
| break; |
| case HSI_EVENT_ERROR: |
| pr_debug("%s, HSI ERROR occured\n", __func__); |
| break; |
| default: |
| pr_warning("%s, Unknown event(%d)\n", __func__, event); |
| break; |
| } |
| } |
| |
| int if_hsi_openchannel(struct if_hsi_channel *channel) |
| { |
| int ret = 0; |
| |
| dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, |
| channel->channel_id); |
| spin_lock(&channel->lock); |
| |
| if (channel->state == HSI_CHANNEL_STATE_UNAVAIL) { |
| ret = -ENODEV; |
| goto leave; |
| } |
| |
| if (channel->opened) { |
| ret = -EBUSY; |
| goto leave; |
| } |
| |
| if (!channel->dev) { |
| pr_err("Channel %d is not ready??\n", channel->channel_id); |
| ret = -ENODEV; |
| goto leave; |
| } |
| spin_unlock(&channel->lock); |
| |
| ret = hsi_open(channel->dev); |
| spin_lock(&channel->lock); |
| if (ret < 0) { |
| pr_err("Could not open channel %d\n", channel->channel_id); |
| goto leave; |
| } |
| |
| channel->opened = 1; |
| channel->tx_state = HSI_LL_TX_STATE_IDLE; |
| channel->rx_state = HSI_LL_RX_STATE_TO_CONN_READY; |
| printk(KERN_INFO "setting channel->opened=1 for channel %d\n", channel->dev->n_ch); |
| leave: |
| spin_unlock(&channel->lock); |
| return ret; |
| } |
| |
| int if_hsi_closechannel(struct if_hsi_channel *channel) |
| { |
| int ret = 0; |
| |
| dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, |
| channel->channel_id); |
| spin_lock(&channel->lock); |
| |
| if (!channel->opened) |
| goto leave; |
| |
| if (!channel->dev) { |
| pr_err("Channel %d is not ready??\n", channel->channel_id); |
| ret = -ENODEV; |
| goto leave; |
| } |
| |
| /* Stop any pending read/write */ |
| if (channel->state & HSI_CHANNEL_STATE_READING) { |
| channel->state &= ~HSI_CHANNEL_STATE_READING; |
| spin_unlock(&channel->lock); |
| hsi_read_cancel(channel->dev); |
| spin_lock(&channel->lock); |
| } |
| if (channel->state & HSI_CHANNEL_STATE_WRITING) { |
| channel->state &= ~HSI_CHANNEL_STATE_WRITING; |
| |
| spin_unlock(&channel->lock); |
| hsi_write_cancel(channel->dev); |
| } else |
| spin_unlock(&channel->lock); |
| |
| hsi_close(channel->dev); |
| |
| spin_lock(&channel->lock); |
| channel->opened = 0; |
| channel->tx_state = HSI_LL_TX_STATE_CLOSED; |
| channel->rx_state = HSI_LL_RX_STATE_CLOSED; |
| leave: |
| spin_unlock(&channel->lock); |
| return ret; |
| } |
| |
| |
| /* Read Thread |
| * Should be responsible for handling commands |
| * Should wait on port events - waitqueue |
| * |
| */ |
| static int hsi_read_thrd(void *data) |
| { |
| u32 cmd_data[4], cmd, channel, param = 0; |
| int ret; |
| |
| printk(KERN_INFO "Inside read thread\n"); |
| while (1) { |
| /*Call hsi_proto_read*/ |
| /*Read 16 bytes due to Modem limitation*/ |
| //hsi_proto_read(0, cmd_data, (4 * 4)); |
| |
| // For es 2.1 ver. |
| hsi_proto_read(0, cmd_data, 4); |
| |
| hsi_cmd_history.rx_cmd[rx_cmd_history_p] = cmd_data[0]; |
| hsi_cmd_history.rx_cmd_time[rx_cmd_history_p] = CURRENT_TIME; |
| rx_cmd_history_p++; |
| if (rx_cmd_history_p >= 50) |
| rx_cmd_history_p = 0; |
| |
| /*Decode Command*/ |
| ret = hsi_decode_cmd(&cmd_data[0], &cmd, &channel, ¶m); |
| if (ret != 0) { |
| pr_err("Can not decode command\n"); |
| } else { |
| printk(KERN_INFO "%s(),CMD Received-> %x, ch-> %d, param-> %d.\n", __func__, cmd, channel, param); |
| /*Rx State Machine*/ |
| rx_stm(cmd, channel, param); |
| } |
| } |
| return 0; |
| } |
| |
| |
| int hsi_start_protocol(void) |
| { |
| struct hst_ctx tx_config; |
| struct hsr_ctx rx_config; |
| int i, ret = 0; |
| |
| printk(KERN_INFO "In function %s()\n", __func__); |
| /*Open All channels */ |
| for (i = 0; i <= 5; i++) { |
| ret = if_hsi_openchannel(&hsi_protocol_iface.channels[i]); |
| if (ret < 0) |
| pr_err("Can not Open channel->%d . Can not start HSI protocol\n", i); |
| else |
| printk(KERN_INFO "Channel->%d Open Successful\n", i); |
| |
| /*Set Rx Config*/ |
| hsi_ioctl(hsi_protocol_iface.channels[i].dev, HSI_IOCTL_GET_RX, &rx_config); |
| rx_config.mode = 2; |
| rx_config.divisor = 1; |
| rx_config.channels = HSI_MAX_CHANNELS; |
| ret = hsi_ioctl(hsi_protocol_iface.channels[i].dev, HSI_IOCTL_SET_RX, &rx_config); |
| if (ret == 0) |
| printk(KERN_INFO "SET_RX Successful for ch->%d\n", i); |
| |
| /*Set Tx Config*/ |
| hsi_ioctl(hsi_protocol_iface.channels[i].dev, HSI_IOCTL_GET_TX, &tx_config); |
| tx_config.mode = 2; |
| tx_config.divisor = 1; |
| tx_config.channels = HSI_MAX_CHANNELS; |
| ret = hsi_ioctl(hsi_protocol_iface.channels[i].dev, HSI_IOCTL_SET_TX, &tx_config); |
| if (ret == 0) |
| printk(KERN_INFO "SET_TX Successful for ch->%d\n", i); |
| } |
| /*Make channel-0 tx_state to IDLE*/ |
| hsi_protocol_iface.channels[0].tx_state = HSI_LL_TX_STATE_IDLE; |
| return ret; |
| } |
| EXPORT_SYMBOL(hsi_start_protocol); |
| |
| static int hsi_protocol_proc(char *page, char **start, off_t off, int count, int *eof, void *data) |
| { |
| char *p = page; |
| int len, i; |
| |
| p += sprintf(p, "======= HISTORY OF CMD =======\n"); |
| p += sprintf(p, " tx_cmd_history_p : %d\n", tx_cmd_history_p); |
| p += sprintf(p, " rx_cmd_history_p : %d\n", rx_cmd_history_p); |
| for (i = 0; i < 50; i++) { |
| p += sprintf(p, " [%d] tx : 0x%08x(%lu.%09lu), rx : 0x%08x(%lu.%09lu)\n", |
| i, hsi_cmd_history.tx_cmd[i], (unsigned long)hsi_cmd_history.tx_cmd_time[i].tv_sec, (unsigned long)hsi_cmd_history.tx_cmd_time[i].tv_nsec, |
| hsi_cmd_history.rx_cmd[i], (unsigned long)hsi_cmd_history.rx_cmd_time[i].tv_sec, (unsigned long)hsi_cmd_history.rx_cmd_time[i].tv_nsec); |
| } |
| p += sprintf(p, "======= HISTORY OF CMD =======\n"); |
| |
| len = (p - page) - off; |
| if (len < 0) |
| len = 0; |
| |
| *eof = (len <= count) ? 1 : 0; |
| *start = page + off; |
| |
| return len; |
| } |
| |
| int __devexit hsi_protocol_remove(struct hsi_device *dev) |
| { |
| struct if_hsi_channel *channel; |
| unsigned long *address; |
| int port, ret; |
| |
| //dev_dbg(&dev->device, "%s, port = %d, ch = %d\n", __func__, dev->n_p, |
| // dev->n_ch); |
| |
| for (port = 0; port < HSI_MAX_PORTS; port++) { |
| if (if_hsi_protocol_driver.ch_mask[port]) |
| break; |
| } |
| |
| address = &if_hsi_protocol_driver.ch_mask[port]; |
| |
| spin_lock_bh(&hsi_protocol_iface.lock); |
| if (test_bit(dev->n_ch, address) && (dev->n_p == port)) { |
| hsi_set_read_cb(dev, NULL); |
| hsi_set_write_cb(dev, NULL); |
| hsi_set_port_event_cb(dev, NULL); |
| channel = &hsi_protocol_iface.channels[dev->n_ch]; |
| channel->dev = NULL; |
| channel->state = HSI_CHANNEL_STATE_UNAVAIL; |
| ret = 0; |
| } |
| spin_unlock_bh(&hsi_protocol_iface.lock); |
| |
| return ret; |
| } |
| |
| int __devinit hsi_protocol_probe(struct hsi_device *dev) |
| { |
| struct if_hsi_channel *channel; |
| unsigned long *address; |
| int port; |
| |
| printk(KERN_INFO "Inside Function %s\n", __func__); |
| for (port = 0; port < HSI_MAX_PORTS; port++) { |
| if (if_hsi_protocol_driver.ch_mask[port]) |
| break; |
| } |
| |
| address = &if_hsi_protocol_driver.ch_mask[port]; |
| |
| spin_lock_bh(&hsi_protocol_iface.lock); |
| if (test_bit(dev->n_ch, address) && (dev->n_p == port)) { |
| printk(KERN_INFO "Regestering callback functions\n"); |
| hsi_set_read_cb(dev, if_hsi_proto_read_done); |
| hsi_set_write_cb(dev, if_hsi_proto_write_done); |
| hsi_set_port_event_cb(dev, if_hsi_protocol_port_event); |
| channel = &hsi_protocol_iface.channels[dev->n_ch]; |
| channel->dev = dev; |
| channel->state = 0; |
| channel->rx_state = HSI_LL_RX_STATE_CLOSED; |
| channel->tx_state = HSI_LL_TX_STATE_CLOSED; |
| channel->tx_count = 0; |
| channel->rx_count = 0; |
| channel->tx_nak_count = 0; |
| channel->rx_nak_count = 0; |
| channel->rx_buf = NULL; |
| channel->tx_buf = NULL; |
| hsi_protocol_iface.init_chan_map ^= (1 << dev->n_ch); |
| } |
| spin_unlock_bh(&hsi_protocol_iface.lock); |
| |
| return 0; |
| |
| } |
| |
| |
| int __init if_hsi_init(void) |
| { |
| struct if_hsi_channel *channel; |
| int i, ret; |
| struct proc_dir_entry *dir; |
| |
| for (i = 0; i < HSI_MAX_PORTS; i++) |
| if_hsi_protocol_driver.ch_mask[i] = 0; |
| |
| for (i = 0; i < HSI_MAX_CHANNELS; i++) { |
| channel = &hsi_protocol_iface.channels[i]; |
| channel->dev = NULL; |
| channel->opened = 0; |
| channel->state = HSI_CHANNEL_STATE_UNAVAIL; |
| channel->channel_id = i; |
| spin_lock_init(&channel->lock); |
| } |
| |
| /*Initialize waitqueue for IPC read*/ |
| init_waitqueue_head(&ipc_read_wait); |
| init_waitqueue_head(&ipc_write_wait); |
| |
| /*Select All Channels of PORT-1.*/ |
| if_hsi_protocol_driver.ch_mask[0] = CHANNEL_MASK; |
| |
| ret = hsi_register_driver(&if_hsi_protocol_driver); |
| if (ret) |
| pr_err("Error while registering HSI driver %d", ret); |
| |
| dir = create_proc_read_entry("driver/hsi_cmd", 0, 0, hsi_protocol_proc, NULL); |
| if (dir == NULL) |
| printk(KERN_INFO "create_proc_read_entry Fail.\n"); |
| printk(KERN_INFO "create_proc_read_entry Done.\n"); |
| |
| return ret; |
| } |
| |
| int __devexit if_hsi_exit(void) |
| { |
| struct if_hsi_channel *channel; |
| unsigned long *address; |
| int i, port; |
| |
| pr_debug("%s\n", __func__); |
| |
| for (port = 0; port < HSI_MAX_PORTS; port++) { |
| if (if_hsi_protocol_driver.ch_mask[port]) |
| break; |
| } |
| |
| address = &if_hsi_protocol_driver.ch_mask[port]; |
| |
| for (i = 0; i < HSI_MAX_CHANNELS; i++) { |
| channel = &hsi_protocol_iface.channels[i]; |
| if (channel->opened) { |
| if_hsi_set_wakeline(i, HSI_IOCTL_ACWAKE_DOWN); |
| if_hsi_closechannel(channel); |
| } |
| } |
| |
| hsi_unregister_driver(&if_hsi_protocol_driver); |
| return 0; |
| |
| } |
| |
| u32 initialization = 0; |
| |
| /*Write data to channel*/ |
| int write_hsi(u32 ch, u32 *data, int length) |
| { |
| int ret; |
| //u32 cmd[4] = {0x00000000, 0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC}; |
| struct if_hsi_channel *channel; |
| struct task_struct *read_thread; |
| |
| channel = &hsi_protocol_iface.channels[ch]; |
| channel->tx_buf = data; |
| channel->tx_count = 0; |
| |
| //cmd[0] = protocol_create_cmd(HSI_LL_MSG_OPEN_CONN_OCTET, ch, (void *)&length); |
| //printk(KERN_INFO "data ptr is %x\n", data); |
| |
| if (initialization == 0) { |
| |
| #if 0 |
| /* ACWAKE ->HIGH */ |
| ret = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_ACWAKE_UP, NULL); |
| if (ret == 0) |
| printk(KERN_INFO "ACWAKE pulled high in %s()\n", __func__); |
| else |
| printk(KERN_INFO "ACWAKE pulled high in %s() ERROR : %d\n", __func__, ret); |
| #endif |
| |
| /*Creating read thread*/ |
| read_thread = kthread_run(hsi_read_thrd, NULL, "hsi_read_thread"); |
| |
| initialization++; |
| } |
| /*Wait till previous data transfer is over*/ |
| while (channel->tx_state != HSI_LL_TX_STATE_IDLE) { |
| //printk(KERN_INFO "Wait 5ms previous data transfer isn't over %s()\n", __func__); |
| |
| //msleep(5); |
| |
| return -EAGAIN; |
| } |
| |
| #if 1 |
| /* ACWAKE ->HIGH */ |
| ret = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_ACWAKE_UP, NULL); |
| if (ret == 0) |
| printk(KERN_INFO "ACWAKE pulled high in %s()\n", __func__); |
| else |
| printk(KERN_INFO "ACWAKE pulled high in %s() ERROR : %d\n", __func__, ret); |
| #endif |
| |
| channel->tx_state = HSI_LL_TX_STATE_WAIT_FOR_ACK; |
| |
| //send_cmd(cmd, channel, data) |
| //ret = hsi_proto_write(0, &cmd, 4*4); |
| //printk(KERN_INFO "Write returned %d\n", ret); |
| hsi_protocol_send_command(HSI_LL_MSG_OPEN_CONN_OCTET, ch, length); |
| |
| wait_event_interruptible(ipc_write_wait, channel->tx_count != 0); |
| |
| return channel->tx_count; |
| |
| |
| } |
| EXPORT_SYMBOL(write_hsi); |
| |
| |
| int read_hsi(u8 *data, u32 ch, u32 *length) |
| { |
| int ret, size, tmp, actual_length; |
| struct if_hsi_channel *channel; |
| |
| channel = &hsi_protocol_iface.channels[ch]; |
| channel->rx_state = HSI_LL_RX_STATE_IDLE; |
| |
| //printk(KERN_INFO "In read_hsi() function, Sleeping ... channel-> %d\n", ch); |
| wait_event_interruptible(ipc_read_wait, (channel->rx_count != 0)); |
| //printk(KERN_INFO "In read_hsi() function, Waking Up ... channel-> %d\n", ch); |
| |
| actual_length = channel->rx_count; |
| size = channel->rx_count; |
| |
| #if 0 |
| // TEMP: send/read by 16 byte unit for v.11A(CP) |
| if ((size > 16) && (size % 16)) |
| size += (16 - (size % 16)); |
| else if (size < 16) |
| size = 16; |
| #endif |
| |
| // For es 2.1 ver. |
| if (size % 4) |
| size += (4 - (size % 4)); |
| |
| ret = hsi_proto_read(ch, (u32 *)data, size); |
| if (ret < 0) |
| printk(KERN_INFO "Read in IPC failed, %s()\n", __func__); |
| |
| //printk(KERN_INFO "%s() read returned %d, actual_length = %d, ch-> %d\n", __func__, ret, actual_length, ch); |
| //printk(KERN_INFO "%s() sending CONN_CLOSED.\n", __func__); |
| tmp = hsi_protocol_send_command(HSI_LL_MSG_CONN_CLOSED, ch, 0); |
| //printk(KERN_INFO "%s() Sending CONN_CLOSED Finished. ret = %d\n", __func__, tmp); |
| |
| *length = actual_length; |
| channel->rx_count = 0; |
| |
| //printk(KERN_INFO "%s() RETURNING TO IPC with ret = %d\n", __func__, ret); |
| return ret; |
| |
| } |
| EXPORT_SYMBOL(read_hsi); |
| |
| |
| //========================================================// |
| // ++ Flashless Boot. ++ // |
| //========================================================// |
| int hsi_start_protocol_single(void) |
| { |
| int ret = 0; |
| |
| struct hst_ctx tx_config; |
| struct hsr_ctx rx_config; |
| |
| /*Open channel 0 */ |
| ret = if_hsi_openchannel(&hsi_protocol_iface.channels[0]); |
| if (ret < 0) { |
| pr_err("Can not Open channel 0. Can not start HSI protocol\n"); |
| goto err; |
| } else |
| printk(KERN_INFO "if_hsi_openchannel() returned %d\n", ret); |
| |
| |
| /*Set Tx Config*/ |
| hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_GET_TX, &tx_config); |
| tx_config.mode = 2; |
| tx_config.channels = 1; |
| tx_config.divisor = 0; |
| ret = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_SET_TX, &tx_config); |
| if (ret < 0) { |
| printk(KERN_INFO "write_hsi_direct : SET_TX Fail : %d\n", ret); |
| return ret; |
| } |
| |
| hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_GET_RX, &rx_config); |
| rx_config.mode = 2; |
| rx_config.channels = 1; |
| rx_config.divisor = 0; |
| //rx_config.timeout = HZ / 2; |
| ret = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_SET_RX, &rx_config); |
| if (ret < 0) { |
| printk(KERN_INFO "write_hsi_direct : SET_RX Fail : %d\n", ret); |
| return ret; |
| } |
| |
| /* ACWAKE ->HIGH */ |
| ret = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_ACWAKE_UP, NULL); |
| if (ret == 0) |
| printk(KERN_INFO "ACWAKE pulled high in %s()\n", __func__); |
| |
| err: |
| |
| return ret; |
| } |
| EXPORT_SYMBOL(hsi_start_protocol_single); |
| |
| int hsi_reconfigure_protocol(void) |
| { |
| int ret = 0; |
| |
| /* ACWAKE ->LOW */ |
| ret = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_ACWAKE_DOWN, NULL); |
| if (ret == 0) |
| printk(KERN_INFO "ACWAKE pulled low in %s()\n", __func__); |
| else |
| printk(KERN_INFO "ACWAKE down fail!! %d\n", ret); |
| |
| |
| /*Clse channel 0 */ |
| ret = if_hsi_closechannel(&hsi_protocol_iface.channels[0]); |
| if (ret < 0) { |
| pr_err("Can not Close channel 0. Can not Stop HSI protocol for flashless\n"); |
| goto err; |
| } |
| |
| |
| printk(KERN_INFO "(%s)(%d) hsi_start_protocol Start.\n", __func__, __LINE__); |
| hsi_start_protocol(); |
| printk(KERN_INFO "(%s)(%d) hsi_start_protocol Done.\n", __func__, __LINE__); |
| |
| err: |
| |
| return ret; |
| } |
| EXPORT_SYMBOL(hsi_reconfigure_protocol); |
| |
| int write_hsi_direct(u32 *data, int length) |
| { |
| int retval = 0; |
| #if 0 |
| struct hst_ctx tx_config; |
| |
| |
| printk(KERN_INFO "write_hsi_direct : len : %d\n", length); |
| hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_GET_TX, &tx_config); |
| tx_config.mode = 2; |
| tx_config.channels = 1; |
| tx_config.divisor = 47; |
| retval = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_SET_TX, &tx_config); |
| if (retval < 0) { |
| printk(KERN_INFO "write_hsi_direct : SET_TX Fail : %d\n", retval); |
| return retval; |
| } |
| printk(KERN_INFO "write_hsi_direct : SET_TX Successful\n"); |
| |
| retval = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_ACWAKE_UP, NULL); |
| if (retval < 0) { |
| printk(KERN_INFO "write_hsi_direct : ACWAKE High Fail : %d\n", retval); |
| return retval; |
| } |
| #endif |
| |
| #if 0 |
| if ((length > 16) && (length % 4)) |
| length += (4 - (length % 4)); |
| else if (length < 16) |
| length = 16; |
| #endif |
| |
| // printk(KERN_INFO "write_hsi_direct : new len : %d\n", length); |
| |
| retval = hsi_proto_write(0, data, length); |
| if (retval < 0) { |
| printk(KERN_INFO "write_hsi_direct : hsi_proto_write Fail : %d\n", retval); |
| return retval; |
| } |
| //printk(KERN_INFO "write_hsi_direct : Write returned %d\n", retval); |
| |
| return retval; |
| } |
| EXPORT_SYMBOL(write_hsi_direct); |
| |
| int read_hsi_direct(u32 *data, int length) |
| { |
| int retval = 0; |
| #if 0 |
| struct hsr_ctx rx_config; |
| |
| |
| printk(KERN_INFO "read_hsi_direct : len : %d\n", length); |
| hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_GET_RX, &rx_config); |
| rx_config.mode = 2; |
| rx_config.channels = 1; |
| rx_config.divisor = 47; |
| retval = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_SET_RX, &rx_config); |
| if (retval < 0) { |
| printk(KERN_INFO "read_hsi_direct : SET_RX Fail : %d\n", retval); |
| return retval; |
| } |
| printk(KERN_INFO "read_hsi_direct : SET_RX Successful\n"); |
| |
| retval = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_ACWAKE_UP, NULL); |
| if (retval < 0) { |
| printk(KERN_INFO "read_hsi_direct : ACWAKE High Fail : %d\n", retval); |
| return retval; |
| } |
| printk(KERN_INFO "read_hsi_direct : ACWAKE High\n"); |
| #endif |
| |
| #if 0 |
| if ((length > 16) && (length % 4)) |
| length += (4 - (length % 4)); |
| else if (length < 16) |
| length = 16; |
| #endif |
| //printk(KERN_INFO "read_hsi_direct : new len : %d\n", length); |
| |
| retval = hsi_proto_read(0, data, length); |
| if (retval < 0) { |
| printk(KERN_INFO "read_hsi_direct : hsi_proto_read Fail : %d\n", retval); |
| return retval; |
| } |
| //printk(KERN_INFO "read_hsi_direct : Read returned %d\n", retval); |
| |
| return retval; |
| } |
| EXPORT_SYMBOL(read_hsi_direct); |
| |
| //========================================================// |
| // -- Flashless Boot. -- // |
| //========================================================// |