/* notify work */ static void dsm_work_func(struct work_struct *work) { int i; struct dsm_client *client; DSM_LOG_DEBUG("%s enter\n", __func__); mutex_lock(&g_dsm_server.mtx_lock); smp_rmb(); for(i=0; i<CLIENT_SIZE; i++){ /* whether it is a valid client */ if(test_bit(DSM_CLIENT_VAILD_BIT, &g_dsm_server.client_flag[i])){ DSM_LOG_DEBUG("No.%d client name %s flag 0x%lx\n", i, g_dsm_server.client_list[i]->client_name, g_dsm_server.client_flag[i]); /* whether the client report error msg, clear a bit and return its old value */ if(!test_and_clear_bit(DSM_CLIENT_NOTIFY_BIT, &g_dsm_server.client_flag[i])) continue; client = g_dsm_server.client_list[i]; if(client == NULL){ DSM_LOG_INFO("%d client is null client.\n",i); continue; } /* wake up wait queue */ wake_up_interruptible_all(&client->waitq); DSM_LOG_INFO("%s finish notify\n", client->client_name); } } mutex_unlock(&g_dsm_server.mtx_lock); DSM_LOG_DEBUG("%s exit\n", __func__); return; }
//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; }
/* 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; }
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; }
static void dsm_work_func(struct work_struct *work) { int i; struct dsm_client *client; DSM_LOG_DEBUG("%s enter\n", __func__); mutex_lock(&g_dsm_server.mtx_lock); smp_rmb(); for(i=0; i<CLIENT_SIZE; i++) { if(test_bit(DSM_CLIENT_VAILD_BIT, &g_dsm_server.client_flag[i])) { DSM_LOG_DEBUG("No.%d client name %s flag 0x%lx\n", i, g_dsm_server.client_list[i]->client_name, g_dsm_server.client_flag[i]); if(!test_and_clear_bit(DSM_CLIENT_NOTIFY_BIT, &g_dsm_server.client_flag[i])) continue; client = g_dsm_server.client_list[i]; wake_up_interruptible_all(&client->waitq); DSM_LOG_INFO("%s finish notify\n", client->client_name); } } mutex_unlock(&g_dsm_server.mtx_lock); DSM_LOG_DEBUG("%s exit\n", __func__); return; }
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; }