qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v6] i2c-tiny-usb: a small usb to i2c bridge


From: Alex Bennée
Subject: Re: [Qemu-devel] [PATCH v6] i2c-tiny-usb: a small usb to i2c bridge
Date: Tue, 16 Feb 2016 16:51:13 +0000
User-agent: mu4e 0.9.17; emacs 25.0.91.3

Tim Sander <address@hidden> writes:

> Oh my, so many stupid little errors. Due to firewall impairment i am sending 
> these
> patches manually. Last time i forgot to disable the newline breaks which made 
> the
> patch v5 unusable. Sorry for this inconvenience.

Please run ${QEMU_SRC}/scripts/checkpatch.pl on your patch and correct
the stylistic errors it reports. I'll echo Gerd's comments about the
value of using git send-email to send patches. If you can glean you
email clients SMTP settings then you should be able to get
git-send-email to do this as well. It's much less error prone once you
have it working.

>
> i2c-tiny-usb is a small usb to i2c bridge:
>  http://www.harbaum.org/till/i2c_tiny_usb/index.shtml
>
> It is pretty simple and has no usb endpoints just a control.
> Reasons for adding this device:
> * Linux device driver available
> * adding an additional i2c bus via command line e.g.
>   -device usb-i2c-tiny,id=i2c-0 -device tmp105,bus=i2c,address=0x50
> Signed-off-by: address@hidden
> ---
>  default-configs/usb.mak |   1 +
>  hw/usb/Makefile.objs    |   1 +
>  hw/usb/dev-i2c-tiny.c   | 314 
> ++++++++++++++++++++++++++++++++++++++++++++++++
>  trace-events            |  11 ++
>  4 files changed, 327 insertions(+)
>  create mode 100644 hw/usb/dev-i2c-tiny.c
>
> diff --git a/default-configs/usb.mak b/default-configs/usb.mak
> index f4b8568..01d2c9f 100644
> --- a/default-configs/usb.mak
> +++ b/default-configs/usb.mak
> @@ -8,3 +8,4 @@ CONFIG_USB_AUDIO=y
>  CONFIG_USB_SERIAL=y
>  CONFIG_USB_NETWORK=y
>  CONFIG_USB_BLUETOOTH=y
> +CONFIG_USB_I2C_TINY=y
> diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
> index 8f00fbd..3a4c337 100644
> --- a/hw/usb/Makefile.objs
> +++ b/hw/usb/Makefile.objs
> @@ -20,6 +20,7 @@ common-obj-$(CONFIG_USB_AUDIO)        += dev-audio.o
>  common-obj-$(CONFIG_USB_SERIAL)       += dev-serial.o
>  common-obj-$(CONFIG_USB_NETWORK)      += dev-network.o
>  common-obj-$(CONFIG_USB_BLUETOOTH)    += dev-bluetooth.o
> +common-obj-$(CONFIG_USB_I2C_TINY)     += dev-i2c-tiny.o
>
>  ifeq ($(CONFIG_USB_SMARTCARD),y)
>  common-obj-y                          += dev-smartcard-reader.o
> diff --git a/hw/usb/dev-i2c-tiny.c b/hw/usb/dev-i2c-tiny.c
> new file mode 100644
> index 0000000..7abb9df
> --- /dev/null
> +++ b/hw/usb/dev-i2c-tiny.c
> @@ -0,0 +1,314 @@
> +/*
> + * I2C tiny usb device emulation
> + *
> + * i2c-tiny-usb is a small usb to i2c bridge:
> + *
> + * http://www.harbaum.org/till/i2c_tiny_usb/index.shtml
> + *
> + * The simulated device is pretty simple and has no usb endpoints.
> + * There is a Linux device driver available named i2c-tiny-usb.
> + *
> + * Below is an example how to use this device from command line:
> + *  -device usb-i2c-tiny,id=i2c-0 -device tmp105,bus=i2c,address=0x50
> + *
> + * Copyright (c) 2015 Tim Sander <address@hidden>
> + *
> + * Loosly based on usb dev-serial.c:
> + * Copyright (c) 2006 CodeSourcery.
> + * Copyright (c) 2008 Samuel Thibault <address@hidden>
> + * Written by Paul Brook, reused for FTDI by Samuel Thibault
> + *
> + * This code is licensed under the LGPL.
> + *
> + */
> +
> +#include "trace.h"
> +#include "qemu-common.h"
> +#include "qemu/error-report.h"
> +#include "hw/usb.h"
> +#include "hw/usb/desc.h"
> +#include "hw/i2c/i2c.h"
> +#include "hw/i2c/smbus.h"
> +#include "sysemu/char.h"
> +#include "endian.h"
> +
> +/* commands from USB, must e.g. match command ids in kernel driver */
> +#define CMD_ECHO       0
> +#define CMD_GET_FUNC   1
> +#define CMD_SET_DELAY  2
> +#define CMD_GET_STATUS 3
> +
> +/* To determine what functionality is present */
> +#define I2C_FUNC_I2C                            0x00000001
> +#define I2C_FUNC_10BIT_ADDR                     0x00000002
> +#define I2C_FUNC_PROTOCOL_MANGLING              0x00000004
> +#define I2C_FUNC_SMBUS_HWPEC_CALC               0x00000008 /* SMBus 2.0 */
> +#define I2C_FUNC_SMBUS_READ_WORD_DATA_PEC       0x00000800 /* SMBus 2.0 */
> +#define I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC      0x00001000 /* SMBus 2.0 */
> +#define I2C_FUNC_SMBUS_PROC_CALL_PEC            0x00002000 /* SMBus 2.0 */
> +#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL_PEC      0x00004000 /* SMBus 2.0 */
> +#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL          0x00008000 /* SMBus 2.0 */
> +#define I2C_FUNC_SMBUS_QUICK                    0x00010000
> +#define I2C_FUNC_SMBUS_READ_BYTE                0x00020000
> +#define I2C_FUNC_SMBUS_WRITE_BYTE               0x00040000
> +#define I2C_FUNC_SMBUS_READ_BYTE_DATA           0x00080000
> +#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA          0x00100000
> +#define I2C_FUNC_SMBUS_READ_WORD_DATA           0x00200000
> +#define I2C_FUNC_SMBUS_WRITE_WORD_DATA          0x00400000
> +#define I2C_FUNC_SMBUS_PROC_CALL                0x00800000
> +#define I2C_FUNC_SMBUS_READ_BLOCK_DATA          0x01000000
> +#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA         0x02000000
> +#define I2C_FUNC_SMBUS_READ_I2C_BLOCK           0x04000000 /*I2C-like 
> blk-xfr */
> +#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK          0x08000000 /*1-byte reg. 
> addr.*/
> +#define I2C_FUNC_SMBUS_READ_I2C_BLOCK_2         0x10000000 /*I2C-like 
> blk-xfer*/
> +#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2        0x20000000 /* w/ 2-byte 
> regadr*/
> +#define I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC      0x40000000 /* SMBus 2.0 */
> +#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC     0x80000000 /* SMBus 2.0 */
> +
> +#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \
> +    I2C_FUNC_SMBUS_WRITE_BYTE)
> +#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \
> +    I2C_FUNC_SMBUS_WRITE_BYTE_DATA)
> +#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \
> +    I2C_FUNC_SMBUS_WRITE_WORD_DATA)
> +#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \
> +    I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)
> +#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \
> +    I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)
> +
> +#define I2C_FUNC_SMBUS_EMUL (I2C_FUNC_SMBUS_QUICK | \
> +    I2C_FUNC_SMBUS_BYTE | \
> +    I2C_FUNC_SMBUS_BYTE_DATA | \
> +    I2C_FUNC_SMBUS_WORD_DATA | \
> +    I2C_FUNC_SMBUS_PROC_CALL | \
> +    I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \
> +    I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \
> +    I2C_FUNC_SMBUS_I2C_BLOCK)
> +
> +#define DeviceOutVendor ((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
> +#define DeviceInVendor  ((USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
> +
> +typedef struct {
> +    USBDevice dev;
> +    I2CBus *i2cbus;
> +} USBI2CTinyState;
> +
> +#define TYPE_USB_I2C_TINY "usb-i2c"
> +#define USB_I2C_TINY_DEV(obj) OBJECT_CHECK(USBI2CTinyState, \
> +    (obj), TYPE_USB_I2C_TINY)
> +
> +enum {
> +    STR_MANUFACTURER = 1,
> +    STR_PRODUCT_SERIAL,
> +    STR_SERIALNUMBER,
> +};
> +
> +static const USBDescStrings desc_strings = {
> +    [STR_MANUFACTURER]    = "QEMU",
> +    [STR_PRODUCT_SERIAL]  = "QEMU USB I2C Tiny",
> +    [STR_SERIALNUMBER]    = "1",
> +};
> +
> +static const USBDescIface desc_iface0 = {
> +    .bInterfaceNumber              = 1,
> +    .bNumEndpoints                 = 0,
> +    .bInterfaceClass               = 0xff,
> +    .bInterfaceSubClass            = 0xff,
> +    .bInterfaceProtocol            = 0xff,
> +    .eps = (USBDescEndpoint[]) {
> +    }
> +};
> +
> +static const USBDescDevice desc_device = {
> +    .bcdUSB                        = 0x0110,
> +    .bMaxPacketSize0               = 8,
> +    .bNumConfigurations            = 1,
> +    .confs = (const USBDescConfig[]) {
> +        {
> +            .bNumInterfaces        = 1,
> +            .bConfigurationValue   = 1,
> +            .bmAttributes          = USB_CFG_ATT_ONE,
> +            .bMaxPower             = 50,
> +            .nif = 1,
> +            .ifs = &desc_iface0,
> +        },
> +    },
> +};
> +
> +static const USBDesc desc_usb_i2c = {
> +    .id = {
> +        .idVendor          = 0x0403,
> +        .idProduct         = 0xc631,
> +        .bcdDevice         = 0x0205,
> +        .iManufacturer     = STR_MANUFACTURER,
> +        .iProduct          = STR_PRODUCT_SERIAL,
> +        .iSerialNumber     = STR_SERIALNUMBER,
> +    },
> +    .full = &desc_device,
> +    .str  = desc_strings,
> +};
> +
> +static void usb_i2c_handle_reset(USBDevice *dev)
> +{
> +    trace_usb_i2c_tiny_reset();
> +}
> +
> +static void usb_i2c_handle_control(USBDevice *dev, USBPacket *p,
> +               int request, int value, int index, int length, uint8_t *data)
> +{
> +    USBI2CTinyState *s = (USBI2CTinyState *)dev;
> +    int ret,i, i2c_value;
> +    uint32_t func;
> +
> +    ret = usb_desc_handle_control(dev, p, request, value, index, length, 
> data);
> +    if (ret >= 0) {
> +        return;
> +    }
> +
> +    switch (request) {
> +    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
> +        break;
> +    case 0x4102:
> +        /* set clock, ignore */
> +        trace_usb_i2c_tiny_set_clock();
> +        break;
> +
> +    case 0x4105:
> +        trace_usb_i2c_tiny_unknown_request(index, request, value, length);
> +        break;
> +
> +    case 0x4107:
> +        /* this seems to be a byte type access */
> +        if (i2c_start_transfer(s->i2cbus, /*address*/index, 0)) {
> +            trace_usb_i2c_tiny_i2c_start_transfer_failed();
> +            p->actual_length = 0; /* write failure */
> +            break;
> +        }
> +        for (i = 0; i < length; i++) {
> +            trace_usb_i2c_tiny_write(request, index, i, data[i]);
> +            i2c_send(s->i2cbus, data[i]);
> +        }
> +        p->actual_length = length;
> +        i2c_end_transfer(s->i2cbus);
> +        break;
> +
> +    case 0xc101:
> +        /* thats what the real thing reports, FIXME: can we do better here? 
> */
> +        func = htole32(I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL);
> +        memcpy(data, &func, sizeof(func));
> +        p->actual_length = sizeof(func);
> +        trace_usb_i2c_tiny_functionality_read(length);
> +        break;
> +
> +    case 0xc103:
> +        trace_usb_i2c_tiny_unknown_request(index, request, value, length);
> +        p->actual_length = 1;
> +        break;
> +
> +    case 0xc106:
> +    case 0xc107:
> +        if (i2c_start_transfer(s->i2cbus, /*address*/ index, 1)) {
> +            trace_usb_i2c_tiny_i2c_start_transfer_failed();
> +            p->actual_length = 0;
> +            break;
> +        }
> +        if(request&1) {
> +            i2c_send(s->i2cbus, data[0]);
> +            i2c_start_transfer(s->i2cbus, /*address*/ index, 1);
> +        }
> +        for (i = 0; i < length; i++) {
> +            i2c_value = i2c_recv(s->i2cbus);
> +            if (i2c_value < 0) {
> +                break;
> +            }
> +            data[i] = i2c_value;
> +            trace_usb_i2c_tiny_read(request, index, i, data[i]);
> +        }
> +        if(request&1) {
> +            i2c_nack(s->i2cbus);
> +        }
> +        p->actual_length = length;
> +        i2c_end_transfer(s->i2cbus);
> +        break;
> +
> +    default:
> +        p->status = USB_RET_STALL;
> +        trace_usb_i2c_tiny_unknown_request(index, request, value, length);
> +        break;
> +    }
> +}
> +
> +static void usb_i2c_handle_data(USBDevice *dev, USBPacket *p)
> +{
> +    trace_usb_i2c_tiny_usb_i2c_handle_data();
> +}
> +
> +static void usb_i2c_realize(USBDevice *dev, Error **errp)
> +{
> +    USBI2CTinyState *s = (USBI2CTinyState *)dev;
> +    Error *local_err = NULL;
> +
> +    usb_desc_create_serial(dev);
> +    usb_desc_init(dev);
> +
> +    usb_check_attach(dev, &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +    s->i2cbus = i2c_init_bus(&dev->qdev, "i2c");
> +    usb_i2c_handle_reset(dev);
> +}
> +
> +static const VMStateDescription vmstate_usb_i2c = {
> +    .name = "usb-i2c-tiny",
> +};
> +
> +static Property usbi2c_properties[] = {
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void usb_i2c_dev_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
> +
> +    uc->realize        = usb_i2c_realize;
> +    uc->handle_reset   = usb_i2c_handle_reset;
> +    uc->handle_control = usb_i2c_handle_control;
> +    uc->handle_data    = usb_i2c_handle_data;
> +    dc->vmsd = &vmstate_usb_i2c;
> +    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
> +}
> +
> +static const TypeInfo usb_i2c_dev_type_info = {
> +    .name = TYPE_USB_I2C_TINY,
> +    .parent = TYPE_USB_DEVICE,
> +    .instance_size = sizeof(USBI2CTinyState),
> +    .abstract = true,
> +    .class_init = usb_i2c_dev_class_init,
> +};
> +
> +static void usb_i2c_class_initfn(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
> +
> +    uc->product_desc   = "QEMU USB I2C Tiny";
> +    uc->usb_desc       = &desc_usb_i2c;
> +    dc->props = usbi2c_properties;
> +}
> +
> +static const TypeInfo usbi2c_info = {
> +    .name          = "usb-i2c-tiny",
> +    .parent        = TYPE_USB_I2C_TINY,
> +    .class_init    = usb_i2c_class_initfn,
> +};
> +
> +static void usb_i2c_register_types(void)
> +{
> +    type_register_static(&usb_i2c_dev_type_info);
> +    type_register_static(&usbi2c_info);
> +}
> +
> +type_init(usb_i2c_register_types)
> diff --git a/trace-events b/trace-events
> index c9ac144..54f977d 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -328,6 +328,17 @@ usb_port_attach(int bus, const char *port, const char 
> *devspeed, const char *por
>  usb_port_detach(int bus, const char *port) "bus %d, port %s"
>  usb_port_release(int bus, const char *port) "bus %d, port %s"
>
> +# hw/usb/dev-tiny-i2c.c
> +usb_i2c_tiny_read(int request, int address,int offset,int data) 
> "request:0x%x address:%i offset:%i data:%i"
> +usb_i2c_tiny_write(int request, int address,int offset,int data) 
> "request:0x%x address:%i offset:%i data:%i"
> +usb_i2c_tiny_functionality_read(int length) "length:%i"
> +usb_i2c_tiny_reset(void) ""
> +usb_i2c_tiny_set_clock(void) ""
> +usb_i2c_tiny_usb_i2c_handle_data(void) ""
> +usb_i2c_tiny_i2c_start_transfer_failed(void) "i2c start transfer failed"
> +usb_i2c_tiny_ignored_request(int index,int request,int value,int length) 
> "index:%i request:0x%x value:%i length:%i"
> +usb_i2c_tiny_unknown_request(int index,int request,int value,int length) 
> "index:%i request:0x%x value:%i length:%i"
> +
>  # hw/usb/hcd-ohci.c
>  usb_ohci_iso_td_read_failed(uint32_t addr) "ISO_TD read error at %x"
>  usb_ohci_iso_td_head(uint32_t head, uint32_t tail, uint32_t flags, uint32_t 
> bp, uint32_t next, uint32_t be, uint32_t framenum, uint32_t startframe, 
> uint32_t framecount, int rel_frame_num) "ISO_TD ED head 0x%.8x tailp 
> 0x%.8x\n0x%.8x 0x%.8x 0x%.8x 0x%.8x\nframe_number 0x%.8x starting_frame 
> 0x%.8x\nframe_count  0x%.8x relative %d"


--
Alex Bennée



reply via email to

[Prev in Thread] Current Thread [Next in Thread]