Re: [PATCH 2/2] can: esd_usb: Add support for esd CAN-USB/3

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Frank,

Thank you for your patch. Here is my first batch of comments.

Some comments also apply to the existing code. So you may want to
address those in separate clean-up patches first.

On Fri. 5 May 2023 at 01:16, Frank Jungclaus <frank.jungclaus@xxxxxx> wrote:
> Add support for esd CAN-USB/3 and CAN FD to esd_usb.
>
> Signed-off-by: Frank Jungclaus <frank.jungclaus@xxxxxx>
> ---
>  drivers/net/can/usb/esd_usb.c | 282 ++++++++++++++++++++++++++++++----
>  1 file changed, 249 insertions(+), 33 deletions(-)
>
> diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c
> index e24fa48b9b42..48cf5e88d216 100644
> --- a/drivers/net/can/usb/esd_usb.c
> +++ b/drivers/net/can/usb/esd_usb.c
> @@ -1,6 +1,6 @@
>  // SPDX-License-Identifier: GPL-2.0-only
>  /*
> - * CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Micro
> + * CAN driver for esd electronics gmbh CAN-USB/2, CAN-USB/3 and CAN-USB/Micro
>   *
>   * Copyright (C) 2010-2012 esd electronic system design gmbh, Matthias Fuchs <socketcan@xxxxxx>
>   * Copyright (C) 2022-2023 esd electronics gmbh, Frank Jungclaus <frank.jungclaus@xxxxxx>
> @@ -18,17 +18,19 @@
>
>  MODULE_AUTHOR("Matthias Fuchs <socketcan@xxxxxx>");
>  MODULE_AUTHOR("Frank Jungclaus <frank.jungclaus@xxxxxx>");
> -MODULE_DESCRIPTION("CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Micro interfaces");
> +MODULE_DESCRIPTION("CAN driver for esd electronics gmbh CAN-USB/2, CAN-USB/3 and CAN-USB/Micro interfaces");
>  MODULE_LICENSE("GPL v2");
>
>  /* USB vendor and product ID */
>  #define USB_ESDGMBH_VENDOR_ID  0x0ab4
>  #define USB_CANUSB2_PRODUCT_ID 0x0010
>  #define USB_CANUSBM_PRODUCT_ID 0x0011
> +#define USB_CANUSB3_PRODUCT_ID 0x0014
>
>  /* CAN controller clock frequencies */
>  #define ESD_USB2_CAN_CLOCK     60000000
>  #define ESD_USBM_CAN_CLOCK     36000000
> +#define ESD_USB3_CAN_CLOCK     80000000

Nitpick: consider using the unit suffixes from linux/units.h:

  #define ESD_USB3_CAN_CLOCK (80 * MEGA)

>  /* Maximum number of CAN nets */
>  #define ESD_USB_MAX_NETS       2
> @@ -43,6 +45,9 @@ MODULE_LICENSE("GPL v2");
>
>  /* esd CAN message flags - dlc field */
>  #define ESD_DLC_RTR            0x10
> +#define ESD_DLC_NO_BRS         0x10
> +#define ESD_DLC_ESI            0x20
> +#define ESD_DLC_FD             0x80

Use the BIT() macro:

#define ESD_DLC_NO_BRS BIT(4)
#define ESD_DLC_ESI BIT(5)
#define ESD_DLC_FD BIT(7)

Also, if this is specific to the ESD_USB3 then add it in the prefix.

>  /* esd CAN message flags - id field */
>  #define ESD_EXTID              0x20000000
> @@ -72,6 +77,28 @@ MODULE_LICENSE("GPL v2");
>  #define ESD_USB2_BRP_INC       1
>  #define ESD_USB2_3_SAMPLES     0x00800000
>
> +/* Bit timing CAN-USB/3 */
> +#define ESD_USB3_TSEG1_MIN     1
> +#define ESD_USB3_TSEG1_MAX     256
> +#define ESD_USB3_TSEG2_MIN     1
> +#define ESD_USB3_TSEG2_MAX     128
> +#define ESD_USB3_SJW_MAX       128
> +#define ESD_USB3_BRP_MIN       1
> +#define ESD_USB3_BRP_MAX       1024
> +#define ESD_USB3_BRP_INC       1
> +/* Bit timing CAN-USB/3, data phase */
> +#define ESD_USB3_DATA_TSEG1_MIN        1
> +#define ESD_USB3_DATA_TSEG1_MAX        32
> +#define ESD_USB3_DATA_TSEG2_MIN        1
> +#define ESD_USB3_DATA_TSEG2_MAX        16
> +#define ESD_USB3_DATA_SJW_MAX  8
> +#define ESD_USB3_DATA_BRP_MIN  1
> +#define ESD_USB3_DATA_BRP_MAX  32
> +#define ESD_USB3_DATA_BRP_INC  1

There is no clear benefit to define macros for some initializers of a
const struct.

Doing as below has zero ambiguity:

static const struct can_bittiming_const esd_usb3_bittiming_const = {
         .name = "esd_usb3",
         .tseg1_min = 1,
         .tseg1_max = 256,
         .tseg2_min = 1,
         .tseg2_max = 128,
         .sjw_max = 128,
         .brp_min = 1,
         .brp_max = 1024,
         .brp_inc = 1,
};

> +/* Transmitter Delay Compensation */
> +#define ESD_TDC_MODE_AUTO      0
> +
>  /* esd IDADD message */
>  #define ESD_ID_ENABLE          0x80
>  #define ESD_MAX_ID_SEGMENT     64
> @@ -95,6 +122,21 @@ MODULE_LICENSE("GPL v2");
>  #define MAX_RX_URBS            4
>  #define MAX_TX_URBS            16 /* must be power of 2 */
>
> +/* Modes for NTCAN_BAUDRATE_X */
> +#define ESD_BAUDRATE_MODE_DISABLE      0 /* remove from bus */
> +#define ESD_BAUDRATE_MODE_INDEX                1 /* ESD (CiA) bit rate idx */
> +#define ESD_BAUDRATE_MODE_BTR_CTRL     2 /* BTR values (Controller)*/
> +#define ESD_BAUDRATE_MODE_BTR_CANONICAL        3 /* BTR values (Canonical) */
> +#define ESD_BAUDRATE_MODE_NUM          4 /* numerical bit rate */
> +#define ESD_BAUDRATE_MODE_AUTOBAUD     5 /* autobaud */
> +
> +/* Flags for NTCAN_BAUDRATE_X */
> +#define ESD_BAUDRATE_FLAG_FD   0x0001 /* enable CAN FD Mode */
> +#define ESD_BAUDRATE_FLAG_LOM  0x0002 /* enable Listen Only mode */
> +#define ESD_BAUDRATE_FLAG_STM  0x0004 /* enable Self test mode */
> +#define ESD_BAUDRATE_FLAG_TRS  0x0008 /* enable Triple Sampling */
> +#define ESD_BAUDRATE_FLAG_TXP  0x0010 /* enable Transmit Pause */
> +
>  struct header_msg {
>         u8 len; /* len is always the total message length in 32bit words */
>         u8 cmd;
> @@ -129,6 +171,7 @@ struct rx_msg {
>         __le32 id; /* upper 3 bits contain flags */
>         union {
>                 u8 data[8];
> +               u8 data_fd[64];
>                 struct {
>                         u8 status; /* CAN Controller Status */
>                         u8 ecc;    /* Error Capture Register */
> @@ -144,8 +187,11 @@ struct tx_msg {
>         u8 net;
>         u8 dlc;
>         u32 hnd;        /* opaque handle, not used by device */
> -       __le32 id; /* upper 3 bits contain flags */
> -       u8 data[8];
> +       __le32 id;      /* upper 3 bits contain flags */
> +       union {
> +               u8 data[8];
> +               u8 data_fd[64];

Nitpick, use the macro:

                  u8 data[CAN_MAX_DLEN];
                  u8 data_fd[CANFD_MAX_DLEN];

> +       };
>  };
>
>  struct tx_done_msg {
> @@ -165,12 +211,37 @@ struct id_filter_msg {
>         __le32 mask[ESD_MAX_ID_SEGMENT + 1];
>  };
>
> +struct baudrate_x_cfg {
> +       __le16 brp;     /* bit rate pre-scaler */
> +       __le16 tseg1;   /* TSEG1 register */
> +       __le16 tseg2;   /* TSEG2 register */
> +       __le16 sjw;     /* SJW register */
> +};
> +
> +struct tdc_cfg {

Please prefix all the structures with the device name. e.g.

  struct esd_usb3_tdc_cfg {

> +       u8 tdc_mode;    /* transmitter Delay Compensation mode  */
> +       u8 ssp_offset;  /* secondary Sample Point offset in mtq */
> +       s8 ssp_shift;   /* secondary Sample Point shift in mtq */
> +       u8 tdc_filter;  /* Transmitter Delay Compensation */
> +};
> +
> +struct baudrate_x {

The x in baudrate_x and baudrate_x_cfg is confusing me. Is it meant to
signify that the structure applies to both nominal and data baudrate?
In that case, just put a comment and remove the x from the name.

> +       __le16 mode;    /* mode word */
> +       __le16 flags;   /* control flags */
> +       struct tdc_cfg tdc;     /* TDC configuration */
> +       struct baudrate_x_cfg arb;      /* bit rate during arbitration phase  */

/* nominal bit rate */

The comment is incorrect. CAN-FD may use the nominal bitrate for the
data phase if the bit rate switch (BRS) is not set.

> +       struct baudrate_x_cfg data;     /* bit rate during data phase */

/* data bit rate */

Please adjust the field names accordingly.

> +};
> +
>  struct set_baudrate_msg {
>         u8 len;
>         u8 cmd;
>         u8 net;
>         u8 rsvd;
> -       __le32 baud;
> +       union {
> +               __le32 baud;
> +               struct baudrate_x baud_x;
> +       };
>  };
>
>  /* Main message type used between library and application */
> @@ -188,6 +259,7 @@ union __packed esd_usb_msg {
>  static struct usb_device_id esd_usb_table[] = {
>         {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB2_PRODUCT_ID)},
>         {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSBM_PRODUCT_ID)},
> +       {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB3_PRODUCT_ID)},
>         {}
>  };
>  MODULE_DEVICE_TABLE(usb, esd_usb_table);
> @@ -326,11 +398,13 @@ static void esd_usb_rx_event(struct esd_usb_net_priv *priv,
>  static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv,
>                                union esd_usb_msg *msg)
>  {
> +       bool is_canfd = msg->rx.dlc & ESD_DLC_FD ? true : false;

This is redundant. Just this is enough:

  bool is_canfd = msg->rx.dlc & ESD_DLC_FD;

This variable being used only twice, you may want to consider not
declaring it and simply doing directly:

          if (msg->rx.dlc & ESD_DLC_FD)

>         struct net_device_stats *stats = &priv->netdev->stats;
>         struct can_frame *cf;
> +       struct canfd_frame *cfd;
>         struct sk_buff *skb;
> -       int i;
>         u32 id;
> +       u8 len;
>
>         if (!netif_device_present(priv->netdev))
>                 return;
> @@ -340,27 +414,42 @@ static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv,
>         if (id & ESD_EVENT) {
>                 esd_usb_rx_event(priv, msg);
>         } else {
> -               skb = alloc_can_skb(priv->netdev, &cf);
> +               if (is_canfd) {
> +                       skb = alloc_canfd_skb(priv->netdev, &cfd);
> +               } else {
> +                       skb = alloc_can_skb(priv->netdev, &cf);
> +                       cfd = (struct canfd_frame *)cf;
> +               }
> +
>                 if (skb == NULL) {
>                         stats->rx_dropped++;
>                         return;
>                 }
>
> -               cf->can_id = id & ESD_IDMASK;
> -               can_frame_set_cc_len(cf, msg->rx.dlc & ~ESD_DLC_RTR,
> -                                    priv->can.ctrlmode);
> -
> -               if (id & ESD_EXTID)
> -                       cf->can_id |= CAN_EFF_FLAG;
> +               cfd->can_id = id & ESD_IDMASK;
>
> -               if (msg->rx.dlc & ESD_DLC_RTR) {
> -                       cf->can_id |= CAN_RTR_FLAG;
> +               if (is_canfd) {
> +                       /* masking by 0x0F is already done within can_fd_dlc2len() */
> +                       cfd->len = can_fd_dlc2len(msg->rx.dlc);
> +                       len = cfd->len;
> +                       if ((msg->rx.dlc & ESD_DLC_NO_BRS) == 0)
> +                               cfd->flags |= CANFD_BRS;
> +                       if (msg->rx.dlc & ESD_DLC_ESI)
> +                               cfd->flags |= CANFD_ESI;
>                 } else {
> -                       for (i = 0; i < cf->len; i++)
> -                               cf->data[i] = msg->rx.data[i];
> -
> -                       stats->rx_bytes += cf->len;
> +                       can_frame_set_cc_len(cf, msg->rx.dlc & ~ESD_DLC_RTR, priv->can.ctrlmode);
> +                       len = cf->len;
> +                       if (msg->rx.dlc & ESD_DLC_RTR) {
> +                               cf->can_id |= CAN_RTR_FLAG;
> +                               len = 0;
> +                       }
>                 }
> +
> +               if (id & ESD_EXTID)
> +                       cfd->can_id |= CAN_EFF_FLAG;
> +
> +               memcpy(cfd->data, msg->rx.data_fd, len);
> +               stats->rx_bytes += len;
>                 stats->rx_packets++;
>
>                 netif_rx(skb);
> @@ -735,7 +824,7 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb,
>         struct esd_usb *dev = priv->usb;
>         struct esd_tx_urb_context *context = NULL;
>         struct net_device_stats *stats = &netdev->stats;
> -       struct can_frame *cf = (struct can_frame *)skb->data;
> +       struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
>         union esd_usb_msg *msg;
>         struct urb *urb;
>         u8 *buf;
> @@ -768,19 +857,28 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb,
>         msg->hdr.len = 3; /* minimal length */
>         msg->hdr.cmd = CMD_CAN_TX;
>         msg->tx.net = priv->index;
> -       msg->tx.dlc = can_get_cc_dlc(cf, priv->can.ctrlmode);
> -       msg->tx.id = cpu_to_le32(cf->can_id & CAN_ERR_MASK);
>
> -       if (cf->can_id & CAN_RTR_FLAG)
> -               msg->tx.dlc |= ESD_DLC_RTR;
> +       if (can_is_canfd_skb(skb)) {
> +               msg->tx.dlc = can_fd_len2dlc(cfd->len);
> +               msg->tx.dlc |= ESD_DLC_FD;
> +
> +               if ((cfd->flags & CANFD_BRS) == 0)
> +                       msg->tx.dlc |= ESD_DLC_NO_BRS;
> +       } else {
> +               msg->tx.dlc = can_get_cc_dlc((struct can_frame *)cfd, priv->can.ctrlmode);
> +
> +               if (cfd->can_id & CAN_RTR_FLAG)
> +                       msg->tx.dlc |= ESD_DLC_RTR;
> +       }
>
> -       if (cf->can_id & CAN_EFF_FLAG)
> +       msg->tx.id = cpu_to_le32(cfd->can_id & CAN_ERR_MASK);
> +
> +       if (cfd->can_id & CAN_EFF_FLAG)
>                 msg->tx.id |= cpu_to_le32(ESD_EXTID);
>
> -       for (i = 0; i < cf->len; i++)
> -               msg->tx.data[i] = cf->data[i];
> +       memcpy(msg->tx.data_fd, cfd->data, cfd->len);
>
> -       msg->hdr.len += (cf->len + 3) >> 2;
> +       msg->hdr.len += (cfd->len + 3) >> 2;

I do not get the logic.

Assuming cfd->len is 8. Then

  hdr.len += (8 + 3) >> 2
  hdr.len += 2

And because hdr.len is initially 3, hdr.len becomes 5. Right? Shouldn't it be 8?

>         for (i = 0; i < MAX_TX_URBS; i++) {
>                 if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
> @@ -966,6 +1064,108 @@ static int esd_usb2_set_bittiming(struct net_device *netdev)
>         return err;
>  }
>
> +static const struct can_bittiming_const esd_usb3_bittiming_const = {
> +       .name = "esd_usb3",
> +       .tseg1_min = ESD_USB3_TSEG1_MIN,
> +       .tseg1_max = ESD_USB3_TSEG1_MAX,
> +       .tseg2_min = ESD_USB3_TSEG2_MIN,
> +       .tseg2_max = ESD_USB3_TSEG2_MAX,
> +       .sjw_max = ESD_USB3_SJW_MAX,
> +       .brp_min = ESD_USB3_BRP_MIN,
> +       .brp_max = ESD_USB3_BRP_MAX,
> +       .brp_inc = ESD_USB3_BRP_INC,
> +};
> +
> +static const struct can_bittiming_const esd_usb3_data_bittiming_const = {
> +       .name = "esd_usb3",
> +       .tseg1_min = ESD_USB3_DATA_TSEG1_MIN,
> +       .tseg1_max = ESD_USB3_DATA_TSEG1_MAX,
> +       .tseg2_min = ESD_USB3_DATA_TSEG2_MIN,
> +       .tseg2_max = ESD_USB3_DATA_TSEG2_MAX,
> +       .sjw_max = ESD_USB3_DATA_SJW_MAX,
> +       .brp_min = ESD_USB3_DATA_BRP_MIN,
> +       .brp_max = ESD_USB3_DATA_BRP_MAX,
> +       .brp_inc = ESD_USB3_DATA_BRP_INC,
> +};
> +
> +static int esd_usb3_set_bittiming(struct net_device *netdev)
> +{
> +       struct esd_usb_net_priv *priv = netdev_priv(netdev);
> +       struct can_bittiming *bt   = &priv->can.bittiming;
> +       struct can_bittiming *d_bt = &priv->can.data_bittiming;
> +       union esd_usb_msg *msg;
> +       int err;
> +       u16 mode;
> +       u16 flags = 0;
> +       u16 brp, tseg1, tseg2, sjw;
> +       u16 d_brp, d_tseg1, d_tseg2, d_sjw;
> +
> +       msg = kmalloc(sizeof(*msg), GFP_KERNEL);
> +       if (!msg)
> +               return -ENOMEM;
> +
> +       /* Canonical is the most reasonable mode for SocketCAN on CAN-USB/3 ... */
> +       mode = ESD_BAUDRATE_MODE_BTR_CANONICAL;
> +
> +       if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
> +               flags |= ESD_BAUDRATE_FLAG_LOM;
> +
> +       if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
> +               flags |= ESD_BAUDRATE_FLAG_TRS;
> +
> +       brp = bt->brp & (ESD_USB3_BRP_MAX - 1);
> +       sjw = bt->sjw & (ESD_USB3_SJW_MAX - 1);
> +       tseg1 = (bt->prop_seg + bt->phase_seg1) & (ESD_USB3_TSEG1_MAX - 1);
> +       tseg2 = bt->phase_seg2 & (ESD_USB3_TSEG2_MAX - 1);

I am not convinced by the use of these intermediate variables brp,
sjw, tseg1 and tseg2. I think you can directly assign them to baud_x.

> +       msg->setbaud.baud_x.arb.brp = cpu_to_le16(brp);
> +       msg->setbaud.baud_x.arb.sjw = cpu_to_le16(sjw);
> +       msg->setbaud.baud_x.arb.tseg1 = cpu_to_le16(tseg1);
> +       msg->setbaud.baud_x.arb.tseg2 = cpu_to_le16(tseg2);

You may want to declare a local variable

  struct baudrate_x *baud_x = &msg->setbaud.baud_x;

so that you do not have to do msg->setbaud.baud_x each time.

> +       if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
> +               d_brp = d_bt->brp & (ESD_USB3_DATA_BRP_MAX - 1);
> +               d_sjw = d_bt->sjw & (ESD_USB3_DATA_SJW_MAX - 1);
> +               d_tseg1 = (d_bt->prop_seg + d_bt->phase_seg1) & (ESD_USB3_DATA_TSEG1_MAX - 1);
> +               d_tseg2 = d_bt->phase_seg2 & (ESD_USB3_DATA_TSEG2_MAX - 1);
> +               flags |= ESD_BAUDRATE_FLAG_FD;
> +       } else {
> +               d_brp = 0;
> +               d_sjw = 0;
> +               d_tseg1 = 0;
> +               d_tseg2 = 0;
> +       }
> +
> +       msg->setbaud.baud_x.data.brp = cpu_to_le16(d_brp);
> +       msg->setbaud.baud_x.data.sjw = cpu_to_le16(d_sjw);
> +       msg->setbaud.baud_x.data.tseg1 = cpu_to_le16(d_tseg1);
> +       msg->setbaud.baud_x.data.tseg2 = cpu_to_le16(d_tseg2);
> +       msg->setbaud.baud_x.mode = cpu_to_le16(mode);
> +       msg->setbaud.baud_x.flags = cpu_to_le16(flags);
> +       msg->setbaud.baud_x.tdc.tdc_mode = ESD_TDC_MODE_AUTO;
> +       msg->setbaud.baud_x.tdc.ssp_offset = 0;
> +       msg->setbaud.baud_x.tdc.ssp_shift = 0;
> +       msg->setbaud.baud_x.tdc.tdc_filter = 0;

It seems that your device supports TDC. What is the reason to not configure it?

Please have a look at struct can_tdc:

  https://elixir.bootlin.com/linux/v6.2/source/include/linux/can/bittiming.h#L21

Please refer to this patch if you want an example of how to use TDC:

  https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1010a8fa9608

> +       msg->hdr.len = 7;

What is this magic number? If possible, replace it with a sizeof().

It seems that this relates to the size of struct set_baudrate_msg, but
that structure is 8 bytes. Is the last byte of struct set_baudrate_msg
really used? If not, reflect this in the declaration of the structure.

> +       msg->hdr.cmd = CMD_SETBAUD;
> +
> +       msg->setbaud.net = priv->index;
> +       msg->setbaud.rsvd = 0;
> +
> +       netdev_info(netdev,
> +                   "ctrlmode=%#x/%#x, esd-net=%u, esd-mode=%#x, esd-flg=%#x, arb: brp=%u, ts1=%u, ts2=%u, sjw=%u, data: dbrp=%u, dts1=%u, dts2=%u dsjw=%u\n",
> +                   priv->can.ctrlmode, priv->can.ctrlmode_supported,
> +                   priv->index, mode, flags,
> +                   brp, tseg1, tseg2, sjw,
> +                   d_brp, d_tseg1, d_tseg2, d_sjw);

Remove this debug message. The bittiming information can be retrieved
with the ip tool.

  ip --details link show canX

> +       err = esd_usb_send_msg(priv->usb, msg);
> +
> +       kfree(msg);

esd_usb_send_msg() uses usb_bulk_msg() which does a synchronous call.
It would be great to go asynchronous and use usb_submit_urb() so that
you minimize the time spent in the driver.

I know that  esd_usb2_set_bittiming() also uses the synchronous call,
so I am fine to have it as-is for this patch but for the future, it
would be great to consider refactoring this.

> +       return err;
> +}
> +
>  static int esd_usb_get_berr_counter(const struct net_device *netdev,
>                                     struct can_berr_counter *bec)
>  {
> @@ -1023,16 +1223,32 @@ static int esd_usb_probe_one_net(struct usb_interface *intf, int index)
>                 CAN_CTRLMODE_CC_LEN8_DLC |
>                 CAN_CTRLMODE_BERR_REPORTING;
>
> -       if (le16_to_cpu(dev->udev->descriptor.idProduct) ==
> -           USB_CANUSBM_PRODUCT_ID)
> +       switch (le16_to_cpu(dev->udev->descriptor.idProduct)) {

Instead of doing a switch on idProduct, you can use the driver_info
field from struct usb_device_id to store the device quirks.

You can pass either a pointer or some flags into driver_info. Examples:

  https://elixir.bootlin.com/linux/v6.2/source/drivers/net/can/usb/peak_usb/pcan_usb_core.c#L30
  https://elixir.bootlin.com/linux/v6.2/source/drivers/net/can/usb/etas_es58x/es58x_core.c#L37

> +       case USB_CANUSB3_PRODUCT_ID:
> +               priv->can.clock.freq = ESD_USB3_CAN_CLOCK;
> +               priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
> +               priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD;
> +               priv->can.bittiming_const = &esd_usb3_bittiming_const;
> +               priv->can.data_bittiming_const = &esd_usb3_data_bittiming_const;
> +               priv->can.do_set_bittiming = esd_usb3_set_bittiming;
> +               priv->can.do_set_data_bittiming = esd_usb3_set_bittiming;
> +               break;
> +
> +       case USB_CANUSBM_PRODUCT_ID:
>                 priv->can.clock.freq = ESD_USBM_CAN_CLOCK;
> -       else {
> +               priv->can.bittiming_const = &esd_usb2_bittiming_const;
> +               priv->can.do_set_bittiming = esd_usb2_set_bittiming;
> +               break;
> +
> +       case USB_CANUSB2_PRODUCT_ID:
> +       default:
>                 priv->can.clock.freq = ESD_USB2_CAN_CLOCK;
>                 priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
> +               priv->can.bittiming_const = &esd_usb2_bittiming_const;
> +               priv->can.do_set_bittiming = esd_usb2_set_bittiming;
> +               break;
>         }
>
> -       priv->can.bittiming_const = &esd_usb2_bittiming_const;
> -       priv->can.do_set_bittiming = esd_usb2_set_bittiming;
>         priv->can.do_set_mode = esd_usb_set_mode;
>         priv->can.do_get_berr_counter = esd_usb_get_berr_counter;
>
> --
> 2.25.1
>



[Index of Archives]     [Automotive Discussions]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]     [CAN Bus]

  Powered by Linux