From patchwork Mon Apr 25 18:01:14 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Kaehn X-Patchwork-Id: 565716 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 alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (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 A7AB4C433EF for ; Mon, 25 Apr 2022 18:03:00 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 673A5184D; Mon, 25 Apr 2022 20:02:08 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 673A5184D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1650909778; bh=AbXGYEFlRBTblefyfIOP4l5sUYFbWKm5TzLhnn3ShkQ=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=ZDGAxoMRscJKYG0sgcQinn1//bvVHfAGzhNs1KJSHWurRSJiJ+vH5mwsbeumkwCWA CUkK5Tl2Dr/G/Fqyt5wkudq7OTCZDbkkrqlu/yVE9dvjsyq4K9n0JlsBPacdNOUxzu i7TfhfAiORfiaZi1+nf4+frBFb6j139ZRaU/kWlY= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id C13A8F80152; Mon, 25 Apr 2022 20:01:33 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id E5F07F8050F; Mon, 25 Apr 2022 20:01:32 +0200 (CEST) Received: from mail-il1-x133.google.com (mail-il1-x133.google.com [IPv6:2607:f8b0:4864:20::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 7CF31F80152 for ; Mon, 25 Apr 2022 20:01:25 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 7CF31F80152 Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="oAPFU3DB" Received: by mail-il1-x133.google.com with SMTP id g10so1830800ilf.6 for ; Mon, 25 Apr 2022 11:01:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=oIpXQOczTIQ/O1VLgkg45A/f+SkXi92vGgGc35m3jEE=; b=oAPFU3DBgJAYT5Kw1WGNSxLDubdRb4++zYbD2kWMXuoSWMPGOszK+v/C88K7qPDNzr 8CrU/OYmSjmnMpana2PB/F7n8qljdRt2FBsLOv/K7XBsf2c1TldF9GOrX1RGtlI7VhZA kG25H19czK9o4WmdVH5UGNWy6ipv6CGHQYTx6MR07rUke2EETxqqHB9dlfccCIAj3m0I 0OZ6HzUHCoedSjQxZdN17UPEuAma83JXvh+WjVzePOHn/mvmMj9fCg9Q+AQmoTD+AtbT vCAPB5L0N5+MmFPMPU9LsxJK4UlyYo9RtegtnLGBbSaLP9mRiTc3JP5rWqti7hDF5P8G M1GA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=oIpXQOczTIQ/O1VLgkg45A/f+SkXi92vGgGc35m3jEE=; b=5oeQ7Rk/n/K5TLKg5Toicib1SoQYe4cQGvgmCRj8f6tiooLq5PIIo35PgXp+2d7Env DwReD+ssyCKwLHAUfFol+9MlYiEnbQId15kXgRDE0IWmtqQI6MRvd9b8G0oiSLmza6qK NK3bWfLI0M6PuC/saIHe1HKJ5/1HYetay/qp71W8xc+XpRqHzSh2/BaztuvdmCbWZV0G ta26gUznYrSm0Fzk9LIy+W8sc2OGKtmlvqs24xd7eeUFMsCVzt3M96rZwrA402VwlJHo fU7kNYcH6/Xg3ndtrD0zWCpBMZHvG0Z/Qg9dGM3PXSr0BG/83I6DepR5TNg9Lvs2ww2P t+zg== X-Gm-Message-State: AOAM531eWONqzNfGXxhFtE/4W5xsEj9Qvelvsbnz06qRmtQk8SRFgh3z 2NCGcLbMQAv00nfU9M2quyg= X-Google-Smtp-Source: ABdhPJwjGzMpGe/Oh7rEeky35gx80wwE7U7kvkfR9j/U2SLIAaKVcic4KbWBe3cdh0jrvTZ/twI32w== X-Received: by 2002:a05:6e02:18c8:b0:2cd:8f11:e9ed with SMTP id s8-20020a056e0218c800b002cd8f11e9edmr3347082ilu.310.1650909684207; Mon, 25 Apr 2022 11:01:24 -0700 (PDT) Received: from localhost.localdomain (cpe-65-29-252-111.wi.res.rr.com. [65.29.252.111]) by smtp.gmail.com with ESMTPSA id a1-20020a923301000000b002cae7560bfesm6447379ilf.62.2022.04.25.11.01.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 25 Apr 2022 11:01:23 -0700 (PDT) From: Daniel Kaehn To: tiwai@suse.com Subject: [PATCH v3 1/2] dt-bindings: sound: Add generic serial MIDI device Date: Mon, 25 Apr 2022 13:01:14 -0500 Message-Id: <20220425180115.757247-2-kaehndan@gmail.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20220425180115.757247-1-kaehndan@gmail.com> References: <20220425180115.757247-1-kaehndan@gmail.com> MIME-Version: 1.0 Cc: devicetree@vger.kernel.org, alsa-devel@alsa-project.org, Daniel Kaehn X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Adds dt-binding for snd-serial-generic serial MIDI driver Signed-off-by: Daniel Kaehn --- .../devicetree/bindings/sound/serialmidi.yaml | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/serialmidi.yaml diff --git a/Documentation/devicetree/bindings/sound/serialmidi.yaml b/Documentation/devicetree/bindings/sound/serialmidi.yaml new file mode 100644 index 000000000000..74f02a9e1190 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/serialmidi.yaml @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause + +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/serialmidi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Generic Serial MIDI Device + +maintainers: + - Daniel Kaehn + +description: | + Generic MIDI interface using a serial device. Can only be set to use standard speeds + corresponding to supported baud rates of the underlying serial device. If standard MIDI + speed of 31.25 kBaud is needed, configure the clocks of the underlying serial device + so that a requested speed of 3.840 kBaud resuts in the standard MIDI baud rate. + +properties: + compatible: + const: serialmidi + + speed: + maxItems: 1 + description: | + Speed to set the serial port to when the MIDI device is opened. + If not specified, the underlying serial device is allowed to use its configured default speed. + +required: + - compatible + +additionalProperties: false + +examples: + - | + serial { + midi { + compatible = "serialmidi"; + speed = <38400>; + }; + }; From patchwork Mon Apr 25 18:01:15 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Kaehn X-Patchwork-Id: 566166 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 alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (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 9E7C1C433FE for ; Mon, 25 Apr 2022 18:03:08 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id E96E81843; Mon, 25 Apr 2022 20:02:16 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz E96E81843 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1650909787; bh=UdrMGbTVOlMMIt/35vuNSTv1SPXXK8FqmxyOD2ENSFE=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=quEIcrke+i5wVYteS554ptpGqigcRcfNfw5YcKq2RYcGTom0M0hTdcehHina60iRc knrryaPJjsotPpM5KmmXYW+GWorNO6/qm+RFHrdgAk9VA7m6EnCHSRSRKKQJRFli7t sdgihjqTuccp+wofW4tL1L6C96XyAI3hTCP6xbIA= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 5A09DF8014B; Mon, 25 Apr 2022 20:01:36 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 71708F80511; Mon, 25 Apr 2022 20:01:34 +0200 (CEST) Received: from mail-il1-x131.google.com (mail-il1-x131.google.com [IPv6:2607:f8b0:4864:20::131]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id DBDBFF8014B for ; Mon, 25 Apr 2022 20:01:26 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz DBDBFF8014B Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="dvMmoITB" Received: by mail-il1-x131.google.com with SMTP id d3so9852071ilr.10 for ; Mon, 25 Apr 2022 11:01:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=fBuBMIfL41ODVT7H7ESbalnkiMR33vpYMTtgYXCIlZs=; b=dvMmoITBE4jsvtT3UfJjCUj9m7lvy8mIYaU0o1avgHO/7tNRMXxCkuf46et9ssUcTl 5kfy/TGWNMYtoiu0Tqc0kQQxeqXzafI8gcHCYE7GMuxhSmDuZu0jTaoYHNu43wzkNf0/ XMF2LSNjh1riY2+C038rCNkrpsTwVvPA7SCSlhyF1ug7ACIpgGnGeTEMgVU7NDTYdX82 iO4RKlzHm0KpodQI44wGQfcUapyhc00/Gebyj1y2J6lX33xAhxLsV07PV2lh55oZkkIy e8tcORq9BTTHL0b3t+SCbRH6AeOLaV+5dxtfD0IQThR3lq/itSls0vea89Si324yWTJx vzqw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=fBuBMIfL41ODVT7H7ESbalnkiMR33vpYMTtgYXCIlZs=; b=sbAssNJZAjCjPFHG/sW600RSCZ0xQCLU1pQHKwsr/GsbC4OVccms8a9U39Jnprg2rc d+vQC57DK4+CsMsdAb4YbS60kH7BvK6TYjQpOS5bLNUeN6XKtCcTGE6ylMhbno/5nbN5 PiA5yXwC3gcepmR2e218gPmJfFV+Vi1iWAmh3WA9T64JFaJYWItkCXbpVwaSQNiOl3Zs iPU071/+E/kMB5LnWEjJtCzHnSW7aUyZlymqZN5XcjLP8YaSG5nEEOLwulE+GUVmmFxg ofeZEbmeLMay4t3CxrUIFisH5JF9wGIflUEd6qftH5e79jsm8DhLm7wdQAVMMpCEzaGp Oyeg== X-Gm-Message-State: AOAM533aC9K5JoFH+qCIMA+pTdcPSlu8ZF2L3ApD2x7KCihZH5B6fMW3 OEuO6nKcNfM9QBYiJNjJpAM= X-Google-Smtp-Source: ABdhPJy6nCzWRSSyPBqRMYhcs5A+dUeZopKijKf+MUo1hmy768jcVqHU8dsaWUP9B5vDPY+6atFV6w== X-Received: by 2002:a92:d212:0:b0:2cb:7635:9940 with SMTP id y18-20020a92d212000000b002cb76359940mr7144835ily.132.1650909684646; Mon, 25 Apr 2022 11:01:24 -0700 (PDT) Received: from localhost.localdomain (cpe-65-29-252-111.wi.res.rr.com. [65.29.252.111]) by smtp.gmail.com with ESMTPSA id a1-20020a923301000000b002cae7560bfesm6447379ilf.62.2022.04.25.11.01.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 25 Apr 2022 11:01:24 -0700 (PDT) From: Daniel Kaehn To: tiwai@suse.com Subject: [PATCH v3 2/2] Add generic serial MIDI driver using serial bus API Date: Mon, 25 Apr 2022 13:01:15 -0500 Message-Id: <20220425180115.757247-3-kaehndan@gmail.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20220425180115.757247-1-kaehndan@gmail.com> References: <20220425180115.757247-1-kaehndan@gmail.com> MIME-Version: 1.0 Cc: devicetree@vger.kernel.org, alsa-devel@alsa-project.org, Daniel Kaehn X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Generic serial MIDI driver adding support for using serial devices compatible with the serial bus as raw MIDI devices, allowing using additional serial devices not compatible with the existing serial-u16550 driver. Supports only setting standard serial baudrates on the underlying serial device; however, the underlying serial device can be configured so that a requested 38.4 kBaud is actually the standard MIDI 31.25 kBaud. Supports DeviceTree configuration. Signed-off-by: Daniel Kaehn --- sound/drivers/Kconfig | 18 ++ sound/drivers/Makefile | 2 + sound/drivers/serial-generic.c | 316 +++++++++++++++++++++++++++++++++ 3 files changed, 336 insertions(+) create mode 100644 sound/drivers/serial-generic.c diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index ca4cdf666f82..6f58a8531ed8 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -165,6 +165,24 @@ config SND_SERIAL_U16550 To compile this driver as a module, choose M here: the module will be called snd-serial-u16550. +config SND_SERIAL_GENERIC + tristate "Generic serial MIDI driver" + depends on SERIAL_DEV_BUS + depends on OF + select SND_RAWMIDI + help + To include support for mapping generic serial devices as raw + ALSA MIDI devices, say Y here. The driver only supports setting + the serial port to standard baudrates. To attain the standard MIDI + baudrate of 31.25 kBaud, configure the clock of the underlying serial + device so that a requested 3.84 kBaud will result in the standard speed. + + Use this devicetree binding to configure serial port mapping + + + To compile this driver as a module, choose M here: the module + will be called snd-serial-generic. + config SND_MPU401 tristate "Generic MPU-401 UART driver" select SND_MPU401_UART diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile index c0fe4eccdaef..b60303180a1b 100644 --- a/sound/drivers/Makefile +++ b/sound/drivers/Makefile @@ -10,6 +10,7 @@ snd-mtpav-objs := mtpav.o snd-mts64-objs := mts64.o snd-portman2x4-objs := portman2x4.o snd-serial-u16550-objs := serial-u16550.o +snd-serial-generic-objs := serial-generic.o snd-virmidi-objs := virmidi.o # Toplevel Module Dependency @@ -17,6 +18,7 @@ obj-$(CONFIG_SND_DUMMY) += snd-dummy.o obj-$(CONFIG_SND_ALOOP) += snd-aloop.o obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o +obj-$(CONFIG_SND_SERIAL_GENERIC) += snd-serial-generic.o obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o obj-$(CONFIG_SND_MTS64) += snd-mts64.o obj-$(CONFIG_SND_PORTMAN2X4) += snd-portman2x4.o diff --git a/sound/drivers/serial-generic.c b/sound/drivers/serial-generic.c new file mode 100644 index 000000000000..af1f19db33aa --- /dev/null +++ b/sound/drivers/serial-generic.c @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * serial-generic.c + * Copyright (c) by Daniel Kaehn , + * Isaku Yamahata , + * George Hansper , + * Hannu Savolainen + * + * Generic serial MIDI driver using the serdev serial bus API for hardware interaction + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +MODULE_DESCRIPTION("Generic serial MIDI driver"); +MODULE_LICENSE("GPL"); + +#define SERIAL_MODE_INPUT_OPEN (1 << 0) +#define SERIAL_MODE_OUTPUT_OPEN (1 << 1) +#define SERIAL_MODE_INPUT_TRIGGERED (1 << 2) +#define SERIAL_MODE_OUTPUT_TRIGGERED (1 << 3) + +struct snd_serial_generic { + struct serdev_device *serdev; + + struct snd_card *card; + struct snd_rawmidi *rmidi; + struct snd_rawmidi_substream *midi_output; + struct snd_rawmidi_substream *midi_input; + + int filemode; /* open status of file */ + unsigned int baudrate; +}; + +static int snd_serial_generic_ensure_serdev_open(struct snd_serial_generic *drvdata) +{ + int err; + unsigned int actual_baud; + + if (!drvdata->filemode) { + err = serdev_device_open(drvdata->serdev); + if (err < 0) + return err; + if (drvdata->baudrate) { + actual_baud = serdev_device_set_baudrate(drvdata->serdev, + drvdata->baudrate); + if (actual_baud != drvdata->baudrate) { + dev_warn(drvdata->card->dev, "snd-serial-generic: requested %d baud for %s but it was actually set to %d\n", + drvdata->baudrate, drvdata->card->shortname, actual_baud); + } + } + } + return 0; +} + +static int snd_serial_generic_input_open(struct snd_rawmidi_substream *substream) +{ + int err; + struct snd_serial_generic *drvdata = substream->rmidi->card->private_data; + + dev_dbg(drvdata->card->dev, "snd-serial-generic: DEBUG - Opening input for card %s\n", + drvdata->card->shortname); + + err = snd_serial_generic_ensure_serdev_open(drvdata); + if (err < 0) + return err; + + drvdata->filemode |= SERIAL_MODE_INPUT_OPEN; + drvdata->midi_input = substream; + return 0; +} + +static int snd_serial_generic_input_close(struct snd_rawmidi_substream *substream) +{ + struct snd_serial_generic *drvdata = substream->rmidi->card->private_data; + + drvdata->filemode &= ~SERIAL_MODE_INPUT_OPEN; + drvdata->midi_input = NULL; + if (!drvdata->filemode) + serdev_device_close(drvdata->serdev); + return 0; +} + +static void snd_serial_generic_input_trigger(struct snd_rawmidi_substream *substream, + int up) +{ + struct snd_serial_generic *drvdata = substream->rmidi->card->private_data; + + if (up) + drvdata->filemode |= SERIAL_MODE_INPUT_TRIGGERED; + else + drvdata->filemode &= ~SERIAL_MODE_INPUT_TRIGGERED; +} + +static int snd_serial_generic_output_open(struct snd_rawmidi_substream *substream) +{ + struct snd_serial_generic *drvdata = substream->rmidi->card->private_data; + int err; + + dev_dbg(drvdata->card->dev, "snd-serial-generic: DEBUG - Opening output for card %s\n", + drvdata->card->shortname); + + err = snd_serial_generic_ensure_serdev_open(drvdata); + if (err < 0) + return err; + + drvdata->filemode |= SERIAL_MODE_OUTPUT_OPEN; + drvdata->midi_output = substream; + return 0; +}; + +static int snd_serial_generic_output_close(struct snd_rawmidi_substream *substream) +{ + struct snd_serial_generic *drvdata = substream->rmidi->card->private_data; + + drvdata->filemode &= ~SERIAL_MODE_OUTPUT_OPEN; + drvdata->midi_output = NULL; + if (!drvdata->filemode) + serdev_device_close(drvdata->serdev); + return 0; +}; + +#define INTERNAL_BUF_SIZE 256 + +static void snd_serial_generic_output_write(struct snd_rawmidi_substream *substream) +{ + static char buf[INTERNAL_BUF_SIZE]; + int num_bytes; + struct snd_serial_generic *drvdata = substream->rmidi->card->private_data; + + while (!snd_rawmidi_transmit_empty(substream)) { + num_bytes = snd_rawmidi_transmit_peek(substream, buf, INTERNAL_BUF_SIZE); + num_bytes = serdev_device_write_buf(drvdata->serdev, buf, num_bytes); + snd_rawmidi_transmit_ack(substream, num_bytes); + } +} + +static void snd_serial_generic_output_trigger(struct snd_rawmidi_substream *substream, + int up) +{ + struct snd_serial_generic *drvdata = substream->rmidi->card->private_data; + + if (up) + drvdata->filemode |= SERIAL_MODE_OUTPUT_TRIGGERED; + else + drvdata->filemode &= ~SERIAL_MODE_OUTPUT_TRIGGERED; + if (up) + snd_serial_generic_output_write(substream); +} + +static const struct snd_rawmidi_ops snd_serial_generic_output = { + .open = snd_serial_generic_output_open, + .close = snd_serial_generic_output_close, + .trigger = snd_serial_generic_output_trigger, +}; + +static const struct snd_rawmidi_ops snd_serial_generic_input = { + .open = snd_serial_generic_input_open, + .close = snd_serial_generic_input_close, + .trigger = snd_serial_generic_input_trigger, +}; + +static int snd_serial_generic_receive_buf(struct serdev_device *serdev, + const unsigned char *buf, size_t count) +{ + int ret; + struct snd_serial_generic *drvdata = serdev_device_get_drvdata(serdev); + + ret = snd_rawmidi_receive(drvdata->midi_input, buf, count); + return ret < 0 ? 0 : ret; +} + +static void snd_serial_generic_write_wakeup(struct serdev_device *serdev) +{ + struct snd_serial_generic *drvdata = serdev_device_get_drvdata(serdev); + + if (!snd_rawmidi_transmit_empty(drvdata->midi_output)) + snd_serial_generic_output_write(drvdata->midi_output); +} + + +static const struct serdev_device_ops snd_serial_generic_serdev_device_ops = { + .receive_buf = snd_serial_generic_receive_buf, + .write_wakeup = snd_serial_generic_write_wakeup +}; + +static void snd_serial_generic_parse_dt(struct serdev_device *serdev, + struct snd_serial_generic *drvdata) +{ + int err; + + if (serdev->dev.of_node) { + err = of_property_read_u32(serdev->dev.of_node, "speed", &drvdata->baudrate); + if (err < 0) { + dev_warn(drvdata->card->dev, + "snd-serial-generic: MIDI device reading of speed DT param failed with error %d, using default baudrate of serial device\n", + err); + drvdata->baudrate = 0; + } + } else { + dev_info(drvdata->card->dev, "snd-serial-generic: MIDI device speed DT param not set for %s, using default baudrate of serial device\n", + drvdata->card->shortname); + drvdata->baudrate = 0; + } +} + +static void snd_serial_generic_substreams(struct snd_rawmidi_str *stream, int dev_num) +{ + struct snd_rawmidi_substream *substream; + + list_for_each_entry(substream, &stream->substreams, list) { + sprintf(substream->name, "Serial MIDI %d-%d", dev_num, substream->number); + } +} + +static int snd_serial_generic_rmidi(struct snd_serial_generic *drvdata, + int outs, int ins, struct snd_rawmidi **rmidi) +{ + struct snd_rawmidi *rrawmidi; + int err; + + err = snd_rawmidi_new(drvdata->card, drvdata->card->driver, 0, outs, ins, &rrawmidi); + if (err < 0) + return err; + + snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_INPUT, + &snd_serial_generic_input); + snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + &snd_serial_generic_output); + strcpy(rrawmidi->name, drvdata->card->shortname); + + snd_serial_generic_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT], + drvdata->serdev->ctrl->nr); + snd_serial_generic_substreams(&rrawmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT], + drvdata->serdev->ctrl->nr); + + rrawmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; + + if (rmidi) + *rmidi = rrawmidi; + return 0; +} + +static int snd_serial_generic_probe(struct serdev_device *serdev) +{ + struct snd_card *card; + struct snd_serial_generic *drvdata; + int err; + + err = snd_devm_card_new(&serdev->dev, SNDRV_DEFAULT_IDX1, + SNDRV_DEFAULT_STR1, THIS_MODULE, + sizeof(struct snd_serial_generic), &card); + + if (err < 0) + return err; + + strcpy(card->driver, "SerialMIDI"); + sprintf(card->shortname, "SerialMIDI-%d", serdev->ctrl->nr); + sprintf(card->longname, "Serial MIDI device at serial%d", serdev->ctrl->nr); + + drvdata = card->private_data; + + drvdata->serdev = serdev; + drvdata->card = card; + + snd_serial_generic_parse_dt(serdev, drvdata); + + err = snd_serial_generic_rmidi(drvdata, 1, 1, &drvdata->rmidi); + if (err < 0) + return err; + + err = snd_card_register(card); + + if (err < 0) + return err; + + serdev_device_set_client_ops(serdev, &snd_serial_generic_serdev_device_ops); + serdev_device_set_drvdata(drvdata->serdev, drvdata); + + return 0; +} + +#define SND_SERIAL_GENERIC_DRIVER "snd-serial-generic" + +static const struct of_device_id snd_serial_generic_dt_ids[] = { + { .compatible = "serialmidi" }, + {}, +}; + +MODULE_DEVICE_TABLE(of, snd_serial_generic_dt_ids); + +static struct serdev_device_driver snd_serial_generic_driver = { + .driver = { + .name = SND_SERIAL_GENERIC_DRIVER, + .of_match_table = of_match_ptr(snd_serial_generic_dt_ids), + }, + .probe = snd_serial_generic_probe, +}; + +module_serdev_device_driver(snd_serial_generic_driver);