On 7/29/24 15:02, Takashi Iwai wrote:
On Mon, 29 Jul 2024 10:59:04 +0200,
Ivan Orlov wrote:
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
(snip)
Hi Takashi,
Thank you so much for the review.
+/*
+ * This structure describes the userspace-driven timer. Such timers are purely virtual,
+ * and can only be triggered from software (for instance, by userspace application).
+ */
+struct snd_utimer_info {
+ /*
+ * To pretend being a normal timer, we need to know the frame rate and
+ * the period size in frames.
+ */
+ snd_pcm_uframes_t frame_rate;
+ snd_pcm_uframes_t period_size;
The units in timer API should be independent from PCM.
So use the explicit type such as __u64 here (so that you don't need
the compat ioctl conversion, too).
Alright, I'll use __u64 here (initially I thought it is going to be more
clear because it specifies the unit `period_size` is stored in, but I
agree that it should be completely independent from pcm).
+ unsigned int id;
+};
We often put some reserved fields for future extension.
But I'm not sure whether it's needed at this time for this kind of
simple interface, though.
Yeah, I don't think we are going to add anything else to the timers
anytime soon... However, I'll probably add a small reserved space here
(16 bytes, for instance), just in case we decide to add more parameters.
Thanks!
#define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int)
#define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id)
#define SNDRV_TIMER_IOCTL_TREAD_OLD _IOW('T', 0x02, int)
@@ -990,6 +1005,8 @@ struct snd_timer_status {
#define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2)
#define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3)
#define SNDRV_TIMER_IOCTL_TREAD64 _IOW('T', 0xa4, int)
+#define SNDRV_TIMER_IOCTL_CREATE _IOWR('T', 0xa5, struct snd_utimer_info)
+#define SNDRV_TIMER_IOCTL_TRIGGER _IO('T', 0xa6)
Once after adding the new API, don't forget to bump the protocol
version defined in SNDRV_TIMER_VERSION.
Ah, alright, I'll fix that in V3. Sorry, haven't noticed it :(
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
(snip)
+#ifdef CONFIG_SND_UTIMER
+/*
+ * Since userspace-driven timers are passed to userspace, we need to have an identifier
+ * which will allow us to use them (basically, the subdevice number of udriven timer).
+ */
+DEFINE_IDA(snd_utimer_ids);
Missing static.
Ah, yes, I missed the static here. thanks!
+static int snd_utimer_create(struct snd_utimer_info *utimer_info,
+ struct snd_utimer **r_utimer)
+{
(snip)
+ err = snd_timer_new(NULL, utimer->name, &tid, &timer);
+ if (err < 0) {
+ pr_err("Can't create userspace-driven timer\n");
+ goto err_timer_new;
+ }
+
+ timer->module = THIS_MODULE;
+ timer->hw = timer_hw;
+ timer->hw.resolution = NANO / utimer_info->frame_rate * utimer_info->period_size;
A sanity check is definitely needed for parameters like this.
e.g. you'd hit a zero-division Oops with this code.
Also, the resolution should be neither too small nor too high.
Yeah, allowing zero division here (and overflows) is a very bad idea...
I'll add some checks in V3.
+static int snd_utimer_ioctl_create(struct file *file,
+ struct snd_utimer_info __user *_utimer_info)
+{
+ struct snd_utimer *utimer;
+ struct snd_utimer_info *utimer_info;
+ int err;
+
+ utimer_info = memdup_user(_utimer_info, sizeof(*utimer_info));
+ if (IS_ERR(utimer_info))
+ return PTR_ERR(no_free_ptr(utimer_info));
no_free_ptr() is used only for the automatic cleanup stuff.
Probably, I should use automatic cleanup here as well (as it is done in
snd_timer_user_ginfo).
+static int snd_utimer_ioctl_create(struct file *file,
+ struct snd_utimer_info __user *_utimer_info)
+{
+ return -EINVAL;
Better to keep -ENOTTY?
Initial idea was that EINVAL here would say that the functionality is
supported, but disabled in the config, but it seems like it breaks the
convention this way so I'm going to change this to ENOTTY in the next
version.
Thank you!
--
Kind regards,
Ivan Orlov