]> rtime.felk.cvut.cz Git - socketcan-devel.git/commitdiff
First version that is able to transmit and receive single CAN messages (only one...
authorJiri Vanek <vanekjir@fel.cvut.cz>
Fri, 16 Mar 2012 15:09:47 +0000 (16:09 +0100)
committerJiri Vanek <vanekjir@fel.cvut.cz>
Fri, 16 Mar 2012 15:09:47 +0000 (16:09 +0100)
kernel/2.6/drivers/net/can/usb/ctu_usbcan.c

index 42bb6984c29f5ba0ebdad1d6039391b313227475..7142b199c9e158be0ab34646d5509009e37e8a38 100644 (file)
 #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 */
@@ -28,6 +41,25 @@ MODULE_DEVICE_TABLE(usb, ctu_usbcan_table);
 
 
 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 {
@@ -36,21 +68,221 @@ 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,
@@ -58,19 +290,22 @@ 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
@@ -82,10 +317,33 @@ static int ctu_usbcan_probe(struct usb_interface *intf,
        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);
 
@@ -96,6 +354,8 @@ static int ctu_usbcan_probe(struct usb_interface *intf,
                        "couldn't register CAN device: %d\n", err);
        }
 
+exit:
+
        return 0;
 }