static ssize_t dsm_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct dsm_client *client = file->private_data; size_t copy_size = 0; DSM_LOG_DEBUG("%s enter\n",__func__); if(!client) { DSM_LOG_ERR("client not bind\n"); goto out; } if(dsm_client_readable(client)) { copy_size = min(count, (client->used_size -client->read_size)); if(copy_to_user(buf, &client->dump_buff[client->read_size], copy_size)) DSM_LOG_ERR("copy to user failed\n"); client->read_size += copy_size; if(client->read_size >= client->used_size) dsm_client_set_idle(client); DSM_LOG_DEBUG("%d bytes read to user\n", copy_size); } out: DSM_LOG_DEBUG("%s exit\n",__func__); return copy_size; }
static int dsm_register_extern_client(struct dsm_extern_client* ext_client) { static int ext_client_cnt = 0; ext_dev[ext_client_cnt].buff_size = ext_client->buf_size; ext_dev[ext_client_cnt].name = ext_client->client_name; if (0 >= ext_dev[ext_client_cnt].buff_size || NULL == ext_dev[ext_client_cnt].name || ext_client_cnt >= EXTERN_DSM_CLIENT_MAX) { DSM_LOG_ERR("[dsm_register_extern_client]client name or buf_size is fault." "don't register!\n"); return -ENOENT; } else if (NULL != dsm_find_client(ext_dev[ext_client_cnt].name)) { DSM_LOG_ERR("[dsm_register_extern_client]register %s has exist, dont register again!\n", ext_dev[ext_client_cnt].name); return -EEXIST; } ext_dsm_client[ext_client_cnt] = dsm_register_client(&ext_dev[ext_client_cnt]); if (!ext_dsm_client[ext_client_cnt]) { DSM_LOG_ERR("[dsm_register_extern_client]register %s failed!\n", ext_dev[ext_client_cnt].name); return -ENOMEM; } ext_client_cnt++; return 0; }
int dsm_client_record(struct dsm_client *client, const char *fmt, ...) { va_list ap; int size = 0; char *str; struct snprintf_ctxt ctxt; if(!client) { DSM_LOG_ERR("%s no client to record\n", __func__); goto out; } if(client->buff_size <= client->used_size) { DSM_LOG_ERR("%s no buffer to record\n", __func__); goto out; } ctxt.avail = client->buff_size - client->used_size -1; str = (char *)&client->dump_buff[client->used_size]; ctxt.next = str; va_start(ap, fmt); __xprintf(fmt, ap, printf_putc, &ctxt); va_end(ap); *ctxt.next = 0; size = ctxt.next - str; client->used_size += size; out: return size; }
/* dsm module init */ static int __init dsm_init(void) { int ret = -EIO; memset(&g_dsm_server, 0, sizeof(struct dsm_server)); g_dsm_server.server_state = DSM_SERVER_UNINIT; mutex_init(&g_dsm_server.mtx_lock); g_dsm_server.dsm_wq = create_singlethread_workqueue("dsm_wq"); if (IS_ERR(g_dsm_server.dsm_wq)){ DSM_LOG_ERR("alloc workqueue failed\n"); goto out; } INIT_WORK(&dsm_work, dsm_work_func); ret = misc_register(&dsm_miscdev); if(ret){ DSM_LOG_ERR("misc register failed\n"); goto out; } /* set server status as ready, client can registe */ g_dsm_server.server_state = DSM_SERVER_INITED; /* registe public client */ dsm_register_public_client(); /* init write semaphore for write func*/ sema_init(&dsm_wbs, 1); out: DSM_LOG_INFO("%s called, ret %d\n", __func__, ret); return ret; }
static ssize_t dsm_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char client_name[CLIENT_NAME_LEN]={0}; int size; struct dsm_client *client = NULL; char *buff = NULL; char *ptr; DSM_LOG_DEBUG("%s enter\n",__func__); buff = (char *)kzalloc(count, GFP_KERNEL); if(!buff){ DSM_LOG_ERR("dsm write malloc failed\n"); goto out; } if(copy_from_user(buff, buf, count)){ DSM_LOG_ERR("dsm write copy failed\n"); goto out; } ptr = buff; while(*ptr){ if(*ptr == '\n') break; ptr++; } if(*ptr == '\n'){ size = ptr - buff; size = (size < CLIENT_NAME_LEN) ? size : (CLIENT_NAME_LEN - 1); memcpy(client_name, buff, size); client = dsm_find_client(client_name); if(client && (!dsm_client_ocuppy(client))){ DSM_LOG_DEBUG("dsm write find client - %s\n", client_name); ptr++;//ignore '/n' size = count - (ptr - buff); dsm_client_copy(client, ptr, size); dsm_client_notify(client, 20203); }else DSM_LOG_INFO("dsm write can't find client - %s\n", client_name); }else DSM_LOG_ERR("dsm write can't find client name\n"); out: if(buff) kfree(buff); DSM_LOG_DEBUG("%s exit\n",__func__); return count; }
int dsm_client_copy(struct dsm_client *client, void *src, int sz) { int size = 0; if(!client) { DSM_LOG_ERR("%s no client to record\n", __func__); goto out; } if((client->used_size + sz) > client->buff_size) { DSM_LOG_ERR("%s no enough buffer to record\n", __func__); goto out; } size = sz; memcpy(&client->dump_buff[client->used_size], src, size); client->used_size += size; out: return size; }
static int __init dsm_init(void) { int ret = -EIO; int i; memset(&g_dsm_server, 0, sizeof(struct dsm_server)); g_dsm_server.server_state = DSM_SERVER_UNINIT; mutex_init(&g_dsm_server.mtx_lock); g_dsm_server.dsm_wq = create_singlethread_workqueue("dsm_wq"); if (IS_ERR(g_dsm_server.dsm_wq)){ DSM_LOG_ERR("alloc workqueue failed\n"); goto out; } INIT_WORK(&dsm_work, dsm_work_func); ret = misc_register(&dsm_miscdev); if(ret){ DSM_LOG_ERR("misc register failed\n"); goto out; } g_dsm_server.server_state = DSM_SERVER_INITED; for (i = 0; i < ARRAY_SIZE(dsm_interface_attrs); i++) { ret = device_create_file(dsm_miscdev.this_device, &dsm_interface_attrs[i]); if (ret < 0) DSM_LOG_ERR("creating sysfs attribute %s failed: %d\n", dsm_interface_attrs[i].attr.name, ret); } dsm_register_public_client(); out: DSM_LOG_INFO("%s called, ret %d\n", __func__, ret); return ret; }
//cnotify format: |client name|,|error no|,|contents| static ssize_t dsm_cnotify_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { char client_name[CLIENT_NAME_LEN]= {0}; int size; int error_no = 0; struct dsm_client *client = NULL; char *strings = NULL; char *ptr; DSM_LOG_DEBUG("%s enter\n",__func__); strings = (char *)kzalloc(count, GFP_KERNEL); if(!strings) { DSM_LOG_ERR("dsm write malloc failed\n"); goto out; } memcpy(strings, buf, count); /*get client name*/ ptr = dsm_strtok(strings, ","); if(ptr) { size = strlen(ptr); size = (size < CLIENT_NAME_LEN) ? size : (CLIENT_NAME_LEN - 1); memcpy(client_name, ptr, size); } /*get error no*/ ptr = dsm_strtok(NULL, ","); if(ptr) error_no = dsm_atoi(ptr); /*get notify content*/ ptr = dsm_strtok(NULL, NULL); DSM_LOG_INFO("client name - %s, error no - %d\n", client_name, error_no); if(ptr) DSM_LOG_INFO("content - %s\n", ptr); client = dsm_find_client(client_name); if(client && (!dsm_client_ocuppy(client))) { DSM_LOG_DEBUG("dsm write find client - %s\n", client_name); if(ptr) dsm_client_copy(client, ptr, strlen(ptr)); dsm_client_notify(client, error_no); } else DSM_LOG_INFO("dsm notify can't find client - %s\n", client_name); out: if(strings) kfree(strings); DSM_LOG_DEBUG("%s exit\n",__func__); return count; }
static void __init dsm_register_public_client(void) { int index; struct dsm_client *client = NULL; for(index = 0; index < ARRAY_SIZE(dsm_pub_clients); index++){ client = dsm_register_client(&dsm_pub_clients[index]); if(client) DSM_LOG_DEBUG("register %d public client - %s success\n", index, dsm_pub_clients[index].name); else DSM_LOG_ERR("register %d public client - %s failed\n", index, dsm_pub_clients[index].name); } }
static unsigned int dsm_poll(struct file *file, poll_table *wait) { struct dsm_client *client = file->private_data; unsigned int mask = 0; DSM_LOG_DEBUG("%s enter\n",__func__); if(!client){ DSM_LOG_ERR("dsm can't poll without client\n"); goto out; } DSM_LOG_DEBUG("client name :%s\n", client->client_name); poll_wait(file, &client->waitq, wait); if(test_bit(CBUFF_READY_BIT, &client->buff_flag)) mask = POLLIN | POLLRDNORM; out: DSM_LOG_DEBUG("%s exit, mask:%d\n",__func__, mask); return mask; }
static long dsm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; struct dsm_client *client = (struct dsm_client *)file->private_data; long ret = 0; int error = 0; char buff[CLIENT_NAME_LEN]= {0}; struct dsm_extern_client tmp_ext_client; DSM_LOG_DEBUG("%s enter,\n",__func__); switch (cmd) { case DSM_IOCTL_GET_CLIENT_COUNT: mutex_lock(&g_dsm_server.mtx_lock); error = g_dsm_server.client_count; mutex_unlock(&g_dsm_server.mtx_lock); DSM_LOG_INFO("client count :%d\n", error); ret = copy_int_to_user(argp, error); break; case DSM_IOCTL_BIND: if (copy_from_user(buff, argp, CLIENT_NAME_LEN)) { DSM_LOG_ERR("copy from user failed\n"); ret = -EFAULT; } else { DSM_LOG_DEBUG("try bind client %s\n", buff); client = dsm_find_client(buff); if(client) { dsm_bind_client(client); file->private_data = (void *)client; } else { ret = -ENXIO; } } break; case DSM_IOCTL_POLL_CLIENT_STATE: if(client && client->cops && client->cops->poll_state) { error = client->cops->poll_state(); DSM_LOG_INFO("poll %s state result :%d\n", client->client_name, error); ret = copy_int_to_user(argp, error); } else { DSM_LOG_ERR("dsm client not bound or poll not support\n"); ret = -ENXIO; } break; case DSM_IOCTL_FORCE_DUMP: if (copy_from_user(buff, argp, UINT_BUF_MAX)) { DSM_LOG_ERR("copy from user failed\n"); ret = -EFAULT; } else { if(client && client->cops && client->cops->dump_func) { if(!dsm_client_ocuppy(client)) { client->error_no = dsm_atoi(buff); client->used_size = client->cops->dump_func(client->error_no, (void *)client->dump_buff, (int)client->buff_size); set_bit(CBUFF_READY_BIT, &client->buff_flag); } else { DSM_LOG_INFO("client %s's buff ocuppy failed\n", client->client_name); ret = -EBUSY; } } else { DSM_LOG_ERR("dsm client not bound or dump not support\n"); ret = -ENXIO; } } break; case DSM_IOCTL_GET_CLIENT_ERROR: if(client) ret = copy_int_to_user(argp, client->error_no); else { DSM_LOG_ERR("dsm find client failed\n"); ret = -ENXIO; } break; case DSM_IOCTL_GET_DEVICE_NAME: if (client && client->device_name) { ret = copy_to_user(argp, client->device_name, DSM_MAX_DEVICE_NAME_LEN); } else { ret = -ENXIO; } break; case DSM_IOCTL_GET_IC_NAME: if (client && client->ic_name) { ret = copy_to_user(argp, client->ic_name, DSM_MAX_IC_NAME_LEN); } else { ret = -ENXIO; } break; case DSM_IOCTL_GET_MODULE_NAME: if (client && client->module_name) { ret = copy_to_user(argp, client->module_name, DSM_MAX_MODULE_NAME_LEN); } else { ret = -ENXIO; } break; case DSM_IOCTL_REGISTER_EXTERN_CLIENT: if (copy_from_user(&tmp_ext_client, (struct dsm_extern_client *)arg, sizeof(struct dsm_extern_client))) { ret = -EFAULT; } else { dsm_register_extern_client(&tmp_ext_client); } break; default: DSM_LOG_ERR("unknown ioctl command :%d\n", cmd); ret = -EINVAL; break; } DSM_LOG_DEBUG("%s exit\n",__func__); return ret; }
static ssize_t dsm_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char client_name[CLIENT_NAME_LEN]= {'\0'}; int size, error_no = 0; struct dsm_client *client = NULL; char *buff = NULL; char *ptr = NULL; #ifdef CONFIG_HUAWEI_SDCARD_VOLD char err_string[20] = {0}; int err; #endif DSM_LOG_DEBUG("%s enter\n",__func__); buff = (char *)kzalloc(count, GFP_KERNEL); if(!buff) { DSM_LOG_ERR("dsm write malloc failed\n"); goto out; } if(copy_from_user(buff, buf, count)) { DSM_LOG_ERR("dsm write copy failed\n"); goto out; } /*get client name*/ ptr = dsm_strtok(buff, ","); if(ptr) { size = strlen(ptr); size = (size < CLIENT_NAME_LEN) ? size : (CLIENT_NAME_LEN - 1); memcpy(client_name, ptr, size); } /*get error no*/ ptr = dsm_strtok(NULL, ","); if(ptr) { error_no = dsm_atoi(ptr); } /*get notify content*/ ptr = dsm_strtok(NULL, NULL); DSM_LOG_INFO("client name - %s, error no - %d\n", client_name, error_no); if(ptr) { DSM_LOG_INFO("content - %s\n", ptr); } client = dsm_find_client(client_name); #ifdef CONFIG_HUAWEI_SDCARD_VOLD if(client && !strncasecmp("sdcard_vold",client_name,size)&&(!dsm_client_ocuppy(client))) { DSM_LOG_DEBUG("dsm write find sdcard_vold\n"); ptr++; while(*ptr) { if(*ptr == '\n') break; ptr++; } if(*ptr == '\n') { memcpy(err_string,ptr-SDCARD_ERR_LEN,SDCARD_ERR_LEN); err_string[SDCARD_ERR_LEN] = '\0'; sscanf(err_string,"%d",&err); dsm_client_copy(client, ptr+1, (count - (ptr+1-buff))); dsm_client_notify(client, err); } } else if(client && (!dsm_client_ocuppy(client))) { #else if(client && (!dsm_client_ocuppy(client))) { #endif DSM_LOG_DEBUG("dsm write find client - %s\n", client_name); if(ptr) dsm_client_copy(client, ptr, strlen(ptr)); dsm_client_notify(client, error_no); } else { DSM_LOG_INFO("dsm notify can't find client - %s\n", client_name); } out: if(buff) kfree(buff); DSM_LOG_DEBUG("%s exit\n",__func__); return count; } static unsigned int dsm_poll(struct file *file, poll_table *wait) { struct dsm_client *client = file->private_data; unsigned int mask = 0; DSM_LOG_DEBUG("%s enter\n",__func__); if(!client) { DSM_LOG_ERR("dsm can't poll without client\n"); goto out; } DSM_LOG_DEBUG("client name :%s\n", client->client_name); poll_wait(file, &client->waitq, wait); if(test_bit(CBUFF_READY_BIT, &client->buff_flag)) mask = POLLIN | POLLRDNORM; out: DSM_LOG_DEBUG("%s exit, mask:%d\n",__func__, mask); return mask; } static int dsm_open(struct inode *inode, struct file *file) { DSM_LOG_DEBUG("%s enter\n",__func__); file->private_data = NULL; DSM_LOG_DEBUG("%s exit\n",__func__); return 0; }
struct dsm_client *dsm_register_client (struct dsm_dev *dev) { int i; int size; int conflict = -1; struct dsm_client *ptr = NULL; if(g_dsm_server.server_state != DSM_SERVER_INITED) { DSM_LOG_ERR("dsm server uninited\n"); goto out; } if(dev == NULL) { DSM_LOG_ERR("dsm_dev is NULL\n"); goto out; } smp_rmb(); if(g_dsm_server.client_count < CLIENT_SIZE) { ptr = (struct dsm_client *)kzalloc((sizeof(struct dsm_client)+dev->buff_size), GFP_KERNEL); if(!ptr) { DSM_LOG_ERR("clients malloc failed\n"); goto out; } mutex_lock(&g_dsm_server.mtx_lock); for(i=0; i<CLIENT_SIZE; i++) { if(!test_bit(DSM_CLIENT_VAILD_BIT, &g_dsm_server.client_flag[i])) break; if (dev->name) { conflict = strncmp(g_dsm_server.client_list[i]->client_name, dev->name, CLIENT_NAME_LEN); if(!conflict) { DSM_LOG_ERR("new client %s conflict with No.%d client %s\n", dev->name, i, g_dsm_server.client_list[i]->client_name); break; } } else { DSM_LOG_ERR("Please specify the dsm device name!\n"); kfree(ptr); ptr = NULL; goto out; } } if(i < CLIENT_SIZE && conflict) { ptr->client_name = dev->name; if (dev->device_name) { ptr->device_name = dev->device_name; } if (dev->ic_name) { ptr->ic_name = dev->ic_name; } if (dev->module_name) { ptr->module_name = dev->module_name; } ptr->client_id = i; ptr->cops = dev->fops; ptr->buff_size = dev->buff_size; init_waitqueue_head(&ptr->waitq); g_dsm_server.client_list[i] = ptr; set_bit(DSM_CLIENT_VAILD_BIT, &g_dsm_server.client_flag[i]); g_dsm_server.client_count++; DSM_LOG_INFO("client %s register success!\n", ptr->client_name); smp_wmb(); } else { DSM_LOG_ERR("clients register failed, index %d, conflict %d\n", i, conflict); kfree(ptr); ptr = NULL; } mutex_unlock(&g_dsm_server.mtx_lock); } else DSM_LOG_INFO("clients has full\n"); out: return ptr; }
/* sysfs write function */ static ssize_t dsm_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char client_name[CLIENT_NAME_LEN]={0}; int size; struct dsm_client *client = NULL; char *buff = NULL; char *ptr; char err_string[20] = {0}; int err; DSM_LOG_INFO("%s enter\n",__func__); /* try to get control of the write buffer */ if (down_trylock(&dsm_wbs)) { /* somebody else has it now; * if we're non-blocking, then exit... */ if (file->f_flags & O_NONBLOCK) { return -EAGAIN; } /* ...or if we want to block, then do so here */ if (down_interruptible(&dsm_wbs)) { /* something went wrong with wait */ return -ERESTARTSYS; } } buff = (char *)kzalloc(count, GFP_KERNEL); if(!buff){ DSM_LOG_ERR("dsm write malloc failed\n"); goto out; } if(copy_from_user(buff, buf, count)){ DSM_LOG_ERR("dsm write copy failed\n"); goto out; } buff[count-1] = '\0'; ptr = buff; while(*ptr){ if(*ptr == '\n') break; ptr++; } /* get the client name */ if(*ptr == '\n') { size = ptr - buff; size = (size < CLIENT_NAME_LEN) ? size : (CLIENT_NAME_LEN - 1); memcpy(client_name, buff, size); DSM_LOG_INFO( "%s client name is: %s \n", __func__ ,client_name ); client = dsm_find_client(client_name); if( client ) { /* found client name */ DSM_LOG_DEBUG("dsm write find client - %s\n", client_name); ptr++; while(*ptr) { if(*ptr == '\n') break; ptr++; } /* get error number */ if(*ptr == '\n') { memcpy(err_string,ptr-DSM_ERR_LEN,DSM_ERR_LEN); err_string[DSM_ERR_LEN] = '\0'; sscanf(err_string,"%d",&err); DSM_LOG_INFO( "%s error number is: %d \n", __func__ ,err ); /* judge if the err number is legal */ if( (err >= DMS_ERR_NUM_MIN ) && (err < DMS_ERR_NUM_MAX) ) { /* report the error */ dsm_client_copy(client, ptr+1, (count - (ptr+1-buff))); dsm_client_notify(client, err); } else { DSM_LOG_ERR("dsm write err number is not legal! err:%d\n", err); } } } else { DSM_LOG_INFO("dsm write can't find client - %s\n", client_name); } } else { DSM_LOG_ERR("dsm write can't find client name\n"); } out: if(buff) kfree(buff); DSM_LOG_DEBUG("%s exit\n", __func__); /* release the write buffer and wake anyone who's waiting for it */ up(&dsm_wbs); return count; }
/* registe client on server */ struct dsm_client *dsm_register_client (struct dsm_dev *dev) { int i; int size; int conflict = -1; struct dsm_client *ptr = NULL; if(g_dsm_server.server_state != DSM_SERVER_INITED){ DSM_LOG_ERR("dsm server uninited\n"); goto out; } if(dev == NULL){ DSM_LOG_ERR("dsm_dev is NULL\n"); goto out; } /* memory barrier */ smp_rmb(); /* whether client list is full */ if(g_dsm_server.client_count < CLIENT_SIZE){ /* malloc memory for this client */ ptr = (struct dsm_client *)kzalloc((sizeof(struct dsm_client)+dev->buff_size), GFP_KERNEL); if(!ptr){ DSM_LOG_ERR("clients malloc failed\n"); goto out; } mutex_lock(&g_dsm_server.mtx_lock); /* try to find a free location on server */ for(i=0; i<CLIENT_SIZE; i++){ /* whether the client is free */ if(!test_bit(DSM_CLIENT_VAILD_BIT, &g_dsm_server.client_flag[i])) break; /* if client is not free,whether a same client is exist */ conflict = strncmp(g_dsm_server.client_list[i]->client_name, dev->name, CLIENT_NAME_LEN); if(!conflict){ DSM_LOG_ERR("new client %s conflict with No.%d client %s\n", dev->name, i, g_dsm_server.client_list[i]->client_name); break; } } /* init a client */ if(i < CLIENT_SIZE && conflict){ size = strlen(dev->name); size = (size < CLIENT_NAME_LEN) ? size : (CLIENT_NAME_LEN - 1); memcpy(ptr->client_name, dev->name, size); // need add a end symbol? size+1? ptr->client_id = i; ptr->cops = dev->fops; ptr->buff_size = dev->buff_size; init_waitqueue_head(&ptr->waitq); g_dsm_server.client_list[i] = ptr; set_bit(DSM_CLIENT_VAILD_BIT, &g_dsm_server.client_flag[i]); g_dsm_server.client_count++; smp_wmb(); }else{ /* if a same client is exist, donot registe */ DSM_LOG_ERR("clients register failed, index %d, conflict %d\n", i, conflict); kfree(ptr); ptr = NULL; } mutex_unlock(&g_dsm_server.mtx_lock); } else DSM_LOG_INFO("clients has full\n"); out: return ptr; }