working usb negociation
networkmanager compatibility
This commit is contained in:
@@ -29,8 +29,7 @@ struct ch349_device {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct usb_device_id ch349_table[] = {
|
static const struct usb_device_id ch349_table[] = {
|
||||||
{ USB_DEVICE_AND_INTERFACE_INFO(CH349_VENDOR_ID, CH349_PRODUCT_ID,
|
{ USB_DEVICE(CH349_VENDOR_ID, CH349_PRODUCT_ID) },
|
||||||
USB_CLASS_CDC_DATA, 0, 0) },
|
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(usb, ch349_table);
|
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 ch349_device *dev = urb->context;
|
||||||
struct net_device *netdev = dev->netdev;
|
struct net_device *netdev = dev->netdev;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct ethhdr *eth;
|
|
||||||
int status = urb->status;
|
int status = urb->status;
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@@ -214,6 +213,7 @@ static int ch349_net_open(struct net_device *netdev)
|
|||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
netif_carrier_on(netdev);
|
||||||
netif_start_queue(netdev);
|
netif_start_queue(netdev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -225,18 +225,63 @@ static int ch349_net_stop(struct net_device *netdev)
|
|||||||
printk(KERN_INFO "ch349: Interface DOWN\n");
|
printk(KERN_INFO "ch349: Interface DOWN\n");
|
||||||
|
|
||||||
netif_stop_queue(netdev);
|
netif_stop_queue(netdev);
|
||||||
|
netif_carrier_off(netdev);
|
||||||
ch349_stop_rx(dev);
|
ch349_stop_rx(dev);
|
||||||
|
|
||||||
return 0;
|
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,
|
static netdev_tx_t ch349_start_xmit(struct sk_buff *skb,
|
||||||
struct net_device *netdev)
|
struct net_device *netdev)
|
||||||
{
|
{
|
||||||
// Pour l'instant, on drop juste les packets TX
|
struct ch349_device *dev = netdev_priv(netdev);
|
||||||
//printk(KERN_INFO "ch349: TX packet dropped (not implemented yet)\n");
|
struct urb *urb;
|
||||||
dev_kfree_skb(skb);
|
int retval;
|
||||||
netdev->stats.tx_dropped++;
|
|
||||||
|
// 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;
|
return NETDEV_TX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,6 +293,7 @@ static const struct net_device_ops ch349_netdev_ops = {
|
|||||||
.ndo_set_mac_address = eth_mac_addr,
|
.ndo_set_mac_address = eth_mac_addr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static int ch349_probe(struct usb_interface *interface,
|
static int ch349_probe(struct usb_interface *interface,
|
||||||
const struct usb_device_id *id)
|
const struct usb_device_id *id)
|
||||||
{
|
{
|
||||||
@@ -256,9 +302,39 @@ static int ch349_probe(struct usb_interface *interface,
|
|||||||
struct usb_endpoint_descriptor *endpoint;
|
struct usb_endpoint_descriptor *endpoint;
|
||||||
u8 mac[ETH_ALEN];
|
u8 mac[ETH_ALEN];
|
||||||
int i;
|
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
|
// Allouer net_device + notre structure
|
||||||
netdev = alloc_etherdev(sizeof(struct ch349_device));
|
netdev = alloc_etherdev(sizeof(struct ch349_device));
|
||||||
@@ -271,19 +347,25 @@ static int ch349_probe(struct usb_interface *interface,
|
|||||||
dev->netdev = netdev;
|
dev->netdev = netdev;
|
||||||
|
|
||||||
mutex_init(&dev->io_mutex);
|
mutex_init(&dev->io_mutex);
|
||||||
dev->udev = usb_get_dev(interface_to_usbdev(interface));
|
dev->udev = usb_get_dev(udev);
|
||||||
dev->interface = interface;
|
dev->interface = interface;
|
||||||
|
|
||||||
// Sélectionne l'altsetting 1
|
// In Config 2, Interface 1: switch to Alt Setting 1 to get bulk endpoints
|
||||||
retval = usb_set_interface(
|
if (config_val == 2 && intf_num == 1) {
|
||||||
dev->udev, interface->cur_altsetting->desc.bInterfaceNumber, 1);
|
retval = usb_set_interface(udev, intf_num, 1);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
dev_err(&interface->dev, "Cannot set altsetting 1: %d\n",
|
dev_err(&interface->dev,
|
||||||
retval);
|
"Cannot set altsetting 1: %d\n", retval);
|
||||||
goto error;
|
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++) {
|
for (i = 0; i < interface->cur_altsetting->desc.bNumEndpoints; i++) {
|
||||||
endpoint = &interface->cur_altsetting->endpoint[i].desc;
|
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)) {
|
if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
|
||||||
dev_err(&interface->dev,
|
dev_err(&interface->dev,
|
||||||
"Could not find both bulk-in and bulk-out endpoints\n");
|
"Could not find both bulk-in and bulk-out endpoints\n");
|
||||||
|
retval = -ENODEV;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,6 +423,8 @@ static int ch349_probe(struct usb_interface *interface,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netif_carrier_off(netdev);
|
||||||
|
|
||||||
dev_info(&interface->dev, "CH349 attached as %s (MAC: %pM)\n",
|
dev_info(&interface->dev, "CH349 attached as %s (MAC: %pM)\n",
|
||||||
netdev->name, mac);
|
netdev->name, mac);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user