#define CTU_USBCAN_VENDOR_ID 0x1669
#define CTU_USBCAN_PRODUCT_ID 0x1011
+#define USBCAN_TOT_RX_URBS 8
+#define USBCAN_TOT_TX_URBS 8
+
+#define USBCAN_TRANSFER_SIZE 16
+
+
+#define CAN_MSG_LENGTH 8
+/* Definitions to use for canmsg_t and canfilt_t flags */
+#define MSG_RTR (1<<0)
+#define MSG_OVR (1<<1)
+#define MSG_EXT (1<<2)
+#define MSG_LOCAL (1<<3)
+
MODULE_LICENSE("GPL");
/* table of devices that work with this driver */
static struct usb_driver ctu_usbcan_driver;
+struct ctu_usbcan_usb;
+
+
+struct usbcan_message {
+ struct urb *u;
+ struct ctu_usbcan_usb *dev;
+ u8 msg[USBCAN_TRANSFER_SIZE];
+ u8 dlc;
+};
+/*
+Structure of byte array msg in struct usbcan_message that represens CAN message (little endian):
+ msg[0] - reserved (1 byte)
+ msg[1] - length (1 byte)
+ msg[2:3] - flags (2 bytes)
+ msg[4:7] - id (4 bytes)
+ msg[8:15] - data (8 bytes)
+
+*/
+
/* Structure to hold all of our device specific stuff */
struct ctu_usbcan_usb {
struct usb_device *udev; /* the usb device for this device */
struct net_device *netdev;
+
+ u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
+ u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
};
+
+
+static void ctu_usbcan_tx_callback(struct urb *urb){
+
+ struct usbcan_message *m = urb->context;
+ struct net_device_stats *stats = &m->dev->netdev->stats;
+
+ if (!netif_device_present(m->dev->netdev))
+ return;
+
+ printk("TX callback: URB successfully transmitted\n");
+
+ stats->tx_packets++;
+ stats->tx_bytes += m->dlc;
+
+
+}
+
+static void ctu_usbcan_rx_callback(struct urb *urb)
+{
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ struct usbcan_message *m = urb->context;
+ u8 *ptr;
+ int i, len;
+ u16 flags = 0;
+ struct net_device_stats *stats = &m->dev->netdev->stats;
+
+ if (!netif_device_present(m->dev->netdev))
+ return;
+
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32)
+ skb = alloc_can_skb(m->dev->netdev, &cf);
+#else
+ skb = netdev_alloc_skb(m->dev->netdev, sizeof(struct can_frame));
+ skb->protocol = htons(ETH_P_CAN);
+ cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
+#endif
+
+ if (skb == NULL){
+ err("RX callback: error alloc skb\n");
+ return;
+ }
+
+ if(urb->status != 0){
+ err("RX callback: error");
+ return;
+ }
+
+ /* success */
+
+ printk("RX callback: URB successfully received\n");
+
+ len=*(u8 *)(m->msg+1);
+ if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
+
+ flags = le16_to_cpu(*(u16 *)(m->msg+2));
+ cf->can_id = le32_to_cpu((*(u32 *)(m->msg+4)));
+
+ if (flags & MSG_RTR)
+ cf->can_id |= CAN_RTR_FLAG;
+
+ if (flags & MSG_EXT)
+ cf->can_id |= CAN_EFF_FLAG;
+
+ cf->can_dlc = len;
+
+ for(ptr=m->msg+8,i=0; i < len; ptr++,i++) {
+ cf->data[i]=*ptr;
+ }
+
+
+ netif_rx(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+
+}
+
+static netdev_tx_t ctu_usbcan_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct ctu_usbcan_usb *dev = netdev_priv(netdev);
+ struct can_frame *cf = (struct can_frame *)skb->data;
+ int i, retval, len;
+ u8 *ptr;
+ u16 flags = 0;
+
+ /* Prepare transmit urb */
+ struct usbcan_message *m;
+ struct urb *u = usb_alloc_urb(0, GFP_ATOMIC);
+
+ if (!u){
+ err("Error allocating usb transmit urb");
+ goto exit;
+ }
+
+ m = kzalloc(sizeof(struct usbcan_message), GFP_ATOMIC);
+ if(!m) {
+ usb_free_urb(u);
+ err("Error allocating transmit usbcan_message");
+ goto exit;
+ }
+ m->u = u;
+ u->dev = dev->udev;
+ m->dev = dev;
+
+ /* naplneni */
+
+ len = cf->can_dlc;
+ if(len > CAN_MSG_LENGTH)
+ len = CAN_MSG_LENGTH;
+
+ if (cf->can_id & CAN_RTR_FLAG)
+ flags |= MSG_RTR;
+
+ if (cf->can_id & CAN_EFF_FLAG)
+ flags |= MSG_EXT;
+
+ *(u8 *)(m->msg)=0;
+ *(u8 *)(m->msg+1)=len & 0xFF;
+ *(u16 *)(m->msg+2)=cpu_to_le16(flags);
+ *(u32 *)(m->msg+4)=cpu_to_le32(cf->can_id & CAN_ERR_MASK);
+
+ for(ptr=m->msg+8, i=0; i < len; ptr++,i++)
+ *ptr= cf->data[i] & 0xFF;
+
+ for(; i < 8; ptr++,i++)
+ *ptr=0;
+
+
+ m->dlc = (u8) len;
+
+ /* odeslani */
+
+ usb_fill_bulk_urb(u, dev->udev,
+ usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
+ m->msg, USBCAN_TRANSFER_SIZE, ctu_usbcan_tx_callback, m);
+
+
+ retval = usb_submit_urb(m->u, GFP_ATOMIC);
+ if (retval){
+ err("Error submitting URB: %d", retval);
+ goto exit;
+ }
+
+
+exit:
+
+ usb_free_urb(u);
+
+ return NETDEV_TX_OK;
+
+}
+
static int ctu_usbcan_open(struct net_device *netdev)
{
+
+ struct ctu_usbcan_usb *dev = netdev_priv(netdev);
+ int retval;
+
+
+ /* Prepare receive urb */
+ struct usbcan_message *m;
+ struct urb *u;
+
+ printk("CTU USBCAN: opening device\n");
+
+ u = usb_alloc_urb(0, GFP_KERNEL);
+ if (!u){
+ err("Error allocating usb receive urb");
+ goto exit;
+ }
+
+ m = kzalloc(sizeof(struct usbcan_message), GFP_KERNEL);
+ if(!m) {
+ usb_free_urb(u);
+ err("Error allocating receive usbcan_message");
+ goto exit;
+ }
+ m->u = u;
+ u->dev = dev->udev;
+ m->dev = dev;
+ usb_fill_bulk_urb(u, dev->udev,
+ usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
+ m->msg, USBCAN_TRANSFER_SIZE, ctu_usbcan_rx_callback, m);
+
+
+ retval=usb_submit_urb(m->u, GFP_KERNEL);
+ if (retval){
+ err("Error submitting URB: %d", retval);
+ goto exit;
+ }
+
+exit:
+ usb_free_urb(u);
+
return 0;
}
static int ctu_usbcan_close(struct net_device *netdev)
{
+
return 0;
}
static const struct net_device_ops ctu_usbcan_netdev_ops = {
.ndo_open = ctu_usbcan_open,
.ndo_stop = ctu_usbcan_close,
+ .ndo_start_xmit = ctu_usbcan_start_xmit,
};
static int ctu_usbcan_probe(struct usb_interface *intf,
{
struct net_device *netdev;
struct ctu_usbcan_usb *dev;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ int i;
int err = -ENOMEM;
printk(KERN_INFO "CTU USBCAN device now attached\n");
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32)
- netdev = alloc_candev(sizeof(struct ctu_usbcan_usb), MAX_TX_URBS);
+ netdev = alloc_candev(sizeof(struct ctu_usbcan_usb), USBCAN_TOT_TX_URBS);
#else
netdev = alloc_candev(sizeof(struct ctu_usbcan_usb));
#endif
if (!netdev) {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32)
- dev_err(&intf->dev, "ems_usb: Couldn't alloc candev\n");
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,33)
+ dev_err(&intf->dev, "Couldn't alloc candev\n");
#else
dev_err(netdev->dev.parent, "Couldn't alloc candev\n");
#endif
dev->udev = interface_to_usbdev(intf);
dev->netdev = netdev;
-
netdev->netdev_ops = &ctu_usbcan_netdev_ops;
netdev->flags |= IFF_ECHO;
+ /* set up the endpoint information */
+ /* use only the first bulk-in and bulk-out endpoints */
+ iface_desc = intf->cur_altsetting;
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+
+ if (!dev->bulk_in_endpointAddr &&
+ usb_endpoint_is_bulk_in(endpoint)) {
+ /* we found a bulk in endpoint */
+ dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
+ }
+
+ if (!dev->bulk_out_endpointAddr &&
+ usb_endpoint_is_bulk_out(endpoint)) {
+ /* we found a bulk out endpoint */
+ dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
+ }
+ }
+ if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
+ err("Could not find both bulk-in and bulk-out endpoints");
+ goto exit;
+ }
+
+
usb_set_intfdata(intf, dev);
SET_NETDEV_DEV(netdev, &intf->dev);
"couldn't register CAN device: %d\n", err);
}
+exit:
+
return 0;
}