196 lines
4.7 KiB
C
196 lines
4.7 KiB
C
#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");
|