From patchwork Thu May 2 18:27:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoph Fritz X-Patchwork-Id: 794321 Received: from fritzc.com (mail.fritzc.com [213.160.72.247]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 30BE617334E; Thu, 2 May 2024 18:29:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.160.72.247 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714674547; cv=none; b=iHoz1//LPOesqEihh8qUUufGOMtlL81NZbtDhAcsHJ/X/CQYnbxXDXBKyu30PvRQ45a/DKUicQ0E50v245AC/bz2PkG8aM7LVKFhxZHHKBQTrktQ5pA11lhWqHxOQCehwg5iroEBhv4N0kNzongwfuIO1yUXSm4niz7Q5dSSGss= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714674547; c=relaxed/simple; bh=9wa7b14p51D4XIHn2ZHneym3xNg/dG/Bn6Y0nHihC6I=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=hEIA7zDC8Fg47u7dJlAJL1/oJPQKJ/Yg2ooGs/wEgLClujQbSfkn68BwLr/dZIY94ZapIFRquJYcWVDnzybs8+Rv99ObcO0dZ5XVz1YVeWNTzWywAZu561dCzAA7vJlV0FYxNJWbhhx8LjrbwmS8jWsA1H86bw2Y4rzWBsvm7mo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=hexdev.de; spf=pass smtp.mailfrom=hexdev.de; dkim=pass (1024-bit key) header.d=fritzc.com header.i=@fritzc.com header.b=sOsS8dk4; arc=none smtp.client-ip=213.160.72.247 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=hexdev.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=hexdev.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=fritzc.com header.i=@fritzc.com header.b="sOsS8dk4" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=fritzc.com; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=ckGlDtp8125Wg0Lsn8iPKmwEso6xTp/njBKVmtt1+n0=; b=sOsS8dk4N6pBeKuR1GFf+k5yhj R/cZydSip2Js+mNNdokDKpC8cH9zxRm7nc6BRR0wsdLDcYRdN/ztgrbgMXl8B3axY3BwbLuDPlE5K vX3akjgqeyBGTLqyC7jJ3FRayfQT10embDblby0ypvte19YL/Jg5XbvpC4RExTtpPuC0=; Received: from 127.0.0.1 by fritzc.com with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim latest) (envelope-from ) id 1s2bAs-001ZbZ-2w; Thu, 02 May 2024 20:28:55 +0200 From: Christoph Fritz To: Jiri Slaby , Oliver Hartkopp , Marc Kleine-Budde , Vincent Mailhol , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jiri Kosina , Benjamin Tissoires , Greg Kroah-Hartman , Sebastian Reichel , Linus Walleij Cc: Andreas Lauser , Jonathan Corbet , Pavel Pisa , linux-can@vger.kernel.org, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-input@vger.kernel.org, linux-serial@vger.kernel.org Subject: [PATCH v3 02/11] HID: hexLIN: Add support for USB LIN bus adapter Date: Thu, 2 May 2024 20:27:55 +0200 Message-Id: <20240502182804.145926-3-christoph.fritz@hexdev.de> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240502182804.145926-1-christoph.fritz@hexdev.de> References: <20240502182804.145926-1-christoph.fritz@hexdev.de> Precedence: bulk X-Mailing-List: linux-serial@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 This patch introduces driver support for the hexLIN USB LIN bus adapter, enabling LIN communication over USB for both controller and responder modes. The driver interfaces with the CAN_LIN framework for userland connectivity. For more details on the adapter, visit: https://hexdev.de/hexlin/ Tested-by: Andreas Lauser Signed-off-by: Christoph Fritz --- drivers/hid/Kconfig | 19 + drivers/hid/Makefile | 1 + drivers/hid/hid-hexdev-hexlin.c | 611 ++++++++++++++++++++++++++++++++ drivers/hid/hid-ids.h | 1 + drivers/hid/hid-quirks.c | 3 + 5 files changed, 635 insertions(+) create mode 100644 drivers/hid/hid-hexdev-hexlin.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 4c682c6507040..d2fb35d83c640 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -496,6 +496,25 @@ config HID_GYRATION help Support for Gyration remote control. +config HID_MCS_HEXDEV + tristate "hexDEV LIN-BUS adapter support" + depends on HID && CAN_NETLINK && CAN_DEV + select CAN_LIN + help + Support for hexDEV its hexLIN USB LIN bus adapter. + + Local Interconnect Network (LIN) to USB adapter for controller and + responder usage. + This device driver is using CAN_LIN for a userland connection on + one side and USB HID for the actual hardware adapter on the other + side. + + If you have such an adapter, say Y here and see + . + + To compile this driver as a module, choose M here: the + module will be called hid-hexlin. + config HID_ICADE tristate "ION iCade arcade controller" help diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 082a728eac600..f9b13e6117e60 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_HID_GOOGLE_STADIA_FF) += hid-google-stadiaff.o obj-$(CONFIG_HID_VIVALDI) += hid-vivaldi.o obj-$(CONFIG_HID_GT683R) += hid-gt683r.o obj-$(CONFIG_HID_GYRATION) += hid-gyration.o +obj-$(CONFIG_HID_MCS_HEXDEV) += hid-hexdev-hexlin.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o diff --git a/drivers/hid/hid-hexdev-hexlin.c b/drivers/hid/hid-hexdev-hexlin.c new file mode 100644 index 0000000000000..1ddc1e00ab2da --- /dev/null +++ b/drivers/hid/hid-hexdev-hexlin.c @@ -0,0 +1,611 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * LIN bus USB adapter driver https://hexdev.de/hexlin + * + * Copyright (C) 2024 hexDEV GmbH + */ + +#include +#include +#include +#include +#include +#include "hid-ids.h" + +enum { + /* answers */ + HEXLIN_SUCCESS = 0x01, + HEXLIN_FRAME = 0x02, + HEXLIN_ERROR = 0x03, + HEXLIN_FAIL = 0x0F, + + /* lin-responder */ + HEXLIN_SET_MODE_RESPONDER = 0x10, + HEXLIN_SET_RESPONDER_ANSWER_ID = 0x11, + HEXLIN_GET_RESPONDER_ANSWER_ID = 0x12, + + /* lin-controller */ + HEXLIN_SET_MODE_CONTROLLER = 0x20, + HEXLIN_SEND_BREAK = 0x21, + HEXLIN_SEND_UNCONDITIONAL_FRAME = 0x22, + + /* lin-div */ + HEXLIN_SET_BAUDRATE = 0x34, + HEXLIN_GET_BAUDRATE = 0x35, + + /* div */ + HEXLIN_RESET = 0xF0, + HEXLIN_GET_VERSION = 0xF1, +}; + +#define HEXLIN_SUCCESS_SZ 1 +#define HEXLIN_FRAME_SZ 17 +#define HEXLIN_FAIL_SZ 1 +#define HEXLIN_GET_RESPONDER_ANSWER_ID_SZ 20 +#define HEXLIN_GET_BAUDRATE_SZ 3 +#define HEXLIN_BAUDRATE_SZ 2 +#define HEXLIN_GET_VERSION_SZ 2 +#define HEXLIN_PKGLEN_MAX_SZ 64 + +struct hexlin_val8_req { + u8 cmd; + u8 v; +} __packed; + +struct hexlin_baudrate_req { + u8 cmd; + u16 baudrate; +} __packed; + +struct hexlin_frame { + u32 flags; + u8 len; + u8 lin_id; + u8 data[LIN_MAX_DLEN]; + u8 checksum; + u8 checksum_mode; +} __packed; + +struct hexlin_unconditional_req { + u8 cmd; + struct hexlin_frame frm; +} __packed; + +struct hexlin_responder_answer { + u8 is_active; + u8 is_event_frame; + u8 event_associated_id; + struct hexlin_frame frm; +} __packed; + +struct hexlin_responder_answer_req { + u8 cmd; + struct hexlin_responder_answer answ; +} __packed; + +struct hexlin_priv_data { + struct hid_device *hid_dev; + struct lin_device *ldev; + u16 baudrate; + struct completion wait_in_report; + bool is_error; + struct mutex tx_lock; /* protects hexlin_tx_report() */ + struct hexlin_responder_answer_req rar; + u8 fw_version; +}; + +static int hexlin_tx_report(struct hexlin_priv_data *priv, + const void *out_report, size_t len) +{ + u8 *buf; + int ret; + + buf = kmemdup(out_report, len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = hid_hw_output_report(priv->hid_dev, buf, len); + kfree(buf); + + if (ret < 0) + return ret; + if (ret != len) + return -EIO; + + return 0; +} + +static int hexlin_tx_req_status(struct hexlin_priv_data *priv, + const void *out_report, int len) +{ + int ret; + unsigned long t; + + mutex_lock(&priv->tx_lock); + + reinit_completion(&priv->wait_in_report); + + ret = hexlin_tx_report(priv, out_report, len); + if (ret) + goto tx_exit; + + t = wait_for_completion_killable_timeout(&priv->wait_in_report, + msecs_to_jiffies(1000)); + if (!t) + ret = -ETIMEDOUT; + + if (priv->is_error) + ret = -EINVAL; + +tx_exit: + mutex_unlock(&priv->tx_lock); + + return ret; +} + +#define HEXLIN_GET_CMD(name, enum_cmd) \ + static int hexlin_##name(struct hexlin_priv_data *priv) \ + { \ + u8 cmd = enum_cmd; \ + int ret; \ + \ + ret = hexlin_tx_req_status(priv, &cmd, sizeof(u8)); \ + if (ret) \ + hid_err(priv->hid_dev, "%s failed with %d\n", \ + __func__, ret); \ + \ + return ret; \ + } + +HEXLIN_GET_CMD(get_version, HEXLIN_GET_VERSION) +HEXLIN_GET_CMD(reset_dev, HEXLIN_RESET) +HEXLIN_GET_CMD(get_baudrate, HEXLIN_GET_BAUDRATE) + +#define HEXLIN_VAL_CMD(name, enum_cmd, struct_type, vtype) \ + static int hexlin_##name(struct hexlin_priv_data *p, vtype val) \ + { \ + struct struct_type req; \ + int ret; \ + \ + req.cmd = enum_cmd; \ + req.v = val; \ + \ + ret = hexlin_tx_req_status(p, &req, \ + sizeof(struct struct_type)); \ + if (ret) \ + hid_err(p->hid_dev, "%s failed with %d\n", \ + __func__, ret); \ + \ + return ret; \ + } + +HEXLIN_VAL_CMD(send_break, HEXLIN_SEND_BREAK, hexlin_val8_req, u8) + +static int hexlin_queue_frames_insert(struct hexlin_priv_data *priv, + const u8 *raw_data, int sz) +{ + struct hid_device *hdev = priv->hid_dev; + struct hexlin_frame hxf; + struct lin_frame lf; + + if (sz != sizeof(struct hexlin_frame)) + return -EREMOTEIO; + + memcpy(&hxf, raw_data, sz); + le32_to_cpus(hxf.flags); + + lf.len = hxf.len; + lf.lin_id = hxf.lin_id; + memcpy(lf.data, hxf.data, LIN_MAX_DLEN); + lf.checksum = hxf.checksum; + lf.checksum_mode = hxf.checksum_mode; + + hid_dbg(hdev, "id:%02x, len:%u, data:%*ph, checksum:%02x (%s)\n", + lf.lin_id, lf.len, lf.len, lf.data, lf.checksum, + lf.checksum_mode ? "enhanced" : "classic"); + + lin_rx(priv->ldev, &lf); + + return 0; +} + +static int hexlin_send_unconditional(struct hexlin_priv_data *priv, + const struct hexlin_frame *hxf) +{ + struct hexlin_unconditional_req req; + int ret; + + if (hxf->lin_id > LIN_ID_MASK) + return -EINVAL; + + req.cmd = HEXLIN_SEND_UNCONDITIONAL_FRAME; + memcpy(&req.frm, hxf, sizeof(struct hexlin_frame)); + + ret = hexlin_tx_req_status(priv, &req, + sizeof(struct hexlin_unconditional_req)); + + if (ret) + hid_err(priv->hid_dev, "%s failed with %d\n", __func__, ret); + + return ret; +} + +static int hexlin_set_baudrate(struct hexlin_priv_data *priv, u16 baudrate) +{ + struct hexlin_baudrate_req req; + int ret; + + if (baudrate < LIN_MIN_BAUDRATE || baudrate > LIN_MAX_BAUDRATE) + return -EINVAL; + + req.cmd = HEXLIN_SET_BAUDRATE; + req.baudrate = cpu_to_le16(baudrate); + + ret = hexlin_tx_req_status(priv, &req, + sizeof(struct hexlin_baudrate_req)); + if (ret) + hid_err(priv->hid_dev, "%s failed with %d\n", __func__, ret); + + return ret; +} + +static int hexlin_get_responder_answer_id(struct hexlin_priv_data *priv, u8 id, + struct hexlin_responder_answer_req *rar) +{ + u8 req[2] = { HEXLIN_GET_RESPONDER_ANSWER_ID, id }; + int ret; + + if (id > LIN_ID_MASK) + return -EINVAL; + + ret = hexlin_tx_req_status(priv, &req, sizeof(req)); + if (ret) { + hid_err(priv->hid_dev, "%s failed with %d\n", __func__, ret); + return ret; + } + + memcpy(rar, &priv->rar, sizeof(struct hexlin_responder_answer_req)); + + return 0; +} + +static int hexlin_set_responder_answer_id(struct hexlin_priv_data *priv, + const struct lin_responder_answer *answ) +{ + struct hexlin_responder_answer_req rar; + int ret; + + if (answ->lf.lin_id > LIN_ID_MASK || + answ->event_associated_id > LIN_ID_MASK) + return -EINVAL; + + rar.cmd = HEXLIN_SET_RESPONDER_ANSWER_ID; + rar.answ.is_active = answ->is_active; + rar.answ.is_event_frame = answ->is_event_frame; + rar.answ.event_associated_id = answ->event_associated_id; + rar.answ.frm.len = answ->lf.len; + rar.answ.frm.lin_id = answ->lf.lin_id; + memcpy(rar.answ.frm.data, answ->lf.data, LIN_MAX_DLEN); + rar.answ.frm.checksum = answ->lf.checksum; + rar.answ.frm.checksum_mode = answ->lf.checksum_mode; + + ret = hexlin_tx_req_status(priv, &rar, + sizeof(struct hexlin_responder_answer_req)); + if (ret) + hid_err(priv->hid_dev, "%s failed with %d\n", __func__, ret); + + return ret; +} + +static int hexlin_open(struct lin_device *ldev) +{ + struct hid_device *hdev = to_hid_device(ldev->dev); + + return hid_hw_open(hdev); +} + +static int hexlin_stop(struct lin_device *ldev) +{ + struct hid_device *hdev = to_hid_device(ldev->dev); + struct hexlin_priv_data *priv = hid_get_drvdata(hdev); + + hid_hw_close(hdev); + + priv->is_error = true; + complete(&priv->wait_in_report); + + return 0; +} + +static int hexlin_ldo_tx(struct lin_device *ldev, + const struct lin_frame *lf) +{ + struct hid_device *hdev = to_hid_device(ldev->dev); + struct hexlin_priv_data *priv = hid_get_drvdata(hdev); + int ret = -EINVAL; + + hid_dbg(hdev, "id:%02x, len:%u, data:%*ph, checksum:%02x (%s)\n", + lf->lin_id, lf->len, lf->len, lf->data, lf->checksum, + lf->checksum_mode ? "enhanced" : "classic"); + + if (lf->lin_id && lf->len == 0) { + ret = hexlin_send_break(priv, lf->lin_id); + } else if (lf->len <= LIN_MAX_DLEN) { + struct hexlin_frame hxf; + + hxf.len = lf->len; + hxf.lin_id = lf->lin_id; + memcpy(&hxf.data, lf->data, LIN_MAX_DLEN); + hxf.checksum = lf->checksum; + hxf.checksum_mode = lf->checksum_mode; + ret = hexlin_send_unconditional(priv, &hxf); + } else { + hid_err(hdev, "unknown format\n"); + } + + return ret; +} + +static int hexlin_update_bitrate(struct lin_device *ldev, u16 bitrate) +{ + struct hid_device *hdev = to_hid_device(ldev->dev); + struct hexlin_priv_data *priv = hid_get_drvdata(hdev); + int ret; + + hid_dbg(hdev, "update bitrate to: %u\n", bitrate); + + ret = hexlin_open(ldev); + if (ret) + return ret; + + ret = hexlin_set_baudrate(priv, bitrate); + if (ret) + return ret; + + ret = hexlin_get_baudrate(priv); + if (ret) + return ret; + + if (priv->baudrate != bitrate) { + hid_err(hdev, "update bitrate failed\n"); + return -EINVAL; + } + + return ret; +} + +static int hexlin_get_responder_answer(struct lin_device *ldev, u8 id, + struct lin_responder_answer *answ) +{ + struct hid_device *hdev = to_hid_device(ldev->dev); + struct hexlin_priv_data *priv = hid_get_drvdata(hdev); + struct hexlin_responder_answer_req rar; + int ret; + + if (answ == NULL) + return -EINVAL; + + ret = hexlin_get_responder_answer_id(priv, id, &rar); + if (ret) + return ret; + + answ->is_active = rar.answ.is_active; + answ->is_event_frame = rar.answ.is_event_frame; + answ->event_associated_id = rar.answ.event_associated_id; + answ->lf.len = rar.answ.frm.len; + answ->lf.lin_id = rar.answ.frm.lin_id; + memcpy(answ->lf.data, rar.answ.frm.data, LIN_MAX_DLEN); + answ->lf.checksum = rar.answ.frm.checksum; + answ->lf.checksum_mode = rar.answ.frm.checksum_mode; + + return 0; +} + +static int hexlin_update_resp_answer(struct lin_device *ldev, + const struct lin_responder_answer *answ) +{ + struct hid_device *hdev = to_hid_device(ldev->dev); + struct hexlin_priv_data *priv = hid_get_drvdata(hdev); + + if (answ == NULL) + return -EINVAL; + + return hexlin_set_responder_answer_id(priv, answ); +} + +static const struct lin_device_ops hexlin_ldo = { + .ldo_open = hexlin_open, + .ldo_stop = hexlin_stop, + .ldo_tx = hexlin_ldo_tx, + .update_bitrate = hexlin_update_bitrate, + .get_responder_answer = hexlin_get_responder_answer, + .update_responder_answer = hexlin_update_resp_answer, +}; + +static int hexlin_raw_event(struct hid_device *hdev, + struct hid_report *report, u8 *data, int sz) +{ + struct hexlin_priv_data *priv; + int ret; + + if (sz < 1 || sz > HEXLIN_PKGLEN_MAX_SZ) + return -EREMOTEIO; + + priv = hid_get_drvdata(hdev); + + hid_dbg(hdev, "%s, size:%i, data[0]: 0x%02x\n", __func__, sz, data[0]); + + priv->is_error = false; + + switch (data[0]) { + case HEXLIN_SUCCESS: + if (sz != HEXLIN_SUCCESS_SZ) + return -EREMOTEIO; + hid_dbg(hdev, "HEXLIN_SUCCESS: 0x%02x\n", data[0]); + complete(&priv->wait_in_report); + break; + case HEXLIN_FAIL: + if (sz != HEXLIN_FAIL_SZ) + return -EREMOTEIO; + hid_err(hdev, "HEXLIN_FAIL: 0x%02x\n", data[0]); + priv->is_error = true; + complete(&priv->wait_in_report); + break; + case HEXLIN_GET_VERSION: + if (sz != HEXLIN_GET_VERSION_SZ) + return -EREMOTEIO; + priv->fw_version = data[1]; + complete(&priv->wait_in_report); + break; + case HEXLIN_GET_RESPONDER_ANSWER_ID: + if (sz != HEXLIN_GET_RESPONDER_ANSWER_ID_SZ) + return -EREMOTEIO; + BUILD_BUG_ON(sizeof(priv->rar) != + HEXLIN_GET_RESPONDER_ANSWER_ID_SZ); + memcpy(&priv->rar, data, sizeof(priv->rar)); + complete(&priv->wait_in_report); + break; + case HEXLIN_GET_BAUDRATE: + if (sz != HEXLIN_GET_BAUDRATE_SZ) + return -EREMOTEIO; + BUILD_BUG_ON(sizeof(priv->baudrate) != HEXLIN_BAUDRATE_SZ); + memcpy(&priv->baudrate, &data[1], sizeof(priv->baudrate)); + le16_to_cpus(priv->baudrate); + complete(&priv->wait_in_report); + break; + /* following cases not initiated by us, so no complete() */ + case HEXLIN_FRAME: + if (sz != HEXLIN_FRAME_SZ) { + hid_err_once(hdev, "frame size mismatch: %i\n", sz); + return -EREMOTEIO; + } + ret = hexlin_queue_frames_insert(priv, &data[1], sz-1); + if (ret) { + hid_err(hdev, "failed to add frame: %i\n", ret); + return ret; + } + break; + case HEXLIN_ERROR: + hid_err(hdev, "error from adapter\n"); + break; + default: + hid_err(hdev, "unknown event: 0x%02x\n", data[0]); + } + + return 0; +} + +static int init_hw(struct hexlin_priv_data *priv) +{ + int ret; + + ret = hexlin_reset_dev(priv); + if (ret) { + /* if first reset fails, try one more time */ + ret = hexlin_reset_dev(priv); + if (ret) + return ret; + } + + ret = hexlin_get_version(priv); + if (ret) + return ret; + + priv->baudrate = LIN_DEFAULT_BAUDRATE; + ret = hexlin_set_baudrate(priv, priv->baudrate); + if (ret) + return ret; + + return 0; +} + +static int hexlin_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + struct hexlin_priv_data *priv; + int ret; + + priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->hid_dev = hdev; + hid_set_drvdata(hdev, priv); + + mutex_init(&priv->tx_lock); + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "hid parse failed with %d\n", ret); + goto fail_and_free; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DRIVER); + if (ret) { + hid_err(hdev, "hid hw start failed with %d\n", ret); + goto fail_and_stop; + } + + ret = hid_hw_open(hdev); + if (ret) { + hid_err(hdev, "hid hw open failed with %d\n", ret); + goto fail_and_close; + } + + init_completion(&priv->wait_in_report); + + hid_device_io_start(hdev); + + ret = init_hw(priv); + if (ret) + goto fail_and_close; + + priv->ldev = register_lin(&hdev->dev, &hexlin_ldo); + if (IS_ERR_OR_NULL(priv->ldev)) { + ret = PTR_ERR(priv->ldev); + goto fail_and_close; + } + + hid_hw_close(hdev); + + hid_info(hdev, "hexLIN (fw-version: %u) probed\n", priv->fw_version); + + return 0; + +fail_and_close: + hid_hw_close(hdev); +fail_and_stop: + hid_hw_stop(hdev); +fail_and_free: + mutex_destroy(&priv->tx_lock); + return ret; +} + +static void hexlin_remove(struct hid_device *hdev) +{ + struct hexlin_priv_data *priv = hid_get_drvdata(hdev); + + unregister_lin(priv->ldev); + hid_hw_stop(hdev); +} + +static const struct hid_device_id hexlin_table[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_MCS, USB_DEVICE_ID_MCS_HEXDEV_HEXLIN) }, + { } +}; + +MODULE_DEVICE_TABLE(hid, hexlin_table); + +static struct hid_driver hexlin_driver = { + .name = "hexLIN", + .id_table = hexlin_table, + .probe = hexlin_probe, + .remove = hexlin_remove, + .raw_event = hexlin_raw_event, +}; + +module_hid_driver(hexlin_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christoph Fritz "); +MODULE_DESCRIPTION("LIN bus driver for hexLIN USB adapter"); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 64164423b592b..8f46d37c2b499 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -907,6 +907,7 @@ #define USB_VENDOR_ID_MCS 0x16d0 #define USB_DEVICE_ID_MCS_GAMEPADBLOCK 0x0bcc +#define USB_DEVICE_ID_MCS_HEXDEV_HEXLIN 0x0648 #define USB_VENDOR_MEGAWORLD 0x07b5 #define USB_DEVICE_ID_MEGAWORLD_GAMEPAD 0x0312 diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 1d1949d62dfaf..a514449c50047 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -438,6 +438,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) }, #endif +#if IS_ENABLED(CONFIG_HID_MCS_HEXDEV) + { HID_USB_DEVICE(USB_VENDOR_ID_MCS, USB_DEVICE_ID_MCS_HEXDEV_HEXLIN) }, +#endif #if IS_ENABLED(CONFIG_HID_HOLTEK) { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) }, From patchwork Thu May 2 18:27:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoph Fritz X-Patchwork-Id: 794322 Received: from fritzc.com (mail.fritzc.com [213.160.72.247]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D509317167B; Thu, 2 May 2024 18:29:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.160.72.247 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714674546; cv=none; b=rOPgpovkcZ75ibkDQEL5XV+QOg2WoTqbTt6tEVRpXJvHUe9chgqfR7B+1hq61KHAbuDA5wALlXgZRZ5/fQMqqv4Q/B/rOBbegocuqpbBlbMZlOu5dhi1VYzzRdI0sUFFTpJxKUPHUlesPkq0xuz0GqF1p/81lncXJdWqp6mFBHg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714674546; c=relaxed/simple; bh=ZrFdSLcIMeL0Gw5YEaKUCGUEp/+XyImajt9Wq1/xfjE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=RdPFbPpzToMH2+KSzQ5adpx9CGzMcbD2YSoj7VNRMgjk7w9GocBlLEH2z4ykMm/5S5iXI3XIEFkImOP2YhRJkvl1wuXIbF5tbzBOk/lt4GOlWfthFCuwPowyVSCy9PJEk3gQWWoW0vlvOzrcXLb7oOIBJXaUJDSaBBdvovtBWtA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=hexdev.de; spf=pass smtp.mailfrom=hexdev.de; dkim=pass (1024-bit key) header.d=fritzc.com header.i=@fritzc.com header.b=jfJxtVeq; arc=none smtp.client-ip=213.160.72.247 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=hexdev.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=hexdev.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=fritzc.com header.i=@fritzc.com header.b="jfJxtVeq" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=fritzc.com; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=ekCjuw1duvOWVggYCKKNCs0aIF99UZrHoS1CtHiTWfg=; b=jfJxtVeq2SxD+2lNekY07f9QAL ylvXuVNQyvjAv3l5js0UkficH9FdjxeOewdgah5EzToiwFITNg26HkOCjwVmya6gnZqXGTAfBc06p x2Njvb3nY/Bu198yrn+ghg8xudC/Hwra9koDVhfwEuD86YrjVmalUFOFVthLasmRK9ts=; Received: from 127.0.0.1 by fritzc.com with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim latest) (envelope-from ) id 1s2bAu-001ZbZ-1h; Thu, 02 May 2024 20:28:57 +0200 From: Christoph Fritz To: Jiri Slaby , Oliver Hartkopp , Marc Kleine-Budde , Vincent Mailhol , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jiri Kosina , Benjamin Tissoires , Greg Kroah-Hartman , Sebastian Reichel , Linus Walleij Cc: Andreas Lauser , Jonathan Corbet , Pavel Pisa , linux-can@vger.kernel.org, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-input@vger.kernel.org, linux-serial@vger.kernel.org Subject: [PATCH v3 03/11] tty: serdev: Add flag buffer aware receive_buf_fp() Date: Thu, 2 May 2024 20:27:56 +0200 Message-Id: <20240502182804.145926-4-christoph.fritz@hexdev.de> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240502182804.145926-1-christoph.fritz@hexdev.de> References: <20240502182804.145926-1-christoph.fritz@hexdev.de> Precedence: bulk X-Mailing-List: linux-serial@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 This patch introduces an additional receive buffer callback variation besides the already existing receive_buf(). This new callback function also passes the flag buffer (TTY_NORMAL, TTY_BREAK, and friends). If defined, this function gets prioritized and called instead of the standard receive_buf(). An alternative approach could have been to enhance the receive_buf() function and update all drivers that use it. Signed-off-by: Christoph Fritz --- drivers/tty/serdev/serdev-ttyport.c | 2 +- include/linux/serdev.h | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c index 3d7ae7fa50186..bb47691afdb21 100644 --- a/drivers/tty/serdev/serdev-ttyport.c +++ b/drivers/tty/serdev/serdev-ttyport.c @@ -32,7 +32,7 @@ static size_t ttyport_receive_buf(struct tty_port *port, const u8 *cp, if (!test_bit(SERPORT_ACTIVE, &serport->flags)) return 0; - ret = serdev_controller_receive_buf(ctrl, cp, count); + ret = serdev_controller_receive_buf(ctrl, cp, fp, count); dev_WARN_ONCE(&ctrl->dev, ret > count, "receive_buf returns %zu (count = %zu)\n", diff --git a/include/linux/serdev.h b/include/linux/serdev.h index ff78efc1f60df..c6ef5a8988e07 100644 --- a/include/linux/serdev.h +++ b/include/linux/serdev.h @@ -23,11 +23,17 @@ struct serdev_device; * struct serdev_device_ops - Callback operations for a serdev device * @receive_buf: Function called with data received from device; * returns number of bytes accepted; may sleep. + * @receive_buf_fp: Function called with data and flag buffer received + * from device; If defined, this function gets called + * instead of @receive_buf; + * returns number of bytes accepted; may sleep. * @write_wakeup: Function called when ready to transmit more data; must * not sleep. */ struct serdev_device_ops { size_t (*receive_buf)(struct serdev_device *, const u8 *, size_t); + ssize_t (*receive_buf_fp)(struct serdev_device *, const u8 *, + const u8 *, size_t); void (*write_wakeup)(struct serdev_device *); }; @@ -186,15 +192,20 @@ static inline void serdev_controller_write_wakeup(struct serdev_controller *ctrl } static inline size_t serdev_controller_receive_buf(struct serdev_controller *ctrl, - const u8 *data, + const u8 *data, const u8 *fp, size_t count) { struct serdev_device *serdev = ctrl->serdev; - if (!serdev || !serdev->ops->receive_buf) + if (!serdev || !serdev->ops) return 0; - return serdev->ops->receive_buf(serdev, data, count); + if (serdev->ops->receive_buf_fp) + return serdev->ops->receive_buf_fp(serdev, data, fp, count); + else if (serdev->ops->receive_buf) + return serdev->ops->receive_buf(serdev, data, count); + + return 0; } #if IS_ENABLED(CONFIG_SERIAL_DEV_BUS) From patchwork Thu May 2 18:27:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoph Fritz X-Patchwork-Id: 794320 Received: from fritzc.com (mail.fritzc.com [213.160.72.247]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 98BB617F385; Thu, 2 May 2024 18:29:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.160.72.247 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714674549; cv=none; b=DNjC4jfVVjPntOvOFjwJ2CCWW51XX0dI/jEX5TMB3mrB9ClbmwyK+/t6gFlpsFlv84Q5TlbRGHVuthuhhvZwPQJe2+eaagX+Lxv/8rmpMtRe1iTnOSrHSNl86P61WFXySTTscMiJQ0uaGUbvLyxUb8mKcImZixg8pCf3ZvcbaKU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714674549; c=relaxed/simple; bh=BCLyRn6CAWrGWzuuim46rr9r7Y1EbKkSb3hW4oSGMKA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=YHpGN+ZQ/i6zwnx/LdW5XVIO+kNbby+zLji+uuMYoulsR1tF1kh+efp/ZBaLJL70T+TEEH+3rfYD6ETznzoxfNsfA+d5/U+1J+GRXQ8OObbsxSkFMYpyDAMbvEtNmkg4z467eWbwjTNNci8vlT6hEJpM2KjEonlvEQ4UpIfya+s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=hexdev.de; spf=pass smtp.mailfrom=hexdev.de; dkim=pass (1024-bit key) header.d=fritzc.com header.i=@fritzc.com header.b=o5Vv90Uj; arc=none smtp.client-ip=213.160.72.247 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=hexdev.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=hexdev.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=fritzc.com header.i=@fritzc.com header.b="o5Vv90Uj" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=fritzc.com; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=ovSYkpeke3/a3PG+6oPTsSVDfi0gMV1wcBnaCGOSfVs=; b=o5Vv90Uj8lJ9qhhk95/QxUXPCH qj5GiVbUKmeW9ZBp1i8ilqjucg4gdgJqaCXBOIVHcn/mO4qqwtR9/RqACvwH5ZJ0+nvvAkWgcGIEq 08bS17Q5uTtSvGksbR9PQgYxeKt5Mx73qceoIxYExpXeDxTzaAmYtSNe4BDHnBmrQCuI=; Received: from 127.0.0.1 by fritzc.com with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim latest) (envelope-from ) id 1s2bAx-001ZbZ-1l; Thu, 02 May 2024 20:29:00 +0200 From: Christoph Fritz To: Jiri Slaby , Oliver Hartkopp , Marc Kleine-Budde , Vincent Mailhol , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jiri Kosina , Benjamin Tissoires , Greg Kroah-Hartman , Sebastian Reichel , Linus Walleij Cc: Andreas Lauser , Jonathan Corbet , Pavel Pisa , linux-can@vger.kernel.org, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-input@vger.kernel.org, linux-serial@vger.kernel.org Subject: [PATCH v3 06/11] dt-bindings: net/can: Add serial (serdev) LIN adapter Date: Thu, 2 May 2024 20:27:59 +0200 Message-Id: <20240502182804.145926-7-christoph.fritz@hexdev.de> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240502182804.145926-1-christoph.fritz@hexdev.de> References: <20240502182804.145926-1-christoph.fritz@hexdev.de> Precedence: bulk X-Mailing-List: linux-serial@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add dt-bindings for serial LIN bus adapters. These adapters are basically just LIN transceivers that are hard-wired to serial devices. Signed-off-by: Christoph Fritz --- .../bindings/net/can/hexdev,lin-serdev.yaml | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/can/hexdev,lin-serdev.yaml diff --git a/Documentation/devicetree/bindings/net/can/hexdev,lin-serdev.yaml b/Documentation/devicetree/bindings/net/can/hexdev,lin-serdev.yaml new file mode 100644 index 0000000000000..c178eb9be1391 --- /dev/null +++ b/Documentation/devicetree/bindings/net/can/hexdev,lin-serdev.yaml @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/can/hexdev,lin-serdev.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Serial LIN Adapter + +description: + LIN transceiver, mostly hard-wired to a serial device, used for communication + on a LIN bus. + For more details on an adapter, visit . + +maintainers: + - Christoph Fritz + +properties: + compatible: + const: hexdev,lin-serdev + +required: + - compatible + +additionalProperties: false + +examples: + - | + serial { + linbus { + compatible = "hexdev,lin-serdev"; + }; + }; From patchwork Thu May 2 18:28:02 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoph Fritz X-Patchwork-Id: 794319 Received: from fritzc.com (mail.fritzc.com [213.160.72.247]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 216D5181324; Thu, 2 May 2024 18:29:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.160.72.247 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714674552; cv=none; b=imSZGKlGkFe9fvTaaJBRB2wQHa94dso0Wus7I6Qzs288DfLPJG0deQXr1nVr7uQJoC/AZS8i/JE1ePxs1Ynyn2sk9Fe2ykDahQJxjlg5tvT3uYrceCZSSMiNxzwj/KCHA2OwJPLHUReUkmt9TZoCHdD0buncPyb9q4TpLd688iw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714674552; c=relaxed/simple; bh=GSulo82rKnPvXyP3RQsoy6rgLW6KWucKAnbWqMbp1f0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=sLvqwDEM1Qq3cGu33BMy08vI2Zi10dpGAdRfR+ca2heXhscierR8OCUBXcKH/oBR399IcHZWq5sKcM0F8OWN4ECidW0RIMWQA/qHyJ9fEiIjZMD0bwThxRgta0HM/5Y5eSMs9EZsMC7vhFFmKqOffukKPOqCD9BQj2TFSO56Pno= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=hexdev.de; spf=pass smtp.mailfrom=hexdev.de; dkim=pass (1024-bit key) header.d=fritzc.com header.i=@fritzc.com header.b=xXJPPhle; arc=none smtp.client-ip=213.160.72.247 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=hexdev.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=hexdev.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=fritzc.com header.i=@fritzc.com header.b="xXJPPhle" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=fritzc.com; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=v2goQZydtQiYmy2+LR80/ACY6cQ1Zev0nahvSPqVvHU=; b=xXJPPhlekkQAaOgnvax3yUoGul ixvrneTkzjbiJK5kbt/4hl5HrMv3QfQs9vWRWqT0obnK5lonXY84ZyFOnrFsni1WA9lxbu9VUDXzO L+Q9M9+RmgXiEL49O2QI+XocmS1rt+AHdHDAWYWStRL7p2i10CBUnbnBG/Wa05obG750=; Received: from 127.0.0.1 by fritzc.com with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim latest) (envelope-from ) id 1s2bB1-001ZbZ-1l; Thu, 02 May 2024 20:29:04 +0200 From: Christoph Fritz To: Jiri Slaby , Oliver Hartkopp , Marc Kleine-Budde , Vincent Mailhol , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jiri Kosina , Benjamin Tissoires , Greg Kroah-Hartman , Sebastian Reichel , Linus Walleij Cc: Andreas Lauser , Jonathan Corbet , Pavel Pisa , linux-can@vger.kernel.org, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-input@vger.kernel.org, linux-serial@vger.kernel.org Subject: [PATCH v3 09/11] can: lin: Handle rx offload config frames Date: Thu, 2 May 2024 20:28:02 +0200 Message-Id: <20240502182804.145926-10-christoph.fritz@hexdev.de> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240502182804.145926-1-christoph.fritz@hexdev.de> References: <20240502182804.145926-1-christoph.fritz@hexdev.de> Precedence: bulk X-Mailing-List: linux-serial@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The CAN Broadcast Manager now has the capability to dispatch CANFD frames marked with the id LINBUS_RXOFFLOAD_ID. This patch introduces functionality to interpret these specific frames, enabling the configuration of RX offloading within the LIN driver. Signed-off-by: Christoph Fritz --- drivers/net/can/lin.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/net/can/lin.c b/drivers/net/can/lin.c index 95906003666fb..ee2ebea2c865f 100644 --- a/drivers/net/can/lin.c +++ b/drivers/net/can/lin.c @@ -194,6 +194,27 @@ static void lin_remove_sysfs_id_files(struct net_device *ndev) } } +static int lin_setup_rxoffload(struct lin_device *ldev, + struct canfd_frame *cfd) +{ + struct lin_responder_answer answ; + + if (!(cfd->flags & CANFD_FDF)) + return -EMSGSIZE; + + BUILD_BUG_ON(sizeof(struct lin_responder_answer) > sizeof(cfd->data)); + memcpy(&answ, cfd->data, sizeof(struct lin_responder_answer)); + + answ.lf.checksum_mode = (cfd->can_id & LIN_ENHANCED_CKSUM_FLAG) ? + LINBUS_ENHANCED : LINBUS_CLASSIC; + + if (answ.lf.lin_id > LIN_ID_MASK || + answ.event_associated_id > LIN_ID_MASK) + return -EINVAL; + + return ldev->ldev_ops->update_responder_answer(ldev, &answ); +} + static void lin_tx_work_handler(struct work_struct *ws) { struct lin_device *ldev = container_of(ws, struct lin_device, @@ -206,6 +227,14 @@ static void lin_tx_work_handler(struct work_struct *ws) ldev->tx_busy = true; cfd = (struct canfd_frame *)ldev->tx_skb->data; + + if (cfd->can_id & LIN_RXOFFLOAD_DATA_FLAG) { + ret = lin_setup_rxoffload(ldev, cfd); + if (ret < 0) + netdev_err(ndev, "setting up rx failed %d\n", ret); + goto lin_tx_out; + } + lf.checksum_mode = (cfd->can_id & LIN_ENHANCED_CKSUM_FLAG) ? LINBUS_ENHANCED : LINBUS_CLASSIC; lf.lin_id = cfd->can_id & LIN_ID_MASK; From patchwork Thu May 2 18:28:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoph Fritz X-Patchwork-Id: 794318 Received: from fritzc.com (mail.fritzc.com [213.160.72.247]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 46B04174EC1; Thu, 2 May 2024 18:29:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.160.72.247 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714674553; cv=none; b=MMz5jZmsDbYycv5Wllo7uRQ20CIqSIlNiSLdQVVljUtEM8No5xZEPBQVqfNBqupXQ3Zhkm/66HP0rtWATexSYb4lhd+ZbDb7q61ylGmOFIu678ME5dk5QG9MtDSRkB7fTJHq4tZReY5+WXpuANdKi8u5eKkjv8IjQcN+IKyFf6A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714674553; c=relaxed/simple; bh=Nj+y3vaJj3DdICDvB8tBJvWf0zz26duCalPTmUbljs8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=kqrxjzcbpFib5k+HAOCTQ9HDe0m+vO2wiky3Sex4FheKcziJ6RXGfSqZ/cUhr+G62qNg1mrw8oY6RzvzTgwqfVjG6Kpaejuq9r5n6MZnfQDUbpMq2KAr3NrqZ7PB/ub9V+yYbvT889m3PGfgmEXtNfz6md6EmWyzjxKj5n2raPk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=hexdev.de; spf=pass smtp.mailfrom=hexdev.de; dkim=pass (1024-bit key) header.d=fritzc.com header.i=@fritzc.com header.b=FTylqayg; arc=none smtp.client-ip=213.160.72.247 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=hexdev.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=hexdev.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=fritzc.com header.i=@fritzc.com header.b="FTylqayg" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=fritzc.com; s=dkim; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=KPRpp6UUpvbAAcRXcnyZXeimntnEpH2UpmxWaVfp/H0=; b=FTylqaygHWelxoyf+3oq1tNN/4 /E0CGgmXMtths0ClrUnq+vdh3K9TaGJWP7afej7RrU4ptblJ2ZlhDYVKQDaOoaKhON3o/jOzUqbGV E0olMa725JAKfglzfJGo0A9WsrH4Y0tPx+umalQFrSXlGM3czoBhqOO6APKnbsVsDBM4=; Received: from 127.0.0.1 by fritzc.com with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim latest) (envelope-from ) id 1s2bB2-001ZbZ-2G; Thu, 02 May 2024 20:29:05 +0200 From: Christoph Fritz To: Jiri Slaby , Oliver Hartkopp , Marc Kleine-Budde , Vincent Mailhol , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jiri Kosina , Benjamin Tissoires , Greg Kroah-Hartman , Sebastian Reichel , Linus Walleij Cc: Andreas Lauser , Jonathan Corbet , Pavel Pisa , linux-can@vger.kernel.org, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-input@vger.kernel.org, linux-serial@vger.kernel.org Subject: [PATCH v3 10/11] can: lin: Support setting LIN mode Date: Thu, 2 May 2024 20:28:03 +0200 Message-Id: <20240502182804.145926-11-christoph.fritz@hexdev.de> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240502182804.145926-1-christoph.fritz@hexdev.de> References: <20240502182804.145926-1-christoph.fritz@hexdev.de> Precedence: bulk X-Mailing-List: linux-serial@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 A LIN node can work as commander or responder. This patch is introducing a new control mode (CAN_CTRLMODE_LIN_COMMANDER), so that e.g. the ip tool from iproute2 can turn on commander mode when the device is being brought up. Signed-off-by: Christoph Fritz --- drivers/net/can/lin.c | 40 +++++++++++++++++++++++++++++++- include/net/lin.h | 7 ++++++ include/uapi/linux/can/netlink.h | 1 + 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/lin.c b/drivers/net/can/lin.c index ee2ebea2c865f..96cd016228fea 100644 --- a/drivers/net/can/lin.c +++ b/drivers/net/can/lin.c @@ -271,11 +271,40 @@ static netdev_tx_t lin_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } +static int lin_update_mode(struct net_device *ndev) +{ + struct lin_device *ldev = netdev_priv(ndev); + u32 ctrlmode = ldev->can.ctrlmode; + enum lin_mode lm; + int ret = 0; + + lm = (ctrlmode & CAN_CTRLMODE_LIN_COMMANDER) ? LINBUS_COMMANDER : + LINBUS_RESPONDER; + if (ldev->lmode != lm) { + if (!ldev->ldev_ops->update_lin_mode) { + netdev_err(ndev, "setting lin mode unsupported\n"); + return -EINVAL; + } + ret = ldev->ldev_ops->update_lin_mode(ldev, lm); + if (ret) { + netdev_err(ndev, "Failed to set lin mode: %d\n", ret); + return ret; + } + ldev->lmode = lm; + } + + return ret; +} + static int lin_open(struct net_device *ndev) { struct lin_device *ldev = netdev_priv(ndev); int ret; + ret = lin_update_mode(ndev); + if (ret) + return ret; + ldev->tx_busy = false; ret = open_candev(ndev); @@ -451,7 +480,7 @@ struct lin_device *register_lin(struct device *dev, ndev->mtu = CANFD_MTU; ldev->can.bittiming.bitrate = LIN_DEFAULT_BAUDRATE; ldev->can.ctrlmode = CAN_CTRLMODE_LIN; - ldev->can.ctrlmode_supported = 0; + ldev->can.ctrlmode_supported = CAN_CTRLMODE_LIN_COMMANDER; ldev->can.bitrate_const = lin_bitrate; ldev->can.bitrate_const_cnt = ARRAY_SIZE(lin_bitrate); ldev->can.do_set_bittiming = lin_set_bittiming; @@ -466,6 +495,15 @@ struct lin_device *register_lin(struct device *dev, goto exit_candev; } + ldev->lmode = LINBUS_RESPONDER; + if (ldev->ldev_ops->update_lin_mode) { + ret = ldev->ldev_ops->update_lin_mode(ldev, ldev->lmode); + if (ret) { + netdev_err(ndev, "updating lin mode failed\n"); + goto exit_candev; + } + } + ret = register_candev(ndev); if (ret) goto exit_candev; diff --git a/include/net/lin.h b/include/net/lin.h index e7c7c820a6e18..e80a4509b7a8c 100644 --- a/include/net/lin.h +++ b/include/net/lin.h @@ -36,6 +36,11 @@ struct lin_attr { struct lin_device *ldev; }; +enum lin_mode { + LINBUS_RESPONDER = 0, + LINBUS_COMMANDER, +}; + struct lin_device { struct can_priv can; /* must be the first member */ struct net_device *ndev; @@ -47,6 +52,7 @@ struct lin_device { struct sk_buff *tx_skb; struct kobject *lin_ids_kobj; struct lin_attr sysfs_entries[LIN_NUM_IDS]; + enum lin_mode lmode; }; enum lin_checksum_mode { @@ -73,6 +79,7 @@ struct lin_device_ops { int (*ldo_open)(struct lin_device *ldev); int (*ldo_stop)(struct lin_device *ldev); int (*ldo_tx)(struct lin_device *ldev, const struct lin_frame *frame); + int (*update_lin_mode)(struct lin_device *ldev, enum lin_mode lm); int (*update_bitrate)(struct lin_device *ldev, u16 bitrate); int (*update_responder_answer)(struct lin_device *ldev, const struct lin_responder_answer *answ); diff --git a/include/uapi/linux/can/netlink.h b/include/uapi/linux/can/netlink.h index 51b0e2a7624e4..6c84a7666c646 100644 --- a/include/uapi/linux/can/netlink.h +++ b/include/uapi/linux/can/netlink.h @@ -104,6 +104,7 @@ struct can_ctrlmode { #define CAN_CTRLMODE_TDC_AUTO 0x200 /* CAN transiver automatically calculates TDCV */ #define CAN_CTRLMODE_TDC_MANUAL 0x400 /* TDCV is manually set up by user */ #define CAN_CTRLMODE_LIN 0x800 /* LIN bus mode */ +#define CAN_CTRLMODE_LIN_COMMANDER 0x1000 /* LIN bus specific commander mode */ /* * CAN device statistics