#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");
struct urb *u;
struct ctu_usbcan_usb *dev;
u8 msg[USBCAN_TRANSFER_SIZE];
+ u32 echo_index;
u8 dlc;
struct list_head list_node;
};
*/
-
/* 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;
wait_queue_head_t queue;
volatile long flags;
+
};
}
+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;
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);
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){
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
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");
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);
exit:
usbcan_kthread_free_urbs(dev);
- printk("CTU USBCAN: usbcan thread finished!");
+ printk("CTU USBCAN: usbcan thread finished\n");
return 0;
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");
struct ctu_usbcan_usb *dev = netdev_priv(netdev);
kthread_stop(dev->comthread);
+
+ close_candev(netdev);
return 0;
}
.ndo_start_xmit = ctu_usbcan_start_xmit,
};
+
static int ctu_usbcan_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
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)
dev->udev = interface_to_usbdev(intf);
dev->netdev = netdev;
+
netdev->netdev_ops = &ctu_usbcan_netdev_ops;
netdev->flags |= IFF_ECHO;
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) {
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);
}
}