diff options
Diffstat (limited to 'drivers/stm/stm_fw.c')
-rw-r--r-- | drivers/stm/stm_fw.c | 198 |
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); + } |