From patchwork Thu Mar 31 16:57:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 12797475 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id A4DD1C433EF for ; Thu, 31 Mar 2022 17:04:01 +0000 (UTC) Received: from localhost ([::1]:36056 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nZyDI-0004mF-JR for qemu-devel@archiver.kernel.org; Thu, 31 Mar 2022 13:04:00 -0400 Received: from eggs.gnu.org ([209.51.188.92]:53474) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nZy7K-0000Th-Pf; Thu, 31 Mar 2022 12:57:50 -0400 Received: from wout4-smtp.messagingengine.com ([64.147.123.20]:36777) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nZy7J-0000td-5U; Thu, 31 Mar 2022 12:57:50 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id EEAE83201F80; Thu, 31 Mar 2022 12:57:46 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Thu, 31 Mar 2022 12:57:47 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=irrelevant.dk; h=cc:cc:content-transfer-encoding:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to; s=fm3; bh=w1PrQnTVn6Sfbh sCoP+N7JZNYIrLtITK7DHkgnGpV20=; b=blE3nlAvTRyNAbr7NaQNxwgvUNzDus AcFV23H1zq9kyCBcOe0I8PzIlWW1bWOzmKY7TfWoB7gnmkp1MTGndXhIAn3reHH/ QOwtliAJCVlThqv37Q6eR90Lltt5rit9rH916sKGUc6v7EjiYTM+pe2bZncoRjEf ODJww8STbU9qC4aEM6Lef9M6XA4gME3zp14FluqD0ftuhChh9mXPiC/5eQxvyqMO WwhvSU7g0GOOfuVt1fhhzdIY17kFaKPRYo4jDb84dM2EhEx3sHlefJlEW9yTmPGC 0NhFoFYu85XUtnAPlhp8ERofZW+ROTbtp3bp/O8fevAcAGtYYjWPrz2g== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm3; bh=w1PrQn TVn6SfbhsCoP+N7JZNYIrLtITK7DHkgnGpV20=; b=GZxvRDzDomWRd1GVY24Hj0 BGUmhXcD8gOzTwY0gtIDmMzeOP1O9H9QtLEq/dJYYENY7BbqmBcwWBav/lXmMyli 1lAbff4l/NXIoJz8EgaBnE4NyJ9xnynspXwNCQcTZ+T1TgG+bE9xspu94MwBCH8t KrB3j+gRv0G+qH+Ns/5Q1mULSM1DU3gHRMzu/Fj7N7UJJqIHjpLOo053leYR3VnX SjgMHB6FgzyvUW5Mwkq+ahApaYwm8y05UbrShbRpTGlh0bx/bbNkYO2dc1ir+wF0 qxB5lAIW/ZwAMRd2t6y1FGyQ/M4XQpsuWMUeD6ym+F0mVsKjoJBcV4edqAfMdHrg == X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudeigedguddtjecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepmfhlrghu shculfgvnhhsvghnuceoihhtshesihhrrhgvlhgvvhgrnhhtrdgukheqnecuggftrfgrth htvghrnhepueelteegieeuhffgkeefgfevjeeigfetkeeitdfgtdeifefhtdfhfeeuffev gfeknecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepih htshesihhrrhgvlhgvvhgrnhhtrdgukh X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Thu, 31 Mar 2022 12:57:43 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [RFC PATCH 1/4] hw/i2c: support multiple masters Date: Thu, 31 Mar 2022 18:57:34 +0200 Message-Id: <20220331165737.1073520-2-its@irrelevant.dk> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220331165737.1073520-1-its@irrelevant.dk> References: <20220331165737.1073520-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=64.147.123.20; envelope-from=its@irrelevant.dk; helo=wout4-smtp.messagingengine.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Arun Kumar Kashinath Agasar , Corey Minyard , Andrew Jeffery , Klaus Jensen , =?utf-8?q?C=C3=A9dric_Le_Goater?= , qemu-arm@nongnu.org, Joel Stanley , Padmakar Kalghatgi , Matt Johnston , Jeremy Kerr Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Allow slaves to master the bus by registering a bottom halve. If the bus is busy, the bottom halve is queued up. When a slave has succesfully mastered the bus, the bottom halve is scheduled. Signed-off-by: Klaus Jensen --- hw/i2c/core.c | 34 +++++++++++++++++++++++++++++++++- include/hw/i2c/i2c.h | 14 ++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/hw/i2c/core.c b/hw/i2c/core.c index d0cb2d32fa44..145dce60782a 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -13,6 +13,7 @@ #include "migration/vmstate.h" #include "qapi/error.h" #include "qemu/module.h" +#include "qemu/main-loop.h" #include "trace.h" #define I2C_BROADCAST 0x00 @@ -62,6 +63,7 @@ I2CBus *i2c_init_bus(DeviceState *parent, const char *name) bus = I2C_BUS(qbus_new(TYPE_I2C_BUS, parent, name)); QLIST_INIT(&bus->current_devs); + QSIMPLEQ_INIT(&bus->pending_masters); vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_i2c_bus, bus); return bus; } @@ -74,7 +76,7 @@ void i2c_slave_set_address(I2CSlave *dev, uint8_t address) /* Return nonzero if bus is busy. */ int i2c_bus_busy(I2CBus *bus) { - return !QLIST_EMPTY(&bus->current_devs); + return !QLIST_EMPTY(&bus->current_devs) || bus->bh; } bool i2c_scan_bus(I2CBus *bus, uint8_t address, bool broadcast, @@ -180,6 +182,26 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, bool is_recv) : I2C_START_SEND); } +void i2c_bus_master(I2CBus *bus, QEMUBH *bh) +{ + if (i2c_bus_busy(bus)) { + I2CPendingMaster *node = g_new(struct I2CPendingMaster, 1); + node->bh = bh; + + QSIMPLEQ_INSERT_TAIL(&bus->pending_masters, node, entry); + + return; + } + + bus->bh = bh; + qemu_bh_schedule(bus->bh); +} + +void i2c_bus_release(I2CBus *bus) +{ + bus->bh = NULL; +} + int i2c_start_recv(I2CBus *bus, uint8_t address) { return i2c_do_start_transfer(bus, address, I2C_START_RECV); @@ -206,6 +228,16 @@ void i2c_end_transfer(I2CBus *bus) g_free(node); } bus->broadcast = false; + + if (!QSIMPLEQ_EMPTY(&bus->pending_masters)) { + I2CPendingMaster *node = QSIMPLEQ_FIRST(&bus->pending_masters); + bus->bh = node->bh; + + QSIMPLEQ_REMOVE_HEAD(&bus->pending_masters, entry); + g_free(node); + + qemu_bh_schedule(bus->bh); + } } int i2c_send(I2CBus *bus, uint8_t data) diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h index 5ca3b708c0be..be8bb8b78a60 100644 --- a/include/hw/i2c/i2c.h +++ b/include/hw/i2c/i2c.h @@ -69,13 +69,25 @@ struct I2CNode { QLIST_ENTRY(I2CNode) next; }; +typedef struct I2CPendingMaster I2CPendingMaster; + +struct I2CPendingMaster { + QEMUBH *bh; + QSIMPLEQ_ENTRY(I2CPendingMaster) entry; +}; + typedef QLIST_HEAD(I2CNodeList, I2CNode) I2CNodeList; +typedef QSIMPLEQ_HEAD(I2CPendingMasters, I2CPendingMaster) I2CPendingMasters; struct I2CBus { BusState qbus; I2CNodeList current_devs; + I2CPendingMasters pending_masters; uint8_t saved_address; bool broadcast; + + /* Set from slave currently mastering the bus. */ + QEMUBH *bh; }; I2CBus *i2c_init_bus(DeviceState *parent, const char *name); @@ -117,6 +129,8 @@ int i2c_start_send(I2CBus *bus, uint8_t address); void i2c_end_transfer(I2CBus *bus); void i2c_nack(I2CBus *bus); +void i2c_bus_master(I2CBus *bus, QEMUBH *bh); +void i2c_bus_release(I2CBus *bus); int i2c_send(I2CBus *bus, uint8_t data); uint8_t i2c_recv(I2CBus *bus); bool i2c_scan_bus(I2CBus *bus, uint8_t address, bool broadcast, From patchwork Thu Mar 31 16:57:35 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 12797477 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 368CBC433F5 for ; Thu, 31 Mar 2022 17:08:30 +0000 (UTC) Received: from localhost ([::1]:40670 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nZyHb-0008B8-VX for qemu-devel@archiver.kernel.org; Thu, 31 Mar 2022 13:08:29 -0400 Received: from eggs.gnu.org ([209.51.188.92]:53496) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nZy7O-0000aF-HO; Thu, 31 Mar 2022 12:57:54 -0400 Received: from wout4-smtp.messagingengine.com ([64.147.123.20]:54403) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nZy7M-0000uB-OZ; Thu, 31 Mar 2022 12:57:54 -0400 Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailout.west.internal (Postfix) with ESMTP id 512A83200D53; Thu, 31 Mar 2022 12:57:50 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute1.internal (MEProxy); Thu, 31 Mar 2022 12:57:51 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=irrelevant.dk; h=cc:cc:content-transfer-encoding:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to; s=fm3; bh=E8TGgHBmb8YTpb lAPf4UvSi8DdBrWVKmfO/PISxXVcM=; b=VEXps+3iasuEIx0p93dJQi5L6mJoNO aT/lIO6g5n/QKxF3UjZBpa44z5fzkWiWTde/OzWyEXJ9E73X0EjvKtQR+4HioLLg WaXh43FG0qw28YiAVLASCXe86+ZV+kriG3pH4gmwyuBBfqMPfrNAIiZQHl5pXSGV 2M4AlLgLMnwIogHtwvvQIgz3AiNVVkz1i2Q+Xm4vKI3ergNZDLsebU+TgCSt7JOX /xlGgv2d/JJclhacb7GhgKZsWmL47phpweD+OrNE1KabRsOGXZEs6MeY4D/Myr47 2VwkWN4dsoktQwElXfQL6In6GEjD87lzn5L7fDyY5g9lFKdUafr8krvQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm3; bh=E8TGgH Bmb8YTpblAPf4UvSi8DdBrWVKmfO/PISxXVcM=; b=DcdcJ4lO5DfoCzhPw3wc8r LAeUyr+y7b2S1pQvCLt0dgfFZNxE+/2QHe3eGO4jEx9NTOxRh461u1llhpM2uwZI d8mWDGi3OW1U/DLb4FsR+kg5fNRrAOEFJyOudaHs45A4WQZmUp/oelw2039bZuM2 T+5rsS56eqxe/boTFCCmf1KVzTVrxsSxLob6uvD/LfLerbfDZjOOvaS7NgLPlALA jVQPa/cebMI8OVUCoz9MOPcTlaHZzgIRHkwMFMn5rGceQEaQKsrNM8M6AJV8gyE2 90xDBrPNFnS8DC6HyOT5vKTsvIY05YRZ0Th6WZK/OlmswUlyej/DkYwGroHbjQTA == X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudeigedguddtjecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepmfhlrghu shculfgvnhhsvghnuceoihhtshesihhrrhgvlhgvvhgrnhhtrdgukheqnecuggftrfgrth htvghrnhepueelteegieeuhffgkeefgfevjeeigfetkeeitdfgtdeifefhtdfhfeeuffev gfeknecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepih htshesihhrrhgvlhgvvhgrnhhtrdgukh X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Thu, 31 Mar 2022 12:57:48 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [RFC PATCH 2/4] hw/i2c: add async send Date: Thu, 31 Mar 2022 18:57:35 +0200 Message-Id: <20220331165737.1073520-3-its@irrelevant.dk> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220331165737.1073520-1-its@irrelevant.dk> References: <20220331165737.1073520-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=64.147.123.20; envelope-from=its@irrelevant.dk; helo=wout4-smtp.messagingengine.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Arun Kumar Kashinath Agasar , Corey Minyard , Andrew Jeffery , Klaus Jensen , =?utf-8?q?C=C3=A9dric_Le_Goater?= , qemu-arm@nongnu.org, Joel Stanley , Padmakar Kalghatgi , Matt Johnston , Jeremy Kerr Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Add an asynchronous version of of i2c_send that requires an explicit acknowledgement on the bus. Signed-off-by: Klaus Jensen --- hw/i2c/core.c | 23 +++++++++++++++++++++++ include/hw/i2c/i2c.h | 5 +++++ 2 files changed, 28 insertions(+) diff --git a/hw/i2c/core.c b/hw/i2c/core.c index 145dce60782a..344d764d7eaa 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -261,6 +261,20 @@ int i2c_send(I2CBus *bus, uint8_t data) return ret ? -1 : 0; } +int i2c_send_async(I2CBus *bus, uint8_t data) +{ + I2CNode *node = QLIST_FIRST(&bus->current_devs); + I2CSlave *slave = node->elt; + I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(slave); + + if (sc->send_async) { + sc->send_async(slave, data); + return 0; + } + + return -1; +} + uint8_t i2c_recv(I2CBus *bus) { uint8_t data = 0xff; @@ -297,6 +311,15 @@ void i2c_nack(I2CBus *bus) } } +void i2c_ack(I2CBus *bus) +{ + if (!bus->bh) { + return; + } + + qemu_bh_schedule(bus->bh); +} + static int i2c_slave_post_load(void *opaque, int version_id) { I2CSlave *dev = opaque; diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h index be8bb8b78a60..ae58e4151585 100644 --- a/include/hw/i2c/i2c.h +++ b/include/hw/i2c/i2c.h @@ -28,6 +28,9 @@ struct I2CSlaveClass { /* Master to slave. Returns non-zero for a NAK, 0 for success. */ int (*send)(I2CSlave *s, uint8_t data); + /* Master to slave. */ + void (*send_async)(I2CSlave *s, uint8_t data); + /* * Slave to master. This cannot fail, the device should always * return something here. @@ -129,9 +132,11 @@ int i2c_start_send(I2CBus *bus, uint8_t address); void i2c_end_transfer(I2CBus *bus); void i2c_nack(I2CBus *bus); +void i2c_ack(I2CBus *bus); void i2c_bus_master(I2CBus *bus, QEMUBH *bh); void i2c_bus_release(I2CBus *bus); int i2c_send(I2CBus *bus, uint8_t data); +int i2c_send_async(I2CBus *bus, uint8_t data); uint8_t i2c_recv(I2CBus *bus); bool i2c_scan_bus(I2CBus *bus, uint8_t address, bool broadcast, I2CNodeList *current_devs); From patchwork Thu Mar 31 16:57:36 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 12797480 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 9B941C433F5 for ; Thu, 31 Mar 2022 17:14:21 +0000 (UTC) Received: from localhost ([::1]:50402 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nZyNI-0006hW-Bg for qemu-devel@archiver.kernel.org; Thu, 31 Mar 2022 13:14:20 -0400 Received: from eggs.gnu.org ([209.51.188.92]:53516) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nZy7R-0000f9-U8; Thu, 31 Mar 2022 12:57:57 -0400 Received: from wout4-smtp.messagingengine.com ([64.147.123.20]:54843) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nZy7P-0000uX-QR; Thu, 31 Mar 2022 12:57:57 -0400 Received: from compute2.internal (compute2.nyi.internal [10.202.2.46]) by mailout.west.internal (Postfix) with ESMTP id 9DC6D3201F8B; Thu, 31 Mar 2022 12:57:53 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute2.internal (MEProxy); Thu, 31 Mar 2022 12:57:54 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=irrelevant.dk; h=cc:cc:content-transfer-encoding:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to; s=fm3; bh=JVRG2cvJfMysYr N5Gr28SQd9WP9ebYIs3e8XYSuZ/vg=; b=AtXTb6HH967BNdBvqpl8kIXrNbnmGD K6jo5bukiKndZEekm/lT2hd2Q2B65bUYCcSZ7lGnd3O3ztnvLuBcYHcINta/GdZI e3CgEsaSuM1HgAipFmCZOD9RzcPLN6rwaMBbpnDV/cbbDNyJkrOY+xnfa9Ust+wl l1OPSmWXk3tMQg711upzq8DkMMlnlRhQyL+6KeU9Zt9YwpGsdBfsM4+nsm07pxgt utNeKoFaaLXRzZR9MM1QBGPxG9ew9747Tq1V6xVuu0QuTMe//CFPkwJa4SBdALZx sl47ecLiTJCU3fB2Kc45m2qg1K8KuVa1/s1N6Jmgk038d4Obvotm51aw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm3; bh=JVRG2c vJfMysYrN5Gr28SQd9WP9ebYIs3e8XYSuZ/vg=; b=BaERtq/XXnOjxgCFPxNY6p rVQAa4Pm7RMDR7a/NLXPw+2dM2YpESLvJXPa9wt0MzPfuWzcKO/OpA5q+PqDYbz+ jcgS7SOJ5rK0z9F5GAyhIiIm6E3jYgF+9gsbQY8JsJLWOeaMxtHEIuBVu+i/m1bH jp2wgLUpMafip4gHyKu6e2XXT9EMmvFlF7n6uOHujIdpoc/xwVLD4SlBWMe3TogT A/M+3kouxAX98owdfzthZHQ4ANOM6E1X2hJk9xGKZM40ZlCkg86b/GbYXSmW4mWd 956YMjhWkzIiIBpFq0yza7tP0NcG9Ma7ATJViGhZdQpqbwU2Jlm3QdsjntatA5ag == X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudeigedguddtjecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepmfhlrghu shculfgvnhhsvghnuceoihhtshesihhrrhgvlhgvvhgrnhhtrdgukheqnecuggftrfgrth htvghrnhepueelteegieeuhffgkeefgfevjeeigfetkeeitdfgtdeifefhtdfhfeeuffev gfeknecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepih htshesihhrrhgvlhgvvhgrnhhtrdgukh X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Thu, 31 Mar 2022 12:57:51 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [RFC PATCH 3/4] hw/i2c: add slave mode for aspeed_i2c Date: Thu, 31 Mar 2022 18:57:36 +0200 Message-Id: <20220331165737.1073520-4-its@irrelevant.dk> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220331165737.1073520-1-its@irrelevant.dk> References: <20220331165737.1073520-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=64.147.123.20; envelope-from=its@irrelevant.dk; helo=wout4-smtp.messagingengine.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Arun Kumar Kashinath Agasar , Corey Minyard , Andrew Jeffery , Klaus Jensen , =?utf-8?q?C=C3=A9dric_Le_Goater?= , qemu-arm@nongnu.org, Joel Stanley , Padmakar Kalghatgi , Matt Johnston , Jeremy Kerr Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Add slave mode functionality for the Aspeed I2C controller. This is implemented by creating an Aspeed I2C Slave device that attaches to the bus. This i2c slave device only implements the asynchronous version of i2c_send() and the event callback. Signed-off-by: Klaus Jensen --- hw/i2c/aspeed_i2c.c | 95 +++++++++++++++++++++++++++++++++---- hw/i2c/trace-events | 2 +- hw/misc/meson.build | 2 + include/hw/i2c/aspeed_i2c.h | 8 ++++ 4 files changed, 97 insertions(+), 10 deletions(-) diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c index 03a4f5a91010..61b6424434f7 100644 --- a/hw/i2c/aspeed_i2c.c +++ b/hw/i2c/aspeed_i2c.c @@ -163,10 +163,15 @@ static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus) bus->intr_status & I2CD_INTR_TX_NAK ? "nak|" : "", bus->intr_status & I2CD_INTR_TX_ACK ? "ack|" : "", bus->intr_status & I2CD_INTR_RX_DONE ? "done|" : "", + bus->intr_status & I2CD_INTR_SLAVE_ADDR_RX_MATCH ? "slave-match|" : "", bus->intr_status & I2CD_INTR_NORMAL_STOP ? "normal|" : "", bus->intr_status & I2CD_INTR_ABNORMAL ? "abnormal" : ""); - bus->intr_status &= bus->intr_ctrl; + /* + * WORKAROUND: the Linux Aspeed I2C driver masks SLAVE_ADDR_RX_MATCH for + * some reason, not sure if it is a bug... + */ + bus->intr_status &= (bus->intr_ctrl | I2CD_INTR_SLAVE_ADDR_RX_MATCH); if (bus->intr_status) { bus->controller->intr_status |= 1 << bus->id; qemu_irq_raise(aic->bus_get_irq(bus)); @@ -196,6 +201,9 @@ static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset, case I2CD_INTR_STS_REG: value = bus->intr_status; break; + case I2CD_DEV_ADDR_REG: + value = bus->dev_addr; + break; case I2CD_POOL_CTRL_REG: value = bus->pool_ctrl; break; @@ -535,10 +543,9 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset, switch (offset) { case I2CD_FUN_CTRL_REG: if (value & I2CD_SLAVE_EN) { - qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", - __func__); - break; + i2c_slave_set_address(&bus->slave->i2c, bus->dev_addr); } + bus->ctrl = value & 0x0071C3FF; break; case I2CD_AC_TIMING_REG1: @@ -558,14 +565,19 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset, bus->controller->intr_status &= ~(1 << bus->id); qemu_irq_lower(aic->bus_get_irq(bus)); } - if (handle_rx && (bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST))) { - aspeed_i2c_handle_rx_cmd(bus); - aspeed_i2c_bus_raise_interrupt(bus); + + if (handle_rx) { + if (bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST)) { + aspeed_i2c_handle_rx_cmd(bus); + aspeed_i2c_bus_raise_interrupt(bus); + } else if (aspeed_i2c_get_state(bus) == I2CD_STXD) { + i2c_ack(bus->bus); + } } + break; case I2CD_DEV_ADDR_REG: - qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", - __func__); + bus->dev_addr = value; break; case I2CD_POOL_CTRL_REG: bus->pool_ctrl &= ~0xffffff; @@ -852,12 +864,74 @@ static const TypeInfo aspeed_i2c_info = { .abstract = true, }; +static int aspeed_i2c_slave_event(I2CSlave *slave, enum i2c_event event) +{ + AspeedI2CSlave *s = ASPEED_I2C_SLAVE(slave); + AspeedI2CBus *bus = s->bus; + + switch (event) { + case I2C_START_SEND: + bus->buf = bus->dev_addr << 1; + + bus->buf &= I2CD_BYTE_BUF_RX_MASK; + bus->buf <<= I2CD_BYTE_BUF_RX_SHIFT; + + bus->intr_status |= (I2CD_INTR_SLAVE_ADDR_RX_MATCH | I2CD_INTR_RX_DONE); + aspeed_i2c_set_state(bus, I2CD_STXD); + + break; + + case I2C_FINISH: + bus->intr_status |= I2CD_INTR_NORMAL_STOP; + aspeed_i2c_set_state(bus, I2CD_IDLE); + + break; + + default: + return -1; + } + + aspeed_i2c_bus_raise_interrupt(bus); + + return 0; +} + +static void aspeed_i2c_slave_send_async(I2CSlave *slave, uint8_t data) +{ + AspeedI2CSlave *s = ASPEED_I2C_SLAVE(slave); + AspeedI2CBus *bus = s->bus; + + bus->buf = (data & I2CD_BYTE_BUF_RX_MASK) << I2CD_BYTE_BUF_RX_SHIFT; + bus->intr_status |= I2CD_INTR_RX_DONE; + + aspeed_i2c_bus_raise_interrupt(bus); +} + +static void aspeed_i2c_slave_class_init(ObjectClass *klass, void *Data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); + + dc->desc = "Aspeed I2C Bus Slave"; + + sc->event = aspeed_i2c_slave_event; + sc->send_async = aspeed_i2c_slave_send_async; +} + +static const TypeInfo aspeed_i2c_slave_info = { + .name = TYPE_ASPEED_I2C_SLAVE, + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(AspeedI2CSlave), + .class_init = aspeed_i2c_slave_class_init, +}; + static void aspeed_i2c_bus_reset(DeviceState *dev) { AspeedI2CBus *s = ASPEED_I2C_BUS(dev); s->intr_ctrl = 0; s->intr_status = 0; + s->dev_addr = 0; s->cmd = 0; s->buf = 0; s->dma_addr = 0; @@ -881,6 +955,8 @@ static void aspeed_i2c_bus_realize(DeviceState *dev, Error **errp) sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); s->bus = i2c_init_bus(dev, name); + s->slave = ASPEED_I2C_SLAVE(i2c_slave_create_simple(s->bus, TYPE_ASPEED_I2C_SLAVE, 0xff)); + s->slave->bus = s; memory_region_init_io(&s->mr, OBJECT(s), &aspeed_i2c_bus_ops, s, name, aic->reg_size); @@ -1016,6 +1092,7 @@ static const TypeInfo aspeed_2600_i2c_info = { static void aspeed_i2c_register_types(void) { type_register_static(&aspeed_i2c_bus_info); + type_register_static(&aspeed_i2c_slave_info); type_register_static(&aspeed_i2c_info); type_register_static(&aspeed_2400_i2c_info); type_register_static(&aspeed_2500_i2c_info); diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events index 7d8907c1eede..85e4bddff936 100644 --- a/hw/i2c/trace-events +++ b/hw/i2c/trace-events @@ -9,7 +9,7 @@ i2c_recv(uint8_t address, uint8_t data) "recv(addr:0x%02x) data:0x%02x" # aspeed_i2c.c aspeed_i2c_bus_cmd(uint32_t cmd, const char *cmd_flags, uint32_t count, uint32_t intr_status) "handling cmd=0x%x %s count=%d intr=0x%x" -aspeed_i2c_bus_raise_interrupt(uint32_t intr_status, const char *str1, const char *str2, const char *str3, const char *str4, const char *str5) "handled intr=0x%x %s%s%s%s%s" +aspeed_i2c_bus_raise_interrupt(uint32_t intr_status, const char *str1, const char *str2, const char *str3, const char *str4, const char *str5, const char *str6) "handled intr=0x%x %s%s%s%s%s%s" aspeed_i2c_bus_read(uint32_t busid, uint64_t offset, unsigned size, uint64_t value) "bus[%d]: To 0x%" PRIx64 " of size %u: 0x%" PRIx64 aspeed_i2c_bus_write(uint32_t busid, uint64_t offset, unsigned size, uint64_t value) "bus[%d]: To 0x%" PRIx64 " of size %u: 0x%" PRIx64 aspeed_i2c_bus_send(const char *mode, int i, int count, uint8_t byte) "%s send %d/%d 0x%02x" diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 6fb69612e064..c1c1abea41dd 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -122,6 +122,8 @@ softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_rng.c')) softmmu_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_ahb_apb_pnp.c')) +softmmu_ss.add(when: 'CONFIG_I2C', if_true: files('i2c-echo.c')) + specific_ss.add(when: 'CONFIG_AVR_POWER', if_true: files('avr_power.c')) specific_ss.add(when: 'CONFIG_IMX', if_true: files('imx6_src.c')) diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h index 4b9be09274c7..3f1a9c07a00b 100644 --- a/include/hw/i2c/aspeed_i2c.h +++ b/include/hw/i2c/aspeed_i2c.h @@ -42,6 +42,7 @@ struct AspeedI2CBus { SysBusDevice parent_obj; struct AspeedI2CState *controller; + struct AspeedI2CSlave *slave; MemoryRegion mr; @@ -53,6 +54,7 @@ struct AspeedI2CBus { uint32_t timing[2]; uint32_t intr_ctrl; uint32_t intr_status; + uint32_t dev_addr; uint32_t cmd; uint32_t buf; uint32_t pool_ctrl; @@ -76,6 +78,12 @@ struct AspeedI2CState { AddressSpace dram_as; }; +#define TYPE_ASPEED_I2C_SLAVE "aspeed.i2c.slave" +OBJECT_DECLARE_SIMPLE_TYPE(AspeedI2CSlave, ASPEED_I2C_SLAVE) +struct AspeedI2CSlave { + I2CSlave i2c; + AspeedI2CBus *bus; +}; struct AspeedI2CClass { SysBusDeviceClass parent_class; From patchwork Thu Mar 31 16:57:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 12797476 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2339AC433F5 for ; Thu, 31 Mar 2022 17:05:04 +0000 (UTC) Received: from localhost ([::1]:37058 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nZyEJ-0005WF-0T for qemu-devel@archiver.kernel.org; Thu, 31 Mar 2022 13:05:03 -0400 Received: from eggs.gnu.org ([209.51.188.92]:53550) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nZy7X-0000hp-0i; Thu, 31 Mar 2022 12:58:04 -0400 Received: from wout4-smtp.messagingengine.com ([64.147.123.20]:51657) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nZy7T-0000uv-9w; Thu, 31 Mar 2022 12:58:01 -0400 Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.west.internal (Postfix) with ESMTP id 1BB413200F81; Thu, 31 Mar 2022 12:57:57 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute4.internal (MEProxy); Thu, 31 Mar 2022 12:57:57 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=irrelevant.dk; h=cc:cc:content-transfer-encoding:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to; s=fm3; bh=UMv+7jwHj3p2XJ sH57Uib59UhRoKlgvJ2+efHY1hh58=; b=KYKX3BTrpKVKaW3SBDrkNisZAeEm9b 7zTrbMUSlMX4Jo1mlmFvIbTdBhvJZLOOY40YHWAgcaK5BOgDX6TZbt+j75zvy3BR hdcfeihf+Zn3OoqH7ggPIe6Zw5jH/L/BI1zk1sJq+F0kJKWV+o65wLMAwPzCR/il SKIdMGYDaVW4nDu7f/CuA38YrhdFaJ4+4YHvknkF/TXCilwFrUnn/k0SqrXi1Tof Kiz4VWh1uCckCSkJ781TJqsl1zfFb3Y6p7vJCAJUh0HnucHspNtatXaIVOkaY+6o 6FE3G0E1fBi4G+n1ZwioN5Zf/1IFWEI3ZRwLtN/pzZ+P35C3b/yRDwHg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding:date:date :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:sender:subject:subject:to:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm3; bh=UMv+7j wHj3p2XJsH57Uib59UhRoKlgvJ2+efHY1hh58=; b=Z4dkklGYjsat0mR0rw/R5L pAEaRKlXx9DWUR7WbrHp6okm10RVNWS7wx2lQhPGk42fDSJ/tg/ev9li0H//nfoP 7S5fDJWeMVu4agbNFBI257MlP4VWzSZH1qObmJgASzsVGgVj9Lz0jjynmpchDfon wUcKbvk0YT7PsHBEWuT8hZNI4YBqQla5/GkXZX6RpV4DYiQmYcVHNy5tsFeT/cWg 9Kd/aZc6Qfe/HQ182kgcutmHoEh5hQrIS2cO5fIHyDpPUwJZqneCFVJRJhElLwVK SN3A6jOkRkt2+UR0aeiftHV4mcBT2GfNXZhGYfj4z6m16pg6P7eT3iINyWUsvbMg == X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudeigedguddtjecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepmfhlrghu shculfgvnhhsvghnuceoihhtshesihhrrhgvlhgvvhgrnhhtrdgukheqnecuggftrfgrth htvghrnhepueelteegieeuhffgkeefgfevjeeigfetkeeitdfgtdeifefhtdfhfeeuffev gfeknecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepih htshesihhrrhgvlhgvvhgrnhhtrdgukh X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Thu, 31 Mar 2022 12:57:54 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [RFC PATCH 4/4] hw/misc: add a toy i2c echo device Date: Thu, 31 Mar 2022 18:57:37 +0200 Message-Id: <20220331165737.1073520-5-its@irrelevant.dk> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220331165737.1073520-1-its@irrelevant.dk> References: <20220331165737.1073520-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=64.147.123.20; envelope-from=its@irrelevant.dk; helo=wout4-smtp.messagingengine.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Arun Kumar Kashinath Agasar , Corey Minyard , Andrew Jeffery , Klaus Jensen , =?utf-8?q?C=C3=A9dric_Le_Goater?= , qemu-arm@nongnu.org, Joel Stanley , Padmakar Kalghatgi , Matt Johnston , Jeremy Kerr Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Add an example i2c device that can master the bus. The device will echo whatever it is sent to the device identified by the first byte received. Signed-off-by: Klaus Jensen --- hw/misc/i2c-echo.c | 144 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 hw/misc/i2c-echo.c diff --git a/hw/misc/i2c-echo.c b/hw/misc/i2c-echo.c new file mode 100644 index 000000000000..72155d850d5f --- /dev/null +++ b/hw/misc/i2c-echo.c @@ -0,0 +1,144 @@ +#include "qemu/osdep.h" +#include "qemu/timer.h" +#include "qemu/main-loop.h" +#include "block/aio.h" +#include "hw/i2c/i2c.h" + +#define TYPE_I2C_ECHO "i2c-echo" +OBJECT_DECLARE_SIMPLE_TYPE(I2CEchoState, I2C_ECHO) + +enum i2c_echo_state { + I2C_ECHO_STATE_REQUEST_MASTER, + I2C_ECHO_STATE_START_SEND, + I2C_ECHO_STATE_ACK, +}; + +typedef struct I2CEchoState { + I2CSlave parent_obj; + + I2CBus *bus; + + enum i2c_echo_state state; + QEMUBH *bh; + + unsigned int pos; + uint8_t data[3]; +} I2CEchoState; + +static void i2c_echo_bh(void *opaque) +{ + I2CEchoState *state = opaque; + + switch (state->state) { + case I2C_ECHO_STATE_REQUEST_MASTER: + i2c_bus_master(state->bus, state->bh); + state->state = I2C_ECHO_STATE_START_SEND; + break; + + case I2C_ECHO_STATE_START_SEND: + i2c_start_send(state->bus, state->data[0]); + state->pos++; + state->state = I2C_ECHO_STATE_ACK; + break; + + case I2C_ECHO_STATE_ACK: + if (state->pos > 2) { + i2c_end_transfer(state->bus); + i2c_bus_release(state->bus); + break; + } + + i2c_send_async(state->bus, state->data[state->pos++]); + break; + } +} + +static int i2c_echo_event(I2CSlave *s, enum i2c_event event) +{ + I2CEchoState *state = I2C_ECHO(s); + + switch (event) { + case I2C_START_RECV: + state->pos = 0; + + break; + + case I2C_START_SEND: + state->pos = 0; + + break; + + case I2C_FINISH: + state->pos = 0; + state->state = I2C_ECHO_STATE_REQUEST_MASTER; + qemu_bh_schedule(state->bh); + + break; + + case I2C_NACK: + break; + } + + return 0; +} + +static uint8_t i2c_echo_recv(I2CSlave *s) +{ + I2CEchoState *state = I2C_ECHO(s); + + if (state->pos > 2) { + return 0xff; + } + + return state->data[state->pos++]; +} + +static int i2c_echo_send(I2CSlave *s, uint8_t data) +{ + I2CEchoState *state = I2C_ECHO(s); + + if (state->pos > 2) { + return -1; + } + + state->data[state->pos++] = data; + + return 0; +} + +static void i2c_echo_realize(DeviceState *dev, Error **errp) +{ + I2CEchoState *state = I2C_ECHO(dev); + BusState *bus = qdev_get_parent_bus(dev); + + state->bus = I2C_BUS(bus); + state->bh = qemu_bh_new(i2c_echo_bh, state); + + return; +} + +static void i2c_echo_class_init(ObjectClass *oc, void *data) +{ + I2CSlaveClass *sc = I2C_SLAVE_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = i2c_echo_realize; + + sc->event = i2c_echo_event; + sc->recv = i2c_echo_recv; + sc->send = i2c_echo_send; +} + +static const TypeInfo i2c_echo = { + .name = TYPE_I2C_ECHO, + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(I2CEchoState), + .class_init = i2c_echo_class_init, +}; + +static void register_types(void) +{ + type_register_static(&i2c_echo); +} + +type_init(register_types);