Hi Christophe Thank you for your comments, I will update the code in the next patch. Best regards, Ming Christophe JAILLET <christophe.jaillet@xxxxxxxxxx> 於 2024年10月26日 週六 下午10:58寫道: > > Le 24/10/2024 à 10:59, Ming Yu a écrit : > > The Nuvoton NCT6694 is a peripheral expander with 16 GPIO chips, > > 6 I2C controllers, 2 CANfd controllers, 2 Watchdog timers, ADC, > > PWM, and RTC. > > > > This driver implements USB device functionality and shares the > > chip's peripherals as a child device. > > > > Each child device can use the USB functions nct6694_read_msg() > > and nct6694_write_msg() to issue a command. They can also register > > a handler function that will be called when the USB device receives > > its interrupt pipe. > > > > Signed-off-by: Ming Yu <tmyu0-KrzQf0k3Iz9BDgjK7y7TUQ@xxxxxxxxxxxxxxxx> > > --- > > ... > > > +static int nct6694_usb_probe(struct usb_interface *iface, > > + const struct usb_device_id *id) > > +{ > > + struct usb_device *udev = interface_to_usbdev(iface); > > + struct device *dev = &udev->dev; > > + struct usb_host_interface *interface; > > + struct usb_endpoint_descriptor *int_endpoint; > > + struct nct6694 *nct6694; > > + int pipe, maxp, bulk_pipe; > > + int ret = EINVAL; > > Nitpick: no need to init > > > + > > + interface = iface->cur_altsetting; > > + /* Binding interface class : 0xFF */ > > + if (interface->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC || > > + interface->desc.bInterfaceSubClass != 0x00 || > > + interface->desc.bInterfaceProtocol != 0x00) > > + return -ENODEV; > > + > > + int_endpoint = &interface->endpoint[0].desc; > > + if (!usb_endpoint_is_int_in(int_endpoint)) > > + return -ENODEV; > > + > > + nct6694 = devm_kzalloc(&udev->dev, sizeof(*nct6694), GFP_KERNEL); > > + if (!nct6694) > > + return -ENOMEM; > > + > > + pipe = usb_rcvintpipe(udev, INT_IN_ENDPOINT); > > + maxp = usb_maxpacket(udev, pipe); > > + > > + nct6694->cmd_buffer = devm_kcalloc(dev, CMD_PACKET_SZ, > > + sizeof(unsigned char), GFP_KERNEL); > > + if (!nct6694->cmd_buffer) > > + return -ENOMEM; > > + nct6694->rx_buffer = devm_kcalloc(dev, MAX_PACKET_SZ, > > + sizeof(unsigned char), GFP_KERNEL); > > + if (!nct6694->rx_buffer) > > + return -ENOMEM; > > + nct6694->tx_buffer = devm_kcalloc(dev, MAX_PACKET_SZ, > > + sizeof(unsigned char), GFP_KERNEL); > > + if (!nct6694->tx_buffer) > > + return -ENOMEM; > > + nct6694->int_buffer = devm_kcalloc(dev, MAX_PACKET_SZ, > > + sizeof(unsigned char), GFP_KERNEL); > > + if (!nct6694->int_buffer) > > + return -ENOMEM; > > + > > + nct6694->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); > > + if (!nct6694->int_in_urb) { > > + dev_err(&udev->dev, "Failed to allocate INT-in urb!\n"); > > + return -ENOMEM; > > + } > > + > > + /* Bulk pipe maximum packet for each transaction */ > > + bulk_pipe = usb_sndbulkpipe(udev, BULK_OUT_ENDPOINT); > > + nct6694->maxp = usb_maxpacket(udev, bulk_pipe); > > + > > + mutex_init(&nct6694->access_lock); > > + nct6694->udev = udev; > > + nct6694->timeout = URB_TIMEOUT; /* Wait until urb complete */ > > + > > + INIT_LIST_HEAD(&nct6694->handler_list); > > + spin_lock_init(&nct6694->lock); > > + > > + usb_fill_int_urb(nct6694->int_in_urb, udev, pipe, > > + nct6694->int_buffer, maxp, usb_int_callback, > > + nct6694, int_endpoint->bInterval); > > + ret = usb_submit_urb(nct6694->int_in_urb, GFP_KERNEL); > > + if (ret) > > + goto err_urb; > > + > > + dev_set_drvdata(&udev->dev, nct6694); > > + usb_set_intfdata(iface, nct6694); > > + > > + ret = mfd_add_hotplug_devices(&udev->dev, nct6694_dev, > > + ARRAY_SIZE(nct6694_dev)); > > + if (ret) { > > + dev_err(&udev->dev, "Failed to add mfd's child device\n"); > > + goto err_mfd; > > + } > > + > > + nct6694->async_workqueue = alloc_ordered_workqueue("asyn_workqueue", 0); > > Missing error handling. > > > + > > + dev_info(&udev->dev, "Probed device: (%04X:%04X)\n", > > + id->idVendor, id->idProduct); > > + return 0; > > + > > +err_mfd: > > + usb_kill_urb(nct6694->int_in_urb); > > +err_urb: > > + usb_free_urb(nct6694->int_in_urb); > > + return ret; > > +} > > + > > +static void nct6694_usb_disconnect(struct usb_interface *iface) > > +{ > > + struct usb_device *udev = interface_to_usbdev(iface); > > + struct nct6694 *nct6694 = usb_get_intfdata(iface); > > + > > + mfd_remove_devices(&udev->dev); > > + flush_workqueue(nct6694->async_workqueue); > > + destroy_workqueue(nct6694->async_workqueue); > > + usb_set_intfdata(iface, NULL); > > + usb_kill_urb(nct6694->int_in_urb); > > + usb_free_urb(nct6694->int_in_urb); > > +} > > + > > +static const struct usb_device_id nct6694_ids[] = { > > + { USB_DEVICE(NCT6694_VENDOR_ID, NCT6694_PRODUCT_ID)}, > > Nitpick: space missing before the ending } > > > + {}, > > Nitpick: usually, no comma is added after a {} terminator. > > > +}; > > +MODULE_DEVICE_TABLE(usb, nct6694_ids); > > ... > > CJ