diff --git a/drivers/i2c/busses/virtio-i2c.c b/drivers/i2c/busses/virtio-i2c.c index 95c35541c295..20d4ff9749cb 100644 --- a/drivers/i2c/busses/virtio-i2c.c +++ b/drivers/i2c/busses/virtio-i2c.c @@ -34,19 +34,6 @@ #define I2C_VIRTIO_WR 0x02 #define I2C_VIRTIO_RDWR 0x03 -/** - * struct virtio_i2c - virtio i2c device - * @adapter: i2c adapter - * @vdev: the virtio device - * @vq: i2c virtqueue - */ -struct virtio_i2c { - struct i2c_adapter adapter; - struct virtio_device *vdev; - struct virtqueue *vq; - wait_queue_head_t inq; -}; - struct i2c_transfer_head { u32 type; /* read or write from or to slave */ u32 addr; /* slave addr */ @@ -64,6 +51,21 @@ struct virtio_i2c_req { struct i2c_transfer_end end; }; +/** + * struct virtio_i2c - virtio i2c device + * @adapter: i2c adapter + * @vdev: the virtio device + * @i2c_req: description of the format of transfer data + * @vq: i2c virtqueue + */ +struct virtio_i2c { + struct i2c_adapter adapter; + struct virtio_device *vdev; + struct virtio_i2c_req i2c_req; + struct virtqueue *vq; + wait_queue_head_t inq; +}; + static int virti2c_transfer(struct virtio_i2c *vi2c, struct virtio_i2c_req *i2c_req) { @@ -117,49 +119,35 @@ req_exit: } /* prepare the transfer req */ -static struct virtio_i2c_req *virti2c_transfer_prepare(struct i2c_msg *msg_1, - struct i2c_msg *msg_2) +static int virti2c_transfer_prepare(struct i2c_msg *msg_1, + struct i2c_msg *msg_2, struct virtio_i2c_req *i2c_req) { - char *ptr = NULL; - int merge = 0; - struct virtio_i2c_req *i2c_req; + if (IS_ERR_OR_NULL(msg_1) || !msg_1->len || + IS_ERR_OR_NULL(msg_1->buf)) + return -EINVAL; - if (msg_1 == NULL) - return NULL; - - if (msg_2) - merge = 1; - - i2c_req = kzalloc(sizeof(struct virtio_i2c_req), GFP_KERNEL); - if (i2c_req == NULL) - return NULL; - - if (merge) - ptr = kzalloc((msg_1->len + msg_2->len), GFP_KERNEL); - else - ptr = msg_1->buf; - if (ptr == NULL) - goto err_mem; - - /* prepare the head */ - i2c_req->head.type = merge ? - I2C_VIRTIO_RDWR : ((msg_1->flags & I2C_M_RD) ? - I2C_VIRTIO_RD : I2C_VIRTIO_WR); i2c_req->head.addr = msg_1->addr; i2c_req->head.length = msg_1->len; - if (merge) + + if (IS_ERR_OR_NULL(msg_2)) { + i2c_req->head.type = (msg_1->flags & I2C_M_RD) ? + I2C_VIRTIO_RD : I2C_VIRTIO_WR; + i2c_req->buf = msg_1->buf; + } else { + if (!msg_2->len || IS_ERR_OR_NULL(msg_2->buf)) + return -EINVAL; + + i2c_req->head.type = I2C_VIRTIO_RDWR; i2c_req->head.total_length = msg_1->len + msg_2->len; - /* prepare the buf */ - if (merge) - memcpy(ptr, msg_1->buf, msg_1->len); - i2c_req->buf = ptr; + i2c_req->buf = kzalloc((msg_1->len + msg_2->len), GFP_KERNEL); + if (IS_ERR_OR_NULL(i2c_req->buf)) + return -ENOMEM; - return i2c_req; -err_mem: - kfree(i2c_req); - i2c_req = NULL; - return NULL; + memcpy(i2c_req->buf, msg_1->buf, msg_1->len); + } + + return 0; } static void virti2c_transfer_end(struct virtio_i2c_req *req, @@ -171,16 +159,15 @@ static void virti2c_transfer_end(struct virtio_i2c_req *req, req->buf = NULL; } - kfree(req); - req = NULL; + memset(req, 0, sizeof(struct virtio_i2c_req)); } static int virtio_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { int i, ret; - struct virtio_i2c_req *i2c_req; struct virtio_i2c *vi2c = i2c_get_adapdata(adap); + struct virtio_i2c_req *i2c_req = &vi2c->i2c_req; if (num < 1) { dev_err(&vi2c->vdev->dev, @@ -197,24 +184,22 @@ static int virtio_i2c_master_xfer(struct i2c_adapter *adap, if (msgs[i].flags & I2C_M_RD) { /* read the data from slave to master*/ - i2c_req = virti2c_transfer_prepare(&msgs[i], NULL); + ret = virti2c_transfer_prepare(&msgs[i], NULL, i2c_req); } else if ((i + 1 < num) && (msgs[i + 1].flags & I2C_M_RD) && (msgs[i].addr == msgs[i + 1].addr)) { /* write then read from same address*/ - i2c_req = virti2c_transfer_prepare(&msgs[i], - &msgs[i+1]); + ret = virti2c_transfer_prepare(&msgs[i], + &msgs[i+1], i2c_req); i += 1; } else { /* write the data to slave */ - i2c_req = virti2c_transfer_prepare(&msgs[i], NULL); + ret = virti2c_transfer_prepare(&msgs[i], NULL, i2c_req); } - if (i2c_req == NULL) { - ret = -ENOMEM; + if (ret) goto err; - } ret = virti2c_transfer(vi2c, i2c_req); virti2c_transfer_end(i2c_req, &msgs[i]); if (ret)