[feat] add usb can driver

This commit is contained in:
zhji 2026-03-15 21:33:08 +08:00
parent 0406680173
commit 75970ef561
4 changed files with 407 additions and 0 deletions

12
usb/usb_can/Makefile Normal file
View File

@ -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

188
usb/usb_can/usb_can.c Normal file
View File

@ -0,0 +1,188 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/usb.h>
#include <linux/netdevice.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#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");

12
usb/usb_canfd/Makefile Normal file
View File

@ -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

195
usb/usb_canfd/usb_canfd.c Normal file
View File

@ -0,0 +1,195 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/usb.h>
#include <linux/netdevice.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#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");