diff --git a/usb/usb_can/Makefile b/usb/usb_can/Makefile new file mode 100644 index 0000000..0636b3d --- /dev/null +++ b/usb/usb_can/Makefile @@ -0,0 +1,12 @@ +ARCH ?= arm +CROSS_COMPILE ?= /home/jzh/work/study/weidongshan/100ask_stm32mp157_pro-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/arm-linux- +KERN_DIR ?= /home/jzh/work/study/weidongshan/100ask_stm32mp157_pro-sdk/Linux-5.4 + +all: + make -C $(KERN_DIR) M=`pwd` ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules + +clean: + make -C $(KERN_DIR) M=`pwd` ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules clean + rm -rf modules.order + +obj-m += usb_can.o diff --git a/usb/usb_can/usb_can.c b/usb/usb_can/usb_can.c new file mode 100644 index 0000000..5691720 --- /dev/null +++ b/usb/usb_can/usb_can.c @@ -0,0 +1,188 @@ +#include +#include +#include +#include +#include +#include + +#define USB_CAN_VENDOR 0xffff +#define USB_CAN_PRODUCT 0xffff + +struct usb_can_priv { + struct can_priv can; + struct usb_device *udev; + struct usb_interface *intf; + + struct net_device *netdev; + + u8 ep_in; + u8 ep_out; + + struct urb *rx_urb; + u8 *rx_buf; +}; + +static void usb_can_rx_callback(struct urb *urb) +{ + struct usb_can_priv *priv = urb->context; + struct net_device *netdev = priv->netdev; + struct sk_buff *skb; + struct can_frame *cf; + + if (urb->status) + return; + + skb = alloc_can_skb(netdev, &cf); + if (!skb) + goto resubmit; + + memcpy(cf, urb->transfer_buffer, sizeof(struct can_frame)); + + netif_rx(skb); + +resubmit: + usb_submit_urb(urb, GFP_ATOMIC); +} + +static int usb_can_open(struct net_device *netdev) +{ + struct usb_can_priv *priv = netdev_priv(netdev); + + priv->rx_urb = usb_alloc_urb(0, GFP_KERNEL); + priv->rx_buf = kmalloc(64, GFP_KERNEL); + + usb_fill_bulk_urb(priv->rx_urb, + priv->udev, + usb_rcvbulkpipe(priv->udev, priv->ep_in), + priv->rx_buf, + 64, + usb_can_rx_callback, + priv); + + usb_submit_urb(priv->rx_urb, GFP_KERNEL); + + netif_start_queue(netdev); + + return 0; +} + +static int usb_can_stop(struct net_device *netdev) +{ + struct usb_can_priv *priv = netdev_priv(netdev); + + netif_stop_queue(netdev); + + usb_kill_urb(priv->rx_urb); + + usb_free_urb(priv->rx_urb); + kfree(priv->rx_buf); + + return 0; +} + +static netdev_tx_t usb_can_start_xmit(struct sk_buff *skb, + struct net_device *netdev) +{ + struct usb_can_priv *priv = netdev_priv(netdev); + struct can_frame *cf = (struct can_frame *)skb->data; + int actual_length; + + usb_bulk_msg(priv->udev, + usb_sndbulkpipe(priv->udev, priv->ep_out), + cf, + sizeof(struct can_frame), + &actual_length, + 1000); + + dev_kfree_skb(skb); + + return NETDEV_TX_OK; +} + +static const struct net_device_ops usb_can_netdev_ops = { + .ndo_open = usb_can_open, + .ndo_stop = usb_can_stop, + .ndo_start_xmit = usb_can_start_xmit, +}; + +static int usb_can_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct net_device *netdev; + struct usb_can_priv *priv; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *ep; + int i; + + iface_desc = intf->cur_altsetting; + + /* 只绑定 data interface */ + if (iface_desc->desc.bInterfaceNumber != 1) + return -ENODEV; + + netdev = alloc_candev(sizeof(struct usb_can_priv), 1); + if (!netdev) + return -ENOMEM; + + priv = netdev_priv(netdev); + + priv->udev = usb_get_dev(interface_to_usbdev(intf)); + priv->intf = intf; + priv->netdev = netdev; + + for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { + + ep = &iface_desc->endpoint[i].desc; + + if (usb_endpoint_is_bulk_in(ep)) + priv->ep_in = ep->bEndpointAddress; + + if (usb_endpoint_is_bulk_out(ep)) + priv->ep_out = ep->bEndpointAddress; + } + + netdev->netdev_ops = &usb_can_netdev_ops; + + priv->can.clock.freq = 48000000; + + SET_NETDEV_DEV(netdev, &intf->dev); + + register_candev(netdev); + + usb_set_intfdata(intf, priv); + + printk("usb_can_simple: device connected\n"); + + return 0; +} + +static void usb_can_disconnect(struct usb_interface *intf) +{ + struct usb_can_priv *priv = usb_get_intfdata(intf); + + unregister_candev(priv->netdev); + + free_candev(priv->netdev); + + printk("usb_can_simple: device disconnected\n"); +} + +static struct usb_device_id usb_can_id_table[] = { + { USB_DEVICE(USB_CAN_VENDOR, USB_CAN_PRODUCT) }, + { } +}; + +MODULE_DEVICE_TABLE(usb, usb_can_id_table); + +static struct usb_driver usb_can_driver = { + .name = "usb_can_simple", + .probe = usb_can_probe, + .disconnect = usb_can_disconnect, + .id_table = usb_can_id_table, +}; + +module_usb_driver(usb_can_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("demo"); +MODULE_DESCRIPTION("Simple USB CAN driver"); diff --git a/usb/usb_canfd/Makefile b/usb/usb_canfd/Makefile new file mode 100644 index 0000000..12c6f19 --- /dev/null +++ b/usb/usb_canfd/Makefile @@ -0,0 +1,12 @@ +ARCH ?= arm +CROSS_COMPILE ?= /home/jzh/work/study/weidongshan/100ask_stm32mp157_pro-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/arm-linux- +KERN_DIR ?= /home/jzh/work/study/weidongshan/100ask_stm32mp157_pro-sdk/Linux-5.4 + +all: + make -C $(KERN_DIR) M=`pwd` ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules + +clean: + make -C $(KERN_DIR) M=`pwd` ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules clean + rm -rf modules.order + +obj-m += usb_canfd.o diff --git a/usb/usb_canfd/usb_canfd.c b/usb/usb_canfd/usb_canfd.c new file mode 100644 index 0000000..b61c416 --- /dev/null +++ b/usb/usb_canfd/usb_canfd.c @@ -0,0 +1,195 @@ +#include +#include +#include +#include +#include +#include + +#define USB_CAN_VENDOR 0xffff +#define USB_CAN_PRODUCT 0xffff +#define USB_MAX_RX_URBS 8 // 支持的最大 URB 数量 + +struct usb_can_priv { + struct can_priv can; + struct usb_device *udev; + struct usb_interface *intf; + struct net_device *netdev; + + u8 ep_in; + u8 ep_out; + + struct urb *rx_urb[USB_MAX_RX_URBS]; // 支持多个URB + u8 *rx_buf[USB_MAX_RX_URBS]; + + struct urb *tx_urb; + u8 *tx_buf; +}; + +static void usb_can_rx_callback(struct urb *urb) +{ + struct usb_can_priv *priv = urb->context; + struct net_device *netdev = priv->netdev; + struct sk_buff *skb; + struct can_frame *cf; + + if (urb->status) { + printk(KERN_ERR "USB CAN RX error: %d\n", urb->status); + return; + } + + skb = alloc_can_skb(netdev, &cf); + if (!skb) + goto resubmit; + + memcpy(cf, urb->transfer_buffer, sizeof(struct can_frame)); + + netif_rx(skb); + +resubmit: + usb_submit_urb(urb, GFP_ATOMIC); // 继续接收 +} + +static int usb_can_open(struct net_device *netdev) +{ + struct usb_can_priv *priv = netdev_priv(netdev); + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *ep; + int i; + + iface_desc = priv->intf->cur_altsetting; + + for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { + ep = &iface_desc->endpoint[i].desc; + + if (usb_endpoint_is_bulk_in(ep)) + priv->ep_in = ep->bEndpointAddress; + + if (usb_endpoint_is_bulk_out(ep)) + priv->ep_out = ep->bEndpointAddress; + } + + // 设置 RX URBs + for (i = 0; i < USB_MAX_RX_URBS; i++) { + priv->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL); + priv->rx_buf[i] = kmalloc(64, GFP_KERNEL); + + usb_fill_bulk_urb(priv->rx_urb[i], + priv->udev, + usb_rcvbulkpipe(priv->udev, priv->ep_in), + priv->rx_buf[i], + 64, + usb_can_rx_callback, + priv); + + usb_submit_urb(priv->rx_urb[i], GFP_KERNEL); // 提交URB以开始接收 + } + + netif_start_queue(netdev); + + return 0; +} + +static int usb_can_stop(struct net_device *netdev) +{ + struct usb_can_priv *priv = netdev_priv(netdev); + int i; + + netif_stop_queue(netdev); + + // 停止所有的URB接收 + for (i = 0; i < USB_MAX_RX_URBS; i++) { + usb_kill_urb(priv->rx_urb[i]); + usb_free_urb(priv->rx_urb[i]); + kfree(priv->rx_buf[i]); + } + + usb_free_urb(priv->tx_urb); + kfree(priv->tx_buf); + + return 0; +} + +static netdev_tx_t usb_can_start_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct usb_can_priv *priv = netdev_priv(netdev); + struct can_frame *cf = (struct can_frame *)skb->data; + int actual_length; + + usb_bulk_msg(priv->udev, + usb_sndbulkpipe(priv->udev, priv->ep_out), + cf, + sizeof(struct can_frame), + &actual_length, + 1000); // 发送数据到USB设备 + + dev_kfree_skb(skb); + + return NETDEV_TX_OK; +} + +static const struct net_device_ops usb_can_netdev_ops = { + .ndo_open = usb_can_open, + .ndo_stop = usb_can_stop, + .ndo_start_xmit = usb_can_start_xmit, +}; + +static int usb_can_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct net_device *netdev; + struct usb_can_priv *priv; + int i; + + netdev = alloc_candev(sizeof(struct usb_can_priv), 1); + if (!netdev) + return -ENOMEM; + + priv = netdev_priv(netdev); + + priv->udev = usb_get_dev(interface_to_usbdev(intf)); + priv->intf = intf; + priv->netdev = netdev; + + netdev->netdev_ops = &usb_can_netdev_ops; + + priv->can.clock.freq = 48000000; // 设置时钟频率 + + SET_NETDEV_DEV(netdev, &intf->dev); + + register_candev(netdev); + + usb_set_intfdata(intf, priv); + + printk("usb_can_fd: device connected\n"); + + return 0; +} + +static void usb_can_disconnect(struct usb_interface *intf) +{ + struct usb_can_priv *priv = usb_get_intfdata(intf); + + unregister_candev(priv->netdev); + free_candev(priv->netdev); + + printk("usb_can_fd: device disconnected\n"); +} + +static struct usb_device_id usb_can_id_table[] = { + { USB_DEVICE(USB_CAN_VENDOR, USB_CAN_PRODUCT) }, + { } +}; + +MODULE_DEVICE_TABLE(usb, usb_can_id_table); + +static struct usb_driver usb_can_driver = { + .name = "usb_can_fd", + .probe = usb_can_probe, + .disconnect = usb_can_disconnect, + .id_table = usb_can_id_table, +}; + +module_usb_driver(usb_can_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("USB CAN Driver"); +MODULE_DESCRIPTION("USB CAN FD Driver");