From nobody Sat Oct 4 17:31:18 2025 Received: from mail-ed1-f54.google.com (mail-ed1-f54.google.com [209.85.208.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DC72323A99E; Thu, 14 Aug 2025 17:22:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755192153; cv=none; b=FTNOYFIZvZEpR8MZ0YZkMl9DS/YYI+B2nTUIKlqYHIjxLwZIB54wUAgs7B4BIriGiBhje+VaH/whBrJnrpCyXt1tKdPAx+sArUZzKA2vxk/UsT3peuKDiMUtlHtt6uF/tVl/H8WuDNMte5UBrJsZydt9bud56Vd2bkTRuhy7Yc8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755192153; c=relaxed/simple; bh=i39qxRZUMj/Pti8Z01aQVvfTsjHQXlej4o0hLXJkQf8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=bKWtEk8am42jV+Ic5RsCQRwr7qoi6AzHH/Z1DChd3QFpEDzWH/d272mK0d8/b7IJGo78LSM6yPwq8jLXyTleraX7xzYcNvHsb6QsLUYsBEYyQ0DkHsEox9g2l3jy8GcxKegtgk1otyQcaJ5cmwdUMp9lULFKIDD5OEyV26+7e64= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=O+DJiEJV; arc=none smtp.client-ip=209.85.208.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="O+DJiEJV" Received: by mail-ed1-f54.google.com with SMTP id 4fb4d7f45d1cf-6188b794743so2052434a12.3; Thu, 14 Aug 2025 10:22:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1755192149; x=1755796949; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=/7HG85ltfZpgCYVmSEwK6SJCMgRp1oaevrqT/YdGjwk=; b=O+DJiEJVBWgGCt7fbDPOKNTLdYzETaKPCz7PlXYUFrkOimVki63Y2lv2/gmZLd7ebL +7ODRk7SdXaGmF20NZy9VboUJGnMFMXEfbPQpU510JSoS//9jkyujpBX5avGPacdZUFF spSFtzzt74AoJuqMhfgQxRcVf/6mqDuPvtrqkLsWug7RAQq1VVWGL2jl5ljtYppGr6Qf IyhXJjE/JRn/1y2iQiMpMjfyxo+ZisDmWDxRnQXwFQjRJuM0tYHKw8MXB8LPdC7kmMnS FFzSoSCHGJa325PpaZEVxsx5Sfkh9cEmnY8TJV6xOWa0yyENaXkMoVVVxCrgvnu3ChlZ 8LsA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1755192149; x=1755796949; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=/7HG85ltfZpgCYVmSEwK6SJCMgRp1oaevrqT/YdGjwk=; b=TAfYWHiQz00eJERe9rwm1q4FEz4R6tnvt0PYMh4skPCLP4V+9kkBuBzpS2ju/I8I9R AejHpCZSRUXINXGa+6aqBwD8SyNUNT6SqkLNoHuCbnHneB/mP65ZG1/kE0+u3XgrM9mV 6L2rDdkBSMmIwx6zEkUMk2C9B+w7v+X4JpT+0h3k54QByRRujaS3Xk0zR2ooxuAwFuE+ Agv4sWKlW+PkYbbqAG3eVscZcTWpsQ+Dg/87TjOiVZxkUpJzKFZJMNOJkLtZBysbhky6 R8RdRlY7RTjV092FwxiSWYrk+5MayVGGu4W5fBVgZHwyYxQWmP0cCE2EBQkmEz0ysXfh AeoQ== X-Forwarded-Encrypted: i=1; AJvYcCWJPSRXllbEyWZrazmWYdymM0RtpwOOX9F2hmN6EbD01eIjx/C8nd9rtveEKo5Z5aV6lS15YK7J8Wb0ww==@vger.kernel.org X-Gm-Message-State: AOJu0YwmOZ7PqxEgJSUcOcif1D4pR0Srado6Hw0y9vENgqdDO+HybPD2 Oie1YR+q4Z/cFYLhbtOrt+t24xUIGp3GjAVu8+Ab7pdJa+CgUuIYF4Kn X-Gm-Gg: ASbGncvKpcFzmZoHBlwrH2/sauelYt8MR6kXsmDVdXdyJtqVxCrMXd2j4GOulEQEktE K5Sh1jqmclABB1zOg78pmMuzq3D2NK9ME+URkVl/3EP+DvNBoD8H1c1DFaepBVoqhM2saJs0fhI HbayMUduBeg+/JNp+zNKrzv0W8BZhRjAs6UexA4cRW44k5JKKQYcBU2GvwLiEhGQzeZkdq7Vy7p Otv5RKmf6cUkE92V2czde8axYixJHu3cLOxPe13CbFeSSKkurN/DD5wY+5x9taSXF9NFnDnYtsK NOpbj9JlGLHH/uefHzFMVfVJmbuGOZJaBeJCkTE++cA820RScqlyAFUzAEzX1bvE6MDky05K2wa 8OE6IP7cFGsmEsLuSwXNdHwNDltu0bjPaRnEHeu3xwK1O+XPiWKv6/fH2+r+2iTL+Vh4o00XNHC xizU0j7Q== X-Google-Smtp-Source: AGHT+IGqOOull4ZnbagWS+ui5xY9j6C8MltoECp4K7ywLv8ENuyFT/fjmLGqAqjS6oSvi0Jx5zJHeQ== X-Received: by 2002:a05:6402:1d53:b0:618:2011:caae with SMTP id 4fb4d7f45d1cf-6188b92e12amr3497493a12.4.1755192148701; Thu, 14 Aug 2025 10:22:28 -0700 (PDT) Received: from localhost.localdomain (93-87-121-223.dynamic.isp.telekom.rs. [93.87.121.223]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-615a8f2c265sm23774115a12.26.2025.08.14.10.22.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 Aug 2025 10:22:28 -0700 (PDT) From: =?UTF-8?q?=C5=A0erif=20Rami?= To: Jaroslav Kysela , Takashi Iwai Cc: linux-kernel@vger.kernel.org, linux-sound@vger.kernel.org, =?UTF-8?q?=C5=A0erif=20Rami?= Subject: [PATCH v6 2/7] ALSA: usb-audio: us144mkii: Add PCM core infrastructure Date: Thu, 14 Aug 2025 19:22:17 +0200 Message-Id: <20250814172222.9448-3-ramiserifpersia@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250814172222.9448-1-ramiserifpersia@gmail.com> References: <20250814172222.9448-1-ramiserifpersia@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable This patch adds the ALSA PCM device infrastructure. It creates a new PCM device with one playback and one capture stream. The hardware capabilities (formats, rates, channels) are defined in `tascam_pcm_hw`. The core PCM operations (`snd_pcm_ops`) for both playback and capture are implemented, including open, close, hw_params, prepare, and pointer callbacks. The trigger callback is a stub for now. This commit allows user-space applications to interact with the ALSA device, but no audio will be streamed yet. Signed-off-by: =C5=A0erif Rami --- sound/usb/usx2y/us144mkii.c | 20 ++++- sound/usb/usx2y/us144mkii.h | 46 +++++++++++- sound/usb/usx2y/us144mkii_capture.c | 107 +++++++++++++++++++++++++++ sound/usb/usx2y/us144mkii_pcm.c | 78 +++++++++++++++++++ sound/usb/usx2y/us144mkii_pcm.h | 76 +++++++++++++++++++ sound/usb/usx2y/us144mkii_playback.c | 107 +++++++++++++++++++++++++++ 6 files changed, 428 insertions(+), 6 deletions(-) create mode 100644 sound/usb/usx2y/us144mkii_capture.c create mode 100644 sound/usb/usx2y/us144mkii_pcm.c create mode 100644 sound/usb/usx2y/us144mkii_pcm.h create mode 100644 sound/usb/usx2y/us144mkii_playback.c diff --git a/sound/usb/usx2y/us144mkii.c b/sound/usb/usx2y/us144mkii.c index 00d13b039589..a41f48fe2bee 100644 --- a/sound/usb/usx2y/us144mkii.c +++ b/sound/usb/usx2y/us144mkii.c @@ -22,7 +22,7 @@ MODULE_LICENSE("GPL"); * Defaults to "US144MKII". * @param enable: Array of booleans to enable or disable each device. * Defaults to {1, 0, ..., 0} (first device enabled). - * @param dev_idx: Internal counter for probed TASCAM devices. + * @param dev_idx: Internal counter for the number of TASCAM devices probe= d. */ static int index[SNDRV_CARDS] =3D SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] =3D SNDRV_DEFAULT_STR; @@ -36,7 +36,7 @@ static int tascam_suspend(struct usb_interface *intf, pm_= message_t message); static int tascam_resume(struct usb_interface *intf); =20 /** - * tascam_card_private_free() - Frees private data for the sound card. + * tascam_card_private_free() - Frees private data associated with the sou= nd * card. * @card: Pointer to the ALSA sound card instance. * @@ -58,12 +58,12 @@ static void tascam_card_private_free(struct snd_card *c= ard) * @intf: The USB interface being probed. * @usb_id: The USB device ID. * - * This function is the entry point for the USB driver on device match. + * This function is the entry point for the USB driver when a matching dev= ice * is found. It performs initial device setup, including: * - Checking for the second interface (MIDI) and associating it. * - Performing a vendor-specific handshake with the device. * - Setting alternate settings for USB interfaces. - * - Creating and registering the ALSA sound card. + * - Creating and registering the ALSA sound card and PCM device. * * Return: 0 on success, or a negative error code on failure. */ @@ -154,6 +154,18 @@ static int tascam_probe(struct usb_interface *intf, tascam->digital_out_source =3D 1; tascam->capture_34_source =3D 1; =20 + spin_lock_init(&tascam->lock); + + err =3D snd_pcm_new(card, "US144MKII PCM", 0, 1, 1, &tascam->pcm); + if (err < 0) + goto free_card; + tascam->pcm->private_data =3D tascam; + strscpy(tascam->pcm->name, "US144MKII PCM", sizeof(tascam->pcm->name)); + + err =3D tascam_init_pcm(tascam->pcm); + if (err < 0) + goto free_card; + strscpy(card->driver, DRIVER_NAME, sizeof(card->driver)); if (dev->descriptor.idProduct =3D=3D USB_PID_TASCAM_US144) { strscpy(card->shortname, "TASCAM US-144", diff --git a/sound/usb/usx2y/us144mkii.h b/sound/usb/usx2y/us144mkii.h index 9f59863fab57..44f3b44bbf3b 100644 --- a/sound/usb/usx2y/us144mkii.h +++ b/sound/usb/usx2y/us144mkii.h @@ -21,18 +21,60 @@ #define MODE_VAL_HANDSHAKE_READ 0x0000 #define USB_CTRL_TIMEOUT_MS 1000 =20 +/* --- Audio Format Configuration --- */ +#define BYTES_PER_SAMPLE 3 +#define NUM_CHANNELS 4 +#define BYTES_PER_FRAME (NUM_CHANNELS * BYTES_PER_SAMPLE) + +/* --- USB Control Message Protocol --- */ +#define RT_D2H_VENDOR_DEV (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE) +#define VENDOR_REQ_MODE_CONTROL 0x49 +#define MODE_VAL_HANDSHAKE_READ 0x0000 +#define USB_CTRL_TIMEOUT_MS 1000 + +struct tascam_card; + +#include "us144mkii_pcm.h" + /** - * struct tascam_card - Driver data structure for TASCAM US-144MKII. + * struct tascam_card - Main driver data structure for the TASCAM US-144MK= II. * @dev: Pointer to the USB device. * @iface0: Pointer to USB interface 0 (audio). * @iface1: Pointer to USB interface 1 (MIDI). * @card: Pointer to the ALSA sound card instance. + * @pcm: Pointer to the ALSA PCM device. + * @playback_substream: Pointer to the active playback PCM substream. + * @capture_substream: Pointer to the active capture PCM substream. + * @playback_active: Atomic flag indicating if playback is active. + * @capture_active: Atomic flag indicating if capture is active. + * @driver_playback_pos: Current position in the ALSA playback buffer (fra= mes). + * @driver_capture_pos: Current position in the ALSA capture buffer (frame= s). + * @playback_frames_consumed: Total frames consumed by playback. + * @capture_frames_processed: Total frames processed for capture. + * @current_rate: Currently configured sample rate of the device. + * @lock: Main spinlock for protecting shared driver state. */ struct tascam_card { struct usb_device *dev; struct usb_interface *iface0; struct usb_interface *iface1; struct snd_card *card; + struct snd_pcm *pcm; + + struct snd_pcm_substream *playback_substream; + struct snd_pcm_substream *capture_substream; + + atomic_t playback_active; + atomic_t capture_active; + + snd_pcm_uframes_t driver_playback_pos; + snd_pcm_uframes_t driver_capture_pos; + + u64 playback_frames_consumed; + u64 capture_frames_processed; + + int current_rate; + spinlock_t lock; }; =20 - #endif /* __US144MKII_H */ +#endif /* __US144MKII_H */ diff --git a/sound/usb/usx2y/us144mkii_capture.c b/sound/usb/usx2y/us144mki= i_capture.c new file mode 100644 index 000000000000..f258198ec94b --- /dev/null +++ b/sound/usb/usx2y/us144mkii_capture.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2025 =C5=A0erif Rami + +#include "us144mkii.h" + +/** + * tascam_capture_open() - Opens the PCM capture substream. + * @substream: The ALSA PCM substream to open. + * + * This function sets the hardware parameters for the capture substream + * and stores a reference to the substream in the driver's private data. + * + * Return: 0 on success. + */ +static int tascam_capture_open(struct snd_pcm_substream *substream) +{ + struct tascam_card *tascam =3D snd_pcm_substream_chip(substream); + + substream->runtime->hw =3D tascam_pcm_hw; + tascam->capture_substream =3D substream; + atomic_set(&tascam->capture_active, 0); + + return 0; +} + +/** + * tascam_capture_close() - Closes the PCM capture substream. + * @substream: The ALSA PCM substream to close. + * + * This function clears the reference to the capture substream in the + * driver's private data. + * + * Return: 0 on success. + */ +static int tascam_capture_close(struct snd_pcm_substream *substream) +{ + struct tascam_card *tascam =3D snd_pcm_substream_chip(substream); + + tascam->capture_substream =3D NULL; + + return 0; +} + +/** + * tascam_capture_prepare() - Prepares the PCM capture substream for use. + * @substream: The ALSA PCM substream to prepare. + * + * This function initializes capture-related counters. + * + * Return: 0 on success. + */ +static int tascam_capture_prepare(struct snd_pcm_substream *substream) +{ + struct tascam_card *tascam =3D snd_pcm_substream_chip(substream); + + tascam->driver_capture_pos =3D 0; + tascam->capture_frames_processed =3D 0; + + return 0; +} + +/** + * tascam_capture_pointer() - Returns the current capture pointer position. + * @substream: The ALSA PCM substream. + * + * This function returns the current position of the capture pointer within + * the ALSA ring buffer, in frames. + * + * Return: The current capture pointer position in frames. + */ +static snd_pcm_uframes_t +tascam_capture_pointer(struct snd_pcm_substream *substream) +{ + struct tascam_card *tascam =3D snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime =3D substream->runtime; + u64 pos; + + if (!atomic_read(&tascam->capture_active)) + return 0; + + scoped_guard(spinlock_irqsave, &tascam->lock) { + pos =3D tascam->capture_frames_processed; + } + + if (runtime->buffer_size =3D=3D 0) + return 0; + + return do_div(pos, runtime->buffer_size); +} + +/** + * tascam_capture_ops - ALSA PCM operations for capture. + * + * This structure defines the callback functions for capture stream operat= ions, + * including open, close, ioctl, hardware parameters, hardware free, prepa= re, + * trigger, and pointer. + */ +const struct snd_pcm_ops tascam_capture_ops =3D { + .open =3D tascam_capture_open, + .close =3D tascam_capture_close, + .ioctl =3D snd_pcm_lib_ioctl, + .hw_params =3D tascam_pcm_hw_params, + .hw_free =3D tascam_pcm_hw_free, + .prepare =3D tascam_capture_prepare, + .trigger =3D tascam_pcm_trigger, + .pointer =3D tascam_capture_pointer, +}; diff --git a/sound/usb/usx2y/us144mkii_pcm.c b/sound/usb/usx2y/us144mkii_pc= m.c new file mode 100644 index 000000000000..944b4d0ee2ec --- /dev/null +++ b/sound/usb/usx2y/us144mkii_pcm.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2025 =C5=A0erif Rami + +#include "us144mkii.h" + +const struct snd_pcm_hardware tascam_pcm_hw =3D { + .info =3D (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), + .formats =3D SNDRV_PCM_FMTBIT_S24_3LE, + .rates =3D (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000), + .rate_min =3D 44100, + .rate_max =3D 96000, + .channels_min =3D NUM_CHANNELS, + .channels_max =3D NUM_CHANNELS, + .buffer_bytes_max =3D 1024 * 1024, + .period_bytes_min =3D 48 * BYTES_PER_FRAME, + .period_bytes_max =3D 1024 * BYTES_PER_FRAME, + .periods_min =3D 2, + .periods_max =3D 1024, +}; + +int tascam_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + return 0; +} + +int tascam_pcm_hw_free(struct snd_pcm_substream *substream) +{ + return 0; +} + +int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct tascam_card *tascam =3D snd_pcm_substream_chip(substream); + int err =3D 0; + + scoped_guard(spinlock_irqsave, &tascam->lock) { + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + if (!atomic_read(&tascam->playback_active)) { + atomic_set(&tascam->playback_active, 1); + atomic_set(&tascam->capture_active, 1); + } + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (atomic_read(&tascam->playback_active)) { + atomic_set(&tascam->playback_active, 0); + atomic_set(&tascam->capture_active, 0); + } + break; + default: + err =3D -EINVAL; + break; + } + } + + return err; +} + +int tascam_init_pcm(struct snd_pcm *pcm) +{ + struct tascam_card *tascam =3D pcm->private_data; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &tascam_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &tascam_capture_ops); + + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + tascam->dev->dev.parent, 64 * 1024, + tascam_pcm_hw.buffer_bytes_max); + + return 0; +} diff --git a/sound/usb/usx2y/us144mkii_pcm.h b/sound/usb/usx2y/us144mkii_pc= m.h new file mode 100644 index 000000000000..bb8b51f9b6fb --- /dev/null +++ b/sound/usb/usx2y/us144mkii_pcm.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +// Copyright (c) 2025 =C5=A0erif Rami + +#ifndef __US144MKII_PCM_H +#define __US144MKII_PCM_H + +#include "us144mkii.h" + +/** + * tascam_pcm_hw - Hardware capabilities for TASCAM US-144MKII PCM. + * + * Defines the supported PCM formats, rates, channels, and buffer/period s= izes + * for the TASCAM US-144MKII audio interface. + */ +extern const struct snd_pcm_hardware tascam_pcm_hw; + +/** + * tascam_playback_ops - ALSA PCM operations for playback. + * + * This structure defines the callback functions for playback stream opera= tions. + */ +extern const struct snd_pcm_ops tascam_playback_ops; + +/** + * tascam_capture_ops - ALSA PCM operations for capture. + * + * This structure defines the callback functions for capture stream operat= ions. + */ +extern const struct snd_pcm_ops tascam_capture_ops; + +/** + * tascam_init_pcm() - Initializes the ALSA PCM device. + * @pcm: Pointer to the ALSA PCM device to initialize. + * + * This function sets up the PCM operations and preallocates pages for the + * PCM buffer. + * + * Return: 0 on success, or a negative error code on failure. + */ +int tascam_init_pcm(struct snd_pcm *pcm); + +/** + * tascam_pcm_hw_params() - Configures hardware parameters for PCM streams. + * @substream: The ALSA PCM substream. + * @params: The hardware parameters to apply. + * + * This function is a stub for handling hardware parameter configuration. + * + * Return: 0 on success. + */ +int tascam_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); + +/** + * tascam_pcm_hw_free() - Frees hardware parameters for PCM streams. + * @substream: The ALSA PCM substream. + * + * This function is a stub for freeing hardware-related resources. + * + * Return: 0 on success. + */ +int tascam_pcm_hw_free(struct snd_pcm_substream *substream); + +/** + * tascam_pcm_trigger() - Triggers the start or stop of PCM streams. + * @substream: The ALSA PCM substream. + * @cmd: The trigger command (e.g., SNDRV_PCM_TRIGGER_START). + * + * This function handles starting and stopping of playback and capture str= eams + * by setting atomic flags. + * + * Return: 0 on success, or a negative error code on failure. + */ +int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd); + +#endif /* __US144MKII_PCM_H */ diff --git a/sound/usb/usx2y/us144mkii_playback.c b/sound/usb/usx2y/us144mk= ii_playback.c new file mode 100644 index 000000000000..0785c58f1197 --- /dev/null +++ b/sound/usb/usx2y/us144mkii_playback.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2025 =C5=A0erif Rami + +#include "us144mkii.h" + +/** + * tascam_playback_open() - Opens the PCM playback substream. + * @substream: The ALSA PCM substream to open. + * + * This function sets the hardware parameters for the playback substream + * and stores a reference to the substream in the driver's private data. + * + * Return: 0 on success. + */ +static int tascam_playback_open(struct snd_pcm_substream *substream) +{ + struct tascam_card *tascam =3D snd_pcm_substream_chip(substream); + + substream->runtime->hw =3D tascam_pcm_hw; + tascam->playback_substream =3D substream; + atomic_set(&tascam->playback_active, 0); + + return 0; +} + +/** + * tascam_playback_close() - Closes the PCM playback substream. + * @substream: The ALSA PCM substream to close. + * + * This function clears the reference to the playback substream in the + * driver's private data. + * + * Return: 0 on success. + */ +static int tascam_playback_close(struct snd_pcm_substream *substream) +{ + struct tascam_card *tascam =3D snd_pcm_substream_chip(substream); + + tascam->playback_substream =3D NULL; + + return 0; +} + +/** + * tascam_playback_prepare() - Prepares the PCM playback substream for use. + * @substream: The ALSA PCM substream to prepare. + * + * This function initializes playback-related counters. + * + * Return: 0 on success. + */ +static int tascam_playback_prepare(struct snd_pcm_substream *substream) +{ + struct tascam_card *tascam =3D snd_pcm_substream_chip(substream); + + tascam->driver_playback_pos =3D 0; + tascam->playback_frames_consumed =3D 0; + + return 0; +} + +/** + * tascam_playback_pointer() - Returns the current playback pointer positi= on. + * @substream: The ALSA PCM substream. + * + * This function returns the current position of the playback pointer with= in + * the ALSA ring buffer, in frames. + * + * Return: The current playback pointer position in frames. + */ +static snd_pcm_uframes_t +tascam_playback_pointer(struct snd_pcm_substream *substream) +{ + struct tascam_card *tascam =3D snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime =3D substream->runtime; + u64 pos; + + if (!atomic_read(&tascam->playback_active)) + return 0; + + scoped_guard(spinlock_irqsave, &tascam->lock) { + pos =3D tascam->playback_frames_consumed; + } + + if (runtime->buffer_size =3D=3D 0) + return 0; + + return do_div(pos, runtime->buffer_size); +} + +/** + * tascam_playback_ops - ALSA PCM operations for playback. + * + * This structure defines the callback functions for playback stream opera= tions, + * including open, close, ioctl, hardware parameters, hardware free, prepa= re, + * trigger, and pointer. + */ +const struct snd_pcm_ops tascam_playback_ops =3D { + .open =3D tascam_playback_open, + .close =3D tascam_playback_close, + .ioctl =3D snd_pcm_lib_ioctl, + .hw_params =3D tascam_pcm_hw_params, + .hw_free =3D tascam_pcm_hw_free, + .prepare =3D tascam_playback_prepare, + .trigger =3D tascam_pcm_trigger, + .pointer =3D tascam_playback_pointer, +}; --=20 2.39.5