]> rtime.felk.cvut.cz Git - socketcan-devel.git/blobdiff - kernel/2.6/drivers/net/can/usb/ctu_usbcan.c
Getting a bit timing constants from device has been done.
[socketcan-devel.git] / kernel / 2.6 / drivers / net / can / usb / ctu_usbcan.c
index 036252c2061d8112e03f0f9ccb7570c4bcfce348..0543bc6440510b99da27e0bbc50a840c82e3213b 100644 (file)
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
 
+// lpc17xx debug
+#define USBCAN_VENDOR_SET_CANBTR       (9)
+#define USBCAN_VENDOR_GET_BITTIMING_CONST      (10)
+// lpc17xx debug - end
+
 #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_TOT_RX_URBS     8
+#define USBCAN_TOT_TX_URBS     8
 
-#define USBCAN_TRANSFER_SIZE 16
+#define USBCAN_TRANSFER_SIZE   16
+#define USBCAN_BITTIMING_SIZE  16
+#define USBCAN_BITTIMING_CONST_SIZE    36
 
-#define CAN_MSG_LENGTH 8
+#define CAN_MSG_LENGTH 8
 
-#define MSG_RTR   (1<<0)
+#define MSG_RTR          (1<<0)
 #define MSG_OVR   (1<<1)
 #define MSG_EXT   (1<<2)
 #define MSG_LOCAL (1<<3)
 
-
 #define USBCAN_DATA_OK (1)
 #define USBCAN_TX_PENDING      (2)
+#define USBCAN_BITTIMING_CONST_SET     (3)
+
 
 MODULE_LICENSE("GPL");
 
@@ -53,6 +61,7 @@ struct usbcan_message {
        struct urb      *u;
        struct ctu_usbcan_usb *dev;
        u8      msg[USBCAN_TRANSFER_SIZE];
+       u32 echo_index;
        u8      dlc;
        struct list_head list_node;
 };
@@ -66,12 +75,14 @@ Structure of byte array msg in struct usbcan_message that represents CAN message
 
 */
 
-
 /* Structure to hold all of our device specific stuff */
 struct ctu_usbcan_usb {
 
        struct can_priv can; /* must be the first member */
 
+       struct can_bittiming_const cbc;
+       u32 can_clock;
+
        struct usb_device *udev;                        /* the usb device for this device */
        struct net_device *netdev;
 
@@ -91,6 +102,7 @@ struct ctu_usbcan_usb {
        wait_queue_head_t queue;
 
        volatile long flags;
+
 };
 
 
@@ -105,6 +117,115 @@ static void usbcan_usb_message_move_list(struct ctu_usbcan_usb *dev,
 }
 
 
+static int get_bittiming_constants(struct ctu_usbcan_usb *dev)
+{
+
+       int retval;
+       u8 *usbbuf;
+       u32 * ptr;
+
+       usbbuf = kzalloc(sizeof(u8)*USBCAN_BITTIMING_CONST_SIZE, GFP_KERNEL);
+
+       if(!usbbuf){
+               err("Error allocating receive buffer for bittiming constants\n");
+               return 1;
+       }
+       
+       retval = usb_control_msg(dev->udev,
+               usb_rcvctrlpipe(dev->udev, 0),
+               USBCAN_VENDOR_GET_BITTIMING_CONST,
+               USB_TYPE_VENDOR,
+               cpu_to_le16(0), cpu_to_le16(0),
+               usbbuf, USBCAN_BITTIMING_CONST_SIZE,
+               1000);
+
+       if(retval<0)
+               goto exit;
+
+       ptr = (u32*) usbbuf;
+
+       dev->can_clock = le32_to_cpu(*(ptr++));
+       dev->cbc.tseg1_min = le32_to_cpu(*(ptr++));
+       dev->cbc.tseg1_max = le32_to_cpu(*(ptr++));
+       dev->cbc.tseg2_min = le32_to_cpu(*(ptr++));
+       dev->cbc.tseg2_max = le32_to_cpu(*(ptr++));
+       dev->cbc.sjw_max = le32_to_cpu(*(ptr++));
+       dev->cbc.brp_min = le32_to_cpu(*(ptr++));
+       dev->cbc.brp_max = le32_to_cpu(*(ptr++));
+       dev->cbc.brp_inc = le32_to_cpu(*(ptr));
+
+       set_bit(USBCAN_BITTIMING_CONST_SET,&dev->flags);
+
+
+exit:
+
+       kfree(usbbuf);
+       if(retval<0)
+               return retval;
+
+       return 0;
+
+}
+
+static int ctu_usbcan_set_mode(struct net_device *netdev, enum can_mode mode)
+{
+       
+       printk("SET MODE\n");
+
+       return 0;
+}
+
+static int ctu_usbcan_set_bittiming(struct net_device *netdev)
+{
+       struct ctu_usbcan_usb *dev = netdev_priv(netdev);
+       struct can_bittiming *bt = &dev->can.bittiming;
+       u8 *usbbuf;     
+       u32 * ptr;
+       int retval;
+       
+
+       if (!dev)
+               return -ENODEV;
+
+
+       usbbuf = kzalloc(sizeof(u8)*USBCAN_BITTIMING_SIZE, GFP_KERNEL);
+
+       if(!usbbuf){
+               err("Error allocating transmit buffer for set bittiming\n");
+               return 1;
+       }       
+       
+       ptr = (u32*) usbbuf;
+
+       *(ptr++)=cpu_to_le32(bt->brp);          // baudrate prescaler
+       *(ptr++)=cpu_to_le32(bt->sjw);  // sjw
+       *(ptr++)=cpu_to_le32(bt->prop_seg + bt->phase_seg1);    // TSEG1
+       *(ptr)=cpu_to_le32(bt->phase_seg2);     // TSEG2
+
+
+       retval = usb_control_msg(dev->udev,
+                               usb_sndctrlpipe(dev->udev, 0),
+                               USBCAN_VENDOR_SET_CANBTR,
+                               USB_TYPE_VENDOR,
+                               cpu_to_le16(0), cpu_to_le16(0),
+                               usbbuf, USBCAN_BITTIMING_SIZE,
+                               1000);
+
+       kfree(usbbuf);
+
+       if(retval){
+               printk("BITRATE %d, BRP: %d, SJW: %d, TSEG1: %d, TSEG2: %d \n", bt->bitrate, bt->brp, bt->sjw,\
+                               (bt->prop_seg + bt->phase_seg1), bt->phase_seg2);       
+               return 0;
+       }
+       else{
+               err("Could not set bittiming\n");
+               return retval;
+       }
+
+}
+
+
 static void ctu_usbcan_tx_callback(struct urb *urb){
 
        struct usbcan_message *m = urb->context;
@@ -125,6 +246,8 @@ static void ctu_usbcan_tx_callback(struct urb *urb){
        stats->tx_packets++;
        stats->tx_bytes += m->dlc;
 
+       
+       can_get_echo_skb(m->dev->netdev, m->echo_index);
 
        set_bit(USBCAN_DATA_OK,&m->dev->flags);
        usbcan_usb_message_move_list(m->dev, m, &m->dev->tx_ready_list);
@@ -196,10 +319,10 @@ static netdev_tx_t ctu_usbcan_start_xmit(struct sk_buff *skb, struct net_device
 
        m->dlc = (u8) len;
 
-
-
        usbcan_usb_message_move_list(dev, m, &dev->tx_pend_list);
 
+       can_put_echo_skb(skb, netdev, m->echo_index);
+
        /* odeslani     */ 
        retval = usb_submit_urb(m->u, GFP_ATOMIC);
        if (retval){
@@ -274,7 +397,7 @@ void usbcan_kthread_read_handler(struct ctu_usbcan_usb *dev, struct usbcan_messa
        u16 flags = 0;
        struct net_device_stats *stats = &m->dev->netdev->stats;
 
-
+/*
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32)
        skb = alloc_can_skb(m->dev->netdev, &cf);
 #else
@@ -282,6 +405,8 @@ void usbcan_kthread_read_handler(struct ctu_usbcan_usb *dev, struct usbcan_messa
        skb->protocol = htons(ETH_P_CAN);
        cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
 #endif
+*/
+       skb = alloc_can_skb(m->dev->netdev, &cf);
 
        if (skb == NULL){
                err("RX: error alloc skb\n");
@@ -415,6 +540,8 @@ int usbcan_kthread(void *data)
                u->dev = dev->udev;
                m->dev = dev;
 
+               m->echo_index = i;
+
                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);
@@ -478,7 +605,7 @@ int usbcan_kthread(void *data)
 
 exit:
        usbcan_kthread_free_urbs(dev);
-       printk("CTU USBCAN: usbcan thread finished!");
+       printk("CTU USBCAN: usbcan thread finished\n");
        
        return 0;
 
@@ -486,9 +613,15 @@ exit:
 
 static int ctu_usbcan_open(struct net_device *netdev)
 {
+       int err;
 
        struct ctu_usbcan_usb *dev = netdev_priv(netdev);
 
+       /* common open */       
+       err = open_candev(netdev);
+       if (err)
+               return err;     
+
        /* start kernel thread */
        dev->comthread = kthread_run(usbcan_kthread, (void *)dev, "usbcan_1");
 
@@ -500,6 +633,8 @@ static int ctu_usbcan_close(struct net_device *netdev)
 
        struct ctu_usbcan_usb *dev = netdev_priv(netdev);
        kthread_stop(dev->comthread);
+
+       close_candev(netdev);
        
        return 0;
 }
@@ -510,6 +645,7 @@ static const struct net_device_ops ctu_usbcan_netdev_ops = {
        .ndo_start_xmit = ctu_usbcan_start_xmit,
 };
 
+
 static int ctu_usbcan_probe(struct usb_interface *intf,
                                                        const struct usb_device_id *id)
 {
@@ -522,11 +658,14 @@ static int ctu_usbcan_probe(struct usb_interface *intf,
 
        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), USBCAN_TOT_TX_URBS);
 #else
        netdev = alloc_candev(sizeof(struct ctu_usbcan_usb));
 #endif
+*/
+       netdev = alloc_candev(sizeof(struct ctu_usbcan_usb), USBCAN_TOT_TX_URBS);
 
        if (!netdev) {
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,33)
@@ -542,6 +681,7 @@ 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;
 
@@ -572,6 +712,16 @@ static int ctu_usbcan_probe(struct usb_interface *intf,
        usb_set_intfdata(intf, dev);
        SET_NETDEV_DEV(netdev, &intf->dev);
 
+       if (get_bittiming_constants(dev)){
+               err("Could not get bittiming constants\n");
+               goto exit;
+       }
+
+       dev->can.clock.freq = dev->can_clock;
+       dev->can.bittiming_const = &dev->cbc;
+       dev->can.do_set_bittiming = ctu_usbcan_set_bittiming;
+       dev->can.do_set_mode = ctu_usbcan_set_mode;
+
 
        err = register_candev(netdev);
        if (err) {
@@ -595,8 +745,11 @@ static void ctu_usbcan_disconnect(struct usb_interface *intf)
        usb_set_intfdata(intf, NULL);
 
        if (dev) {
-               unregister_netdev(dev->netdev);
+               if(test_bit(USBCAN_BITTIMING_CONST_SET,&dev->flags))            
+                       unregister_netdev(dev->netdev);
+
                free_candev(dev->netdev);
+               clear_bit(USBCAN_BITTIMING_CONST_SET,&dev->flags);
        }
 
 }