summaryrefslogtreecommitdiff
path: root/drivers/stm/stm_fw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/stm/stm_fw.c')
-rw-r--r--drivers/stm/stm_fw.c198
1 files changed, 174 insertions, 24 deletions
diff --git a/drivers/stm/stm_fw.c b/drivers/stm/stm_fw.c
index 057963c65e7..1ef1bda8080 100644
--- a/drivers/stm/stm_fw.c
+++ b/drivers/stm/stm_fw.c
@@ -93,6 +93,8 @@ static struct stm_device dev;
*****************************************************************************/
static int8_t cal_checksum(unsigned char *buf, int cnt);
+static struct stm_chn_descriptor *gen_chn_descriptor(enum stm_usecase uc_id);
+
static void rm_chn_descriptor(struct stm_chn_descriptor *chn_descriptor);
static int parse_to_user(char *buf, loff_t buf_pos,
@@ -125,7 +127,7 @@ static ssize_t stm_file_write(struct file *filp, const char __user *user_buf,
struct stm_chn_descriptor *chn_descriptor = filp->private_data;
char *buf = NULL;
char *kbuf = NULL;
- bool uspace = false;
+ bool uspace = (chn_descriptor->write_dentry != NULL) ? true : false;
bool timestamp = false;
uint msg_cnt = 0;
int ret = 0;
@@ -180,9 +182,13 @@ static ssize_t stm_file_write(struct file *filp, const char __user *user_buf,
goto stm_file_write_exit;
}
- if (copy_from_user(kbuf + header, user_buf, count)) {
- ret = -EFAULT;
- goto stm_file_write_exit;
+ if (uspace == true) {
+ if (copy_from_user(kbuf + header, user_buf, count)) {
+ ret = -EFAULT;
+ goto stm_file_write_exit;
+ }
+ } else {
+ memcpy(kbuf + header, user_buf, count);
}
if (chn_descriptor->ost_enable) {
@@ -212,7 +218,6 @@ static ssize_t stm_file_write(struct file *filp, const char __user *user_buf,
case VENDOR:
buf = (char *)user_buf;
- uspace = true;
/* Note module specific driver can treat timestamp as false*/
timestamp = true;
msg_cnt = count;
@@ -220,7 +225,6 @@ static ssize_t stm_file_write(struct file *filp, const char __user *user_buf,
case RAW:
buf = (char *)user_buf;
- uspace = true;
timestamp = true;
msg_cnt = count;
break;
@@ -310,23 +314,27 @@ static ssize_t config_file_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct stm_chn_descriptor *chn_descriptor = file->private_data;
+ bool uspace = (chn_descriptor->write_dentry != NULL) ? true : false;
char *kbuf = NULL, kbuffer[MAX_CONFIG_STRING_BYTES];
enum config_id cfg_id;
int cfg_len;
int err = 0;
bool vendor_pass = false;
- if (count > MAX_CONFIG_STRING_BYTES) {
+ /* Get userspace string and assure termination */
+ if (count >= sizeof(kbuffer)) {
err = -EINVAL;
goto cfg_wrt_exit1;
}
- /* Get userspace string and assure termination */
- if (count >= sizeof(kbuffer))
- return -EINVAL;
-
- if (copy_from_user(kbuffer, user_buf, count))
- return -EFAULT;
+ if (uspace) {
+ if (copy_from_user(kbuffer, user_buf, count)) {
+ err = -EFAULT;
+ goto cfg_wrt_exit1;
+ }
+ } else {
+ memcpy(kbuffer, user_buf, count);
+ }
kbuffer[count] = 0;
@@ -390,8 +398,13 @@ static ssize_t config_file_write(struct file *file, const char __user *user_buf,
chn_descriptor->ost_enable = false;
break;
case CFGID_FMT_USER:
- chn_descriptor->msg_format = USER;
- vendor_pass = true;
+ if (uspace) {
+ chn_descriptor->msg_format = USER;
+ vendor_pass = true;
+ } else {
+ err = -EINVAL;
+ vendor_pass = false;
+ }
break;
case CFGID_FMT_VENDOR:
chn_descriptor->msg_format = VENDOR;
@@ -421,16 +434,38 @@ cfg_wrt_exit1:
return count;
}
+
+enum attr_id {
+ ATTR_CHN_ENABLE,
+ ATTR_CHN_PROTECT,
+ ATTR_MODE_VENDOR,
+ ATTR_MODE_USER,
+ ATTR_MODE_RAW,
+ ATTR_LAST
+};
+
+static struct _attributes {
+ char *name;
+ unsigned int value;
+} attributes[] = {
+ [ATTR_CHN_ENABLE] = {"chn_enable", 0},
+ [ATTR_CHN_PROTECT] = {"chn_protected", 0},
+ [ATTR_MODE_VENDOR] = {"mode_vendor", 1},
+ [ATTR_MODE_USER] = {"mode_user", 0},
+ [ATTR_MODE_RAW] = {"mode_raw", 0}
+};
+
/* Provide channel configuration data on user read from file */
static ssize_t config_file_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct stm_chn_descriptor *chn_descriptor = file->private_data;
- const int max_buf = 256;
+ const int max_buf = 320;
char buf[max_buf];
int buf_cnt = 0;
char delims[] = ",";
loff_t buf_pos = 0;
+ int i;
if (!dev.stm_ops->config_read)
return 0;
@@ -438,9 +473,24 @@ static ssize_t config_file_read(struct file *file, char __user *user_buf,
if (mutex_lock_interruptible(&chn_descriptor->lock))
return -ERESTARTSYS;
+ /* get the attributes the framework driver knows about */
+ attributes[ATTR_CHN_ENABLE].value = chn_descriptor->chn_enable;
+ attributes[ATTR_CHN_PROTECT].value = chn_descriptor->write_protect;
+ attributes[ATTR_MODE_VENDOR].value =
+ (chn_descriptor->msg_format == VENDOR);
+ attributes[ATTR_MODE_USER].value =
+ (chn_descriptor->msg_format == USER);
+ attributes[ATTR_MODE_RAW].value = (chn_descriptor->msg_format == RAW);
+
+ for (i = 0; i < ATTR_LAST; i++) {
+ buf_cnt += snprintf(buf+buf_cnt, max_buf-buf_cnt,
+ "%s %u\n,", attributes[i].name,
+ attributes[i].value);
+ }
+
/* config_read puts formatted comma seperated strings in buf */
buf_cnt = dev.stm_ops->config_read(chn_descriptor->chn_id,
- buf, max_buf);
+ buf+buf_cnt, max_buf-buf_cnt);
mutex_unlock(&chn_descriptor->lock);
@@ -615,6 +665,7 @@ static ssize_t request_file_write(struct file *filp,
}
}
+#if 0
/* Malloc the channel descriptor */
chn_descriptor = kmalloc(sizeof *chn_descriptor, GFP_KERNEL);
if (!chn_descriptor) {
@@ -645,7 +696,14 @@ static ssize_t request_file_write(struct file *filp,
chn_descriptor->chn_id = NULL;
goto alloc_err_exit;
}
+#else
+ chn_descriptor = gen_chn_descriptor(uc_id);
+ if (IS_ERR(chn_descriptor)) {
+ err = PTR_ERR(chn_descriptor);
+ goto err_exit;
+ }
+#endif
/* If user command create debugfs message write file */
if (uc_id == USER_CHANNEL_REQUEST) {
@@ -691,8 +749,10 @@ static ssize_t request_file_write(struct file *filp,
goto alloc_err_exit;
}
+#if 0
list_add_tail(&chn_descriptor->chn_list_link,
&dev.chn_list_head);
+#endif
break;
@@ -720,12 +780,10 @@ static ssize_t request_file_write(struct file *filp,
err = -EINVAL;
goto err_exit;
}
-
- rm_chn_descriptor(chn_descriptor);
-
+#if 0
list_del(&chn_descriptor->chn_list_link);
-
- kfree(chn_descriptor);
+#endif
+ rm_chn_descriptor(chn_descriptor);
break;
@@ -744,7 +802,6 @@ static ssize_t request_file_write(struct file *filp,
alloc_err_exit:
rm_chn_descriptor(chn_descriptor);
- kfree(chn_descriptor);
err_exit:
mutex_unlock(&dev.lock);
@@ -897,7 +954,52 @@ module_exit(stm_fw_exit);
MODULE_LICENSE("Dual BSD/GPL");
/*****************************************************************************/
-/* Support functions */
+/* Public Kernel APIs */
+/*****************************************************************************/
+void *stm_channel_alloc(enum stm_usecase uc_id)
+{
+ struct stm_chn_descriptor *chn_descriptor = NULL;
+
+ chn_descriptor = gen_chn_descriptor(uc_id);
+ if (IS_ERR(chn_descriptor))
+ return (void *)PTR_ERR(chn_descriptor);
+
+/* Note: for kernel defined channnels chn_descriptor->write_dentry is NULL. */
+
+ return (void *)chn_descriptor;
+}
+
+int stm_channel_free(void *chn_id)
+{
+ rm_chn_descriptor((struct stm_chn_descriptor *)chn_id);
+ return 0;
+}
+int stm_channel_config(void *chn_id, char * config_string)
+{
+ struct file cfgfile;
+ loff_t offset = 0;
+ cfgfile.private_data = chn_id;
+
+ return config_file_write(&cfgfile, config_string,
+ strlen(config_string), &offset);
+}
+int stm_channel_write(void *chn_id, void * src, size_t byte_cnt)
+{
+ struct file wrtfile;
+ loff_t offset = 0;
+ wrtfile.private_data = chn_id;
+
+ return stm_file_write(&wrtfile, src, byte_cnt, &offset);
+
+}
+
+EXPORT_SYMBOL(stm_channel_alloc);
+EXPORT_SYMBOL(stm_channel_free);
+EXPORT_SYMBOL(stm_channel_config);
+EXPORT_SYMBOL(stm_channel_write);
+
+/*****************************************************************************/
+/* Support functions */
/*****************************************************************************/
static int8_t cal_checksum(unsigned char *buf, int cnt)
{
@@ -909,6 +1011,50 @@ static int8_t cal_checksum(unsigned char *buf, int cnt)
return -checksum;
}
+static struct stm_chn_descriptor *gen_chn_descriptor(enum stm_usecase uc_id)
+{
+ int err;
+ struct stm_chn_descriptor *chn_descriptor = NULL;
+
+ /* Malloc the channel descriptor */
+ chn_descriptor = kmalloc(sizeof *chn_descriptor, GFP_KERNEL);
+ if (!chn_descriptor) {
+ err = -ENOMEM;
+ goto gen_chn_exit;
+ }
+
+ /* Initialize chn descriptor */
+ chn_descriptor->write_dentry = NULL;
+ chn_descriptor->config_dentry = NULL;
+ chn_descriptor->chn_enable = true;
+ chn_descriptor->write_protect = true;
+
+ mutex_init(&chn_descriptor->lock);
+ chn_descriptor->msg_format = VENDOR;
+ chn_descriptor->msg_timing = GUARANTEED;
+ chn_descriptor->ost_protocol = OST_PROTOCOL_CHARSTREAM;
+ chn_descriptor->ost_entity = OST_ENTITY_ID;
+ chn_descriptor->timestamp_enable = true;
+ chn_descriptor->checksum_enable = false;
+ /* set to invlaid id so first write will export pid message */
+ chn_descriptor->pid = 0;
+
+ /* Allocate a channel */
+ err = dev.stm_ops->allocate_channel(uc_id, &chn_descriptor->chn_id);
+ if (err < 0) {
+ chn_descriptor->chn_id = NULL;
+ goto gen_chn_exit;
+ }
+
+ list_add_tail(&chn_descriptor->chn_list_link, &dev.chn_list_head);
+
+ return chn_descriptor;
+
+gen_chn_exit:
+ kfree(chn_descriptor);
+ return ERR_PTR(err);
+}
+
static void rm_chn_descriptor(struct stm_chn_descriptor *chn_descriptor)
{
if (!chn_descriptor)
@@ -923,6 +1069,10 @@ static void rm_chn_descriptor(struct stm_chn_descriptor *chn_descriptor)
if (chn_descriptor->chn_id)
dev.stm_ops->free_channel(chn_descriptor->chn_id);
+ list_del(&chn_descriptor->chn_list_link);
+
+ kfree(chn_descriptor);
+
}