📄 smscoreapi.c
字号:
* return client handle or NULL. * * @param coredev pointer to a coredev object returned by * smscore_register_device * @param data_type client data type (SMS_DONT_CARE for all types) * @param id client id (SMS_DONT_CARE for all id) * */static structsmscore_client_t *smscore_find_client(struct smscore_device_t *coredev, int data_type, int id){ struct smscore_client_t *client = NULL; struct list_head *next, *first; unsigned long flags; struct list_head *firstid, *nextid; spin_lock_irqsave(&coredev->clientslock, flags); first = &coredev->clients; for (next = first->next; (next != first) && !client; next = next->next) { firstid = &((struct smscore_client_t *)next)->idlist; for (nextid = firstid->next; nextid != firstid; nextid = nextid->next) { if ((((struct smscore_idlist_t *)nextid)->id == id) && (((struct smscore_idlist_t *)nextid)->data_type == data_type || (((struct smscore_idlist_t *)nextid)->data_type == 0))) { client = (struct smscore_client_t *) next; break; } } } spin_unlock_irqrestore(&coredev->clientslock, flags); return client;}/** * find client by response id/type, call clients onresponse handler * return buffer to pool on error * * @param coredev pointer to a coredev object returned by * smscore_register_device * @param cb pointer to response buffer descriptor * */void smscore_onresponse(struct smscore_device_t *coredev, struct smscore_buffer_t *cb){ struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset); struct smscore_client_t *client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId); int rc = -EBUSY;#if 1 static unsigned long last_sample_time; /* = 0; */ static int data_total; /* = 0; */ unsigned long time_now = jiffies_to_msecs(jiffies); if (!last_sample_time) last_sample_time = time_now; if (time_now - last_sample_time > 10000) { sms_debug("\ndata rate %d bytes/secs", (int)((data_total * 1000) / (time_now - last_sample_time))); last_sample_time = time_now; data_total = 0; } data_total += cb->size;#endif /* If no client registered for type & id, * check for control client where type is not registered */#if 0 if (!client) client = smscore_find_client(coredev, 0, phdr->msgDstId);#endif if (client) rc = client->onresponse_handler(client->context, cb); if (rc < 0) { switch (phdr->msgType) { case MSG_SMS_GET_VERSION_EX_RES: { struct SmsVersionRes_ST *ver = (struct SmsVersionRes_ST *) phdr; sms_debug("MSG_SMS_GET_VERSION_EX_RES " "id %d prots 0x%x ver %d.%d", ver->FirmwareId, ver->SupportedProtocols, ver->RomVersionMajor, ver->RomVersionMinor); coredev->mode = ver->FirmwareId == 255 ? DEVICE_MODE_NONE : ver->FirmwareId; coredev->modes_supported = ver->SupportedProtocols; complete(&coredev->version_ex_done); break; } case MSG_SMS_INIT_DEVICE_RES: sms_debug("MSG_SMS_INIT_DEVICE_RES"); complete(&coredev->init_device_done); break; case MSG_SW_RELOAD_START_RES: sms_debug("MSG_SW_RELOAD_START_RES"); complete(&coredev->reload_start_done); break; case MSG_SMS_DATA_DOWNLOAD_RES: complete(&coredev->data_download_done); break; case MSG_SW_RELOAD_EXEC_RES: sms_debug("MSG_SW_RELOAD_EXEC_RES"); break; case MSG_SMS_SWDOWNLOAD_TRIGGER_RES: sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES"); complete(&coredev->trigger_done); break; case MSG_SMS_SLEEP_RESUME_COMP_IND: complete(&coredev->resume_done); break; default:#if 0 sms_info("no client (%p) or error (%d), " "type:%d dstid:%d", client, rc, phdr->msgType, phdr->msgDstId);#endif break; } smscore_putbuffer(coredev, cb); }}/** * return pointer to next free buffer descriptor from core pool * * @param coredev pointer to a coredev object returned by * smscore_register_device * * @return pointer to descriptor on success, NULL on error. */struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev){ struct smscore_buffer_t *cb = NULL; unsigned long flags; spin_lock_irqsave(&coredev->bufferslock, flags); if (!list_empty(&coredev->buffers)) { cb = (struct smscore_buffer_t *) coredev->buffers.next; list_del(&cb->entry); } spin_unlock_irqrestore(&coredev->bufferslock, flags); return cb;}/** * return buffer descriptor to a pool * * @param coredev pointer to a coredev object returned by * smscore_register_device * @param cb pointer buffer descriptor * */void smscore_putbuffer(struct smscore_device_t *coredev, struct smscore_buffer_t *cb){ list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);}static int smscore_validate_client(struct smscore_device_t *coredev, struct smscore_client_t *client, int data_type, int id){ struct smscore_idlist_t *listentry; struct smscore_client_t *registered_client; if (!client) { sms_err("bad parameter."); return -EFAULT; } registered_client = smscore_find_client(coredev, data_type, id); if (registered_client == client) return 0; if (registered_client) { sms_err("The msg ID already registered to another client."); return -EEXIST; } listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL); if (!listentry) { sms_err("Can't allocate memory for client id."); return -ENOMEM; } listentry->id = id; listentry->data_type = data_type; list_add_locked(&listentry->entry, &client->idlist, &coredev->clientslock); return 0;}/** * creates smsclient object, check that id is taken by another client * * @param coredev pointer to a coredev object from clients hotplug * @param initial_id all messages with this id would be sent to this client * @param data_type all messages of this type would be sent to this client * @param onresponse_handler client handler that is called to * process incoming messages * @param onremove_handler client handler that is called when device is removed * @param context client-specific context * @param client pointer to a value that receives created smsclient object * * @return 0 on success, <0 on error. */int smscore_register_client(struct smscore_device_t *coredev, struct smsclient_params_t *params, struct smscore_client_t **client){ struct smscore_client_t *newclient; /* check that no other channel with same parameters exists */ if (smscore_find_client(coredev, params->data_type, params->initial_id)) { sms_err("Client already exist."); return -EEXIST; } newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL); if (!newclient) { sms_err("Failed to allocate memory for client."); return -ENOMEM; } INIT_LIST_HEAD(&newclient->idlist); newclient->coredev = coredev; newclient->onresponse_handler = params->onresponse_handler; newclient->onremove_handler = params->onremove_handler; newclient->context = params->context; list_add_locked(&newclient->entry, &coredev->clients, &coredev->clientslock); smscore_validate_client(coredev, newclient, params->data_type, params->initial_id); *client = newclient; sms_debug("%p %d %d", params->context, params->data_type, params->initial_id); return 0;}/** * frees smsclient object and all subclients associated with it * * @param client pointer to smsclient object returned by * smscore_register_client * */void smscore_unregister_client(struct smscore_client_t *client){ struct smscore_device_t *coredev = client->coredev; unsigned long flags; spin_lock_irqsave(&coredev->clientslock, flags); while (!list_empty(&client->idlist)) { struct smscore_idlist_t *identry = (struct smscore_idlist_t *) client->idlist.next; list_del(&identry->entry); kfree(identry); } sms_info("%p", client->context); list_del(&client->entry); kfree(client); spin_unlock_irqrestore(&coredev->clientslock, flags);}/** * verifies that source id is not taken by another client, * calls device handler to send requests to the device * * @param client pointer to smsclient object returned by * smscore_register_client * @param buffer pointer to a request buffer * @param size size (in bytes) of request buffer * * @return 0 on success, <0 on error. */int smsclient_sendrequest(struct smscore_client_t *client, void *buffer, size_t size){ struct smscore_device_t *coredev; struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer; int rc; if (client == NULL) { sms_err("Got NULL client"); return -EINVAL; } coredev = client->coredev; /* check that no other channel with same id exists */ if (coredev == NULL) { sms_err("Got NULL coredev"); return -EINVAL; } rc = smscore_validate_client(client->coredev, client, 0, phdr->msgSrcId); if (rc < 0) return rc; return coredev->sendrequest_handler(coredev->context, buffer, size);}#if 0/** * return the size of large (common) buffer * * @param coredev pointer to a coredev object from clients hotplug * * @return size (in bytes) of the buffer */int smscore_get_common_buffer_size(struct smscore_device_t *coredev){ return coredev->common_buffer_size;}/** * maps common buffer (if supported by platform) * * @param coredev pointer to a coredev object from clients hotplug * @param vma pointer to vma struct from mmap handler * * @return 0 on success, <0 on error. */static int smscore_map_common_buffer(struct smscore_device_t *coredev, struct vm_area_struct *vma){ unsigned long end = vma->vm_end, start = vma->vm_start, size = PAGE_ALIGN(coredev->common_buffer_size); if (!(vma->vm_flags & (VM_READ | VM_SHARED)) || (vma->vm_flags & VM_WRITE)) { sms_err("invalid vm flags"); return -EINVAL; } if ((end - start) != size) { sms_err("invalid size %d expected %d", (int)(end - start), (int) size); return -EINVAL; } if (remap_pfn_range(vma, start, coredev->common_buffer_phys >> PAGE_SHIFT, size, pgprot_noncached(vma->vm_page_prot))) { sms_err("remap_page_range failed"); return -EAGAIN; } return 0;}#endifstatic int __init smscore_module_init(void){ int rc = 0; INIT_LIST_HEAD(&g_smscore_notifyees); INIT_LIST_HEAD(&g_smscore_devices); kmutex_init(&g_smscore_deviceslock); INIT_LIST_HEAD(&g_smscore_registry); kmutex_init(&g_smscore_registrylock); /* USB Register */ rc = smsusb_register(); /* DVB Register */ rc = smsdvb_register(); sms_debug("rc %d", rc); return rc;}static void __exit smscore_module_exit(void){ kmutex_lock(&g_smscore_deviceslock); while (!list_empty(&g_smscore_notifyees)) { struct smscore_device_notifyee_t *notifyee = (struct smscore_device_notifyee_t *) g_smscore_notifyees.next; list_del(¬ifyee->entry); kfree(notifyee); } kmutex_unlock(&g_smscore_deviceslock); kmutex_lock(&g_smscore_registrylock); while (!list_empty(&g_smscore_registry)) { struct smscore_registry_entry_t *entry = (struct smscore_registry_entry_t *) g_smscore_registry.next; list_del(&entry->entry); kfree(entry); } kmutex_unlock(&g_smscore_registrylock); /* DVB UnRegister */ smsdvb_unregister(); /* Unregister USB */ smsusb_unregister(); sms_debug("");}module_init(smscore_module_init);module_exit(smscore_module_exit);MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle");MODULE_AUTHOR("Siano Mobile Silicon,,, (doronc@siano-ms.com)");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -