Message ID | 6712401.QIBatU8kCx@dabox (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Tim Sander <tim@krieglstein.org> 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: tim@krieglstein.org > --- > 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 <tim@krieglstein.org> > + * > + * Loosly based on usb dev-serial.c: > + * Copyright (c) 2006 CodeSourcery. > + * Copyright (c) 2008 Samuel Thibault <samuel.thibault@ens-lyon.org> > + * 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
On Di, 2016-02-16 at 16:51 +0000, Alex Bennée wrote: > Tim Sander <tim@krieglstein.org> 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. "git am" accepts this one, but ... > Please run ${QEMU_SRC}/scripts/checkpatch.pl on your patch and correct > the stylistic errors it reports. ... checkpatch.pl indeed throws a bunch of codestyle warnings. > 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. Yes, you can configure git send-email to use your internal mail server to send out patches. Best place it in the global config ($HOME/.gitconfig instead of $repo/.git/config) so you don't have to repeat the procedure for every git tree you have. Alternatively you can configure a mail daemon such as postfix on your workstation to deliver mails using your internal mail server as relay. cheers, Gerd
On Di, 2016-02-16 at 16:55 +0100, Tim Sander wrote: > 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. Didn't work again: nilsson kraxel ~/projects/qemu (queue/usb)# patches apply -s id:2351494.kn6DdoE8y3@dabox Applying: i2c-tiny-usb is a small usb to i2c bridge fatal: corrupt patch at line 101 cheers, Gerd
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 <tim@krieglstein.org> + * + * Loosly based on usb dev-serial.c: + * Copyright (c) 2006 CodeSourcery. + * Copyright (c) 2008 Samuel Thibault <samuel.thibault@ens-lyon.org> + * 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"
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. 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: tim@krieglstein.org --- 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