#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nvt_bus.h" #include "nvt_diag.h" #include "nvt_util_dbg.h" static int ref_count; /** * nvt_diag_read -read operation for diagnostic device node * * */ ssize_t nvt_diag_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { ssize_t retval = 0; struct _nvt_diag_resp *diag_resp; //struct _nvt_diag *diag_node = filp->private_data; struct _nvt_bus *bus = filp->private_data; diag_resp = kzalloc(sizeof(struct _nvt_diag_resp), GFP_KERNEL); if (diag_resp == NULL) { nvt_dbg(DIAG, "%s: kzalloc is failed\n", __func__); retval = -1; return retval; } //diag_node->rece_resp((void *)diag_node, diag_resp); retval = bus->nvt_wdev_bus_ops.rx_ctrl(bus, (u8 *)diag_resp, sizeof(struct _nvt_diag_resp)); if (retval < 0) { nvt_dbg(DIAG, "%s: failed to recv diag resp!!\n", __func__); kfree(diag_resp); return retval; } if (copy_to_user(buf, (void *)diag_resp, (diag_resp->resp_len + NVT_DIAG_HDR_LEN))) { nvt_dbg(DIAG, "%s: copy err code to user failed\n", __func__); //20151218 nash: coverity#48965 kfree(diag_resp); return -1; } kfree(diag_resp); return 0; } /** * nvt_diag_write -write operation for diagnostic device node * * */ ssize_t nvt_diag_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { u8 *cfu_buf; ssize_t retval = 0; struct _nvt_bus *bus = filp->private_data; cfu_buf = kzalloc(count, GFP_KERNEL); if (cfu_buf == NULL) { nvt_dbg(DIAG, "%s: kzalloc is failed\n", __func__); retval = -1; goto alloc_cfu_err; } if (copy_from_user(cfu_buf, buf, count)) { nvt_dbg(DIAG, "%s: copy_from_user is failed\n", __func__); retval = -1; goto cfu_err; } if (*cfu_buf == NVT_DIAG_CMD_CLASS_0 || *cfu_buf == NVT_DIAG_CMD_CLASS_1 || *cfu_buf == NVT_DIAG_CMD_CLASS_2) { bus->nvt_wdev_bus_ops.tx_ctrl(bus, cfu_buf, count); } else { nvt_dbg(DIAG, "%s: Unsupported!(Data:0x%08x)\n", __func__, *((s32 *)(cfu_buf))); } cfu_err: kfree(cfu_buf); alloc_cfu_err: return retval; } /** * nvt_diag_open() -open operation for diagnostic device node * * */ int nvt_diag_open(struct inode *inode, struct file *filp) { struct _nvt_diag *diag_node; ref_count++; diag_node = container_of(inode->i_cdev, struct _nvt_diag, chr_dev); /* private_data is _nvt_bus */ filp->private_data = diag_node->private_data; nvt_dbg(DIAG, "Major num:%d\n", diag_node->major_nm); return 0; } /** * nvt_diag_release() -release operation for diagnostic device node * * */ int nvt_diag_release(struct inode *inode, struct file *filp) { ref_count--; return 0; } const struct file_operations diag_fops = { .owner = THIS_MODULE, .read = nvt_diag_read, .write = nvt_diag_write, .open = nvt_diag_open, }; /** * nvt_diag_create_node - create a node for diagnostic * @bus_if: bus interface * * Return: 0:success, negative value:fail */ int nvt_diag_create_node(struct _nvt_bus *bus_if) { int ret; dev_t dev; struct _nvt_diag *diag_node; diag_node = &bus_if->nvt_diag; diag_node->private_data = (void *)bus_if; init_waitqueue_head(&diag_node->diag_resp_wait); nvt_dbg(DIAG, "%s: diag_node=%p\n", __func__, diag_node); diag_node->diag_class = class_create(THIS_MODULE, "diag"); if (IS_ERR(diag_node->diag_class)) { nvt_dbg(DIAG, "%s: diag class_create is failed\n", __func__); ret = -1; goto class_create_failed; } ret = alloc_chrdev_region(&diag_node->dev_n, 0, 1, DIAG_NODE_NAME); if (ret < 0) { nvt_dbg(DIAG, "%s: alloc_chrdev_region is failed(err:0x%x)\n", __func__, ret); goto alloc_chrdev_region_failed; } diag_node->major_nm = MAJOR(diag_node->dev_n); diag_node->minor_nm = MINOR(diag_node->dev_n); cdev_init(&diag_node->chr_dev, &diag_fops); ret = cdev_add(&diag_node->chr_dev, diag_node->dev_n, 1); if (ret < 0) { nvt_dbg(DIAG, "%s: cdev_add is failed (err:0x%x)\n", __func__, ret); goto cdev_add_failed; } dev = MKDEV(diag_node->major_nm, diag_node->minor_nm); diag_node->diag_device = device_create(diag_node->diag_class, NULL, dev, NULL, "diag%d", diag_node->minor_nm); if (IS_ERR(diag_node->diag_device)) goto device_create_failed; nvt_dbg(DIAG, "%s: Major num for Diag:%d\n", __func__, diag_node->major_nm); return 0; device_create_failed: cdev_del(&diag_node->chr_dev); cdev_add_failed: unregister_chrdev_region(diag_node->dev_n, 1); alloc_chrdev_region_failed: class_destroy(diag_node->diag_class); class_create_failed: return ret; } /** * nvt_diag_delete_node - delete the diagnostic device node * @data: struct _nvt_bus * * * Return: 0:success, negative value:fail */ int nvt_diag_delete_node(void *data) { struct _nvt_diag *diag_node; dev_t dev; struct _nvt_bus *bus = (struct _nvt_bus *)(data); diag_node = &bus->nvt_diag; dev = MKDEV(diag_node->major_nm, diag_node->minor_nm); device_destroy(diag_node->diag_class, dev); cdev_del(&diag_node->chr_dev); unregister_chrdev_region(diag_node->dev_n , 1); class_destroy(diag_node->diag_class); nvt_dbg(DIAG, "%s: removed diag node\n", __func__); return 0; } /** * nvt_diag_pack_req - pack a diagnostic request for sending * @cmd_class: c0, c1, or c2 command class * @type: command type * @addr: address for memory read/write * @data_len: data byte length * @buf: data byte buffer * @diag_req: * @pkt_len: length of returned diagnostic request * * This function will pack a diagnostic request and put it in diag_req * * Return: 0:success; -1:fail */ int nvt_diag_pack_req(u8 cmd_class, u8 type, u32 addr, u32 data_len, u8 *buf, struct _nvt_diag_req *diag_req, s32 *pkt_len) { diag_req->req_class = cmd_class; nvt_dbg(DIAG, "%s: cmd_class=%x\n", __func__, cmd_class); if (cmd_class == NVT_DIAG_CMD_CLASS_0) { switch (type) { case NVT_DIAG_WRITE_CMD: nvt_dbg(DIAG, "%s: write cmd\n", __func__); diag_req->req_cmd = NVT_DIAG_WRITE_CMD; diag_req->req_len = (u16)(data_len + NVT_DIAG_HDR_LEN); diag_req->sel.write.addr = (u32)addr; if (buf && data_len > 0) { memcpy(diag_req->sel.write.data, buf, data_len); } *pkt_len = NVT_DIAG_HDR_LEN + sizeof(diag_req->sel.write.addr) + data_len; nvt_dbg(DIAG, "pkt_len=%x\r\n", *pkt_len); break; case NVT_DIAG_READ_CMD: nvt_dbg(DIAG, "%s: read cmd\n", __func__); diag_req->req_cmd = NVT_DIAG_READ_CMD; diag_req->req_len = sizeof(diag_req->sel.read); diag_req->sel.read.addr = (u32)addr; diag_req->sel.read.len = (u32)data_len; *pkt_len = NVT_DIAG_HDR_LEN + diag_req->req_len; break; case NVT_DIAG_ECHO_CMD: nvt_dbg(DIAG, "%s: echo cmd\n", __func__); diag_req->req_cmd = NVT_DIAG_ECHO_CMD; diag_req->req_len = (u32)data_len; if (buf && data_len > 0) memcpy(diag_req->sel.echo.data, buf, data_len); *pkt_len = NVT_DIAG_HDR_LEN + data_len; break; case NVT_DIAG_CHECK_SUM_CMD: nvt_dbg(DIAG, "%s: crc cmd\n", __func__); diag_req->req_cmd = NVT_DIAG_CHECK_SUM_CMD; diag_req->req_len = sizeof(diag_req->sel.cksum_veri); diag_req->sel.cksum_veri.addr = (u32)addr; diag_req->sel.cksum_veri.len = (u32)data_len; *pkt_len = NVT_DIAG_HDR_LEN + diag_req->req_len; break; case NVT_DIAG_GET_FW_VER_CMD: nvt_dbg(DIAG, "%s: ver cmd\n", __func__); diag_req->req_cmd = NVT_DIAG_GET_FW_VER_CMD; diag_req->req_len = 0; *pkt_len = NVT_DIAG_HDR_LEN; break; case NVT_DIAG_GET_MAC_ADDR_CMD: nvt_dbg(DIAG, "%s: get mac addr cmd\n", __func__); diag_req->req_cmd = NVT_DIAG_GET_MAC_ADDR_CMD; diag_req->req_len = 0; *pkt_len = NVT_DIAG_HDR_LEN; break; case NVT_DIAG_REBOOT_CMD: nvt_dbg(DIAG, "%s: reboot cmd\n", __func__); diag_req->req_cmd = NVT_DIAG_REBOOT_CMD; diag_req->req_len = sizeof(diag_req->sel.reboot_cmd); if (buf && data_len > 0) { memcpy((u8 *)&(diag_req->sel.reboot_cmd. boot_type), buf, data_len); } *pkt_len = NVT_DIAG_HDR_LEN + diag_req->req_len; break; default: return -1; } } else if (cmd_class == NVT_DIAG_CMD_CLASS_1) { switch (type) { case NVT_DIAG_ICONFIG_CMD: diag_req->req_cmd = NVT_DIAG_ICONFIG_CMD; diag_req->req_len = (u16)data_len; if (buf && data_len > 0) { memcpy(diag_req->sel.iconfig_cmd.data, buf, data_len); } *pkt_len = NVT_DIAG_HDR_LEN + data_len; break; default: return -1; } } return 0; } /** * nvt_diag_rsp_header_check - diag response header check * @diag_resp: * * diag response header check * * Return: 0:success; -1:fail */ s32 nvt_diag_rsp_header_check(struct _nvt_diag_resp *diag_resp) { if (diag_resp == NULL) { return -1; } if (diag_resp->resp_class != NVT_DIAG_CMD_CLASS_0 && diag_resp->resp_class != NVT_DIAG_CMD_CLASS_1 && diag_resp->resp_class != NVT_DIAG_CMD_CLASS_2) { nvt_dbg(ERROR, "%s: class error!!\n", __func__); return -2; } if ((diag_resp->resp_cmd & NVT_DIAG_RSP_FLAG) != NVT_DIAG_RSP_FLAG) { nvt_dbg(ERROR, "%s: cmd error!!\n", __func__); return -3; } return 0; }