diff --git a/src/ch349_driver.c b/src/ch349_driver.c index f426ac1..1e81f83 100644 --- a/src/ch349_driver.c +++ b/src/ch349_driver.c @@ -29,8 +29,7 @@ struct ch349_device { }; static const struct usb_device_id ch349_table[] = { - { USB_DEVICE_AND_INTERFACE_INFO(CH349_VENDOR_ID, CH349_PRODUCT_ID, - USB_CLASS_CDC_DATA, 0, 0) }, + { USB_DEVICE(CH349_VENDOR_ID, CH349_PRODUCT_ID) }, {} }; MODULE_DEVICE_TABLE(usb, ch349_table); @@ -99,7 +98,7 @@ static void ch349_read_callback(struct urb *urb) struct ch349_device *dev = urb->context; struct net_device *netdev = dev->netdev; struct sk_buff *skb; - struct ethhdr *eth; + int status = urb->status; switch (status) { @@ -214,6 +213,7 @@ static int ch349_net_open(struct net_device *netdev) if (retval) return retval; + netif_carrier_on(netdev); netif_start_queue(netdev); return 0; } @@ -225,18 +225,63 @@ static int ch349_net_stop(struct net_device *netdev) printk(KERN_INFO "ch349: Interface DOWN\n"); netif_stop_queue(netdev); + netif_carrier_off(netdev); ch349_stop_rx(dev); return 0; } +static void ch349_write_callback(struct urb *urb) +{ + struct sk_buff *skb = urb->context; + struct net_device *netdev = skb->dev; + + if (urb->status == 0) { + // Transmission réussie + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += skb->len; + } else { + netdev->stats.tx_errors++; + } + + // Libérer le skb et l'urb + dev_kfree_skb_any(skb); + usb_free_urb(urb); +} + static netdev_tx_t ch349_start_xmit(struct sk_buff *skb, struct net_device *netdev) { - // Pour l'instant, on drop juste les packets TX - //printk(KERN_INFO "ch349: TX packet dropped (not implemented yet)\n"); - dev_kfree_skb(skb); - netdev->stats.tx_dropped++; + struct ch349_device *dev = netdev_priv(netdev); + struct urb *urb; + int retval; + + // Allouer un URB pour l'envoi + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + dev_kfree_skb(skb); + netdev->stats.tx_dropped++; + return NETDEV_TX_OK; + } + + // Préparer l'URB (Bulk OUT) + usb_fill_bulk_urb(urb, dev->udev, + usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), + skb->data, skb->len, + ch349_write_callback, skb); + + // Soumettre l'URB + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) { + dev_err(&dev->interface->dev, "Failed to submit TX URB: %d\n", retval); + usb_free_urb(urb); + dev_kfree_skb(skb); + netdev->stats.tx_errors++; + } else { + // Arrêter la queue si on a trop d'URB en vol (simplification ici: on laisse couler) + // netif_stop_queue(netdev); + } + return NETDEV_TX_OK; } @@ -248,6 +293,7 @@ static const struct net_device_ops ch349_netdev_ops = { .ndo_set_mac_address = eth_mac_addr, }; + static int ch349_probe(struct usb_interface *interface, const struct usb_device_id *id) { @@ -256,9 +302,39 @@ static int ch349_probe(struct usb_interface *interface, struct usb_endpoint_descriptor *endpoint; u8 mac[ETH_ALEN]; int i; - int retval = -ENOMEM; + int retval = 0; + struct usb_device *udev = interface_to_usbdev(interface); + int config_val = udev->actconfig->desc.bConfigurationValue; + int intf_num = interface->cur_altsetting->desc.bInterfaceNumber; - dev_info(&interface->dev, "Probing CH349 device\n"); + + dev_info(&interface->dev, + "Probing CH349 device (config %d, interface %d)\n", + config_val, intf_num); + + /* + * This device exposes 3 USB configurations: + * Config 1: Vendor Specific - Interface 0 has bulk endpoints directly + * Config 2: CDC Ethernet - Interface 0 = CDC Comm (no bulk) + * Interface 1, Alt 1 = CDC Data (bulk endpoints) + * Config 3: CDC NCM + * + * We handle Config 1 and Config 2. In Config 2, we skip Interface 0 + * (CDC Comm) and only claim Interface 1 (CDC Data) with Alt Setting 1. + */ + + // Config 2: Skip Interface 0 (CDC Communications, no bulk endpoints) + if (config_val == 2 && intf_num == 0) { + dev_info(&interface->dev, + "Skipping CDC Comm interface (no bulk endpoints)\n"); + return -ENODEV; + } + + // Config 3: Not supported for now + if (config_val == 3) { + dev_info(&interface->dev, "Config 3 (NCM) not supported\n"); + return -ENODEV; + } // Allouer net_device + notre structure netdev = alloc_etherdev(sizeof(struct ch349_device)); @@ -271,19 +347,25 @@ static int ch349_probe(struct usb_interface *interface, dev->netdev = netdev; mutex_init(&dev->io_mutex); - dev->udev = usb_get_dev(interface_to_usbdev(interface)); + dev->udev = usb_get_dev(udev); dev->interface = interface; - // Sélectionne l'altsetting 1 - retval = usb_set_interface( - dev->udev, interface->cur_altsetting->desc.bInterfaceNumber, 1); - if (retval) { - dev_err(&interface->dev, "Cannot set altsetting 1: %d\n", - retval); - goto error; + // In Config 2, Interface 1: switch to Alt Setting 1 to get bulk endpoints + if (config_val == 2 && intf_num == 1) { + retval = usb_set_interface(udev, intf_num, 1); + if (retval) { + dev_err(&interface->dev, + "Cannot set altsetting 1: %d\n", retval); + goto error; + } + dev_info(&interface->dev, + "Switched to altsetting 1 for CDC Data\n"); } - dev_info(&interface->dev, "Interface obtained\n"); + dev_info(&interface->dev, "Interface %d obtained (altsetting %d)\n", + intf_num, + interface->cur_altsetting->desc.bAlternateSetting); + for (i = 0; i < interface->cur_altsetting->desc.bNumEndpoints; i++) { endpoint = &interface->cur_altsetting->endpoint[i].desc; @@ -319,6 +401,7 @@ static int ch349_probe(struct usb_interface *interface, if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { dev_err(&interface->dev, "Could not find both bulk-in and bulk-out endpoints\n"); + retval = -ENODEV; goto error; } @@ -340,6 +423,8 @@ static int ch349_probe(struct usb_interface *interface, goto error; } + netif_carrier_off(netdev); + dev_info(&interface->dev, "CH349 attached as %s (MAC: %pM)\n", netdev->name, mac);