[feat] add usb can driver
This commit is contained in:
parent
0406680173
commit
75970ef561
12
usb/usb_can/Makefile
Normal file
12
usb/usb_can/Makefile
Normal 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
188
usb/usb_can/usb_can.c
Normal 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
12
usb/usb_canfd/Makefile
Normal 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
195
usb/usb_canfd/usb_canfd.c
Normal 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");
|
||||
Loading…
Reference in New Issue
Block a user