From: Takashi Iwai <tiwai@suse.de>
To: "Geoffrey D. Bennett" <g@b4.vu>
Cc: Takashi Iwai <tiwai@suse.de>, Takashi Iwai <tiwai@suse.com>,
linux-sound@vger.kernel.org
Subject: Re: [PATCH v5 1/2] ALSA: FCP: Add Focusrite Control Protocol driver
Date: Mon, 13 Jan 2025 18:02:58 +0100 [thread overview]
Message-ID: <87plkq1wal.wl-tiwai@suse.de> (raw)
In-Reply-To: <e2fa99cd1eefd2bd25584a5bfe93a21c643622dd.1736699490.git.g@b4.vu>
On Sun, 12 Jan 2025 18:10:31 +0100,
Geoffrey D. Bennett wrote:
>
> +/* Send an FCP command and get the response */
> +static int fcp_usb(struct usb_mixer_interface *mixer, u32 opcode,
> + const void *req_data, u16 req_size,
> + void *resp_data, u16 resp_size)
> +{
> + struct fcp_data *private = mixer->private_data;
> + struct usb_device *dev = mixer->chip->dev;
> + struct fcp_usb_packet *req __free(kfree) = NULL;
> + struct fcp_usb_packet *resp __free(kfree) = NULL;
> + size_t req_buf_size = struct_size(req, data, req_size);
> + size_t resp_buf_size = struct_size(resp, data, resp_size);
> + int retries = 0;
> + const int max_retries = 5;
> + int err;
> +
> + if (!mixer->urb) {
> + void *step0_resp __free(kfree) = NULL;
> + void *step2_resp __free(kfree) = NULL;
> +
> + step0_resp = kmalloc(private->step0_resp_size, GFP_KERNEL);
> + if (!step0_resp)
> + return -ENOMEM;
> + step2_resp = kmalloc(private->step2_resp_size, GFP_KERNEL);
> + if (!step2_resp)
> + return -ENOMEM;
> + err = fcp_init(mixer, step0_resp, step2_resp);
> + if (err < 0)
> + return err;
> + }
This happens only after the suspend, and this is for automatic
re-initialization, right?
It's a bit scary that such a low-level function itself does
re-initialization, as fcp_init() will call this function again.
That said, it's more straightforward if the re-initialization is
checked and done in the upper level. (And here check only mixer->urb
and return error (or spew WARN_ON()).
> +static int fcp_meter_tlv_callback(struct snd_kcontrol *kctl,
> + int op_flag, unsigned int size,
> + unsigned int __user *tlv)
> +{
> + struct usb_mixer_elem_info *elem = kctl->private_data;
> + struct usb_mixer_interface *mixer = elem->head.mixer;
> + struct fcp_data *private = mixer->private_data;
> +
> + if (op_flag == SNDRV_CTL_TLV_OP_READ) {
> + if (private->meter_labels_size == 0)
> + return 0;
> +
> + if (size > private->meter_labels_size)
> + size = private->meter_labels_size;
> +
> + if (copy_to_user(tlv, private->meter_labels, size))
> + return -EFAULT;
> +
> + return size;
> + }
> +
> + if (op_flag == SNDRV_CTL_TLV_OP_WRITE) {
> + kfree(private->meter_labels);
> + private->meter_labels = NULL;
> + private->meter_labels_size = 0;
> +
> + if (size == 0)
> + return 0;
> +
> + if (size > 4096)
> + return -EINVAL;
> +
> + private->meter_labels = kmalloc(size, GFP_KERNEL);
> + if (!private->meter_labels)
> + return -ENOMEM;
> +
> + if (copy_from_user(private->meter_labels, tlv, size)) {
> + kfree(private->meter_labels);
> + private->meter_labels = NULL;
> + return -EFAULT;
> + }
> +
> + private->meter_labels_size = size;
> + return 0;
> + }
> +
> + return -EINVAL;
> +}
Hmm, this special is a special use of TLV in non-standard way, which
needs definitely documentation. The use is no longer TLV, just some
raw read/write of a bulk data for the kcontrol , after all.
Also, I couldn't figure out what exactly this "meter_labels" stuff
serves for. It's not referred from anywhere else than TLV read?
> +/* Execute an FCP command specified by the user */
> +static int fcp_ioctl_cmd(struct usb_mixer_interface *mixer, unsigned long arg)
> +{
> + struct fcp_cmd cmd;
> + int err, buf_size;
> + void *data __free(kfree) = NULL;
> +
> + /* get opcode and request/response size */
> + if (copy_from_user(&cmd, (void __user *)arg, sizeof(cmd)))
> + return -EFAULT;
You can avoid unneeded multiple cast. e.g. make a void * pointer in
the caller side cast from arg, then pass it to each function.
Each function may have an argument with the explicit type pointer,
here would be "struct fcp_cmd *arg". Then the rest can be just "arg"
here as the address, and...
> + /* copy request from user */
> + if (cmd.req_size > 0)
> + if (copy_from_user(data, ((void __user *)arg) + sizeof(cmd),
> + cmd.req_size))
"arg.data" here instead of the error-prone cast + offset.
thanks,
Takashi
next prev parent reply other threads:[~2025-01-13 17:03 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-12 17:10 [PATCH v5 0/2] ALSA: Add driver for big Scarlett 4th Gen interfaces Geoffrey D. Bennett
2025-01-12 17:10 ` [PATCH v5 1/2] ALSA: FCP: Add Focusrite Control Protocol driver Geoffrey D. Bennett
2025-01-13 17:02 ` Takashi Iwai [this message]
2025-01-13 17:14 ` Jaroslav Kysela
2025-01-12 17:10 ` [PATCH v5 2/2] ALSA: scarlett2: Add device_setup option to use FCP driver Geoffrey D. Bennett
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87plkq1wal.wl-tiwai@suse.de \
--to=tiwai@suse.de \
--cc=g@b4.vu \
--cc=linux-sound@vger.kernel.org \
--cc=tiwai@suse.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.