diff options
Diffstat (limited to 'drivers/net/can/usb')
| -rw-r--r-- | drivers/net/can/usb/Kconfig | 53 | ||||
| -rw-r--r-- | drivers/net/can/usb/Makefile | 4 | ||||
| -rw-r--r-- | drivers/net/can/usb/ems_usb.c | 122 | ||||
| -rw-r--r-- | drivers/net/can/usb/esd_usb2.c | 241 | ||||
| -rw-r--r-- | drivers/net/can/usb/gs_usb.c | 971 | ||||
| -rw-r--r-- | drivers/net/can/usb/kvaser_usb.c | 1665 | ||||
| -rw-r--r-- | drivers/net/can/usb/peak_usb/Makefile | 2 | ||||
| -rw-r--r-- | drivers/net/can/usb/peak_usb/pcan_usb.c | 903 | ||||
| -rw-r--r-- | drivers/net/can/usb/peak_usb/pcan_usb_core.c | 950 | ||||
| -rw-r--r-- | drivers/net/can/usb/peak_usb/pcan_usb_core.h | 145 | ||||
| -rw-r--r-- | drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 1064 | ||||
| -rw-r--r-- | drivers/net/can/usb/peak_usb/pcan_usb_pro.h | 179 | ||||
| -rw-r--r-- | drivers/net/can/usb/usb_8dev.c | 1035 | 
13 files changed, 7138 insertions, 196 deletions
diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig index 04525495b15..a77db919363 100644 --- a/drivers/net/can/usb/Kconfig +++ b/drivers/net/can/usb/Kconfig @@ -1,5 +1,5 @@  menu "CAN USB interfaces" -	depends on USB && CAN_DEV +	depends on USB  config CAN_EMS_USB  	tristate "EMS CPC-USB/ARM7 CAN/USB interface" @@ -13,4 +13,55 @@ config CAN_ESD_USB2            This driver supports the CAN-USB/2 interface            from esd electronic system design gmbh (http://www.esd.eu). +config CAN_GS_USB +	tristate "Geschwister Schneider UG interfaces" +	---help--- +	  This driver supports the Geschwister Schneider USB/CAN devices. +	  If unsure choose N, +	  choose Y for built in support, +	  M to compile as module (module will be named: gs_usb). + +config CAN_KVASER_USB +	tristate "Kvaser CAN/USB interface" +	---help--- +	  This driver adds support for Kvaser CAN/USB devices like Kvaser +	  Leaf Light. + +	  The driver provides support for the following devices: +	    - Kvaser Leaf Light +	    - Kvaser Leaf Professional HS +	    - Kvaser Leaf SemiPro HS +	    - Kvaser Leaf Professional LS +	    - Kvaser Leaf Professional SWC +	    - Kvaser Leaf Professional LIN +	    - Kvaser Leaf SemiPro LS +	    - Kvaser Leaf SemiPro SWC +	    - Kvaser Memorator II HS/HS +	    - Kvaser USBcan Professional HS/HS +	    - Kvaser Leaf Light GI +	    - Kvaser Leaf Professional HS (OBD-II connector) +	    - Kvaser Memorator Professional HS/LS +	    - Kvaser Leaf Light "China" +	    - Kvaser BlackBird SemiPro +	    - Kvaser USBcan R +	    - Kvaser Leaf Light v2 +	    - Kvaser Mini PCI Express HS + +	  If unsure, say N. + +	  To compile this driver as a module, choose M here: the +	  module will be called kvaser_usb. + +config CAN_PEAK_USB +	tristate "PEAK PCAN-USB/USB Pro interfaces" +	---help--- +	  This driver supports the PCAN-USB and PCAN-USB Pro adapters +	  from PEAK-System Technik (http://www.peak-system.com). + +config CAN_8DEV_USB +	tristate "8 devices USB2CAN interface" +	---help--- +	  This driver supports the USB2CAN interface +	  from 8 devices (http://www.8devices.com). +  endmenu diff --git a/drivers/net/can/usb/Makefile b/drivers/net/can/usb/Makefile index fce3cf11719..7b9a393b1ac 100644 --- a/drivers/net/can/usb/Makefile +++ b/drivers/net/can/usb/Makefile @@ -4,5 +4,9 @@  obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o  obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o +obj-$(CONFIG_CAN_GS_USB) += gs_usb.o +obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o +obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/ +obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o  ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index e75f1a87697..00f2534dde7 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -16,7 +16,6 @@   * with this program; if not, write to the Free Software Foundation, Inc.,   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.   */ -#include <linux/init.h>  #include <linux/signal.h>  #include <linux/slab.h>  #include <linux/module.h> @@ -245,7 +244,6 @@ struct ems_tx_urb_context {  struct ems_usb {  	struct can_priv can; /* must be the first member */ -	int open_time;  	struct sk_buff *echo_skb[MAX_TX_URBS]; @@ -288,8 +286,7 @@ static void ems_usb_read_interrupt_callback(struct urb *urb)  		return;  	default: -		dev_info(netdev->dev.parent, "Rx interrupt aborted %d\n", -			 urb->status); +		netdev_info(netdev, "Rx interrupt aborted %d\n", urb->status);  		break;  	} @@ -298,8 +295,7 @@ static void ems_usb_read_interrupt_callback(struct urb *urb)  	if (err == -ENODEV)  		netif_device_detach(netdev);  	else if (err) -		dev_err(netdev->dev.parent, -			"failed resubmitting intr urb: %d\n", err); +		netdev_err(netdev, "failed resubmitting intr urb: %d\n", err);  }  static void ems_usb_rx_can_msg(struct ems_usb *dev, struct ems_cpc_msg *msg) @@ -386,7 +382,7 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)  			break;  		} -		/* Error occured during transmission? */ +		/* Error occurred during transmission? */  		if ((ecc & SJA1000_ECC_DIR) == 0)  			cf->data[2] |= CAN_ERR_PROT_TX; @@ -431,8 +427,7 @@ static void ems_usb_read_bulk_callback(struct urb *urb)  		return;  	default: -		dev_info(netdev->dev.parent, "Rx URB aborted (%d)\n", -			 urb->status); +		netdev_info(netdev, "Rx URB aborted (%d)\n", urb->status);  		goto resubmit_urb;  	} @@ -477,7 +472,7 @@ static void ems_usb_read_bulk_callback(struct urb *urb)  			msg_count--;  			if (start > urb->transfer_buffer_length) { -				dev_err(netdev->dev.parent, "format error\n"); +				netdev_err(netdev, "format error\n");  				break;  			}  		} @@ -493,8 +488,8 @@ resubmit_urb:  	if (retval == -ENODEV)  		netif_device_detach(netdev);  	else if (retval) -		dev_err(netdev->dev.parent, -			"failed resubmitting read bulk urb: %d\n", retval); +		netdev_err(netdev, +			   "failed resubmitting read bulk urb: %d\n", retval);  }  /* @@ -521,8 +516,7 @@ static void ems_usb_write_bulk_callback(struct urb *urb)  		return;  	if (urb->status) -		dev_info(netdev->dev.parent, "Tx URB aborted (%d)\n", -			 urb->status); +		netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status);  	netdev->trans_start = jiffies; @@ -605,18 +599,18 @@ static int ems_usb_start(struct ems_usb *dev)  		/* create a URB, and a buffer for it */  		urb = usb_alloc_urb(0, GFP_KERNEL);  		if (!urb) { -			dev_err(netdev->dev.parent, -				"No memory left for URBs\n"); -			return -ENOMEM; +			netdev_err(netdev, "No memory left for URBs\n"); +			err = -ENOMEM; +			break;  		}  		buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE, GFP_KERNEL,  					 &urb->transfer_dma);  		if (!buf) { -			dev_err(netdev->dev.parent, -				"No memory left for USB buffer\n"); +			netdev_err(netdev, "No memory left for USB buffer\n");  			usb_free_urb(urb); -			return -ENOMEM; +			err = -ENOMEM; +			break;  		}  		usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 2), @@ -627,12 +621,10 @@ static int ems_usb_start(struct ems_usb *dev)  		err = usb_submit_urb(urb, GFP_KERNEL);  		if (err) { -			if (err == -ENODEV) -				netif_device_detach(dev->netdev); -  			usb_unanchor_urb(urb);  			usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf,  					  urb->transfer_dma); +			usb_free_urb(urb);  			break;  		} @@ -642,13 +634,13 @@ static int ems_usb_start(struct ems_usb *dev)  	/* Did we submit any URBs */  	if (i == 0) { -		dev_warn(netdev->dev.parent, "couldn't setup read URBs\n"); +		netdev_warn(netdev, "couldn't setup read URBs\n");  		return err;  	}  	/* Warn if we've couldn't transmit all the URBs */  	if (i < MAX_RX_URBS) -		dev_warn(netdev->dev.parent, "rx performance may be slow\n"); +		netdev_warn(netdev, "rx performance may be slow\n");  	/* Setup and start interrupt URB */  	usb_fill_int_urb(dev->intr_urb, dev->udev, @@ -659,11 +651,7 @@ static int ems_usb_start(struct ems_usb *dev)  	err = usb_submit_urb(dev->intr_urb, GFP_KERNEL);  	if (err) { -		if (err == -ENODEV) -			netif_device_detach(dev->netdev); - -		dev_warn(netdev->dev.parent, "intr URB submit failed: %d\n", -			 err); +		netdev_warn(netdev, "intr URB submit failed: %d\n", err);  		return err;  	} @@ -692,10 +680,7 @@ static int ems_usb_start(struct ems_usb *dev)  	return 0;  failed: -	if (err == -ENODEV) -		netif_device_detach(dev->netdev); - -	dev_warn(netdev->dev.parent, "couldn't submit control: %d\n", err); +	netdev_warn(netdev, "couldn't submit control: %d\n", err);  	return err;  } @@ -735,15 +720,13 @@ static int ems_usb_open(struct net_device *netdev)  		if (err == -ENODEV)  			netif_device_detach(dev->netdev); -		dev_warn(netdev->dev.parent, "couldn't start device: %d\n", -			 err); +		netdev_warn(netdev, "couldn't start device: %d\n", err);  		close_candev(netdev);  		return err;  	} -	dev->open_time = jiffies;  	netif_start_queue(netdev); @@ -769,13 +752,13 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne  	/* create a URB, and a buffer for it, and copy the data to the URB */  	urb = usb_alloc_urb(0, GFP_ATOMIC);  	if (!urb) { -		dev_err(netdev->dev.parent, "No memory left for URBs\n"); +		netdev_err(netdev, "No memory left for URBs\n");  		goto nomem;  	}  	buf = usb_alloc_coherent(dev->udev, size, GFP_ATOMIC, &urb->transfer_dma);  	if (!buf) { -		dev_err(netdev->dev.parent, "No memory left for USB buffer\n"); +		netdev_err(netdev, "No memory left for USB buffer\n");  		usb_free_urb(urb);  		goto nomem;  	} @@ -815,10 +798,10 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne  	 * allowed (MAX_TX_URBS).  	 */  	if (!context) { -		usb_unanchor_urb(urb);  		usb_free_coherent(dev->udev, size, buf, urb->transfer_dma); +		usb_free_urb(urb); -		dev_warn(netdev->dev.parent, "couldn't find free context\n"); +		netdev_warn(netdev, "couldn't find free context\n");  		return NETDEV_TX_BUSY;  	} @@ -849,7 +832,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne  		if (err == -ENODEV) {  			netif_device_detach(netdev);  		} else { -			dev_warn(netdev->dev.parent, "failed tx_urb %d\n", err); +			netdev_warn(netdev, "failed tx_urb %d\n", err);  			stats->tx_dropped++;  		} @@ -889,12 +872,10 @@ static int ems_usb_close(struct net_device *netdev)  	/* Set CAN controller to reset mode */  	if (ems_usb_write_mode(dev, SJA1000_MOD_RM)) -		dev_warn(netdev->dev.parent, "couldn't stop device"); +		netdev_warn(netdev, "couldn't stop device");  	close_candev(netdev); -	dev->open_time = 0; -  	return 0;  } @@ -902,9 +883,10 @@ static const struct net_device_ops ems_usb_netdev_ops = {  	.ndo_open = ems_usb_open,  	.ndo_stop = ems_usb_close,  	.ndo_start_xmit = ems_usb_start_xmit, +	.ndo_change_mtu = can_change_mtu,  }; -static struct can_bittiming_const ems_usb_bittiming_const = { +static const struct can_bittiming_const ems_usb_bittiming_const = {  	.name = "ems_usb",  	.tseg1_min = 1,  	.tseg1_max = 16, @@ -920,13 +902,10 @@ static int ems_usb_set_mode(struct net_device *netdev, enum can_mode mode)  {  	struct ems_usb *dev = netdev_priv(netdev); -	if (!dev->open_time) -		return -EINVAL; -  	switch (mode) {  	case CAN_MODE_START:  		if (ems_usb_write_mode(dev, SJA1000_MOD_NORMAL)) -			dev_warn(netdev->dev.parent, "couldn't start device"); +			netdev_warn(netdev, "couldn't start device");  		if (netif_queue_stopped(netdev))  			netif_wake_queue(netdev); @@ -951,8 +930,7 @@ static int ems_usb_set_bittiming(struct net_device *netdev)  	if (dev->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)  		btr1 |= 0x80; -	dev_info(netdev->dev.parent, "setting BTR0=0x%02x BTR1=0x%02x\n", -		 btr0, btr1); +	netdev_info(netdev, "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1);  	dev->active_params.msg.can_params.cc_params.sja1000.btr0 = btr0;  	dev->active_params.msg.can_params.cc_params.sja1000.btr1 = btr1; @@ -1037,17 +1015,13 @@ static int ems_usb_probe(struct usb_interface *intf,  	}  	dev->intr_in_buffer = kzalloc(INTR_IN_BUFFER_SIZE, GFP_KERNEL); -	if (!dev->intr_in_buffer) { -		dev_err(&intf->dev, "Couldn't alloc Intr buffer\n"); +	if (!dev->intr_in_buffer)  		goto cleanup_intr_urb; -	}  	dev->tx_msg_buffer = kzalloc(CPC_HEADER_SIZE +  				     sizeof(struct ems_cpc_msg), GFP_KERNEL); -	if (!dev->tx_msg_buffer) { -		dev_err(&intf->dev, "Couldn't alloc Tx buffer\n"); +	if (!dev->tx_msg_buffer)  		goto cleanup_intr_in_buffer; -	}  	usb_set_intfdata(intf, dev); @@ -1057,15 +1031,13 @@ static int ems_usb_probe(struct usb_interface *intf,  	err = ems_usb_command_msg(dev, &dev->active_params);  	if (err) { -		dev_err(netdev->dev.parent, -			"couldn't initialize controller: %d\n", err); +		netdev_err(netdev, "couldn't initialize controller: %d\n", err);  		goto cleanup_tx_msg_buffer;  	}  	err = register_candev(netdev);  	if (err) { -		dev_err(netdev->dev.parent, -			"couldn't register CAN device: %d\n", err); +		netdev_err(netdev, "couldn't register CAN device: %d\n", err);  		goto cleanup_tx_msg_buffer;  	} @@ -1115,28 +1087,4 @@ static struct usb_driver ems_usb_driver = {  	.id_table = ems_usb_table,  }; -static int __init ems_usb_init(void) -{ -	int err; - -	printk(KERN_INFO "CPC-USB kernel driver loaded\n"); - -	/* register this driver with the USB subsystem */ -	err = usb_register(&ems_usb_driver); - -	if (err) { -		err("usb_register failed. Error number %d\n", err); -		return err; -	} - -	return 0; -} - -static void __exit ems_usb_exit(void) -{ -	/* deregister this driver with the USB subsystem */ -	usb_deregister(&ems_usb_driver); -} - -module_init(ems_usb_init); -module_exit(ems_usb_exit); +module_usb_driver(ems_usb_driver); diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c index 05a52754f48..b7c9e8b1146 100644 --- a/drivers/net/can/usb/esd_usb2.c +++ b/drivers/net/can/usb/esd_usb2.c @@ -1,7 +1,7 @@  /* - * CAN driver for esd CAN-USB/2 + * CAN driver for esd CAN-USB/2 and CAN-USB/Micro   * - * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh + * Copyright (C) 2010-2012 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh   *   * This program is free software; you can redistribute it and/or modify it   * under the terms of the GNU General Public License as published @@ -16,7 +16,6 @@   * with this program; if not, write to the Free Software Foundation, Inc.,   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.   */ -#include <linux/init.h>  #include <linux/signal.h>  #include <linux/slab.h>  #include <linux/module.h> @@ -28,14 +27,16 @@  #include <linux/can/error.h>  MODULE_AUTHOR("Matthias Fuchs <matthias.fuchs@esd.eu>"); -MODULE_DESCRIPTION("CAN driver for esd CAN-USB/2 interfaces"); +MODULE_DESCRIPTION("CAN driver for esd CAN-USB/2 and CAN-USB/Micro interfaces");  MODULE_LICENSE("GPL v2");  /* Define these values to match your devices */  #define USB_ESDGMBH_VENDOR_ID	0x0ab4  #define USB_CANUSB2_PRODUCT_ID	0x0010 +#define USB_CANUSBM_PRODUCT_ID	0x0011  #define ESD_USB2_CAN_CLOCK	60000000 +#define ESD_USBM_CAN_CLOCK	36000000  #define ESD_USB2_MAX_NETS	2  /* USB2 commands */ @@ -69,6 +70,7 @@ MODULE_LICENSE("GPL v2");  #define ESD_USB2_TSEG2_SHIFT	20  #define ESD_USB2_SJW_MAX	4  #define ESD_USB2_SJW_SHIFT	14 +#define ESD_USBM_SJW_SHIFT	24  #define ESD_USB2_BRP_MIN	1  #define ESD_USB2_BRP_MAX	1024  #define ESD_USB2_BRP_INC	1 @@ -183,6 +185,7 @@ struct __attribute__ ((packed)) esd_usb2_msg {  static struct usb_device_id esd_usb2_table[] = {  	{USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB2_PRODUCT_ID)}, +	{USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSBM_PRODUCT_ID)},  	{}  };  MODULE_DEVICE_TABLE(usb, esd_usb2_table); @@ -213,7 +216,6 @@ struct esd_usb2_net_priv {  	struct usb_anchor tx_submitted;  	struct esd_tx_urb_context tx_contexts[MAX_TX_URBS]; -	int open_time;  	struct esd_usb2 *usb2;  	struct net_device *netdev;  	int index; @@ -284,7 +286,7 @@ static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv,  				break;  			} -			/* Error occured during transmission? */ +			/* Error occurred during transmission? */  			if (!(ecc & SJA1000_ECC_DIR))  				cf->data[2] |= CAN_ERR_PROT_TX; @@ -409,10 +411,20 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)  		switch (msg->msg.hdr.cmd) {  		case CMD_CAN_RX: +			if (msg->msg.rx.net >= dev->net_count) { +				dev_err(dev->udev->dev.parent, "format error\n"); +				break; +			} +  			esd_usb2_rx_can_msg(dev->nets[msg->msg.rx.net], msg);  			break;  		case CMD_CAN_TX: +			if (msg->msg.txdone.net >= dev->net_count) { +				dev_err(dev->udev->dev.parent, "format error\n"); +				break; +			} +  			esd_usb2_tx_done_msg(dev->nets[msg->msg.txdone.net],  					     msg);  			break; @@ -470,8 +482,7 @@ static void esd_usb2_write_bulk_callback(struct urb *urb)  		return;  	if (urb->status) -		dev_info(netdev->dev.parent, "Tx URB aborted (%d)\n", -			 urb->status); +		netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status);  	netdev->trans_start = jiffies;  } @@ -610,9 +621,15 @@ static int esd_usb2_start(struct esd_usb2_net_priv *priv)  {  	struct esd_usb2 *dev = priv->usb2;  	struct net_device *netdev = priv->netdev; -	struct esd_usb2_msg msg; +	struct esd_usb2_msg *msg;  	int err, i; +	msg = kmalloc(sizeof(*msg), GFP_KERNEL); +	if (!msg) { +		err = -ENOMEM; +		goto out; +	} +  	/*  	 * Enable all IDs  	 * The IDADD message takes up to 64 32 bit bitmasks (2048 bits). @@ -626,40 +643,39 @@ static int esd_usb2_start(struct esd_usb2_net_priv *priv)  	 * the number of the starting bitmask (0..64) to the filter.option  	 * field followed by only some bitmasks.  	 */ -	msg.msg.hdr.cmd = CMD_IDADD; -	msg.msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT; -	msg.msg.filter.net = priv->index; -	msg.msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */ +	msg->msg.hdr.cmd = CMD_IDADD; +	msg->msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT; +	msg->msg.filter.net = priv->index; +	msg->msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */  	for (i = 0; i < ESD_MAX_ID_SEGMENT; i++) -		msg.msg.filter.mask[i] = cpu_to_le32(0xffffffff); +		msg->msg.filter.mask[i] = cpu_to_le32(0xffffffff);  	/* enable 29bit extended IDs */ -	msg.msg.filter.mask[ESD_MAX_ID_SEGMENT] = cpu_to_le32(0x00000001); +	msg->msg.filter.mask[ESD_MAX_ID_SEGMENT] = cpu_to_le32(0x00000001); -	err = esd_usb2_send_msg(dev, &msg); +	err = esd_usb2_send_msg(dev, msg);  	if (err) -		goto failed; +		goto out;  	err = esd_usb2_setup_rx_urbs(dev);  	if (err) -		goto failed; +		goto out;  	priv->can.state = CAN_STATE_ERROR_ACTIVE; -	return 0; - -failed: +out:  	if (err == -ENODEV)  		netif_device_detach(netdev); +	if (err) +		netdev_err(netdev, "couldn't start device: %d\n", err); -	dev_err(netdev->dev.parent, "couldn't start device: %d\n", err); - +	kfree(msg);  	return err;  }  static void unlink_all_urbs(struct esd_usb2 *dev)  {  	struct esd_usb2_net_priv *priv; -	int i; +	int i, j;  	usb_kill_anchored_urbs(&dev->rx_submitted);  	for (i = 0; i < dev->net_count; i++) { @@ -668,8 +684,8 @@ static void unlink_all_urbs(struct esd_usb2 *dev)  			usb_kill_anchored_urbs(&priv->tx_submitted);  			atomic_set(&priv->active_tx_jobs, 0); -			for (i = 0; i < MAX_TX_URBS; i++) -				priv->tx_contexts[i].echo_index = MAX_TX_URBS; +			for (j = 0; j < MAX_TX_URBS; j++) +				priv->tx_contexts[j].echo_index = MAX_TX_URBS;  		}  	}  } @@ -687,14 +703,11 @@ static int esd_usb2_open(struct net_device *netdev)  	/* finally start device */  	err = esd_usb2_start(priv);  	if (err) { -		dev_warn(netdev->dev.parent, -			 "couldn't start device: %d\n", err); +		netdev_warn(netdev, "couldn't start device: %d\n", err);  		close_candev(netdev);  		return err;  	} -	priv->open_time = jiffies; -  	netif_start_queue(netdev);  	return 0; @@ -721,7 +734,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,  	/* create a URB, and a buffer for it, and copy the data to the URB */  	urb = usb_alloc_urb(0, GFP_ATOMIC);  	if (!urb) { -		dev_err(netdev->dev.parent, "No memory left for URBs\n"); +		netdev_err(netdev, "No memory left for URBs\n");  		stats->tx_dropped++;  		dev_kfree_skb(skb);  		goto nourbmem; @@ -730,7 +743,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,  	buf = usb_alloc_coherent(dev->udev, size, GFP_ATOMIC,  				 &urb->transfer_dma);  	if (!buf) { -		dev_err(netdev->dev.parent, "No memory left for USB buffer\n"); +		netdev_err(netdev, "No memory left for USB buffer\n");  		stats->tx_dropped++;  		dev_kfree_skb(skb);  		goto nobufmem; @@ -766,7 +779,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,  	 * This may never happen.  	 */  	if (!context) { -		dev_warn(netdev->dev.parent, "couldn't find free context\n"); +		netdev_warn(netdev, "couldn't find free context\n");  		ret = NETDEV_TX_BUSY;  		goto releasebuf;  	} @@ -806,7 +819,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,  		if (err == -ENODEV)  			netif_device_detach(netdev);  		else -			dev_warn(netdev->dev.parent, "failed tx_urb %d\n", err); +			netdev_warn(netdev, "failed tx_urb %d\n", err);  		goto releasebuf;  	} @@ -834,27 +847,31 @@ nourbmem:  static int esd_usb2_close(struct net_device *netdev)  {  	struct esd_usb2_net_priv *priv = netdev_priv(netdev); -	struct esd_usb2_msg msg; +	struct esd_usb2_msg *msg;  	int i; +	msg = kmalloc(sizeof(*msg), GFP_KERNEL); +	if (!msg) +		return -ENOMEM; +  	/* Disable all IDs (see esd_usb2_start()) */ -	msg.msg.hdr.cmd = CMD_IDADD; -	msg.msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT; -	msg.msg.filter.net = priv->index; -	msg.msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */ +	msg->msg.hdr.cmd = CMD_IDADD; +	msg->msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT; +	msg->msg.filter.net = priv->index; +	msg->msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */  	for (i = 0; i <= ESD_MAX_ID_SEGMENT; i++) -		msg.msg.filter.mask[i] = 0; -	if (esd_usb2_send_msg(priv->usb2, &msg) < 0) -		dev_err(netdev->dev.parent, "sending idadd message failed\n"); +		msg->msg.filter.mask[i] = 0; +	if (esd_usb2_send_msg(priv->usb2, msg) < 0) +		netdev_err(netdev, "sending idadd message failed\n");  	/* set CAN controller to reset mode */ -	msg.msg.hdr.len = 2; -	msg.msg.hdr.cmd = CMD_SETBAUD; -	msg.msg.setbaud.net = priv->index; -	msg.msg.setbaud.rsvd = 0; -	msg.msg.setbaud.baud = cpu_to_le32(ESD_USB2_NO_BAUDRATE); -	if (esd_usb2_send_msg(priv->usb2, &msg) < 0) -		dev_err(netdev->dev.parent, "sending setbaud message failed\n"); +	msg->msg.hdr.len = 2; +	msg->msg.hdr.cmd = CMD_SETBAUD; +	msg->msg.setbaud.net = priv->index; +	msg->msg.setbaud.rsvd = 0; +	msg->msg.setbaud.baud = cpu_to_le32(ESD_USB2_NO_BAUDRATE); +	if (esd_usb2_send_msg(priv->usb2, msg) < 0) +		netdev_err(netdev, "sending setbaud message failed\n");  	priv->can.state = CAN_STATE_STOPPED; @@ -862,7 +879,7 @@ static int esd_usb2_close(struct net_device *netdev)  	close_candev(netdev); -	priv->open_time = 0; +	kfree(msg);  	return 0;  } @@ -871,9 +888,10 @@ static const struct net_device_ops esd_usb2_netdev_ops = {  	.ndo_open = esd_usb2_open,  	.ndo_stop = esd_usb2_close,  	.ndo_start_xmit = esd_usb2_start_xmit, +	.ndo_change_mtu = can_change_mtu,  }; -static struct can_bittiming_const esd_usb2_bittiming_const = { +static const struct can_bittiming_const esd_usb2_bittiming_const = {  	.name = "esd_usb2",  	.tseg1_min = ESD_USB2_TSEG1_MIN,  	.tseg1_max = ESD_USB2_TSEG1_MAX, @@ -889,13 +907,25 @@ static int esd_usb2_set_bittiming(struct net_device *netdev)  {  	struct esd_usb2_net_priv *priv = netdev_priv(netdev);  	struct can_bittiming *bt = &priv->can.bittiming; -	struct esd_usb2_msg msg; +	struct esd_usb2_msg *msg; +	int err;  	u32 canbtr; +	int sjw_shift;  	canbtr = ESD_USB2_UBR; +	if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) +		canbtr |= ESD_USB2_LOM; +  	canbtr |= (bt->brp - 1) & (ESD_USB2_BRP_MAX - 1); + +	if (le16_to_cpu(priv->usb2->udev->descriptor.idProduct) == +	    USB_CANUSBM_PRODUCT_ID) +		sjw_shift = ESD_USBM_SJW_SHIFT; +	else +		sjw_shift = ESD_USB2_SJW_SHIFT; +  	canbtr |= ((bt->sjw - 1) & (ESD_USB2_SJW_MAX - 1)) -		<< ESD_USB2_SJW_SHIFT; +		<< sjw_shift;  	canbtr |= ((bt->prop_seg + bt->phase_seg1 - 1)  		   & (ESD_USB2_TSEG1_MAX - 1))  		<< ESD_USB2_TSEG1_SHIFT; @@ -904,15 +934,22 @@ static int esd_usb2_set_bittiming(struct net_device *netdev)  	if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)  		canbtr |= ESD_USB2_3_SAMPLES; -	msg.msg.hdr.len = 2; -	msg.msg.hdr.cmd = CMD_SETBAUD; -	msg.msg.setbaud.net = priv->index; -	msg.msg.setbaud.rsvd = 0; -	msg.msg.setbaud.baud = cpu_to_le32(canbtr); +	msg = kmalloc(sizeof(*msg), GFP_KERNEL); +	if (!msg) +		return -ENOMEM; -	dev_info(netdev->dev.parent, "setting BTR=%#x\n", canbtr); +	msg->msg.hdr.len = 2; +	msg->msg.hdr.cmd = CMD_SETBAUD; +	msg->msg.setbaud.net = priv->index; +	msg->msg.setbaud.rsvd = 0; +	msg->msg.setbaud.baud = cpu_to_le32(canbtr); -	return esd_usb2_send_msg(priv->usb2, &msg); +	netdev_info(netdev, "setting BTR=%#x\n", canbtr); + +	err = esd_usb2_send_msg(priv->usb2, msg); + +	kfree(msg); +	return err;  }  static int esd_usb2_get_berr_counter(const struct net_device *netdev, @@ -928,11 +965,6 @@ static int esd_usb2_get_berr_counter(const struct net_device *netdev,  static int esd_usb2_set_mode(struct net_device *netdev, enum can_mode mode)  { -	struct esd_usb2_net_priv *priv = netdev_priv(netdev); - -	if (!priv->open_time) -		return -EINVAL; -  	switch (mode) {  	case CAN_MODE_START:  		netif_wake_queue(netdev); @@ -973,30 +1005,38 @@ static int esd_usb2_probe_one_net(struct usb_interface *intf, int index)  	priv->index = index;  	priv->can.state = CAN_STATE_STOPPED; -	priv->can.clock.freq = ESD_USB2_CAN_CLOCK; +	priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY; + +	if (le16_to_cpu(dev->udev->descriptor.idProduct) == +	    USB_CANUSBM_PRODUCT_ID) +		priv->can.clock.freq = ESD_USBM_CAN_CLOCK; +	else { +		priv->can.clock.freq = ESD_USB2_CAN_CLOCK; +		priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; +	} +  	priv->can.bittiming_const = &esd_usb2_bittiming_const;  	priv->can.do_set_bittiming = esd_usb2_set_bittiming;  	priv->can.do_set_mode = esd_usb2_set_mode;  	priv->can.do_get_berr_counter = esd_usb2_get_berr_counter; -	priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;  	netdev->flags |= IFF_ECHO; /* we support local echo */  	netdev->netdev_ops = &esd_usb2_netdev_ops;  	SET_NETDEV_DEV(netdev, &intf->dev); +	netdev->dev_id = index;  	err = register_candev(netdev);  	if (err) { -		dev_err(&intf->dev, -			"couldn't register CAN device: %d\n", err); +		dev_err(&intf->dev, "couldn't register CAN device: %d\n", err);  		free_candev(netdev);  		err = -ENOMEM;  		goto done;  	}  	dev->nets[index] = priv; -	dev_info(netdev->dev.parent, "device %s registered\n", netdev->name); +	netdev_info(netdev, "device %s registered\n", netdev->name);  done:  	return err; @@ -1012,7 +1052,7 @@ static int esd_usb2_probe(struct usb_interface *intf,  			 const struct usb_device_id *id)  {  	struct esd_usb2 *dev; -	struct esd_usb2_msg msg; +	struct esd_usb2_msg *msg;  	int i, err;  	dev = kzalloc(sizeof(*dev), GFP_KERNEL); @@ -1027,27 +1067,33 @@ static int esd_usb2_probe(struct usb_interface *intf,  	usb_set_intfdata(intf, dev); +	msg = kmalloc(sizeof(*msg), GFP_KERNEL); +	if (!msg) { +		err = -ENOMEM; +		goto free_msg; +	} +  	/* query number of CAN interfaces (nets) */ -	msg.msg.hdr.cmd = CMD_VERSION; -	msg.msg.hdr.len = 2; -	msg.msg.version.rsvd = 0; -	msg.msg.version.flags = 0; -	msg.msg.version.drv_version = 0; +	msg->msg.hdr.cmd = CMD_VERSION; +	msg->msg.hdr.len = 2; +	msg->msg.version.rsvd = 0; +	msg->msg.version.flags = 0; +	msg->msg.version.drv_version = 0; -	err = esd_usb2_send_msg(dev, &msg); +	err = esd_usb2_send_msg(dev, msg);  	if (err < 0) {  		dev_err(&intf->dev, "sending version message failed\n"); -		goto free_dev; +		goto free_msg;  	} -	err = esd_usb2_wait_msg(dev, &msg); +	err = esd_usb2_wait_msg(dev, msg);  	if (err < 0) {  		dev_err(&intf->dev, "no version message answer\n"); -		goto free_dev; +		goto free_msg;  	} -	dev->net_count = (int)msg.msg.version_reply.nets; -	dev->version = le32_to_cpu(msg.msg.version_reply.version); +	dev->net_count = (int)msg->msg.version_reply.nets; +	dev->version = le32_to_cpu(msg->msg.version_reply.version);  	if (device_create_file(&intf->dev, &dev_attr_firmware))  		dev_err(&intf->dev, @@ -1065,10 +1111,10 @@ static int esd_usb2_probe(struct usb_interface *intf,  	for (i = 0; i < dev->net_count; i++)  		esd_usb2_probe_one_net(intf, i); -	return 0; - -free_dev: -	kfree(dev); +free_msg: +	kfree(msg); +	if (err) +		kfree(dev);  done:  	return err;  } @@ -1108,25 +1154,4 @@ static struct usb_driver esd_usb2_driver = {  	.id_table = esd_usb2_table,  }; -static int __init esd_usb2_init(void) -{ -	int err; - -	/* register this driver with the USB subsystem */ -	err = usb_register(&esd_usb2_driver); - -	if (err) { -		err("usb_register failed. Error number %d\n", err); -		return err; -	} - -	return 0; -} -module_init(esd_usb2_init); - -static void __exit esd_usb2_exit(void) -{ -	/* deregister this driver with the USB subsystem */ -	usb_deregister(&esd_usb2_driver); -} -module_exit(esd_usb2_exit); +module_usb_driver(esd_usb2_driver); diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c new file mode 100644 index 00000000000..04b0f84612f --- /dev/null +++ b/drivers/net/can/usb/gs_usb.c @@ -0,0 +1,971 @@ +/* CAN driver for Geschwister Schneider USB/CAN devices. + * + * Copyright (C) 2013 Geschwister Schneider Technologie-, + * Entwicklungs- und Vertriebs UG (Haftungsbeschränkt). + * + * Many thanks to all socketcan devs! + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include <linux/init.h> +#include <linux/signal.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/usb.h> + +#include <linux/can.h> +#include <linux/can/dev.h> +#include <linux/can/error.h> + +/* Device specific constants */ +#define USB_GSUSB_1_VENDOR_ID      0x1d50 +#define USB_GSUSB_1_PRODUCT_ID     0x606f + +#define GSUSB_ENDPOINT_IN          1 +#define GSUSB_ENDPOINT_OUT         2 + +/* Device specific constants */ +enum gs_usb_breq { +	GS_USB_BREQ_HOST_FORMAT = 0, +	GS_USB_BREQ_BITTIMING, +	GS_USB_BREQ_MODE, +	GS_USB_BREQ_BERR, +	GS_USB_BREQ_BT_CONST, +	GS_USB_BREQ_DEVICE_CONFIG +}; + +enum gs_can_mode { +	/* reset a channel. turns it off */ +	GS_CAN_MODE_RESET = 0, +	/* starts a channel */ +	GS_CAN_MODE_START +}; + +enum gs_can_state { +	GS_CAN_STATE_ERROR_ACTIVE = 0, +	GS_CAN_STATE_ERROR_WARNING, +	GS_CAN_STATE_ERROR_PASSIVE, +	GS_CAN_STATE_BUS_OFF, +	GS_CAN_STATE_STOPPED, +	GS_CAN_STATE_SLEEPING +}; + +/* data types passed between host and device */ +struct gs_host_config { +	u32 byte_order; +} __packed; +/* All data exchanged between host and device is exchanged in host byte order, + * thanks to the struct gs_host_config byte_order member, which is sent first + * to indicate the desired byte order. + */ + +struct gs_device_config { +	u8 reserved1; +	u8 reserved2; +	u8 reserved3; +	u8 icount; +	u32 sw_version; +	u32 hw_version; +} __packed; + +#define GS_CAN_MODE_NORMAL               0 +#define GS_CAN_MODE_LISTEN_ONLY          (1<<0) +#define GS_CAN_MODE_LOOP_BACK            (1<<1) +#define GS_CAN_MODE_TRIPLE_SAMPLE        (1<<2) +#define GS_CAN_MODE_ONE_SHOT             (1<<3) + +struct gs_device_mode { +	u32 mode; +	u32 flags; +} __packed; + +struct gs_device_state { +	u32 state; +	u32 rxerr; +	u32 txerr; +} __packed; + +struct gs_device_bittiming { +	u32 prop_seg; +	u32 phase_seg1; +	u32 phase_seg2; +	u32 sjw; +	u32 brp; +} __packed; + +#define GS_CAN_FEATURE_LISTEN_ONLY      (1<<0) +#define GS_CAN_FEATURE_LOOP_BACK        (1<<1) +#define GS_CAN_FEATURE_TRIPLE_SAMPLE    (1<<2) +#define GS_CAN_FEATURE_ONE_SHOT         (1<<3) + +struct gs_device_bt_const { +	u32 feature; +	u32 fclk_can; +	u32 tseg1_min; +	u32 tseg1_max; +	u32 tseg2_min; +	u32 tseg2_max; +	u32 sjw_max; +	u32 brp_min; +	u32 brp_max; +	u32 brp_inc; +} __packed; + +#define GS_CAN_FLAG_OVERFLOW 1 + +struct gs_host_frame { +	u32 echo_id; +	u32 can_id; + +	u8 can_dlc; +	u8 channel; +	u8 flags; +	u8 reserved; + +	u8 data[8]; +} __packed; +/* The GS USB devices make use of the same flags and masks as in + * linux/can.h and linux/can/error.h, and no additional mapping is necessary. + */ + +/* Only send a max of GS_MAX_TX_URBS frames per channel at a time. */ +#define GS_MAX_TX_URBS 10 +/* Only launch a max of GS_MAX_RX_URBS usb requests at a time. */ +#define GS_MAX_RX_URBS 30 +/* Maximum number of interfaces the driver supports per device. + * Current hardware only supports 2 interfaces. The future may vary. + */ +#define GS_MAX_INTF 2 + +struct gs_tx_context { +	struct gs_can *dev; +	unsigned int echo_id; +}; + +struct gs_can { +	struct can_priv can; /* must be the first member */ + +	struct gs_usb *parent; + +	struct net_device *netdev; +	struct usb_device *udev; +	struct usb_interface *iface; + +	struct can_bittiming_const bt_const; +	unsigned int channel;	/* channel number */ + +	/* This lock prevents a race condition between xmit and recieve. */ +	spinlock_t tx_ctx_lock; +	struct gs_tx_context tx_context[GS_MAX_TX_URBS]; + +	struct usb_anchor tx_submitted; +	atomic_t active_tx_urbs; +}; + +/* usb interface struct */ +struct gs_usb { +	struct gs_can *canch[GS_MAX_INTF]; +	struct usb_anchor rx_submitted; +	atomic_t active_channels; +	struct usb_device *udev; +}; + +/* 'allocate' a tx context. + * returns a valid tx context or NULL if there is no space. + */ +static struct gs_tx_context *gs_alloc_tx_context(struct gs_can *dev) +{ +	int i = 0; +	unsigned long flags; + +	spin_lock_irqsave(&dev->tx_ctx_lock, flags); + +	for (; i < GS_MAX_TX_URBS; i++) { +		if (dev->tx_context[i].echo_id == GS_MAX_TX_URBS) { +			dev->tx_context[i].echo_id = i; +			spin_unlock_irqrestore(&dev->tx_ctx_lock, flags); +			return &dev->tx_context[i]; +		} +	} + +	spin_unlock_irqrestore(&dev->tx_ctx_lock, flags); +	return NULL; +} + +/* releases a tx context + */ +static void gs_free_tx_context(struct gs_tx_context *txc) +{ +	txc->echo_id = GS_MAX_TX_URBS; +} + +/* Get a tx context by id. + */ +static struct gs_tx_context *gs_get_tx_context(struct gs_can *dev, unsigned int id) +{ +	unsigned long flags; + +	if (id < GS_MAX_TX_URBS) { +		spin_lock_irqsave(&dev->tx_ctx_lock, flags); +		if (dev->tx_context[id].echo_id == id) { +			spin_unlock_irqrestore(&dev->tx_ctx_lock, flags); +			return &dev->tx_context[id]; +		} +		spin_unlock_irqrestore(&dev->tx_ctx_lock, flags); +	} +	return NULL; +} + +static int gs_cmd_reset(struct gs_usb *gsusb, struct gs_can *gsdev) +{ +	struct gs_device_mode *dm; +	struct usb_interface *intf = gsdev->iface; +	int rc; + +	dm = kzalloc(sizeof(*dm), GFP_KERNEL); +	if (!dm) +		return -ENOMEM; + +	dm->mode = GS_CAN_MODE_RESET; + +	rc = usb_control_msg(interface_to_usbdev(intf), +			     usb_sndctrlpipe(interface_to_usbdev(intf), 0), +			     GS_USB_BREQ_MODE, +			     USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, +			     gsdev->channel, +			     0, +			     dm, +			     sizeof(*dm), +			     1000); + +	return rc; +} + +static void gs_update_state(struct gs_can *dev, struct can_frame *cf) +{ +	struct can_device_stats *can_stats = &dev->can.can_stats; + +	if (cf->can_id & CAN_ERR_RESTARTED) { +		dev->can.state = CAN_STATE_ERROR_ACTIVE; +		can_stats->restarts++; +	} else if (cf->can_id & CAN_ERR_BUSOFF) { +		dev->can.state = CAN_STATE_BUS_OFF; +		can_stats->bus_off++; +	} else if (cf->can_id & CAN_ERR_CRTL) { +		if ((cf->data[1] & CAN_ERR_CRTL_TX_WARNING) || +		    (cf->data[1] & CAN_ERR_CRTL_RX_WARNING)) { +			dev->can.state = CAN_STATE_ERROR_WARNING; +			can_stats->error_warning++; +		} else if ((cf->data[1] & CAN_ERR_CRTL_TX_PASSIVE) || +			   (cf->data[1] & CAN_ERR_CRTL_RX_PASSIVE)) { +			dev->can.state = CAN_STATE_ERROR_PASSIVE; +			can_stats->error_passive++; +		} else { +			dev->can.state = CAN_STATE_ERROR_ACTIVE; +		} +	} +} + +static void gs_usb_recieve_bulk_callback(struct urb *urb) +{ +	struct gs_usb *usbcan = urb->context; +	struct gs_can *dev; +	struct net_device *netdev; +	int rc; +	struct net_device_stats *stats; +	struct gs_host_frame *hf = urb->transfer_buffer; +	struct gs_tx_context *txc; +	struct can_frame *cf; +	struct sk_buff *skb; + +	BUG_ON(!usbcan); + +	switch (urb->status) { +	case 0: /* success */ +		break; +	case -ENOENT: +	case -ESHUTDOWN: +		return; +	default: +		/* do not resubmit aborted urbs. eg: when device goes down */ +		return; +	} + +	/* device reports out of range channel id */ +	if (hf->channel >= GS_MAX_INTF) +		goto resubmit_urb; + +	dev = usbcan->canch[hf->channel]; + +	netdev = dev->netdev; +	stats = &netdev->stats; + +	if (!netif_device_present(netdev)) +		return; + +	if (hf->echo_id == -1) { /* normal rx */ +		skb = alloc_can_skb(dev->netdev, &cf); +		if (!skb) +			return; + +		cf->can_id = hf->can_id; + +		cf->can_dlc = get_can_dlc(hf->can_dlc); +		memcpy(cf->data, hf->data, 8); + +		/* ERROR frames tell us information about the controller */ +		if (hf->can_id & CAN_ERR_FLAG) +			gs_update_state(dev, cf); + +		netdev->stats.rx_packets++; +		netdev->stats.rx_bytes += hf->can_dlc; + +		netif_rx(skb); +	} else { /* echo_id == hf->echo_id */ +		if (hf->echo_id >= GS_MAX_TX_URBS) { +			netdev_err(netdev, +				   "Unexpected out of range echo id %d\n", +				   hf->echo_id); +			goto resubmit_urb; +		} + +		netdev->stats.tx_packets++; +		netdev->stats.tx_bytes += hf->can_dlc; + +		txc = gs_get_tx_context(dev, hf->echo_id); + +		/* bad devices send bad echo_ids. */ +		if (!txc) { +			netdev_err(netdev, +				   "Unexpected unused echo id %d\n", +				   hf->echo_id); +			goto resubmit_urb; +		} + +		can_get_echo_skb(netdev, hf->echo_id); + +		gs_free_tx_context(txc); + +		netif_wake_queue(netdev); +	} + +	if (hf->flags & GS_CAN_FLAG_OVERFLOW) { +		skb = alloc_can_err_skb(netdev, &cf); +		if (!skb) +			goto resubmit_urb; + +		cf->can_id |= CAN_ERR_CRTL; +		cf->can_dlc = CAN_ERR_DLC; +		cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; +		stats->rx_over_errors++; +		stats->rx_errors++; +		netif_rx(skb); +	} + + resubmit_urb: +	usb_fill_bulk_urb(urb, +			  usbcan->udev, +			  usb_rcvbulkpipe(usbcan->udev, GSUSB_ENDPOINT_IN), +			  hf, +			  sizeof(struct gs_host_frame), +			  gs_usb_recieve_bulk_callback, +			  usbcan +			  ); + +	rc = usb_submit_urb(urb, GFP_ATOMIC); + +	/* USB failure take down all interfaces */ +	if (rc == -ENODEV) { +		for (rc = 0; rc < GS_MAX_INTF; rc++) { +			if (usbcan->canch[rc]) +				netif_device_detach(usbcan->canch[rc]->netdev); +		} +	} +} + +static int gs_usb_set_bittiming(struct net_device *netdev) +{ +	struct gs_can *dev = netdev_priv(netdev); +	struct can_bittiming *bt = &dev->can.bittiming; +	struct usb_interface *intf = dev->iface; +	int rc; +	struct gs_device_bittiming *dbt; + +	dbt = kmalloc(sizeof(*dbt), GFP_KERNEL); +	if (!dbt) +		return -ENOMEM; + +	dbt->prop_seg = bt->prop_seg; +	dbt->phase_seg1 = bt->phase_seg1; +	dbt->phase_seg2 = bt->phase_seg2; +	dbt->sjw = bt->sjw; +	dbt->brp = bt->brp; + +	/* request bit timings */ +	rc = usb_control_msg(interface_to_usbdev(intf), +			     usb_sndctrlpipe(interface_to_usbdev(intf), 0), +			     GS_USB_BREQ_BITTIMING, +			     USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, +			     dev->channel, +			     0, +			     dbt, +			     sizeof(*dbt), +			     1000); + +	kfree(dbt); + +	if (rc < 0) +		dev_err(netdev->dev.parent, "Couldn't set bittimings (err=%d)", +			rc); + +	return rc; +} + +static void gs_usb_xmit_callback(struct urb *urb) +{ +	struct gs_tx_context *txc = urb->context; +	struct gs_can *dev = txc->dev; +	struct net_device *netdev = dev->netdev; + +	if (urb->status) +		netdev_info(netdev, "usb xmit fail %d\n", txc->echo_id); + +	usb_free_coherent(urb->dev, +			  urb->transfer_buffer_length, +			  urb->transfer_buffer, +			  urb->transfer_dma); + +	atomic_dec(&dev->active_tx_urbs); + +	if (!netif_device_present(netdev)) +		return; + +	if (netif_queue_stopped(netdev)) +		netif_wake_queue(netdev); +} + +static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb, struct net_device *netdev) +{ +	struct gs_can *dev = netdev_priv(netdev); +	struct net_device_stats *stats = &dev->netdev->stats; +	struct urb *urb; +	struct gs_host_frame *hf; +	struct can_frame *cf; +	int rc; +	unsigned int idx; +	struct gs_tx_context *txc; + +	if (can_dropped_invalid_skb(netdev, skb)) +		return NETDEV_TX_OK; + +	/* find an empty context to keep track of transmission */ +	txc = gs_alloc_tx_context(dev); +	if (!txc) +		return NETDEV_TX_BUSY; + +	/* create a URB, and a buffer for it */ +	urb = usb_alloc_urb(0, GFP_ATOMIC); +	if (!urb) { +		netdev_err(netdev, "No memory left for URB\n"); +		goto nomem_urb; +	} + +	hf = usb_alloc_coherent(dev->udev, sizeof(*hf), GFP_ATOMIC, +				&urb->transfer_dma); +	if (!hf) { +		netdev_err(netdev, "No memory left for USB buffer\n"); +		goto nomem_hf; +	} + +	idx = txc->echo_id; + +	if (idx >= GS_MAX_TX_URBS) { +		netdev_err(netdev, "Invalid tx context %d\n", idx); +		goto badidx; +	} + +	hf->echo_id = idx; +	hf->channel = dev->channel; + +	cf = (struct can_frame *)skb->data; + +	hf->can_id = cf->can_id; +	hf->can_dlc = cf->can_dlc; +	memcpy(hf->data, cf->data, cf->can_dlc); + +	usb_fill_bulk_urb(urb, dev->udev, +			  usb_sndbulkpipe(dev->udev, GSUSB_ENDPOINT_OUT), +			  hf, +			  sizeof(*hf), +			  gs_usb_xmit_callback, +			  txc); + +	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; +	usb_anchor_urb(urb, &dev->tx_submitted); + +	can_put_echo_skb(skb, netdev, idx); + +	atomic_inc(&dev->active_tx_urbs); + +	rc = usb_submit_urb(urb, GFP_ATOMIC); +	if (unlikely(rc)) {			/* usb send failed */ +		atomic_dec(&dev->active_tx_urbs); + +		can_free_echo_skb(netdev, idx); +		gs_free_tx_context(txc); + +		usb_unanchor_urb(urb); +		usb_free_coherent(dev->udev, +				  sizeof(*hf), +				  hf, +				  urb->transfer_dma); + + +		if (rc == -ENODEV) { +			netif_device_detach(netdev); +		} else { +			netdev_err(netdev, "usb_submit failed (err=%d)\n", rc); +			stats->tx_dropped++; +		} +	} else { +		/* Slow down tx path */ +		if (atomic_read(&dev->active_tx_urbs) >= GS_MAX_TX_URBS) +			netif_stop_queue(netdev); +	} + +	/* let usb core take care of this urb */ +	usb_free_urb(urb); + +	return NETDEV_TX_OK; + + badidx: +	usb_free_coherent(dev->udev, +			  sizeof(*hf), +			  hf, +			  urb->transfer_dma); + nomem_hf: +	usb_free_urb(urb); + + nomem_urb: +	gs_free_tx_context(txc); +	dev_kfree_skb(skb); +	stats->tx_dropped++; +	return NETDEV_TX_OK; +} + +static int gs_can_open(struct net_device *netdev) +{ +	struct gs_can *dev = netdev_priv(netdev); +	struct gs_usb *parent = dev->parent; +	int rc, i; +	struct gs_device_mode *dm; +	u32 ctrlmode; + +	rc = open_candev(netdev); +	if (rc) +		return rc; + +	if (atomic_add_return(1, &parent->active_channels) == 1) { +		for (i = 0; i < GS_MAX_RX_URBS; i++) { +			struct urb *urb; +			u8 *buf; + +			/* alloc rx urb */ +			urb = usb_alloc_urb(0, GFP_KERNEL); +			if (!urb) { +				netdev_err(netdev, +					   "No memory left for URB\n"); +				return -ENOMEM; +			} + +			/* alloc rx buffer */ +			buf = usb_alloc_coherent(dev->udev, +						 sizeof(struct gs_host_frame), +						 GFP_KERNEL, +						 &urb->transfer_dma); +			if (!buf) { +				netdev_err(netdev, +					   "No memory left for USB buffer\n"); +				usb_free_urb(urb); +				return -ENOMEM; +			} + +			/* fill, anchor, and submit rx urb */ +			usb_fill_bulk_urb(urb, +					  dev->udev, +					  usb_rcvbulkpipe(dev->udev, +							  GSUSB_ENDPOINT_IN), +					  buf, +					  sizeof(struct gs_host_frame), +					  gs_usb_recieve_bulk_callback, +					  parent); +			urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + +			usb_anchor_urb(urb, &parent->rx_submitted); + +			rc = usb_submit_urb(urb, GFP_KERNEL); +			if (rc) { +				if (rc == -ENODEV) +					netif_device_detach(dev->netdev); + +				netdev_err(netdev, +					   "usb_submit failed (err=%d)\n", +					   rc); + +				usb_unanchor_urb(urb); +				break; +			} + +			/* Drop reference, +			 * USB core will take care of freeing it +			 */ +			usb_free_urb(urb); +		} +	} + +	dm = kmalloc(sizeof(*dm), GFP_KERNEL); +	if (!dm) +		return -ENOMEM; + +	/* flags */ +	ctrlmode = dev->can.ctrlmode; +	dm->flags = 0; + +	if (ctrlmode & CAN_CTRLMODE_LOOPBACK) +		dm->flags |= GS_CAN_MODE_LOOP_BACK; +	else if (ctrlmode & CAN_CTRLMODE_LISTENONLY) +		dm->flags |= GS_CAN_MODE_LISTEN_ONLY; + +	/* Controller is not allowed to retry TX +	 * this mode is unavailable on atmels uc3c hardware +	 */ +	if (ctrlmode & CAN_CTRLMODE_ONE_SHOT) +		dm->flags |= GS_CAN_MODE_ONE_SHOT; + +	if (ctrlmode & CAN_CTRLMODE_3_SAMPLES) +		dm->flags |= GS_CAN_MODE_TRIPLE_SAMPLE; + +	/* finally start device */ +	dm->mode = GS_CAN_MODE_START; +	rc = usb_control_msg(interface_to_usbdev(dev->iface), +			     usb_sndctrlpipe(interface_to_usbdev(dev->iface), 0), +			     GS_USB_BREQ_MODE, +			     USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, +			     dev->channel, +			     0, +			     dm, +			     sizeof(*dm), +			     1000); + +	if (rc < 0) { +		netdev_err(netdev, "Couldn't start device (err=%d)\n", rc); +		kfree(dm); +		return rc; +	} + +	kfree(dm); + +	dev->can.state = CAN_STATE_ERROR_ACTIVE; + +	if (!(dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)) +		netif_start_queue(netdev); + +	return 0; +} + +static int gs_can_close(struct net_device *netdev) +{ +	int rc; +	struct gs_can *dev = netdev_priv(netdev); +	struct gs_usb *parent = dev->parent; + +	netif_stop_queue(netdev); + +	/* Stop polling */ +	if (atomic_dec_and_test(&parent->active_channels)) +		usb_kill_anchored_urbs(&parent->rx_submitted); + +	/* Stop sending URBs */ +	usb_kill_anchored_urbs(&dev->tx_submitted); +	atomic_set(&dev->active_tx_urbs, 0); + +	/* reset the device */ +	rc = gs_cmd_reset(parent, dev); +	if (rc < 0) +		netdev_warn(netdev, "Couldn't shutdown device (err=%d)", rc); + +	/* reset tx contexts */ +	for (rc = 0; rc < GS_MAX_TX_URBS; rc++) { +		dev->tx_context[rc].dev = dev; +		dev->tx_context[rc].echo_id = GS_MAX_TX_URBS; +	} + +	/* close the netdev */ +	close_candev(netdev); + +	return 0; +} + +static const struct net_device_ops gs_usb_netdev_ops = { +	.ndo_open = gs_can_open, +	.ndo_stop = gs_can_close, +	.ndo_start_xmit = gs_can_start_xmit, +}; + +static struct gs_can *gs_make_candev(unsigned int channel, struct usb_interface *intf) +{ +	struct gs_can *dev; +	struct net_device *netdev; +	int rc; +	struct gs_device_bt_const *bt_const; + +	bt_const = kmalloc(sizeof(*bt_const), GFP_KERNEL); +	if (!bt_const) +		return ERR_PTR(-ENOMEM); + +	/* fetch bit timing constants */ +	rc = usb_control_msg(interface_to_usbdev(intf), +			     usb_rcvctrlpipe(interface_to_usbdev(intf), 0), +			     GS_USB_BREQ_BT_CONST, +			     USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, +			     channel, +			     0, +			     bt_const, +			     sizeof(*bt_const), +			     1000); + +	if (rc < 0) { +		dev_err(&intf->dev, +			"Couldn't get bit timing const for channel (err=%d)\n", +			rc); +		kfree(bt_const); +		return ERR_PTR(rc); +	} + +	/* create netdev */ +	netdev = alloc_candev(sizeof(struct gs_can), GS_MAX_TX_URBS); +	if (!netdev) { +		dev_err(&intf->dev, "Couldn't allocate candev\n"); +		kfree(bt_const); +		return ERR_PTR(-ENOMEM); +	} + +	dev = netdev_priv(netdev); + +	netdev->netdev_ops = &gs_usb_netdev_ops; + +	netdev->flags |= IFF_ECHO; /* we support full roundtrip echo */ + +	/* dev settup */ +	strcpy(dev->bt_const.name, "gs_usb"); +	dev->bt_const.tseg1_min = bt_const->tseg1_min; +	dev->bt_const.tseg1_max = bt_const->tseg1_max; +	dev->bt_const.tseg2_min = bt_const->tseg2_min; +	dev->bt_const.tseg2_max = bt_const->tseg2_max; +	dev->bt_const.sjw_max = bt_const->sjw_max; +	dev->bt_const.brp_min = bt_const->brp_min; +	dev->bt_const.brp_max = bt_const->brp_max; +	dev->bt_const.brp_inc = bt_const->brp_inc; + +	dev->udev = interface_to_usbdev(intf); +	dev->iface = intf; +	dev->netdev = netdev; +	dev->channel = channel; + +	init_usb_anchor(&dev->tx_submitted); +	atomic_set(&dev->active_tx_urbs, 0); +	spin_lock_init(&dev->tx_ctx_lock); +	for (rc = 0; rc < GS_MAX_TX_URBS; rc++) { +		dev->tx_context[rc].dev = dev; +		dev->tx_context[rc].echo_id = GS_MAX_TX_URBS; +	} + +	/* can settup */ +	dev->can.state = CAN_STATE_STOPPED; +	dev->can.clock.freq = bt_const->fclk_can; +	dev->can.bittiming_const = &dev->bt_const; +	dev->can.do_set_bittiming = gs_usb_set_bittiming; + +	dev->can.ctrlmode_supported = 0; + +	if (bt_const->feature & GS_CAN_FEATURE_LISTEN_ONLY) +		dev->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY; + +	if (bt_const->feature & GS_CAN_FEATURE_LOOP_BACK) +		dev->can.ctrlmode_supported |= CAN_CTRLMODE_LOOPBACK; + +	if (bt_const->feature & GS_CAN_FEATURE_TRIPLE_SAMPLE) +		dev->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; + +	if (bt_const->feature & GS_CAN_FEATURE_ONE_SHOT) +		dev->can.ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT; + +	kfree(bt_const); + +	SET_NETDEV_DEV(netdev, &intf->dev); + +	rc = register_candev(dev->netdev); +	if (rc) { +		free_candev(dev->netdev); +		dev_err(&intf->dev, "Couldn't register candev (err=%d)\n", rc); +		return ERR_PTR(rc); +	} + +	return dev; +} + +static void gs_destroy_candev(struct gs_can *dev) +{ +	unregister_candev(dev->netdev); +	free_candev(dev->netdev); +	usb_kill_anchored_urbs(&dev->tx_submitted); +	kfree(dev); +} + +static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ +	struct gs_usb *dev; +	int rc = -ENOMEM; +	unsigned int icount, i; +	struct gs_host_config *hconf; +	struct gs_device_config *dconf; + +	hconf = kmalloc(sizeof(*hconf), GFP_KERNEL); +	if (!hconf) +		return -ENOMEM; + +	hconf->byte_order = 0x0000beef; + +	/* send host config */ +	rc = usb_control_msg(interface_to_usbdev(intf), +			     usb_sndctrlpipe(interface_to_usbdev(intf), 0), +			     GS_USB_BREQ_HOST_FORMAT, +			     USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, +			     1, +			     intf->altsetting[0].desc.bInterfaceNumber, +			     hconf, +			     sizeof(*hconf), +			     1000); + +	kfree(hconf); + +	if (rc < 0) { +		dev_err(&intf->dev, "Couldn't send data format (err=%d)\n", +			rc); +		return rc; +	} + +	dconf = kmalloc(sizeof(*dconf), GFP_KERNEL); +	if (!dconf) +		return -ENOMEM; + +	/* read device config */ +	rc = usb_control_msg(interface_to_usbdev(intf), +			     usb_rcvctrlpipe(interface_to_usbdev(intf), 0), +			     GS_USB_BREQ_DEVICE_CONFIG, +			     USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, +			     1, +			     intf->altsetting[0].desc.bInterfaceNumber, +			     dconf, +			     sizeof(*dconf), +			     1000); +	if (rc < 0) { +		dev_err(&intf->dev, "Couldn't get device config: (err=%d)\n", +			rc); + +		kfree(dconf); + +		return rc; +	} + +	icount = dconf->icount+1; + +	kfree(dconf); + +	dev_info(&intf->dev, "Configuring for %d interfaces\n", icount); + +	if (icount > GS_MAX_INTF) { +		dev_err(&intf->dev, +			"Driver cannot handle more that %d CAN interfaces\n", +			GS_MAX_INTF); +		return -EINVAL; +	} + +	dev = kzalloc(sizeof(*dev), GFP_KERNEL); +	init_usb_anchor(&dev->rx_submitted); + +	atomic_set(&dev->active_channels, 0); + +	usb_set_intfdata(intf, dev); +	dev->udev = interface_to_usbdev(intf); + +	for (i = 0; i < icount; i++) { +		dev->canch[i] = gs_make_candev(i, intf); +		if (IS_ERR_OR_NULL(dev->canch[i])) { +			/* on failure destroy previously created candevs */ +			icount = i; +			for (i = 0; i < icount; i++) { +				gs_destroy_candev(dev->canch[i]); +				dev->canch[i] = NULL; +			} +			kfree(dev); +			return rc; +		} +		dev->canch[i]->parent = dev; +	} + +	return 0; +} + +static void gs_usb_disconnect(struct usb_interface *intf) +{ +	unsigned i; +	struct gs_usb *dev = usb_get_intfdata(intf); +	usb_set_intfdata(intf, NULL); + +	if (!dev) { +		dev_err(&intf->dev, "Disconnect (nodata)\n"); +		return; +	} + +	for (i = 0; i < GS_MAX_INTF; i++) { +		struct gs_can *can = dev->canch[i]; + +		if (!can) +			continue; + +		gs_destroy_candev(can); +	} + +	usb_kill_anchored_urbs(&dev->rx_submitted); +} + +static const struct usb_device_id gs_usb_table[] = { +	{USB_DEVICE(USB_GSUSB_1_VENDOR_ID, USB_GSUSB_1_PRODUCT_ID)}, +	{} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, gs_usb_table); + +static struct usb_driver gs_usb_driver = { +	.name       = "gs_usb", +	.probe      = gs_usb_probe, +	.disconnect = gs_usb_disconnect, +	.id_table   = gs_usb_table, +}; + +module_usb_driver(gs_usb_driver); + +MODULE_AUTHOR("Maximilian Schneider <mws@schneidersoft.net>"); +MODULE_DESCRIPTION( +"Socket CAN device driver for Geschwister Schneider Technologie-, " +"Entwicklungs- und Vertriebs UG. USB2.0 to CAN interfaces."); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c new file mode 100644 index 00000000000..541fb7a0562 --- /dev/null +++ b/drivers/net/can/usb/kvaser_usb.c @@ -0,0 +1,1665 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * Parts of this driver are based on the following: + *  - Kvaser linux leaf driver (version 4.78) + *  - CAN driver for esd CAN-USB/2 + * + * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved. + * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh + * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be> + */ + +#include <linux/completion.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/usb.h> + +#include <linux/can.h> +#include <linux/can/dev.h> +#include <linux/can/error.h> + +#define MAX_TX_URBS			16 +#define MAX_RX_URBS			4 +#define START_TIMEOUT			1000 /* msecs */ +#define STOP_TIMEOUT			1000 /* msecs */ +#define USB_SEND_TIMEOUT		1000 /* msecs */ +#define USB_RECV_TIMEOUT		1000 /* msecs */ +#define RX_BUFFER_SIZE			3072 +#define CAN_USB_CLOCK			8000000 +#define MAX_NET_DEVICES			3 + +/* Kvaser USB devices */ +#define KVASER_VENDOR_ID		0x0bfd +#define USB_LEAF_DEVEL_PRODUCT_ID	10 +#define USB_LEAF_LITE_PRODUCT_ID	11 +#define USB_LEAF_PRO_PRODUCT_ID		12 +#define USB_LEAF_SPRO_PRODUCT_ID	14 +#define USB_LEAF_PRO_LS_PRODUCT_ID	15 +#define USB_LEAF_PRO_SWC_PRODUCT_ID	16 +#define USB_LEAF_PRO_LIN_PRODUCT_ID	17 +#define USB_LEAF_SPRO_LS_PRODUCT_ID	18 +#define USB_LEAF_SPRO_SWC_PRODUCT_ID	19 +#define USB_MEMO2_DEVEL_PRODUCT_ID	22 +#define USB_MEMO2_HSHS_PRODUCT_ID	23 +#define USB_UPRO_HSHS_PRODUCT_ID	24 +#define USB_LEAF_LITE_GI_PRODUCT_ID	25 +#define USB_LEAF_PRO_OBDII_PRODUCT_ID	26 +#define USB_MEMO2_HSLS_PRODUCT_ID	27 +#define USB_LEAF_LITE_CH_PRODUCT_ID	28 +#define USB_BLACKBIRD_SPRO_PRODUCT_ID	29 +#define USB_OEM_MERCURY_PRODUCT_ID	34 +#define USB_OEM_LEAF_PRODUCT_ID		35 +#define USB_CAN_R_PRODUCT_ID		39 +#define USB_LEAF_LITE_V2_PRODUCT_ID	288 +#define USB_MINI_PCIE_HS_PRODUCT_ID	289 + +/* USB devices features */ +#define KVASER_HAS_SILENT_MODE		BIT(0) +#define KVASER_HAS_TXRX_ERRORS		BIT(1) + +/* Message header size */ +#define MSG_HEADER_LEN			2 + +/* Can message flags */ +#define MSG_FLAG_ERROR_FRAME		BIT(0) +#define MSG_FLAG_OVERRUN		BIT(1) +#define MSG_FLAG_NERR			BIT(2) +#define MSG_FLAG_WAKEUP			BIT(3) +#define MSG_FLAG_REMOTE_FRAME		BIT(4) +#define MSG_FLAG_RESERVED		BIT(5) +#define MSG_FLAG_TX_ACK			BIT(6) +#define MSG_FLAG_TX_REQUEST		BIT(7) + +/* Can states */ +#define M16C_STATE_BUS_RESET		BIT(0) +#define M16C_STATE_BUS_ERROR		BIT(4) +#define M16C_STATE_BUS_PASSIVE		BIT(5) +#define M16C_STATE_BUS_OFF		BIT(6) + +/* Can msg ids */ +#define CMD_RX_STD_MESSAGE		12 +#define CMD_TX_STD_MESSAGE		13 +#define CMD_RX_EXT_MESSAGE		14 +#define CMD_TX_EXT_MESSAGE		15 +#define CMD_SET_BUS_PARAMS		16 +#define CMD_GET_BUS_PARAMS		17 +#define CMD_GET_BUS_PARAMS_REPLY	18 +#define CMD_GET_CHIP_STATE		19 +#define CMD_CHIP_STATE_EVENT		20 +#define CMD_SET_CTRL_MODE		21 +#define CMD_GET_CTRL_MODE		22 +#define CMD_GET_CTRL_MODE_REPLY		23 +#define CMD_RESET_CHIP			24 +#define CMD_RESET_CARD			25 +#define CMD_START_CHIP			26 +#define CMD_START_CHIP_REPLY		27 +#define CMD_STOP_CHIP			28 +#define CMD_STOP_CHIP_REPLY		29 +#define CMD_GET_CARD_INFO2		32 +#define CMD_GET_CARD_INFO		34 +#define CMD_GET_CARD_INFO_REPLY		35 +#define CMD_GET_SOFTWARE_INFO		38 +#define CMD_GET_SOFTWARE_INFO_REPLY	39 +#define CMD_ERROR_EVENT			45 +#define CMD_FLUSH_QUEUE			48 +#define CMD_RESET_ERROR_COUNTER		49 +#define CMD_TX_ACKNOWLEDGE		50 +#define CMD_CAN_ERROR_EVENT		51 +#define CMD_USB_THROTTLE		77 +#define CMD_LOG_MESSAGE			106 + +/* error factors */ +#define M16C_EF_ACKE			BIT(0) +#define M16C_EF_CRCE			BIT(1) +#define M16C_EF_FORME			BIT(2) +#define M16C_EF_STFE			BIT(3) +#define M16C_EF_BITE0			BIT(4) +#define M16C_EF_BITE1			BIT(5) +#define M16C_EF_RCVE			BIT(6) +#define M16C_EF_TRE			BIT(7) + +/* bittiming parameters */ +#define KVASER_USB_TSEG1_MIN		1 +#define KVASER_USB_TSEG1_MAX		16 +#define KVASER_USB_TSEG2_MIN		1 +#define KVASER_USB_TSEG2_MAX		8 +#define KVASER_USB_SJW_MAX		4 +#define KVASER_USB_BRP_MIN		1 +#define KVASER_USB_BRP_MAX		64 +#define KVASER_USB_BRP_INC		1 + +/* ctrl modes */ +#define KVASER_CTRL_MODE_NORMAL		1 +#define KVASER_CTRL_MODE_SILENT		2 +#define KVASER_CTRL_MODE_SELFRECEPTION	3 +#define KVASER_CTRL_MODE_OFF		4 + +/* log message */ +#define KVASER_EXTENDED_FRAME		BIT(31) + +struct kvaser_msg_simple { +	u8 tid; +	u8 channel; +} __packed; + +struct kvaser_msg_cardinfo { +	u8 tid; +	u8 nchannels; +	__le32 serial_number; +	__le32 padding; +	__le32 clock_resolution; +	__le32 mfgdate; +	u8 ean[8]; +	u8 hw_revision; +	u8 usb_hs_mode; +	__le16 padding2; +} __packed; + +struct kvaser_msg_cardinfo2 { +	u8 tid; +	u8 channel; +	u8 pcb_id[24]; +	__le32 oem_unlock_code; +} __packed; + +struct kvaser_msg_softinfo { +	u8 tid; +	u8 channel; +	__le32 sw_options; +	__le32 fw_version; +	__le16 max_outstanding_tx; +	__le16 padding[9]; +} __packed; + +struct kvaser_msg_busparams { +	u8 tid; +	u8 channel; +	__le32 bitrate; +	u8 tseg1; +	u8 tseg2; +	u8 sjw; +	u8 no_samp; +} __packed; + +struct kvaser_msg_tx_can { +	u8 channel; +	u8 tid; +	u8 msg[14]; +	u8 padding; +	u8 flags; +} __packed; + +struct kvaser_msg_rx_can { +	u8 channel; +	u8 flag; +	__le16 time[3]; +	u8 msg[14]; +} __packed; + +struct kvaser_msg_chip_state_event { +	u8 tid; +	u8 channel; +	__le16 time[3]; +	u8 tx_errors_count; +	u8 rx_errors_count; +	u8 status; +	u8 padding[3]; +} __packed; + +struct kvaser_msg_tx_acknowledge { +	u8 channel; +	u8 tid; +	__le16 time[3]; +	u8 flags; +	u8 time_offset; +} __packed; + +struct kvaser_msg_error_event { +	u8 tid; +	u8 flags; +	__le16 time[3]; +	u8 channel; +	u8 padding; +	u8 tx_errors_count; +	u8 rx_errors_count; +	u8 status; +	u8 error_factor; +} __packed; + +struct kvaser_msg_ctrl_mode { +	u8 tid; +	u8 channel; +	u8 ctrl_mode; +	u8 padding[3]; +} __packed; + +struct kvaser_msg_flush_queue { +	u8 tid; +	u8 channel; +	u8 flags; +	u8 padding[3]; +} __packed; + +struct kvaser_msg_log_message { +	u8 channel; +	u8 flags; +	__le16 time[3]; +	u8 dlc; +	u8 time_offset; +	__le32 id; +	u8 data[8]; +} __packed; + +struct kvaser_msg { +	u8 len; +	u8 id; +	union	{ +		struct kvaser_msg_simple simple; +		struct kvaser_msg_cardinfo cardinfo; +		struct kvaser_msg_cardinfo2 cardinfo2; +		struct kvaser_msg_softinfo softinfo; +		struct kvaser_msg_busparams busparams; +		struct kvaser_msg_tx_can tx_can; +		struct kvaser_msg_rx_can rx_can; +		struct kvaser_msg_chip_state_event chip_state_event; +		struct kvaser_msg_tx_acknowledge tx_acknowledge; +		struct kvaser_msg_error_event error_event; +		struct kvaser_msg_ctrl_mode ctrl_mode; +		struct kvaser_msg_flush_queue flush_queue; +		struct kvaser_msg_log_message log_message; +	} u; +} __packed; + +struct kvaser_usb_tx_urb_context { +	struct kvaser_usb_net_priv *priv; +	u32 echo_index; +	int dlc; +}; + +struct kvaser_usb { +	struct usb_device *udev; +	struct kvaser_usb_net_priv *nets[MAX_NET_DEVICES]; + +	struct usb_endpoint_descriptor *bulk_in, *bulk_out; +	struct usb_anchor rx_submitted; + +	u32 fw_version; +	unsigned int nchannels; + +	bool rxinitdone; +	void *rxbuf[MAX_RX_URBS]; +	dma_addr_t rxbuf_dma[MAX_RX_URBS]; +}; + +struct kvaser_usb_net_priv { +	struct can_priv can; + +	atomic_t active_tx_urbs; +	struct usb_anchor tx_submitted; +	struct kvaser_usb_tx_urb_context tx_contexts[MAX_TX_URBS]; + +	struct completion start_comp, stop_comp; + +	struct kvaser_usb *dev; +	struct net_device *netdev; +	int channel; + +	struct can_berr_counter bec; +}; + +static const struct usb_device_id kvaser_usb_table[] = { +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID), +		.driver_info = KVASER_HAS_TXRX_ERRORS | +			       KVASER_HAS_SILENT_MODE }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_PRODUCT_ID), +		.driver_info = KVASER_HAS_TXRX_ERRORS | +			       KVASER_HAS_SILENT_MODE }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LS_PRODUCT_ID), +		.driver_info = KVASER_HAS_TXRX_ERRORS | +			       KVASER_HAS_SILENT_MODE }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_SWC_PRODUCT_ID), +		.driver_info = KVASER_HAS_TXRX_ERRORS | +			       KVASER_HAS_SILENT_MODE }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LIN_PRODUCT_ID), +		.driver_info = KVASER_HAS_TXRX_ERRORS | +			       KVASER_HAS_SILENT_MODE }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_LS_PRODUCT_ID), +		.driver_info = KVASER_HAS_TXRX_ERRORS | +			       KVASER_HAS_SILENT_MODE }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_SWC_PRODUCT_ID), +		.driver_info = KVASER_HAS_TXRX_ERRORS | +			       KVASER_HAS_SILENT_MODE }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_DEVEL_PRODUCT_ID), +		.driver_info = KVASER_HAS_TXRX_ERRORS | +			       KVASER_HAS_SILENT_MODE }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSHS_PRODUCT_ID), +		.driver_info = KVASER_HAS_TXRX_ERRORS | +			       KVASER_HAS_SILENT_MODE }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_UPRO_HSHS_PRODUCT_ID), +		.driver_info = KVASER_HAS_TXRX_ERRORS }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID) }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_OBDII_PRODUCT_ID), +		.driver_info = KVASER_HAS_TXRX_ERRORS | +			       KVASER_HAS_SILENT_MODE }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSLS_PRODUCT_ID), +		.driver_info = KVASER_HAS_TXRX_ERRORS }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_CH_PRODUCT_ID), +		.driver_info = KVASER_HAS_TXRX_ERRORS }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_SPRO_PRODUCT_ID), +		.driver_info = KVASER_HAS_TXRX_ERRORS }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_MERCURY_PRODUCT_ID), +		.driver_info = KVASER_HAS_TXRX_ERRORS }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_LEAF_PRODUCT_ID), +		.driver_info = KVASER_HAS_TXRX_ERRORS }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID), +		.driver_info = KVASER_HAS_TXRX_ERRORS }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) }, +	{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) }, +	{ } +}; +MODULE_DEVICE_TABLE(usb, kvaser_usb_table); + +static inline int kvaser_usb_send_msg(const struct kvaser_usb *dev, +				      struct kvaser_msg *msg) +{ +	int actual_len; + +	return usb_bulk_msg(dev->udev, +			    usb_sndbulkpipe(dev->udev, +					dev->bulk_out->bEndpointAddress), +			    msg, msg->len, &actual_len, +			    USB_SEND_TIMEOUT); +} + +static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id, +			       struct kvaser_msg *msg) +{ +	struct kvaser_msg *tmp; +	void *buf; +	int actual_len; +	int err; +	int pos; +	unsigned long to = jiffies + msecs_to_jiffies(USB_RECV_TIMEOUT); + +	buf = kzalloc(RX_BUFFER_SIZE, GFP_KERNEL); +	if (!buf) +		return -ENOMEM; + +	do { +		err = usb_bulk_msg(dev->udev, +				   usb_rcvbulkpipe(dev->udev, +					dev->bulk_in->bEndpointAddress), +				   buf, RX_BUFFER_SIZE, &actual_len, +				   USB_RECV_TIMEOUT); +		if (err < 0) +			goto end; + +		pos = 0; +		while (pos <= actual_len - MSG_HEADER_LEN) { +			tmp = buf + pos; + +			if (!tmp->len) +				break; + +			if (pos + tmp->len > actual_len) { +				dev_err(dev->udev->dev.parent, +					"Format error\n"); +				break; +			} + +			if (tmp->id == id) { +				memcpy(msg, tmp, tmp->len); +				goto end; +			} + +			pos += tmp->len; +		} +	} while (time_before(jiffies, to)); + +	err = -EINVAL; + +end: +	kfree(buf); + +	return err; +} + +static int kvaser_usb_send_simple_msg(const struct kvaser_usb *dev, +				      u8 msg_id, int channel) +{ +	struct kvaser_msg *msg; +	int rc; + +	msg = kmalloc(sizeof(*msg), GFP_KERNEL); +	if (!msg) +		return -ENOMEM; + +	msg->id = msg_id; +	msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_simple); +	msg->u.simple.channel = channel; +	msg->u.simple.tid = 0xff; + +	rc = kvaser_usb_send_msg(dev, msg); + +	kfree(msg); +	return rc; +} + +static int kvaser_usb_get_software_info(struct kvaser_usb *dev) +{ +	struct kvaser_msg msg; +	int err; + +	err = kvaser_usb_send_simple_msg(dev, CMD_GET_SOFTWARE_INFO, 0); +	if (err) +		return err; + +	err = kvaser_usb_wait_msg(dev, CMD_GET_SOFTWARE_INFO_REPLY, &msg); +	if (err) +		return err; + +	dev->fw_version = le32_to_cpu(msg.u.softinfo.fw_version); + +	return 0; +} + +static int kvaser_usb_get_card_info(struct kvaser_usb *dev) +{ +	struct kvaser_msg msg; +	int err; + +	err = kvaser_usb_send_simple_msg(dev, CMD_GET_CARD_INFO, 0); +	if (err) +		return err; + +	err = kvaser_usb_wait_msg(dev, CMD_GET_CARD_INFO_REPLY, &msg); +	if (err) +		return err; + +	dev->nchannels = msg.u.cardinfo.nchannels; +	if (dev->nchannels > MAX_NET_DEVICES) +		return -EINVAL; + +	return 0; +} + +static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev, +				      const struct kvaser_msg *msg) +{ +	struct net_device_stats *stats; +	struct kvaser_usb_tx_urb_context *context; +	struct kvaser_usb_net_priv *priv; +	struct sk_buff *skb; +	struct can_frame *cf; +	u8 channel = msg->u.tx_acknowledge.channel; +	u8 tid = msg->u.tx_acknowledge.tid; + +	if (channel >= dev->nchannels) { +		dev_err(dev->udev->dev.parent, +			"Invalid channel number (%d)\n", channel); +		return; +	} + +	priv = dev->nets[channel]; + +	if (!netif_device_present(priv->netdev)) +		return; + +	stats = &priv->netdev->stats; + +	context = &priv->tx_contexts[tid % MAX_TX_URBS]; + +	/* Sometimes the state change doesn't come after a bus-off event */ +	if (priv->can.restart_ms && +	    (priv->can.state >= CAN_STATE_BUS_OFF)) { +		skb = alloc_can_err_skb(priv->netdev, &cf); +		if (skb) { +			cf->can_id |= CAN_ERR_RESTARTED; +			netif_rx(skb); + +			stats->rx_packets++; +			stats->rx_bytes += cf->can_dlc; +		} else { +			netdev_err(priv->netdev, +				   "No memory left for err_skb\n"); +		} + +		priv->can.can_stats.restarts++; +		netif_carrier_on(priv->netdev); + +		priv->can.state = CAN_STATE_ERROR_ACTIVE; +	} + +	stats->tx_packets++; +	stats->tx_bytes += context->dlc; +	can_get_echo_skb(priv->netdev, context->echo_index); + +	context->echo_index = MAX_TX_URBS; +	atomic_dec(&priv->active_tx_urbs); + +	netif_wake_queue(priv->netdev); +} + +static void kvaser_usb_simple_msg_callback(struct urb *urb) +{ +	struct net_device *netdev = urb->context; + +	kfree(urb->transfer_buffer); + +	if (urb->status) +		netdev_warn(netdev, "urb status received: %d\n", +			    urb->status); +} + +static int kvaser_usb_simple_msg_async(struct kvaser_usb_net_priv *priv, +				       u8 msg_id) +{ +	struct kvaser_usb *dev = priv->dev; +	struct net_device *netdev = priv->netdev; +	struct kvaser_msg *msg; +	struct urb *urb; +	void *buf; +	int err; + +	urb = usb_alloc_urb(0, GFP_ATOMIC); +	if (!urb) { +		netdev_err(netdev, "No memory left for URBs\n"); +		return -ENOMEM; +	} + +	buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC); +	if (!buf) { +		usb_free_urb(urb); +		return -ENOMEM; +	} + +	msg = (struct kvaser_msg *)buf; +	msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_simple); +	msg->id = msg_id; +	msg->u.simple.channel = priv->channel; + +	usb_fill_bulk_urb(urb, dev->udev, +			  usb_sndbulkpipe(dev->udev, +					  dev->bulk_out->bEndpointAddress), +			  buf, msg->len, +			  kvaser_usb_simple_msg_callback, priv); +	usb_anchor_urb(urb, &priv->tx_submitted); + +	err = usb_submit_urb(urb, GFP_ATOMIC); +	if (err) { +		netdev_err(netdev, "Error transmitting URB\n"); +		usb_unanchor_urb(urb); +		usb_free_urb(urb); +		kfree(buf); +		return err; +	} + +	usb_free_urb(urb); + +	return 0; +} + +static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) +{ +	int i; + +	usb_kill_anchored_urbs(&priv->tx_submitted); +	atomic_set(&priv->active_tx_urbs, 0); + +	for (i = 0; i < MAX_TX_URBS; i++) +		priv->tx_contexts[i].echo_index = MAX_TX_URBS; +} + +static void kvaser_usb_rx_error(const struct kvaser_usb *dev, +				const struct kvaser_msg *msg) +{ +	struct can_frame *cf; +	struct sk_buff *skb; +	struct net_device_stats *stats; +	struct kvaser_usb_net_priv *priv; +	unsigned int new_state; +	u8 channel, status, txerr, rxerr, error_factor; + +	switch (msg->id) { +	case CMD_CAN_ERROR_EVENT: +		channel = msg->u.error_event.channel; +		status =  msg->u.error_event.status; +		txerr = msg->u.error_event.tx_errors_count; +		rxerr = msg->u.error_event.rx_errors_count; +		error_factor = msg->u.error_event.error_factor; +		break; +	case CMD_LOG_MESSAGE: +		channel = msg->u.log_message.channel; +		status = msg->u.log_message.data[0]; +		txerr = msg->u.log_message.data[2]; +		rxerr = msg->u.log_message.data[3]; +		error_factor = msg->u.log_message.data[1]; +		break; +	case CMD_CHIP_STATE_EVENT: +		channel = msg->u.chip_state_event.channel; +		status =  msg->u.chip_state_event.status; +		txerr = msg->u.chip_state_event.tx_errors_count; +		rxerr = msg->u.chip_state_event.rx_errors_count; +		error_factor = 0; +		break; +	default: +		dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n", +			msg->id); +		return; +	} + +	if (channel >= dev->nchannels) { +		dev_err(dev->udev->dev.parent, +			"Invalid channel number (%d)\n", channel); +		return; +	} + +	priv = dev->nets[channel]; +	stats = &priv->netdev->stats; + +	if (status & M16C_STATE_BUS_RESET) { +		kvaser_usb_unlink_tx_urbs(priv); +		return; +	} + +	skb = alloc_can_err_skb(priv->netdev, &cf); +	if (!skb) { +		stats->rx_dropped++; +		return; +	} + +	new_state = priv->can.state; + +	netdev_dbg(priv->netdev, "Error status: 0x%02x\n", status); + +	if (status & M16C_STATE_BUS_OFF) { +		cf->can_id |= CAN_ERR_BUSOFF; + +		priv->can.can_stats.bus_off++; +		if (!priv->can.restart_ms) +			kvaser_usb_simple_msg_async(priv, CMD_STOP_CHIP); + +		netif_carrier_off(priv->netdev); + +		new_state = CAN_STATE_BUS_OFF; +	} else if (status & M16C_STATE_BUS_PASSIVE) { +		if (priv->can.state != CAN_STATE_ERROR_PASSIVE) { +			cf->can_id |= CAN_ERR_CRTL; + +			if (txerr || rxerr) +				cf->data[1] = (txerr > rxerr) +						? CAN_ERR_CRTL_TX_PASSIVE +						: CAN_ERR_CRTL_RX_PASSIVE; +			else +				cf->data[1] = CAN_ERR_CRTL_TX_PASSIVE | +					      CAN_ERR_CRTL_RX_PASSIVE; + +			priv->can.can_stats.error_passive++; +		} + +		new_state = CAN_STATE_ERROR_PASSIVE; +	} + +	if (status == M16C_STATE_BUS_ERROR) { +		if ((priv->can.state < CAN_STATE_ERROR_WARNING) && +		    ((txerr >= 96) || (rxerr >= 96))) { +			cf->can_id |= CAN_ERR_CRTL; +			cf->data[1] = (txerr > rxerr) +					? CAN_ERR_CRTL_TX_WARNING +					: CAN_ERR_CRTL_RX_WARNING; + +			priv->can.can_stats.error_warning++; +			new_state = CAN_STATE_ERROR_WARNING; +		} else if (priv->can.state > CAN_STATE_ERROR_ACTIVE) { +			cf->can_id |= CAN_ERR_PROT; +			cf->data[2] = CAN_ERR_PROT_ACTIVE; + +			new_state = CAN_STATE_ERROR_ACTIVE; +		} +	} + +	if (!status) { +		cf->can_id |= CAN_ERR_PROT; +		cf->data[2] = CAN_ERR_PROT_ACTIVE; + +		new_state = CAN_STATE_ERROR_ACTIVE; +	} + +	if (priv->can.restart_ms && +	    (priv->can.state >= CAN_STATE_BUS_OFF) && +	    (new_state < CAN_STATE_BUS_OFF)) { +		cf->can_id |= CAN_ERR_RESTARTED; +		netif_carrier_on(priv->netdev); + +		priv->can.can_stats.restarts++; +	} + +	if (error_factor) { +		priv->can.can_stats.bus_error++; +		stats->rx_errors++; + +		cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT; + +		if (error_factor & M16C_EF_ACKE) +			cf->data[3] |= (CAN_ERR_PROT_LOC_ACK); +		if (error_factor & M16C_EF_CRCE) +			cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ | +					CAN_ERR_PROT_LOC_CRC_DEL); +		if (error_factor & M16C_EF_FORME) +			cf->data[2] |= CAN_ERR_PROT_FORM; +		if (error_factor & M16C_EF_STFE) +			cf->data[2] |= CAN_ERR_PROT_STUFF; +		if (error_factor & M16C_EF_BITE0) +			cf->data[2] |= CAN_ERR_PROT_BIT0; +		if (error_factor & M16C_EF_BITE1) +			cf->data[2] |= CAN_ERR_PROT_BIT1; +		if (error_factor & M16C_EF_TRE) +			cf->data[2] |= CAN_ERR_PROT_TX; +	} + +	cf->data[6] = txerr; +	cf->data[7] = rxerr; + +	priv->bec.txerr = txerr; +	priv->bec.rxerr = rxerr; + +	priv->can.state = new_state; + +	netif_rx(skb); + +	stats->rx_packets++; +	stats->rx_bytes += cf->can_dlc; +} + +static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, +				  const struct kvaser_msg *msg) +{ +	struct can_frame *cf; +	struct sk_buff *skb; +	struct net_device_stats *stats = &priv->netdev->stats; + +	if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | +					 MSG_FLAG_NERR)) { +		netdev_err(priv->netdev, "Unknow error (flags: 0x%02x)\n", +			   msg->u.rx_can.flag); + +		stats->rx_errors++; +		return; +	} + +	if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) { +		skb = alloc_can_err_skb(priv->netdev, &cf); +		if (!skb) { +			stats->rx_dropped++; +			return; +		} + +		cf->can_id |= CAN_ERR_CRTL; +		cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; + +		stats->rx_over_errors++; +		stats->rx_errors++; + +		netif_rx(skb); + +		stats->rx_packets++; +		stats->rx_bytes += cf->can_dlc; +	} +} + +static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, +				  const struct kvaser_msg *msg) +{ +	struct kvaser_usb_net_priv *priv; +	struct can_frame *cf; +	struct sk_buff *skb; +	struct net_device_stats *stats; +	u8 channel = msg->u.rx_can.channel; + +	if (channel >= dev->nchannels) { +		dev_err(dev->udev->dev.parent, +			"Invalid channel number (%d)\n", channel); +		return; +	} + +	priv = dev->nets[channel]; +	stats = &priv->netdev->stats; + +	if ((msg->u.rx_can.flag & MSG_FLAG_ERROR_FRAME) && +	    (msg->id == CMD_LOG_MESSAGE)) { +		kvaser_usb_rx_error(dev, msg); +		return; +	} else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | +					 MSG_FLAG_NERR | +					 MSG_FLAG_OVERRUN)) { +		kvaser_usb_rx_can_err(priv, msg); +		return; +	} else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME) { +		netdev_warn(priv->netdev, +			    "Unhandled frame (flags: 0x%02x)", +			    msg->u.rx_can.flag); +		return; +	} + +	skb = alloc_can_skb(priv->netdev, &cf); +	if (!skb) { +		stats->tx_dropped++; +		return; +	} + +	if (msg->id == CMD_LOG_MESSAGE) { +		cf->can_id = le32_to_cpu(msg->u.log_message.id); +		if (cf->can_id & KVASER_EXTENDED_FRAME) +			cf->can_id &= CAN_EFF_MASK | CAN_EFF_FLAG; +		else +			cf->can_id &= CAN_SFF_MASK; + +		cf->can_dlc = get_can_dlc(msg->u.log_message.dlc); + +		if (msg->u.log_message.flags & MSG_FLAG_REMOTE_FRAME) +			cf->can_id |= CAN_RTR_FLAG; +		else +			memcpy(cf->data, &msg->u.log_message.data, +			       cf->can_dlc); +	} else { +		cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) | +			     (msg->u.rx_can.msg[1] & 0x3f); + +		if (msg->id == CMD_RX_EXT_MESSAGE) { +			cf->can_id <<= 18; +			cf->can_id |= ((msg->u.rx_can.msg[2] & 0x0f) << 14) | +				      ((msg->u.rx_can.msg[3] & 0xff) << 6) | +				      (msg->u.rx_can.msg[4] & 0x3f); +			cf->can_id |= CAN_EFF_FLAG; +		} + +		cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]); + +		if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME) +			cf->can_id |= CAN_RTR_FLAG; +		else +			memcpy(cf->data, &msg->u.rx_can.msg[6], +			       cf->can_dlc); +	} + +	netif_rx(skb); + +	stats->rx_packets++; +	stats->rx_bytes += cf->can_dlc; +} + +static void kvaser_usb_start_chip_reply(const struct kvaser_usb *dev, +					const struct kvaser_msg *msg) +{ +	struct kvaser_usb_net_priv *priv; +	u8 channel = msg->u.simple.channel; + +	if (channel >= dev->nchannels) { +		dev_err(dev->udev->dev.parent, +			"Invalid channel number (%d)\n", channel); +		return; +	} + +	priv = dev->nets[channel]; + +	if (completion_done(&priv->start_comp) && +	    netif_queue_stopped(priv->netdev)) { +		netif_wake_queue(priv->netdev); +	} else { +		netif_start_queue(priv->netdev); +		complete(&priv->start_comp); +	} +} + +static void kvaser_usb_stop_chip_reply(const struct kvaser_usb *dev, +				       const struct kvaser_msg *msg) +{ +	struct kvaser_usb_net_priv *priv; +	u8 channel = msg->u.simple.channel; + +	if (channel >= dev->nchannels) { +		dev_err(dev->udev->dev.parent, +			"Invalid channel number (%d)\n", channel); +		return; +	} + +	priv = dev->nets[channel]; + +	complete(&priv->stop_comp); +} + +static void kvaser_usb_handle_message(const struct kvaser_usb *dev, +				      const struct kvaser_msg *msg) +{ +	switch (msg->id) { +	case CMD_START_CHIP_REPLY: +		kvaser_usb_start_chip_reply(dev, msg); +		break; + +	case CMD_STOP_CHIP_REPLY: +		kvaser_usb_stop_chip_reply(dev, msg); +		break; + +	case CMD_RX_STD_MESSAGE: +	case CMD_RX_EXT_MESSAGE: +	case CMD_LOG_MESSAGE: +		kvaser_usb_rx_can_msg(dev, msg); +		break; + +	case CMD_CHIP_STATE_EVENT: +	case CMD_CAN_ERROR_EVENT: +		kvaser_usb_rx_error(dev, msg); +		break; + +	case CMD_TX_ACKNOWLEDGE: +		kvaser_usb_tx_acknowledge(dev, msg); +		break; + +	default: +		dev_warn(dev->udev->dev.parent, +			 "Unhandled message (%d)\n", msg->id); +		break; +	} +} + +static void kvaser_usb_read_bulk_callback(struct urb *urb) +{ +	struct kvaser_usb *dev = urb->context; +	struct kvaser_msg *msg; +	int pos = 0; +	int err, i; + +	switch (urb->status) { +	case 0: +		break; +	case -ENOENT: +	case -ESHUTDOWN: +		return; +	default: +		dev_info(dev->udev->dev.parent, "Rx URB aborted (%d)\n", +			 urb->status); +		goto resubmit_urb; +	} + +	while (pos <= urb->actual_length - MSG_HEADER_LEN) { +		msg = urb->transfer_buffer + pos; + +		if (!msg->len) +			break; + +		if (pos + msg->len > urb->actual_length) { +			dev_err(dev->udev->dev.parent, "Format error\n"); +			break; +		} + +		kvaser_usb_handle_message(dev, msg); + +		pos += msg->len; +	} + +resubmit_urb: +	usb_fill_bulk_urb(urb, dev->udev, +			  usb_rcvbulkpipe(dev->udev, +					  dev->bulk_in->bEndpointAddress), +			  urb->transfer_buffer, RX_BUFFER_SIZE, +			  kvaser_usb_read_bulk_callback, dev); + +	err = usb_submit_urb(urb, GFP_ATOMIC); +	if (err == -ENODEV) { +		for (i = 0; i < dev->nchannels; i++) { +			if (!dev->nets[i]) +				continue; + +			netif_device_detach(dev->nets[i]->netdev); +		} +	} else if (err) { +		dev_err(dev->udev->dev.parent, +			"Failed resubmitting read bulk urb: %d\n", err); +	} + +	return; +} + +static int kvaser_usb_setup_rx_urbs(struct kvaser_usb *dev) +{ +	int i, err = 0; + +	if (dev->rxinitdone) +		return 0; + +	for (i = 0; i < MAX_RX_URBS; i++) { +		struct urb *urb = NULL; +		u8 *buf = NULL; +		dma_addr_t buf_dma; + +		urb = usb_alloc_urb(0, GFP_KERNEL); +		if (!urb) { +			dev_warn(dev->udev->dev.parent, +				 "No memory left for URBs\n"); +			err = -ENOMEM; +			break; +		} + +		buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE, +					 GFP_KERNEL, &buf_dma); +		if (!buf) { +			dev_warn(dev->udev->dev.parent, +				 "No memory left for USB buffer\n"); +			usb_free_urb(urb); +			err = -ENOMEM; +			break; +		} + +		usb_fill_bulk_urb(urb, dev->udev, +				  usb_rcvbulkpipe(dev->udev, +					  dev->bulk_in->bEndpointAddress), +				  buf, RX_BUFFER_SIZE, +				  kvaser_usb_read_bulk_callback, +				  dev); +		urb->transfer_dma = buf_dma; +		urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; +		usb_anchor_urb(urb, &dev->rx_submitted); + +		err = usb_submit_urb(urb, GFP_KERNEL); +		if (err) { +			usb_unanchor_urb(urb); +			usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf, +					  buf_dma); +			usb_free_urb(urb); +			break; +		} + +		dev->rxbuf[i] = buf; +		dev->rxbuf_dma[i] = buf_dma; + +		usb_free_urb(urb); +	} + +	if (i == 0) { +		dev_warn(dev->udev->dev.parent, +			 "Cannot setup read URBs, error %d\n", err); +		return err; +	} else if (i < MAX_RX_URBS) { +		dev_warn(dev->udev->dev.parent, +			 "RX performances may be slow\n"); +	} + +	dev->rxinitdone = true; + +	return 0; +} + +static int kvaser_usb_set_opt_mode(const struct kvaser_usb_net_priv *priv) +{ +	struct kvaser_msg *msg; +	int rc; + +	msg = kmalloc(sizeof(*msg), GFP_KERNEL); +	if (!msg) +		return -ENOMEM; + +	msg->id = CMD_SET_CTRL_MODE; +	msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_ctrl_mode); +	msg->u.ctrl_mode.tid = 0xff; +	msg->u.ctrl_mode.channel = priv->channel; + +	if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) +		msg->u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_SILENT; +	else +		msg->u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_NORMAL; + +	rc = kvaser_usb_send_msg(priv->dev, msg); + +	kfree(msg); +	return rc; +} + +static int kvaser_usb_start_chip(struct kvaser_usb_net_priv *priv) +{ +	int err; + +	init_completion(&priv->start_comp); + +	err = kvaser_usb_send_simple_msg(priv->dev, CMD_START_CHIP, +					 priv->channel); +	if (err) +		return err; + +	if (!wait_for_completion_timeout(&priv->start_comp, +					 msecs_to_jiffies(START_TIMEOUT))) +		return -ETIMEDOUT; + +	return 0; +} + +static int kvaser_usb_open(struct net_device *netdev) +{ +	struct kvaser_usb_net_priv *priv = netdev_priv(netdev); +	struct kvaser_usb *dev = priv->dev; +	int err; + +	err = open_candev(netdev); +	if (err) +		return err; + +	err = kvaser_usb_setup_rx_urbs(dev); +	if (err) +		goto error; + +	err = kvaser_usb_set_opt_mode(priv); +	if (err) +		goto error; + +	err = kvaser_usb_start_chip(priv); +	if (err) { +		netdev_warn(netdev, "Cannot start device, error %d\n", err); +		goto error; +	} + +	priv->can.state = CAN_STATE_ERROR_ACTIVE; + +	return 0; + +error: +	close_candev(netdev); +	return err; +} + +static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev) +{ +	int i; + +	usb_kill_anchored_urbs(&dev->rx_submitted); + +	for (i = 0; i < MAX_RX_URBS; i++) +		usb_free_coherent(dev->udev, RX_BUFFER_SIZE, +				  dev->rxbuf[i], +				  dev->rxbuf_dma[i]); + +	for (i = 0; i < MAX_NET_DEVICES; i++) { +		struct kvaser_usb_net_priv *priv = dev->nets[i]; + +		if (priv) +			kvaser_usb_unlink_tx_urbs(priv); +	} +} + +static int kvaser_usb_stop_chip(struct kvaser_usb_net_priv *priv) +{ +	int err; + +	init_completion(&priv->stop_comp); + +	err = kvaser_usb_send_simple_msg(priv->dev, CMD_STOP_CHIP, +					 priv->channel); +	if (err) +		return err; + +	if (!wait_for_completion_timeout(&priv->stop_comp, +					 msecs_to_jiffies(STOP_TIMEOUT))) +		return -ETIMEDOUT; + +	return 0; +} + +static int kvaser_usb_flush_queue(struct kvaser_usb_net_priv *priv) +{ +	struct kvaser_msg *msg; +	int rc; + +	msg = kmalloc(sizeof(*msg), GFP_KERNEL); +	if (!msg) +		return -ENOMEM; + +	msg->id = CMD_FLUSH_QUEUE; +	msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_flush_queue); +	msg->u.flush_queue.channel = priv->channel; +	msg->u.flush_queue.flags = 0x00; + +	rc = kvaser_usb_send_msg(priv->dev, msg); + +	kfree(msg); +	return rc; +} + +static int kvaser_usb_close(struct net_device *netdev) +{ +	struct kvaser_usb_net_priv *priv = netdev_priv(netdev); +	struct kvaser_usb *dev = priv->dev; +	int err; + +	netif_stop_queue(netdev); + +	err = kvaser_usb_flush_queue(priv); +	if (err) +		netdev_warn(netdev, "Cannot flush queue, error %d\n", err); + +	if (kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, priv->channel)) +		netdev_warn(netdev, "Cannot reset card, error %d\n", err); + +	err = kvaser_usb_stop_chip(priv); +	if (err) +		netdev_warn(netdev, "Cannot stop device, error %d\n", err); + +	priv->can.state = CAN_STATE_STOPPED; +	close_candev(priv->netdev); + +	return 0; +} + +static void kvaser_usb_write_bulk_callback(struct urb *urb) +{ +	struct kvaser_usb_tx_urb_context *context = urb->context; +	struct kvaser_usb_net_priv *priv; +	struct net_device *netdev; + +	if (WARN_ON(!context)) +		return; + +	priv = context->priv; +	netdev = priv->netdev; + +	kfree(urb->transfer_buffer); + +	if (!netif_device_present(netdev)) +		return; + +	if (urb->status) +		netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status); +} + +static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, +					 struct net_device *netdev) +{ +	struct kvaser_usb_net_priv *priv = netdev_priv(netdev); +	struct kvaser_usb *dev = priv->dev; +	struct net_device_stats *stats = &netdev->stats; +	struct can_frame *cf = (struct can_frame *)skb->data; +	struct kvaser_usb_tx_urb_context *context = NULL; +	struct urb *urb; +	void *buf; +	struct kvaser_msg *msg; +	int i, err; +	int ret = NETDEV_TX_OK; + +	if (can_dropped_invalid_skb(netdev, skb)) +		return NETDEV_TX_OK; + +	urb = usb_alloc_urb(0, GFP_ATOMIC); +	if (!urb) { +		netdev_err(netdev, "No memory left for URBs\n"); +		stats->tx_dropped++; +		goto nourbmem; +	} + +	buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC); +	if (!buf) { +		stats->tx_dropped++; +		goto nobufmem; +	} + +	msg = buf; +	msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_tx_can); +	msg->u.tx_can.flags = 0; +	msg->u.tx_can.channel = priv->channel; + +	if (cf->can_id & CAN_EFF_FLAG) { +		msg->id = CMD_TX_EXT_MESSAGE; +		msg->u.tx_can.msg[0] = (cf->can_id >> 24) & 0x1f; +		msg->u.tx_can.msg[1] = (cf->can_id >> 18) & 0x3f; +		msg->u.tx_can.msg[2] = (cf->can_id >> 14) & 0x0f; +		msg->u.tx_can.msg[3] = (cf->can_id >> 6) & 0xff; +		msg->u.tx_can.msg[4] = cf->can_id & 0x3f; +	} else { +		msg->id = CMD_TX_STD_MESSAGE; +		msg->u.tx_can.msg[0] = (cf->can_id >> 6) & 0x1f; +		msg->u.tx_can.msg[1] = cf->can_id & 0x3f; +	} + +	msg->u.tx_can.msg[5] = cf->can_dlc; +	memcpy(&msg->u.tx_can.msg[6], cf->data, cf->can_dlc); + +	if (cf->can_id & CAN_RTR_FLAG) +		msg->u.tx_can.flags |= MSG_FLAG_REMOTE_FRAME; + +	for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) { +		if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) { +			context = &priv->tx_contexts[i]; +			break; +		} +	} + +	if (!context) { +		netdev_warn(netdev, "cannot find free context\n"); +		ret =  NETDEV_TX_BUSY; +		goto releasebuf; +	} + +	context->priv = priv; +	context->echo_index = i; +	context->dlc = cf->can_dlc; + +	msg->u.tx_can.tid = context->echo_index; + +	usb_fill_bulk_urb(urb, dev->udev, +			  usb_sndbulkpipe(dev->udev, +					  dev->bulk_out->bEndpointAddress), +			  buf, msg->len, +			  kvaser_usb_write_bulk_callback, context); +	usb_anchor_urb(urb, &priv->tx_submitted); + +	can_put_echo_skb(skb, netdev, context->echo_index); + +	atomic_inc(&priv->active_tx_urbs); + +	if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS) +		netif_stop_queue(netdev); + +	err = usb_submit_urb(urb, GFP_ATOMIC); +	if (unlikely(err)) { +		can_free_echo_skb(netdev, context->echo_index); + +		skb = NULL; /* set to NULL to avoid double free in +			     * dev_kfree_skb(skb) */ + +		atomic_dec(&priv->active_tx_urbs); +		usb_unanchor_urb(urb); + +		stats->tx_dropped++; + +		if (err == -ENODEV) +			netif_device_detach(netdev); +		else +			netdev_warn(netdev, "Failed tx_urb %d\n", err); + +		goto releasebuf; +	} + +	usb_free_urb(urb); + +	return NETDEV_TX_OK; + +releasebuf: +	kfree(buf); +nobufmem: +	usb_free_urb(urb); +nourbmem: +	dev_kfree_skb(skb); +	return ret; +} + +static const struct net_device_ops kvaser_usb_netdev_ops = { +	.ndo_open = kvaser_usb_open, +	.ndo_stop = kvaser_usb_close, +	.ndo_start_xmit = kvaser_usb_start_xmit, +	.ndo_change_mtu = can_change_mtu, +}; + +static const struct can_bittiming_const kvaser_usb_bittiming_const = { +	.name = "kvaser_usb", +	.tseg1_min = KVASER_USB_TSEG1_MIN, +	.tseg1_max = KVASER_USB_TSEG1_MAX, +	.tseg2_min = KVASER_USB_TSEG2_MIN, +	.tseg2_max = KVASER_USB_TSEG2_MAX, +	.sjw_max = KVASER_USB_SJW_MAX, +	.brp_min = KVASER_USB_BRP_MIN, +	.brp_max = KVASER_USB_BRP_MAX, +	.brp_inc = KVASER_USB_BRP_INC, +}; + +static int kvaser_usb_set_bittiming(struct net_device *netdev) +{ +	struct kvaser_usb_net_priv *priv = netdev_priv(netdev); +	struct can_bittiming *bt = &priv->can.bittiming; +	struct kvaser_usb *dev = priv->dev; +	struct kvaser_msg *msg; +	int rc; + +	msg = kmalloc(sizeof(*msg), GFP_KERNEL); +	if (!msg) +		return -ENOMEM; + +	msg->id = CMD_SET_BUS_PARAMS; +	msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_busparams); +	msg->u.busparams.channel = priv->channel; +	msg->u.busparams.tid = 0xff; +	msg->u.busparams.bitrate = cpu_to_le32(bt->bitrate); +	msg->u.busparams.sjw = bt->sjw; +	msg->u.busparams.tseg1 = bt->prop_seg + bt->phase_seg1; +	msg->u.busparams.tseg2 = bt->phase_seg2; + +	if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) +		msg->u.busparams.no_samp = 3; +	else +		msg->u.busparams.no_samp = 1; + +	rc = kvaser_usb_send_msg(dev, msg); + +	kfree(msg); +	return rc; +} + +static int kvaser_usb_set_mode(struct net_device *netdev, +			       enum can_mode mode) +{ +	struct kvaser_usb_net_priv *priv = netdev_priv(netdev); +	int err; + +	switch (mode) { +	case CAN_MODE_START: +		err = kvaser_usb_simple_msg_async(priv, CMD_START_CHIP); +		if (err) +			return err; +		break; +	default: +		return -EOPNOTSUPP; +	} + +	return 0; +} + +static int kvaser_usb_get_berr_counter(const struct net_device *netdev, +				       struct can_berr_counter *bec) +{ +	struct kvaser_usb_net_priv *priv = netdev_priv(netdev); + +	*bec = priv->bec; + +	return 0; +} + +static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev) +{ +	int i; + +	for (i = 0; i < dev->nchannels; i++) { +		if (!dev->nets[i]) +			continue; + +		unregister_netdev(dev->nets[i]->netdev); +	} + +	kvaser_usb_unlink_all_urbs(dev); + +	for (i = 0; i < dev->nchannels; i++) { +		if (!dev->nets[i]) +			continue; + +		free_candev(dev->nets[i]->netdev); +	} +} + +static int kvaser_usb_init_one(struct usb_interface *intf, +			       const struct usb_device_id *id, int channel) +{ +	struct kvaser_usb *dev = usb_get_intfdata(intf); +	struct net_device *netdev; +	struct kvaser_usb_net_priv *priv; +	int i, err; + +	netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS); +	if (!netdev) { +		dev_err(&intf->dev, "Cannot alloc candev\n"); +		return -ENOMEM; +	} + +	priv = netdev_priv(netdev); + +	init_completion(&priv->start_comp); +	init_completion(&priv->stop_comp); + +	init_usb_anchor(&priv->tx_submitted); +	atomic_set(&priv->active_tx_urbs, 0); + +	for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) +		priv->tx_contexts[i].echo_index = MAX_TX_URBS; + +	priv->dev = dev; +	priv->netdev = netdev; +	priv->channel = channel; + +	priv->can.state = CAN_STATE_STOPPED; +	priv->can.clock.freq = CAN_USB_CLOCK; +	priv->can.bittiming_const = &kvaser_usb_bittiming_const; +	priv->can.do_set_bittiming = kvaser_usb_set_bittiming; +	priv->can.do_set_mode = kvaser_usb_set_mode; +	if (id->driver_info & KVASER_HAS_TXRX_ERRORS) +		priv->can.do_get_berr_counter = kvaser_usb_get_berr_counter; +	priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; +	if (id->driver_info & KVASER_HAS_SILENT_MODE) +		priv->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY; + +	netdev->flags |= IFF_ECHO; + +	netdev->netdev_ops = &kvaser_usb_netdev_ops; + +	SET_NETDEV_DEV(netdev, &intf->dev); +	netdev->dev_id = channel; + +	dev->nets[channel] = priv; + +	err = register_candev(netdev); +	if (err) { +		dev_err(&intf->dev, "Failed to register can device\n"); +		free_candev(netdev); +		dev->nets[channel] = NULL; +		return err; +	} + +	netdev_dbg(netdev, "device registered\n"); + +	return 0; +} + +static int kvaser_usb_get_endpoints(const struct usb_interface *intf, +				    struct usb_endpoint_descriptor **in, +				    struct usb_endpoint_descriptor **out) +{ +	const struct usb_host_interface *iface_desc; +	struct usb_endpoint_descriptor *endpoint; +	int i; + +	iface_desc = &intf->altsetting[0]; + +	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { +		endpoint = &iface_desc->endpoint[i].desc; + +		if (!*in && usb_endpoint_is_bulk_in(endpoint)) +			*in = endpoint; + +		if (!*out && usb_endpoint_is_bulk_out(endpoint)) +			*out = endpoint; + +		/* use first bulk endpoint for in and out */ +		if (*in && *out) +			return 0; +	} + +	return -ENODEV; +} + +static int kvaser_usb_probe(struct usb_interface *intf, +			    const struct usb_device_id *id) +{ +	struct kvaser_usb *dev; +	int err = -ENOMEM; +	int i; + +	dev = devm_kzalloc(&intf->dev, sizeof(*dev), GFP_KERNEL); +	if (!dev) +		return -ENOMEM; + +	err = kvaser_usb_get_endpoints(intf, &dev->bulk_in, &dev->bulk_out); +	if (err) { +		dev_err(&intf->dev, "Cannot get usb endpoint(s)"); +		return err; +	} + +	dev->udev = interface_to_usbdev(intf); + +	init_usb_anchor(&dev->rx_submitted); + +	usb_set_intfdata(intf, dev); + +	for (i = 0; i < MAX_NET_DEVICES; i++) +		kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, i); + +	err = kvaser_usb_get_software_info(dev); +	if (err) { +		dev_err(&intf->dev, +			"Cannot get software infos, error %d\n", err); +		return err; +	} + +	err = kvaser_usb_get_card_info(dev); +	if (err) { +		dev_err(&intf->dev, +			"Cannot get card infos, error %d\n", err); +		return err; +	} + +	dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n", +		((dev->fw_version >> 24) & 0xff), +		((dev->fw_version >> 16) & 0xff), +		(dev->fw_version & 0xffff)); + +	for (i = 0; i < dev->nchannels; i++) { +		err = kvaser_usb_init_one(intf, id, i); +		if (err) { +			kvaser_usb_remove_interfaces(dev); +			return err; +		} +	} + +	return 0; +} + +static void kvaser_usb_disconnect(struct usb_interface *intf) +{ +	struct kvaser_usb *dev = usb_get_intfdata(intf); + +	usb_set_intfdata(intf, NULL); + +	if (!dev) +		return; + +	kvaser_usb_remove_interfaces(dev); +} + +static struct usb_driver kvaser_usb_driver = { +	.name = "kvaser_usb", +	.probe = kvaser_usb_probe, +	.disconnect = kvaser_usb_disconnect, +	.id_table = kvaser_usb_table, +}; + +module_usb_driver(kvaser_usb_driver); + +MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>"); +MODULE_DESCRIPTION("CAN driver for Kvaser CAN/USB devices"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/can/usb/peak_usb/Makefile b/drivers/net/can/usb/peak_usb/Makefile new file mode 100644 index 00000000000..1aefbc88d64 --- /dev/null +++ b/drivers/net/can/usb/peak_usb/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_CAN_PEAK_USB) += peak_usb.o +peak_usb-y = pcan_usb_core.o pcan_usb.o pcan_usb_pro.o diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c new file mode 100644 index 00000000000..925ab8ec932 --- /dev/null +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -0,0 +1,903 @@ +/* + * CAN driver for PEAK System PCAN-USB adapter + * Derived from the PCAN project file driver/src/pcan_usb.c + * + * Copyright (C) 2003-2010 PEAK System-Technik GmbH + * Copyright (C) 2011-2012 Stephane Grosjean <s.grosjean@peak-system.com> + * + * Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#include <linux/netdevice.h> +#include <linux/usb.h> +#include <linux/module.h> + +#include <linux/can.h> +#include <linux/can/dev.h> +#include <linux/can/error.h> + +#include "pcan_usb_core.h" + +MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB adapter"); + +/* PCAN-USB Endpoints */ +#define PCAN_USB_EP_CMDOUT		1 +#define PCAN_USB_EP_CMDIN		(PCAN_USB_EP_CMDOUT | USB_DIR_IN) +#define PCAN_USB_EP_MSGOUT		2 +#define PCAN_USB_EP_MSGIN		(PCAN_USB_EP_MSGOUT | USB_DIR_IN) + +/* PCAN-USB command struct */ +#define PCAN_USB_CMD_FUNC		0 +#define PCAN_USB_CMD_NUM		1 +#define PCAN_USB_CMD_ARGS		2 +#define PCAN_USB_CMD_ARGS_LEN		14 +#define PCAN_USB_CMD_LEN		(PCAN_USB_CMD_ARGS + \ +					 PCAN_USB_CMD_ARGS_LEN) + +/* PCAN-USB command timeout (ms.) */ +#define PCAN_USB_COMMAND_TIMEOUT	1000 + +/* PCAN-USB startup timeout (ms.) */ +#define PCAN_USB_STARTUP_TIMEOUT	10 + +/* PCAN-USB rx/tx buffers size */ +#define PCAN_USB_RX_BUFFER_SIZE		64 +#define PCAN_USB_TX_BUFFER_SIZE		64 + +#define PCAN_USB_MSG_HEADER_LEN		2 + +/* PCAN-USB adapter internal clock (MHz) */ +#define PCAN_USB_CRYSTAL_HZ		16000000 + +/* PCAN-USB USB message record status/len field */ +#define PCAN_USB_STATUSLEN_TIMESTAMP	(1 << 7) +#define PCAN_USB_STATUSLEN_INTERNAL	(1 << 6) +#define PCAN_USB_STATUSLEN_EXT_ID	(1 << 5) +#define PCAN_USB_STATUSLEN_RTR		(1 << 4) +#define PCAN_USB_STATUSLEN_DLC		(0xf) + +/* PCAN-USB error flags */ +#define PCAN_USB_ERROR_TXFULL		0x01 +#define PCAN_USB_ERROR_RXQOVR		0x02 +#define PCAN_USB_ERROR_BUS_LIGHT	0x04 +#define PCAN_USB_ERROR_BUS_HEAVY	0x08 +#define PCAN_USB_ERROR_BUS_OFF		0x10 +#define PCAN_USB_ERROR_RXQEMPTY		0x20 +#define PCAN_USB_ERROR_QOVR		0x40 +#define PCAN_USB_ERROR_TXQFULL		0x80 + +/* SJA1000 modes */ +#define SJA1000_MODE_NORMAL		0x00 +#define SJA1000_MODE_INIT		0x01 + +/* + * tick duration = 42.666 us => + * (tick_number * 44739243) >> 20 ~ (tick_number * 42666) / 1000 + * accuracy = 10^-7 + */ +#define PCAN_USB_TS_DIV_SHIFTER		20 +#define PCAN_USB_TS_US_PER_TICK		44739243 + +/* PCAN-USB messages record types */ +#define PCAN_USB_REC_ERROR		1 +#define PCAN_USB_REC_ANALOG		2 +#define PCAN_USB_REC_BUSLOAD		3 +#define PCAN_USB_REC_TS			4 +#define PCAN_USB_REC_BUSEVT		5 + +/* private to PCAN-USB adapter */ +struct pcan_usb { +	struct peak_usb_device dev; +	struct peak_time_ref time_ref; +	struct timer_list restart_timer; +}; + +/* incoming message context for decoding */ +struct pcan_usb_msg_context { +	u16 ts16; +	u8 prev_ts8; +	u8 *ptr; +	u8 *end; +	u8 rec_cnt; +	u8 rec_idx; +	u8 rec_data_idx; +	struct net_device *netdev; +	struct pcan_usb *pdev; +}; + +/* + * send a command + */ +static int pcan_usb_send_cmd(struct peak_usb_device *dev, u8 f, u8 n, u8 *p) +{ +	int err; +	int actual_length; + +	/* usb device unregistered? */ +	if (!(dev->state & PCAN_USB_STATE_CONNECTED)) +		return 0; + +	dev->cmd_buf[PCAN_USB_CMD_FUNC] = f; +	dev->cmd_buf[PCAN_USB_CMD_NUM] = n; + +	if (p) +		memcpy(dev->cmd_buf + PCAN_USB_CMD_ARGS, +			p, PCAN_USB_CMD_ARGS_LEN); + +	err = usb_bulk_msg(dev->udev, +			usb_sndbulkpipe(dev->udev, PCAN_USB_EP_CMDOUT), +			dev->cmd_buf, PCAN_USB_CMD_LEN, &actual_length, +			PCAN_USB_COMMAND_TIMEOUT); +	if (err) +		netdev_err(dev->netdev, +			"sending cmd f=0x%x n=0x%x failure: %d\n", +			f, n, err); +	return err; +} + +/* + * send a command then wait for its response + */ +static int pcan_usb_wait_rsp(struct peak_usb_device *dev, u8 f, u8 n, u8 *p) +{ +	int err; +	int actual_length; + +	/* usb device unregistered? */ +	if (!(dev->state & PCAN_USB_STATE_CONNECTED)) +		return 0; + +	/* first, send command */ +	err = pcan_usb_send_cmd(dev, f, n, NULL); +	if (err) +		return err; + +	err = usb_bulk_msg(dev->udev, +		usb_rcvbulkpipe(dev->udev, PCAN_USB_EP_CMDIN), +		dev->cmd_buf, PCAN_USB_CMD_LEN, &actual_length, +		PCAN_USB_COMMAND_TIMEOUT); +	if (err) +		netdev_err(dev->netdev, +			"waiting rsp f=0x%x n=0x%x failure: %d\n", f, n, err); +	else if (p) +		memcpy(p, dev->cmd_buf + PCAN_USB_CMD_ARGS, +			PCAN_USB_CMD_ARGS_LEN); + +	return err; +} + +static int pcan_usb_set_sja1000(struct peak_usb_device *dev, u8 mode) +{ +	u8 args[PCAN_USB_CMD_ARGS_LEN] = { +		[1] = mode, +	}; + +	return pcan_usb_send_cmd(dev, 9, 2, args); +} + +static int pcan_usb_set_bus(struct peak_usb_device *dev, u8 onoff) +{ +	u8 args[PCAN_USB_CMD_ARGS_LEN] = { +		[0] = !!onoff, +	}; + +	return pcan_usb_send_cmd(dev, 3, 2, args); +} + +static int pcan_usb_set_silent(struct peak_usb_device *dev, u8 onoff) +{ +	u8 args[PCAN_USB_CMD_ARGS_LEN] = { +		[0] = !!onoff, +	}; + +	return pcan_usb_send_cmd(dev, 3, 3, args); +} + +static int pcan_usb_set_ext_vcc(struct peak_usb_device *dev, u8 onoff) +{ +	u8 args[PCAN_USB_CMD_ARGS_LEN] = { +		[0] = !!onoff, +	}; + +	return pcan_usb_send_cmd(dev, 10, 2, args); +} + +/* + * set bittiming value to can + */ +static int pcan_usb_set_bittiming(struct peak_usb_device *dev, +				  struct can_bittiming *bt) +{ +	u8 args[PCAN_USB_CMD_ARGS_LEN]; +	u8 btr0, btr1; + +	btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6); +	btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) | +		(((bt->phase_seg2 - 1) & 0x7) << 4); +	if (dev->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) +		btr1 |= 0x80; + +	netdev_info(dev->netdev, "setting BTR0=0x%02x BTR1=0x%02x\n", +		btr0, btr1); + +	args[0] = btr1; +	args[1] = btr0; + +	return pcan_usb_send_cmd(dev, 1, 2, args); +} + +/* + * init/reset can + */ +static int pcan_usb_write_mode(struct peak_usb_device *dev, u8 onoff) +{ +	int err; + +	err = pcan_usb_set_bus(dev, onoff); +	if (err) +		return err; + +	if (!onoff) { +		err = pcan_usb_set_sja1000(dev, SJA1000_MODE_INIT); +	} else { +		/* the PCAN-USB needs time to init */ +		set_current_state(TASK_INTERRUPTIBLE); +		schedule_timeout(msecs_to_jiffies(PCAN_USB_STARTUP_TIMEOUT)); +	} + +	return err; +} + +/* + * handle end of waiting for the device to reset + */ +static void pcan_usb_restart(unsigned long arg) +{ +	/* notify candev and netdev */ +	peak_usb_restart_complete((struct peak_usb_device *)arg); +} + +/* + * handle the submission of the restart urb + */ +static void pcan_usb_restart_pending(struct urb *urb) +{ +	struct pcan_usb *pdev = urb->context; + +	/* the PCAN-USB needs time to restart */ +	mod_timer(&pdev->restart_timer, +			jiffies + msecs_to_jiffies(PCAN_USB_STARTUP_TIMEOUT)); + +	/* can delete usb resources */ +	peak_usb_async_complete(urb); +} + +/* + * handle asynchronous restart + */ +static int pcan_usb_restart_async(struct peak_usb_device *dev, struct urb *urb, +				  u8 *buf) +{ +	struct pcan_usb *pdev = container_of(dev, struct pcan_usb, dev); + +	if (timer_pending(&pdev->restart_timer)) +		return -EBUSY; + +	/* set bus on */ +	buf[PCAN_USB_CMD_FUNC] = 3; +	buf[PCAN_USB_CMD_NUM] = 2; +	buf[PCAN_USB_CMD_ARGS] = 1; + +	usb_fill_bulk_urb(urb, dev->udev, +			usb_sndbulkpipe(dev->udev, PCAN_USB_EP_CMDOUT), +			buf, PCAN_USB_CMD_LEN, +			pcan_usb_restart_pending, pdev); + +	return usb_submit_urb(urb, GFP_ATOMIC); +} + +/* + * read serial number from device + */ +static int pcan_usb_get_serial(struct peak_usb_device *dev, u32 *serial_number) +{ +	u8 args[PCAN_USB_CMD_ARGS_LEN]; +	int err; + +	err = pcan_usb_wait_rsp(dev, 6, 1, args); +	if (err) { +		netdev_err(dev->netdev, "getting serial failure: %d\n", err); +	} else if (serial_number) { +		u32 tmp32; + +		memcpy(&tmp32, args, 4); +		*serial_number = le32_to_cpu(tmp32); +	} + +	return err; +} + +/* + * read device id from device + */ +static int pcan_usb_get_device_id(struct peak_usb_device *dev, u32 *device_id) +{ +	u8 args[PCAN_USB_CMD_ARGS_LEN]; +	int err; + +	err = pcan_usb_wait_rsp(dev, 4, 1, args); +	if (err) +		netdev_err(dev->netdev, "getting device id failure: %d\n", err); +	else if (device_id) +		*device_id = args[0]; + +	return err; +} + +/* + * update current time ref with received timestamp + */ +static int pcan_usb_update_ts(struct pcan_usb_msg_context *mc) +{ +	u16 tmp16; + +	if ((mc->ptr+2) > mc->end) +		return -EINVAL; + +	memcpy(&tmp16, mc->ptr, 2); + +	mc->ts16 = le16_to_cpu(tmp16); + +	if (mc->rec_idx > 0) +		peak_usb_update_ts_now(&mc->pdev->time_ref, mc->ts16); +	else +		peak_usb_set_ts_now(&mc->pdev->time_ref, mc->ts16); + +	return 0; +} + +/* + * decode received timestamp + */ +static int pcan_usb_decode_ts(struct pcan_usb_msg_context *mc, u8 first_packet) +{ +	/* only 1st packet supplies a word timestamp */ +	if (first_packet) { +		u16 tmp16; + +		if ((mc->ptr + 2) > mc->end) +			return -EINVAL; + +		memcpy(&tmp16, mc->ptr, 2); +		mc->ptr += 2; + +		mc->ts16 = le16_to_cpu(tmp16); +		mc->prev_ts8 = mc->ts16 & 0x00ff; +	} else { +		u8 ts8; + +		if ((mc->ptr + 1) > mc->end) +			return -EINVAL; + +		ts8 = *mc->ptr++; + +		if (ts8 < mc->prev_ts8) +			mc->ts16 += 0x100; + +		mc->ts16 &= 0xff00; +		mc->ts16 |= ts8; +		mc->prev_ts8 = ts8; +	} + +	return 0; +} + +static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n, +				 u8 status_len) +{ +	struct sk_buff *skb; +	struct can_frame *cf; +	struct timeval tv; +	enum can_state new_state; + +	/* ignore this error until 1st ts received */ +	if (n == PCAN_USB_ERROR_QOVR) +		if (!mc->pdev->time_ref.tick_count) +			return 0; + +	new_state = mc->pdev->dev.can.state; + +	switch (mc->pdev->dev.can.state) { +	case CAN_STATE_ERROR_ACTIVE: +		if (n & PCAN_USB_ERROR_BUS_LIGHT) { +			new_state = CAN_STATE_ERROR_WARNING; +			break; +		} + +	case CAN_STATE_ERROR_WARNING: +		if (n & PCAN_USB_ERROR_BUS_HEAVY) { +			new_state = CAN_STATE_ERROR_PASSIVE; +			break; +		} +		if (n & PCAN_USB_ERROR_BUS_OFF) { +			new_state = CAN_STATE_BUS_OFF; +			break; +		} +		if (n & (PCAN_USB_ERROR_RXQOVR | PCAN_USB_ERROR_QOVR)) { +			/* +			 * trick to bypass next comparison and process other +			 * errors +			 */ +			new_state = CAN_STATE_MAX; +			break; +		} +		if ((n & PCAN_USB_ERROR_BUS_LIGHT) == 0) { +			/* no error (back to active state) */ +			mc->pdev->dev.can.state = CAN_STATE_ERROR_ACTIVE; +			return 0; +		} +		break; + +	case CAN_STATE_ERROR_PASSIVE: +		if (n & PCAN_USB_ERROR_BUS_OFF) { +			new_state = CAN_STATE_BUS_OFF; +			break; +		} +		if (n & PCAN_USB_ERROR_BUS_LIGHT) { +			new_state = CAN_STATE_ERROR_WARNING; +			break; +		} +		if (n & (PCAN_USB_ERROR_RXQOVR | PCAN_USB_ERROR_QOVR)) { +			/* +			 * trick to bypass next comparison and process other +			 * errors +			 */ +			new_state = CAN_STATE_MAX; +			break; +		} + +		if ((n & PCAN_USB_ERROR_BUS_HEAVY) == 0) { +			/* no error (back to active state) */ +			mc->pdev->dev.can.state = CAN_STATE_ERROR_ACTIVE; +			return 0; +		} +		break; + +	default: +		/* do nothing waiting for restart */ +		return 0; +	} + +	/* donot post any error if current state didn't change */ +	if (mc->pdev->dev.can.state == new_state) +		return 0; + +	/* allocate an skb to store the error frame */ +	skb = alloc_can_err_skb(mc->netdev, &cf); +	if (!skb) +		return -ENOMEM; + +	switch (new_state) { +	case CAN_STATE_BUS_OFF: +		cf->can_id |= CAN_ERR_BUSOFF; +		can_bus_off(mc->netdev); +		break; + +	case CAN_STATE_ERROR_PASSIVE: +		cf->can_id |= CAN_ERR_CRTL; +		cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE | +			       CAN_ERR_CRTL_RX_PASSIVE; +		mc->pdev->dev.can.can_stats.error_passive++; +		break; + +	case CAN_STATE_ERROR_WARNING: +		cf->can_id |= CAN_ERR_CRTL; +		cf->data[1] |= CAN_ERR_CRTL_TX_WARNING | +			       CAN_ERR_CRTL_RX_WARNING; +		mc->pdev->dev.can.can_stats.error_warning++; +		break; + +	default: +		/* CAN_STATE_MAX (trick to handle other errors) */ +		cf->can_id |= CAN_ERR_CRTL; +		cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; +		mc->netdev->stats.rx_over_errors++; +		mc->netdev->stats.rx_errors++; + +		new_state = mc->pdev->dev.can.state; +		break; +	} + +	mc->pdev->dev.can.state = new_state; + +	if (status_len & PCAN_USB_STATUSLEN_TIMESTAMP) { +		struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb); + +		peak_usb_get_ts_tv(&mc->pdev->time_ref, mc->ts16, &tv); +		hwts->hwtstamp = timeval_to_ktime(tv); +	} + +	netif_rx(skb); +	mc->netdev->stats.rx_packets++; +	mc->netdev->stats.rx_bytes += cf->can_dlc; + +	return 0; +} + +/* + * decode non-data usb message + */ +static int pcan_usb_decode_status(struct pcan_usb_msg_context *mc, +				  u8 status_len) +{ +	u8 rec_len = status_len & PCAN_USB_STATUSLEN_DLC; +	u8 f, n; +	int err; + +	/* check whether function and number can be read */ +	if ((mc->ptr + 2) > mc->end) +		return -EINVAL; + +	f = mc->ptr[PCAN_USB_CMD_FUNC]; +	n = mc->ptr[PCAN_USB_CMD_NUM]; +	mc->ptr += PCAN_USB_CMD_ARGS; + +	if (status_len & PCAN_USB_STATUSLEN_TIMESTAMP) { +		int err = pcan_usb_decode_ts(mc, !mc->rec_idx); + +		if (err) +			return err; +	} + +	switch (f) { +	case PCAN_USB_REC_ERROR: +		err = pcan_usb_decode_error(mc, n, status_len); +		if (err) +			return err; +		break; + +	case PCAN_USB_REC_ANALOG: +		/* analog values (ignored) */ +		rec_len = 2; +		break; + +	case PCAN_USB_REC_BUSLOAD: +		/* bus load (ignored) */ +		rec_len = 1; +		break; + +	case PCAN_USB_REC_TS: +		/* only timestamp */ +		if (pcan_usb_update_ts(mc)) +			return -EINVAL; +		break; + +	case PCAN_USB_REC_BUSEVT: +		/* error frame/bus event */ +		if (n & PCAN_USB_ERROR_TXQFULL) +			netdev_dbg(mc->netdev, "device Tx queue full)\n"); +		break; +	default: +		netdev_err(mc->netdev, "unexpected function %u\n", f); +		break; +	} + +	if ((mc->ptr + rec_len) > mc->end) +		return -EINVAL; + +	mc->ptr += rec_len; + +	return 0; +} + +/* + * decode data usb message + */ +static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len) +{ +	u8 rec_len = status_len & PCAN_USB_STATUSLEN_DLC; +	struct sk_buff *skb; +	struct can_frame *cf; +	struct timeval tv; +	struct skb_shared_hwtstamps *hwts; + +	skb = alloc_can_skb(mc->netdev, &cf); +	if (!skb) +		return -ENOMEM; + +	if (status_len & PCAN_USB_STATUSLEN_EXT_ID) { +		u32 tmp32; + +		if ((mc->ptr + 4) > mc->end) +			goto decode_failed; + +		memcpy(&tmp32, mc->ptr, 4); +		mc->ptr += 4; + +		cf->can_id = le32_to_cpu(tmp32 >> 3) | CAN_EFF_FLAG; +	} else { +		u16 tmp16; + +		if ((mc->ptr + 2) > mc->end) +			goto decode_failed; + +		memcpy(&tmp16, mc->ptr, 2); +		mc->ptr += 2; + +		cf->can_id = le16_to_cpu(tmp16 >> 5); +	} + +	cf->can_dlc = get_can_dlc(rec_len); + +	/* first data packet timestamp is a word */ +	if (pcan_usb_decode_ts(mc, !mc->rec_data_idx)) +		goto decode_failed; + +	/* read data */ +	memset(cf->data, 0x0, sizeof(cf->data)); +	if (status_len & PCAN_USB_STATUSLEN_RTR) { +		cf->can_id |= CAN_RTR_FLAG; +	} else { +		if ((mc->ptr + rec_len) > mc->end) +			goto decode_failed; + +		memcpy(cf->data, mc->ptr, cf->can_dlc); +		mc->ptr += rec_len; +	} + +	/* convert timestamp into kernel time */ +	peak_usb_get_ts_tv(&mc->pdev->time_ref, mc->ts16, &tv); +	hwts = skb_hwtstamps(skb); +	hwts->hwtstamp = timeval_to_ktime(tv); + +	/* push the skb */ +	netif_rx(skb); + +	/* update statistics */ +	mc->netdev->stats.rx_packets++; +	mc->netdev->stats.rx_bytes += cf->can_dlc; + +	return 0; + +decode_failed: +	dev_kfree_skb(skb); +	return -EINVAL; +} + +/* + * process incoming message + */ +static int pcan_usb_decode_msg(struct peak_usb_device *dev, u8 *ibuf, u32 lbuf) +{ +	struct pcan_usb_msg_context mc = { +		.rec_cnt = ibuf[1], +		.ptr = ibuf + PCAN_USB_MSG_HEADER_LEN, +		.end = ibuf + lbuf, +		.netdev = dev->netdev, +		.pdev = container_of(dev, struct pcan_usb, dev), +	}; +	int err; + +	for (err = 0; mc.rec_idx < mc.rec_cnt && !err; mc.rec_idx++) { +		u8 sl = *mc.ptr++; + +		/* handle status and error frames here */ +		if (sl & PCAN_USB_STATUSLEN_INTERNAL) { +			err = pcan_usb_decode_status(&mc, sl); +		/* handle normal can frames here */ +		} else { +			err = pcan_usb_decode_data(&mc, sl); +			mc.rec_data_idx++; +		} +	} + +	return err; +} + +/* + * process any incoming buffer + */ +static int pcan_usb_decode_buf(struct peak_usb_device *dev, struct urb *urb) +{ +	int err = 0; + +	if (urb->actual_length > PCAN_USB_MSG_HEADER_LEN) { +		err = pcan_usb_decode_msg(dev, urb->transfer_buffer, +			urb->actual_length); + +	} else if (urb->actual_length > 0) { +		netdev_err(dev->netdev, "usb message length error (%u)\n", +			urb->actual_length); +		err = -EINVAL; +	} + +	return err; +} + +/* + * process outgoing packet + */ +static int pcan_usb_encode_msg(struct peak_usb_device *dev, struct sk_buff *skb, +			       u8 *obuf, size_t *size) +{ +	struct net_device *netdev = dev->netdev; +	struct net_device_stats *stats = &netdev->stats; +	struct can_frame *cf = (struct can_frame *)skb->data; +	u8 *pc; + +	obuf[0] = 2; +	obuf[1] = 1; + +	pc = obuf + PCAN_USB_MSG_HEADER_LEN; + +	/* status/len byte */ +	*pc = cf->can_dlc; +	if (cf->can_id & CAN_RTR_FLAG) +		*pc |= PCAN_USB_STATUSLEN_RTR; + +	/* can id */ +	if (cf->can_id & CAN_EFF_FLAG) { +		__le32 tmp32 = cpu_to_le32((cf->can_id & CAN_ERR_MASK) << 3); + +		*pc |= PCAN_USB_STATUSLEN_EXT_ID; +		memcpy(++pc, &tmp32, 4); +		pc += 4; +	} else { +		__le16 tmp16 = cpu_to_le16((cf->can_id & CAN_ERR_MASK) << 5); + +		memcpy(++pc, &tmp16, 2); +		pc += 2; +	} + +	/* can data */ +	if (!(cf->can_id & CAN_RTR_FLAG)) { +		memcpy(pc, cf->data, cf->can_dlc); +		pc += cf->can_dlc; +	} + +	obuf[(*size)-1] = (u8)(stats->tx_packets & 0xff); + +	return 0; +} + +/* + * start interface + */ +static int pcan_usb_start(struct peak_usb_device *dev) +{ +	struct pcan_usb *pdev = container_of(dev, struct pcan_usb, dev); + +	/* number of bits used in timestamps read from adapter struct */ +	peak_usb_init_time_ref(&pdev->time_ref, &pcan_usb); + +	/* if revision greater than 3, can put silent mode on/off */ +	if (dev->device_rev > 3) { +		int err; + +		err = pcan_usb_set_silent(dev, +				dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY); +		if (err) +			return err; +	} + +	return pcan_usb_set_ext_vcc(dev, 0); +} + +static int pcan_usb_init(struct peak_usb_device *dev) +{ +	struct pcan_usb *pdev = container_of(dev, struct pcan_usb, dev); +	u32 serial_number; +	int err; + +	/* initialize a timer needed to wait for hardware restart */ +	init_timer(&pdev->restart_timer); +	pdev->restart_timer.function = pcan_usb_restart; +	pdev->restart_timer.data = (unsigned long)dev; + +	/* +	 * explicit use of dev_xxx() instead of netdev_xxx() here: +	 * information displayed are related to the device itself, not +	 * to the canx netdevice. +	 */ +	err = pcan_usb_get_serial(dev, &serial_number); +	if (err) { +		dev_err(dev->netdev->dev.parent, +			"unable to read %s serial number (err %d)\n", +			pcan_usb.name, err); +		return err; +	} + +	dev_info(dev->netdev->dev.parent, +		 "PEAK-System %s adapter hwrev %u serial %08X (%u channel)\n", +		 pcan_usb.name, dev->device_rev, serial_number, +		 pcan_usb.ctrl_count); + +	return 0; +} + +/* + * probe function for new PCAN-USB usb interface + */ +static int pcan_usb_probe(struct usb_interface *intf) +{ +	struct usb_host_interface *if_desc; +	int i; + +	if_desc = intf->altsetting; + +	/* check interface endpoint addresses */ +	for (i = 0; i < if_desc->desc.bNumEndpoints; i++) { +		struct usb_endpoint_descriptor *ep = &if_desc->endpoint[i].desc; + +		switch (ep->bEndpointAddress) { +		case PCAN_USB_EP_CMDOUT: +		case PCAN_USB_EP_CMDIN: +		case PCAN_USB_EP_MSGOUT: +		case PCAN_USB_EP_MSGIN: +			break; +		default: +			return -ENODEV; +		} +	} + +	return 0; +} + +/* + * describe the PCAN-USB adapter + */ +struct peak_usb_adapter pcan_usb = { +	.name = "PCAN-USB", +	.device_id = PCAN_USB_PRODUCT_ID, +	.ctrl_count = 1, +	.clock = { +		.freq = PCAN_USB_CRYSTAL_HZ / 2 , +	}, +	.bittiming_const = { +		.name = "pcan_usb", +		.tseg1_min = 1, +		.tseg1_max = 16, +		.tseg2_min = 1, +		.tseg2_max = 8, +		.sjw_max = 4, +		.brp_min = 1, +		.brp_max = 64, +		.brp_inc = 1, +	}, + +	/* size of device private data */ +	.sizeof_dev_private = sizeof(struct pcan_usb), + +	/* timestamps usage */ +	.ts_used_bits = 16, +	.ts_period = 24575, /* calibration period in ts. */ +	.us_per_ts_scale = PCAN_USB_TS_US_PER_TICK, /* us=(ts*scale) */ +	.us_per_ts_shift = PCAN_USB_TS_DIV_SHIFTER, /*  >> shift     */ + +	/* give here messages in/out endpoints */ +	.ep_msg_in = PCAN_USB_EP_MSGIN, +	.ep_msg_out = {PCAN_USB_EP_MSGOUT}, + +	/* size of rx/tx usb buffers */ +	.rx_buffer_size = PCAN_USB_RX_BUFFER_SIZE, +	.tx_buffer_size = PCAN_USB_TX_BUFFER_SIZE, + +	/* device callbacks */ +	.intf_probe = pcan_usb_probe, +	.dev_init = pcan_usb_init, +	.dev_set_bus = pcan_usb_write_mode, +	.dev_set_bittiming = pcan_usb_set_bittiming, +	.dev_get_device_id = pcan_usb_get_device_id, +	.dev_decode_buf = pcan_usb_decode_buf, +	.dev_encode_msg = pcan_usb_encode_msg, +	.dev_start = pcan_usb_start, +	.dev_restart_async = pcan_usb_restart_async, +}; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c new file mode 100644 index 00000000000..644e6ab8a48 --- /dev/null +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -0,0 +1,950 @@ +/* + * CAN driver for PEAK System USB adapters + * Derived from the PCAN project file driver/src/pcan_usb_core.c + * + * Copyright (C) 2003-2010 PEAK System-Technik GmbH + * Copyright (C) 2010-2012 Stephane Grosjean <s.grosjean@peak-system.com> + * + * Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#include <linux/init.h> +#include <linux/signal.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/usb.h> + +#include <linux/can.h> +#include <linux/can/dev.h> +#include <linux/can/error.h> + +#include "pcan_usb_core.h" + +MODULE_AUTHOR("Stephane Grosjean <s.grosjean@peak-system.com>"); +MODULE_DESCRIPTION("CAN driver for PEAK-System USB adapters"); +MODULE_LICENSE("GPL v2"); + +/* Table of devices that work with this driver */ +static struct usb_device_id peak_usb_table[] = { +	{USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USB_PRODUCT_ID)}, +	{USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBPRO_PRODUCT_ID)}, +	{} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, peak_usb_table); + +/* List of supported PCAN-USB adapters (NULL terminated list) */ +static struct peak_usb_adapter *peak_usb_adapters_list[] = { +	&pcan_usb, +	&pcan_usb_pro, +	NULL, +}; + +/* + * dump memory + */ +#define DUMP_WIDTH	16 +void pcan_dump_mem(char *prompt, void *p, int l) +{ +	pr_info("%s dumping %s (%d bytes):\n", +		PCAN_USB_DRIVER_NAME, prompt ? prompt : "memory", l); +	print_hex_dump(KERN_INFO, PCAN_USB_DRIVER_NAME " ", DUMP_PREFIX_NONE, +		       DUMP_WIDTH, 1, p, l, false); +} + +/* + * initialize a time_ref object with usb adapter own settings + */ +void peak_usb_init_time_ref(struct peak_time_ref *time_ref, +			    struct peak_usb_adapter *adapter) +{ +	if (time_ref) { +		memset(time_ref, 0, sizeof(struct peak_time_ref)); +		time_ref->adapter = adapter; +	} +} + +static void peak_usb_add_us(struct timeval *tv, u32 delta_us) +{ +	/* number of s. to add to final time */ +	u32 delta_s = delta_us / 1000000; + +	delta_us -= delta_s * 1000000; + +	tv->tv_usec += delta_us; +	if (tv->tv_usec >= 1000000) { +		tv->tv_usec -= 1000000; +		delta_s++; +	} +	tv->tv_sec += delta_s; +} + +/* + * sometimes, another now may be  more recent than current one... + */ +void peak_usb_update_ts_now(struct peak_time_ref *time_ref, u32 ts_now) +{ +	time_ref->ts_dev_2 = ts_now; + +	/* should wait at least two passes before computing */ +	if (time_ref->tv_host.tv_sec > 0) { +		u32 delta_ts = time_ref->ts_dev_2 - time_ref->ts_dev_1; + +		if (time_ref->ts_dev_2 < time_ref->ts_dev_1) +			delta_ts &= (1 << time_ref->adapter->ts_used_bits) - 1; + +		time_ref->ts_total += delta_ts; +	} +} + +/* + * register device timestamp as now + */ +void peak_usb_set_ts_now(struct peak_time_ref *time_ref, u32 ts_now) +{ +	if (time_ref->tv_host_0.tv_sec == 0) { +		/* use monotonic clock to correctly compute further deltas */ +		time_ref->tv_host_0 = ktime_to_timeval(ktime_get()); +		time_ref->tv_host.tv_sec = 0; +	} else { +		/* +		 * delta_us should not be >= 2^32 => delta_s should be < 4294 +		 * handle 32-bits wrapping here: if count of s. reaches 4200, +		 * reset counters and change time base +		 */ +		if (time_ref->tv_host.tv_sec != 0) { +			u32 delta_s = time_ref->tv_host.tv_sec +						- time_ref->tv_host_0.tv_sec; +			if (delta_s > 4200) { +				time_ref->tv_host_0 = time_ref->tv_host; +				time_ref->ts_total = 0; +			} +		} + +		time_ref->tv_host = ktime_to_timeval(ktime_get()); +		time_ref->tick_count++; +	} + +	time_ref->ts_dev_1 = time_ref->ts_dev_2; +	peak_usb_update_ts_now(time_ref, ts_now); +} + +/* + * compute timeval according to current ts and time_ref data + */ +void peak_usb_get_ts_tv(struct peak_time_ref *time_ref, u32 ts, +			struct timeval *tv) +{ +	/* protect from getting timeval before setting now */ +	if (time_ref->tv_host.tv_sec > 0) { +		u64 delta_us; + +		delta_us = ts - time_ref->ts_dev_2; +		if (ts < time_ref->ts_dev_2) +			delta_us &= (1 << time_ref->adapter->ts_used_bits) - 1; + +		delta_us += time_ref->ts_total; + +		delta_us *= time_ref->adapter->us_per_ts_scale; +		delta_us >>= time_ref->adapter->us_per_ts_shift; + +		*tv = time_ref->tv_host_0; +		peak_usb_add_us(tv, (u32)delta_us); +	} else { +		*tv = ktime_to_timeval(ktime_get()); +	} +} + +/* + * callback for bulk Rx urb + */ +static void peak_usb_read_bulk_callback(struct urb *urb) +{ +	struct peak_usb_device *dev = urb->context; +	struct net_device *netdev; +	int err; + +	netdev = dev->netdev; + +	if (!netif_device_present(netdev)) +		return; + +	/* check reception status */ +	switch (urb->status) { +	case 0: +		/* success */ +		break; + +	case -EILSEQ: +	case -ENOENT: +	case -ECONNRESET: +	case -ESHUTDOWN: +		return; + +	default: +		if (net_ratelimit()) +			netdev_err(netdev, +				   "Rx urb aborted (%d)\n", urb->status); +		goto resubmit_urb; +	} + +	/* protect from any incoming empty msgs */ +	if ((urb->actual_length > 0) && (dev->adapter->dev_decode_buf)) { +		/* handle these kinds of msgs only if _start callback called */ +		if (dev->state & PCAN_USB_STATE_STARTED) { +			err = dev->adapter->dev_decode_buf(dev, urb); +			if (err) +				pcan_dump_mem("received usb message", +					      urb->transfer_buffer, +					      urb->transfer_buffer_length); +		} +	} + +resubmit_urb: +	usb_fill_bulk_urb(urb, dev->udev, +		usb_rcvbulkpipe(dev->udev, dev->ep_msg_in), +		urb->transfer_buffer, dev->adapter->rx_buffer_size, +		peak_usb_read_bulk_callback, dev); + +	usb_anchor_urb(urb, &dev->rx_submitted); +	err = usb_submit_urb(urb, GFP_ATOMIC); +	if (!err) +		return; + +	usb_unanchor_urb(urb); + +	if (err == -ENODEV) +		netif_device_detach(netdev); +	else +		netdev_err(netdev, "failed resubmitting read bulk urb: %d\n", +			   err); +} + +/* + * callback for bulk Tx urb + */ +static void peak_usb_write_bulk_callback(struct urb *urb) +{ +	struct peak_tx_urb_context *context = urb->context; +	struct peak_usb_device *dev; +	struct net_device *netdev; + +	BUG_ON(!context); + +	dev = context->dev; +	netdev = dev->netdev; + +	atomic_dec(&dev->active_tx_urbs); + +	if (!netif_device_present(netdev)) +		return; + +	/* check tx status */ +	switch (urb->status) { +	case 0: +		/* transmission complete */ +		netdev->stats.tx_packets++; +		netdev->stats.tx_bytes += context->dlc; + +		/* prevent tx timeout */ +		netdev->trans_start = jiffies; +		break; + +	default: +		if (net_ratelimit()) +			netdev_err(netdev, "Tx urb aborted (%d)\n", +				   urb->status); +	case -EPROTO: +	case -ENOENT: +	case -ECONNRESET: +	case -ESHUTDOWN: + +		break; +	} + +	/* should always release echo skb and corresponding context */ +	can_get_echo_skb(netdev, context->echo_index); +	context->echo_index = PCAN_USB_MAX_TX_URBS; + +	/* do wakeup tx queue in case of success only */ +	if (!urb->status) +		netif_wake_queue(netdev); +} + +/* + * called by netdev to send one skb on the CAN interface. + */ +static netdev_tx_t peak_usb_ndo_start_xmit(struct sk_buff *skb, +					   struct net_device *netdev) +{ +	struct peak_usb_device *dev = netdev_priv(netdev); +	struct peak_tx_urb_context *context = NULL; +	struct net_device_stats *stats = &netdev->stats; +	struct can_frame *cf = (struct can_frame *)skb->data; +	struct urb *urb; +	u8 *obuf; +	int i, err; +	size_t size = dev->adapter->tx_buffer_size; + +	if (can_dropped_invalid_skb(netdev, skb)) +		return NETDEV_TX_OK; + +	for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++) +		if (dev->tx_contexts[i].echo_index == PCAN_USB_MAX_TX_URBS) { +			context = dev->tx_contexts + i; +			break; +		} + +	if (!context) { +		/* should not occur except during restart */ +		return NETDEV_TX_BUSY; +	} + +	urb = context->urb; +	obuf = urb->transfer_buffer; + +	err = dev->adapter->dev_encode_msg(dev, skb, obuf, &size); +	if (err) { +		if (net_ratelimit()) +			netdev_err(netdev, "packet dropped\n"); +		dev_kfree_skb(skb); +		stats->tx_dropped++; +		return NETDEV_TX_OK; +	} + +	context->echo_index = i; +	context->dlc = cf->can_dlc; + +	usb_anchor_urb(urb, &dev->tx_submitted); + +	can_put_echo_skb(skb, netdev, context->echo_index); + +	atomic_inc(&dev->active_tx_urbs); + +	err = usb_submit_urb(urb, GFP_ATOMIC); +	if (err) { +		can_free_echo_skb(netdev, context->echo_index); + +		usb_unanchor_urb(urb); + +		/* this context is not used in fact */ +		context->echo_index = PCAN_USB_MAX_TX_URBS; + +		atomic_dec(&dev->active_tx_urbs); + +		switch (err) { +		case -ENODEV: +			netif_device_detach(netdev); +			break; +		default: +			netdev_warn(netdev, "tx urb submitting failed err=%d\n", +				    err); +		case -ENOENT: +			/* cable unplugged */ +			stats->tx_dropped++; +		} +	} else { +		netdev->trans_start = jiffies; + +		/* slow down tx path */ +		if (atomic_read(&dev->active_tx_urbs) >= PCAN_USB_MAX_TX_URBS) +			netif_stop_queue(netdev); +	} + +	return NETDEV_TX_OK; +} + +/* + * start the CAN interface. + * Rx and Tx urbs are allocated here. Rx urbs are submitted here. + */ +static int peak_usb_start(struct peak_usb_device *dev) +{ +	struct net_device *netdev = dev->netdev; +	int err, i; + +	for (i = 0; i < PCAN_USB_MAX_RX_URBS; i++) { +		struct urb *urb; +		u8 *buf; + +		/* create a URB, and a buffer for it, to receive usb messages */ +		urb = usb_alloc_urb(0, GFP_KERNEL); +		if (!urb) { +			netdev_err(netdev, "No memory left for URBs\n"); +			err = -ENOMEM; +			break; +		} + +		buf = kmalloc(dev->adapter->rx_buffer_size, GFP_KERNEL); +		if (!buf) { +			usb_free_urb(urb); +			err = -ENOMEM; +			break; +		} + +		usb_fill_bulk_urb(urb, dev->udev, +			usb_rcvbulkpipe(dev->udev, dev->ep_msg_in), +			buf, dev->adapter->rx_buffer_size, +			peak_usb_read_bulk_callback, dev); + +		/* ask last usb_free_urb() to also kfree() transfer_buffer */ +		urb->transfer_flags |= URB_FREE_BUFFER; +		usb_anchor_urb(urb, &dev->rx_submitted); + +		err = usb_submit_urb(urb, GFP_KERNEL); +		if (err) { +			if (err == -ENODEV) +				netif_device_detach(dev->netdev); + +			usb_unanchor_urb(urb); +			kfree(buf); +			usb_free_urb(urb); +			break; +		} + +		/* drop reference, USB core will take care of freeing it */ +		usb_free_urb(urb); +	} + +	/* did we submit any URBs? Warn if we was not able to submit all urbs */ +	if (i < PCAN_USB_MAX_RX_URBS) { +		if (i == 0) { +			netdev_err(netdev, "couldn't setup any rx URB\n"); +			return err; +		} + +		netdev_warn(netdev, "rx performance may be slow\n"); +	} + +	/* pre-alloc tx buffers and corresponding urbs */ +	for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++) { +		struct peak_tx_urb_context *context; +		struct urb *urb; +		u8 *buf; + +		/* create a URB and a buffer for it, to transmit usb messages */ +		urb = usb_alloc_urb(0, GFP_KERNEL); +		if (!urb) { +			netdev_err(netdev, "No memory left for URBs\n"); +			err = -ENOMEM; +			break; +		} + +		buf = kmalloc(dev->adapter->tx_buffer_size, GFP_KERNEL); +		if (!buf) { +			usb_free_urb(urb); +			err = -ENOMEM; +			break; +		} + +		context = dev->tx_contexts + i; +		context->dev = dev; +		context->urb = urb; + +		usb_fill_bulk_urb(urb, dev->udev, +			usb_sndbulkpipe(dev->udev, dev->ep_msg_out), +			buf, dev->adapter->tx_buffer_size, +			peak_usb_write_bulk_callback, context); + +		/* ask last usb_free_urb() to also kfree() transfer_buffer */ +		urb->transfer_flags |= URB_FREE_BUFFER; +	} + +	/* warn if we were not able to allocate enough tx contexts */ +	if (i < PCAN_USB_MAX_TX_URBS) { +		if (i == 0) { +			netdev_err(netdev, "couldn't setup any tx URB\n"); +			goto err_tx; +		} + +		netdev_warn(netdev, "tx performance may be slow\n"); +	} + +	if (dev->adapter->dev_start) { +		err = dev->adapter->dev_start(dev); +		if (err) +			goto err_adapter; +	} + +	dev->state |= PCAN_USB_STATE_STARTED; + +	/* can set bus on now */ +	if (dev->adapter->dev_set_bus) { +		err = dev->adapter->dev_set_bus(dev, 1); +		if (err) +			goto err_adapter; +	} + +	dev->can.state = CAN_STATE_ERROR_ACTIVE; + +	return 0; + +err_adapter: +	if (err == -ENODEV) +		netif_device_detach(dev->netdev); + +	netdev_warn(netdev, "couldn't submit control: %d\n", err); + +	for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++) { +		usb_free_urb(dev->tx_contexts[i].urb); +		dev->tx_contexts[i].urb = NULL; +	} +err_tx: +	usb_kill_anchored_urbs(&dev->rx_submitted); + +	return err; +} + +/* + * called by netdev to open the corresponding CAN interface. + */ +static int peak_usb_ndo_open(struct net_device *netdev) +{ +	struct peak_usb_device *dev = netdev_priv(netdev); +	int err; + +	/* common open */ +	err = open_candev(netdev); +	if (err) +		return err; + +	/* finally start device */ +	err = peak_usb_start(dev); +	if (err) { +		netdev_err(netdev, "couldn't start device: %d\n", err); +		close_candev(netdev); +		return err; +	} + +	netif_start_queue(netdev); + +	return 0; +} + +/* + * unlink in-flight Rx and Tx urbs and free their memory. + */ +static void peak_usb_unlink_all_urbs(struct peak_usb_device *dev) +{ +	int i; + +	/* free all Rx (submitted) urbs */ +	usb_kill_anchored_urbs(&dev->rx_submitted); + +	/* free unsubmitted Tx urbs first */ +	for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++) { +		struct urb *urb = dev->tx_contexts[i].urb; + +		if (!urb || +		    dev->tx_contexts[i].echo_index != PCAN_USB_MAX_TX_URBS) { +			/* +			 * this urb is already released or always submitted, +			 * let usb core free by itself +			 */ +			continue; +		} + +		usb_free_urb(urb); +		dev->tx_contexts[i].urb = NULL; +	} + +	/* then free all submitted Tx urbs */ +	usb_kill_anchored_urbs(&dev->tx_submitted); +	atomic_set(&dev->active_tx_urbs, 0); +} + +/* + * called by netdev to close the corresponding CAN interface. + */ +static int peak_usb_ndo_stop(struct net_device *netdev) +{ +	struct peak_usb_device *dev = netdev_priv(netdev); + +	dev->state &= ~PCAN_USB_STATE_STARTED; +	netif_stop_queue(netdev); + +	/* unlink all pending urbs and free used memory */ +	peak_usb_unlink_all_urbs(dev); + +	if (dev->adapter->dev_stop) +		dev->adapter->dev_stop(dev); + +	close_candev(netdev); + +	dev->can.state = CAN_STATE_STOPPED; + +	/* can set bus off now */ +	if (dev->adapter->dev_set_bus) { +		int err = dev->adapter->dev_set_bus(dev, 0); +		if (err) +			return err; +	} + +	return 0; +} + +/* + * handle end of waiting for the device to reset + */ +void peak_usb_restart_complete(struct peak_usb_device *dev) +{ +	/* finally MUST update can state */ +	dev->can.state = CAN_STATE_ERROR_ACTIVE; + +	/* netdev queue can be awaken now */ +	netif_wake_queue(dev->netdev); +} + +void peak_usb_async_complete(struct urb *urb) +{ +	kfree(urb->transfer_buffer); +	usb_free_urb(urb); +} + +/* + * device (auto-)restart mechanism runs in a timer context => + * MUST handle restart with asynchronous usb transfers + */ +static int peak_usb_restart(struct peak_usb_device *dev) +{ +	struct urb *urb; +	int err; +	u8 *buf; + +	/* +	 * if device doesn't define any asynchronous restart handler, simply +	 * wake the netdev queue up +	 */ +	if (!dev->adapter->dev_restart_async) { +		peak_usb_restart_complete(dev); +		return 0; +	} + +	/* first allocate a urb to handle the asynchronous steps */ +	urb = usb_alloc_urb(0, GFP_ATOMIC); +	if (!urb) { +		netdev_err(dev->netdev, "no memory left for urb\n"); +		return -ENOMEM; +	} + +	/* also allocate enough space for the commands to send */ +	buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_ATOMIC); +	if (!buf) { +		usb_free_urb(urb); +		return -ENOMEM; +	} + +	/* call the device specific handler for the restart */ +	err = dev->adapter->dev_restart_async(dev, urb, buf); +	if (!err) +		return 0; + +	kfree(buf); +	usb_free_urb(urb); + +	return err; +} + +/* + * candev callback used to change CAN mode. + * Warning: this is called from a timer context! + */ +static int peak_usb_set_mode(struct net_device *netdev, enum can_mode mode) +{ +	struct peak_usb_device *dev = netdev_priv(netdev); +	int err = 0; + +	switch (mode) { +	case CAN_MODE_START: +		err = peak_usb_restart(dev); +		if (err) +			netdev_err(netdev, "couldn't start device (err %d)\n", +				   err); +		break; + +	default: +		return -EOPNOTSUPP; +	} + +	return err; +} + +/* + * candev callback used to set device bitrate. + */ +static int peak_usb_set_bittiming(struct net_device *netdev) +{ +	struct peak_usb_device *dev = netdev_priv(netdev); +	struct can_bittiming *bt = &dev->can.bittiming; + +	if (dev->adapter->dev_set_bittiming) { +		int err = dev->adapter->dev_set_bittiming(dev, bt); + +		if (err) +			netdev_info(netdev, "couldn't set bitrate (err %d)\n", +				err); +		return err; +	} + +	return 0; +} + +static const struct net_device_ops peak_usb_netdev_ops = { +	.ndo_open = peak_usb_ndo_open, +	.ndo_stop = peak_usb_ndo_stop, +	.ndo_start_xmit = peak_usb_ndo_start_xmit, +	.ndo_change_mtu = can_change_mtu, +}; + +/* + * create one device which is attached to CAN controller #ctrl_idx of the + * usb adapter. + */ +static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter, +			       struct usb_interface *intf, int ctrl_idx) +{ +	struct usb_device *usb_dev = interface_to_usbdev(intf); +	int sizeof_candev = peak_usb_adapter->sizeof_dev_private; +	struct peak_usb_device *dev; +	struct net_device *netdev; +	int i, err; +	u16 tmp16; + +	if (sizeof_candev < sizeof(struct peak_usb_device)) +		sizeof_candev = sizeof(struct peak_usb_device); + +	netdev = alloc_candev(sizeof_candev, PCAN_USB_MAX_TX_URBS); +	if (!netdev) { +		dev_err(&intf->dev, "%s: couldn't alloc candev\n", +			PCAN_USB_DRIVER_NAME); +		return -ENOMEM; +	} + +	dev = netdev_priv(netdev); + +	/* allocate a buffer large enough to send commands */ +	dev->cmd_buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_KERNEL); +	if (!dev->cmd_buf) { +		err = -ENOMEM; +		goto lbl_set_intf_data; +	} + +	dev->udev = usb_dev; +	dev->netdev = netdev; +	dev->adapter = peak_usb_adapter; +	dev->ctrl_idx = ctrl_idx; +	dev->state = PCAN_USB_STATE_CONNECTED; + +	dev->ep_msg_in = peak_usb_adapter->ep_msg_in; +	dev->ep_msg_out = peak_usb_adapter->ep_msg_out[ctrl_idx]; + +	dev->can.clock = peak_usb_adapter->clock; +	dev->can.bittiming_const = &peak_usb_adapter->bittiming_const; +	dev->can.do_set_bittiming = peak_usb_set_bittiming; +	dev->can.do_set_mode = peak_usb_set_mode; +	dev->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | +				      CAN_CTRLMODE_LISTENONLY; + +	netdev->netdev_ops = &peak_usb_netdev_ops; + +	netdev->flags |= IFF_ECHO; /* we support local echo */ + +	init_usb_anchor(&dev->rx_submitted); + +	init_usb_anchor(&dev->tx_submitted); +	atomic_set(&dev->active_tx_urbs, 0); + +	for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++) +		dev->tx_contexts[i].echo_index = PCAN_USB_MAX_TX_URBS; + +	dev->prev_siblings = usb_get_intfdata(intf); +	usb_set_intfdata(intf, dev); + +	SET_NETDEV_DEV(netdev, &intf->dev); +	netdev->dev_id = ctrl_idx; + +	err = register_candev(netdev); +	if (err) { +		dev_err(&intf->dev, "couldn't register CAN device: %d\n", err); +		goto lbl_free_cmd_buf; +	} + +	if (dev->prev_siblings) +		(dev->prev_siblings)->next_siblings = dev; + +	/* keep hw revision into the netdevice */ +	tmp16 = le16_to_cpu(usb_dev->descriptor.bcdDevice); +	dev->device_rev = tmp16 >> 8; + +	if (dev->adapter->dev_init) { +		err = dev->adapter->dev_init(dev); +		if (err) +			goto lbl_free_cmd_buf; +	} + +	/* set bus off */ +	if (dev->adapter->dev_set_bus) { +		err = dev->adapter->dev_set_bus(dev, 0); +		if (err) +			goto lbl_free_cmd_buf; +	} + +	/* get device number early */ +	if (dev->adapter->dev_get_device_id) +		dev->adapter->dev_get_device_id(dev, &dev->device_number); + +	netdev_info(netdev, "attached to %s channel %u (device %u)\n", +			peak_usb_adapter->name, ctrl_idx, dev->device_number); + +	return 0; + +lbl_free_cmd_buf: +	kfree(dev->cmd_buf); + +lbl_set_intf_data: +	usb_set_intfdata(intf, dev->prev_siblings); +	free_candev(netdev); + +	return err; +} + +/* + * called by the usb core when the device is unplugged from the system + */ +static void peak_usb_disconnect(struct usb_interface *intf) +{ +	struct peak_usb_device *dev; + +	/* unregister as many netdev devices as siblings */ +	for (dev = usb_get_intfdata(intf); dev; dev = dev->prev_siblings) { +		struct net_device *netdev = dev->netdev; +		char name[IFNAMSIZ]; + +		dev->state &= ~PCAN_USB_STATE_CONNECTED; +		strncpy(name, netdev->name, IFNAMSIZ); + +		unregister_netdev(netdev); +		free_candev(netdev); + +		kfree(dev->cmd_buf); +		dev->next_siblings = NULL; +		if (dev->adapter->dev_free) +			dev->adapter->dev_free(dev); + +		dev_info(&intf->dev, "%s removed\n", name); +	} + +	usb_set_intfdata(intf, NULL); +} + +/* + * probe function for new PEAK-System devices + */ +static int peak_usb_probe(struct usb_interface *intf, +			  const struct usb_device_id *id) +{ +	struct usb_device *usb_dev = interface_to_usbdev(intf); +	struct peak_usb_adapter *peak_usb_adapter, **pp; +	int i, err = -ENOMEM; + +	usb_dev = interface_to_usbdev(intf); + +	/* get corresponding PCAN-USB adapter */ +	for (pp = peak_usb_adapters_list; *pp; pp++) +		if ((*pp)->device_id == usb_dev->descriptor.idProduct) +			break; + +	peak_usb_adapter = *pp; +	if (!peak_usb_adapter) { +		/* should never come except device_id bad usage in this file */ +		pr_err("%s: didn't find device id. 0x%x in devices list\n", +			PCAN_USB_DRIVER_NAME, usb_dev->descriptor.idProduct); +		return -ENODEV; +	} + +	/* got corresponding adapter: check if it handles current interface */ +	if (peak_usb_adapter->intf_probe) { +		err = peak_usb_adapter->intf_probe(intf); +		if (err) +			return err; +	} + +	for (i = 0; i < peak_usb_adapter->ctrl_count; i++) { +		err = peak_usb_create_dev(peak_usb_adapter, intf, i); +		if (err) { +			/* deregister already created devices */ +			peak_usb_disconnect(intf); +			break; +		} +	} + +	return err; +} + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver peak_usb_driver = { +	.name = PCAN_USB_DRIVER_NAME, +	.disconnect = peak_usb_disconnect, +	.probe = peak_usb_probe, +	.id_table = peak_usb_table, +}; + +static int __init peak_usb_init(void) +{ +	int err; + +	/* register this driver with the USB subsystem */ +	err = usb_register(&peak_usb_driver); +	if (err) +		pr_err("%s: usb_register failed (err %d)\n", +			PCAN_USB_DRIVER_NAME, err); + +	return err; +} + +static int peak_usb_do_device_exit(struct device *d, void *arg) +{ +	struct usb_interface *intf = to_usb_interface(d); +	struct peak_usb_device *dev; + +	/* stop as many netdev devices as siblings */ +	for (dev = usb_get_intfdata(intf); dev; dev = dev->prev_siblings) { +		struct net_device *netdev = dev->netdev; + +		if (netif_device_present(netdev)) +			if (dev->adapter->dev_exit) +				dev->adapter->dev_exit(dev); +	} + +	return 0; +} + +static void __exit peak_usb_exit(void) +{ +	int err; + +	/* last chance do send any synchronous commands here */ +	err = driver_for_each_device(&peak_usb_driver.drvwrap.driver, NULL, +				     NULL, peak_usb_do_device_exit); +	if (err) +		pr_err("%s: failed to stop all can devices (err %d)\n", +			PCAN_USB_DRIVER_NAME, err); + +	/* deregister this driver with the USB subsystem */ +	usb_deregister(&peak_usb_driver); + +	pr_info("%s: PCAN-USB interfaces driver unloaded\n", +		PCAN_USB_DRIVER_NAME); +} + +module_init(peak_usb_init); +module_exit(peak_usb_exit); diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h new file mode 100644 index 00000000000..073b47ff8ee --- /dev/null +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h @@ -0,0 +1,145 @@ +/* + * CAN driver for PEAK System USB adapters + * Derived from the PCAN project file driver/src/pcan_usb_core.c + * + * Copyright (C) 2003-2010 PEAK System-Technik GmbH + * Copyright (C) 2010-2012 Stephane Grosjean <s.grosjean@peak-system.com> + * + * Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef PCAN_USB_CORE_H +#define PCAN_USB_CORE_H + +/* PEAK-System vendor id. */ +#define PCAN_USB_VENDOR_ID		0x0c72 + +/* supported device ids. */ +#define PCAN_USB_PRODUCT_ID		0x000c +#define PCAN_USBPRO_PRODUCT_ID		0x000d + +#define PCAN_USB_DRIVER_NAME		"peak_usb" + +/* number of urbs that are submitted for rx/tx per channel */ +#define PCAN_USB_MAX_RX_URBS		4 +#define PCAN_USB_MAX_TX_URBS		10 + +/* usb adapters maximum channels per usb interface */ +#define PCAN_USB_MAX_CHANNEL		2 + +/* maximum length of the usb commands sent to/received from  the devices */ +#define PCAN_USB_MAX_CMD_LEN		32 + +struct peak_usb_device; + +/* PEAK-System USB adapter descriptor */ +struct peak_usb_adapter { +	char *name; +	u32 device_id; +	struct can_clock clock; +	const struct can_bittiming_const bittiming_const; +	unsigned int ctrl_count; + +	int (*intf_probe)(struct usb_interface *intf); + +	int (*dev_init)(struct peak_usb_device *dev); +	void (*dev_exit)(struct peak_usb_device *dev); +	void (*dev_free)(struct peak_usb_device *dev); +	int (*dev_open)(struct peak_usb_device *dev); +	int (*dev_close)(struct peak_usb_device *dev); +	int (*dev_set_bittiming)(struct peak_usb_device *dev, +					struct can_bittiming *bt); +	int (*dev_set_bus)(struct peak_usb_device *dev, u8 onoff); +	int (*dev_get_device_id)(struct peak_usb_device *dev, u32 *device_id); +	int (*dev_decode_buf)(struct peak_usb_device *dev, struct urb *urb); +	int (*dev_encode_msg)(struct peak_usb_device *dev, struct sk_buff *skb, +					u8 *obuf, size_t *size); +	int (*dev_start)(struct peak_usb_device *dev); +	int (*dev_stop)(struct peak_usb_device *dev); +	int (*dev_restart_async)(struct peak_usb_device *dev, struct urb *urb, +					u8 *buf); +	u8 ep_msg_in; +	u8 ep_msg_out[PCAN_USB_MAX_CHANNEL]; +	u8 ts_used_bits; +	u32 ts_period; +	u8 us_per_ts_shift; +	u32 us_per_ts_scale; + +	int rx_buffer_size; +	int tx_buffer_size; +	int sizeof_dev_private; +}; + +extern struct peak_usb_adapter pcan_usb; +extern struct peak_usb_adapter pcan_usb_pro; + +struct peak_time_ref { +	struct timeval tv_host_0, tv_host; +	u32 ts_dev_1, ts_dev_2; +	u64 ts_total; +	u32 tick_count; +	struct peak_usb_adapter *adapter; +}; + +struct peak_tx_urb_context { +	struct peak_usb_device *dev; +	u32 echo_index; +	u8 dlc; +	struct urb *urb; +}; + +#define PCAN_USB_STATE_CONNECTED	0x00000001 +#define PCAN_USB_STATE_STARTED		0x00000002 + +/* PEAK-System USB device */ +struct peak_usb_device { +	struct can_priv can; +	struct peak_usb_adapter *adapter; +	unsigned int ctrl_idx; +	u32 state; + +	struct sk_buff *echo_skb[PCAN_USB_MAX_TX_URBS]; + +	struct usb_device *udev; +	struct net_device *netdev; + +	atomic_t active_tx_urbs; +	struct usb_anchor tx_submitted; +	struct peak_tx_urb_context tx_contexts[PCAN_USB_MAX_TX_URBS]; + +	u8 *cmd_buf; +	struct usb_anchor rx_submitted; + +	u32 device_number; +	u8 device_rev; + +	u8 ep_msg_in; +	u8 ep_msg_out; + +	u16 bus_load; + +	struct peak_usb_device *prev_siblings; +	struct peak_usb_device *next_siblings; +}; + +void pcan_dump_mem(char *prompt, void *p, int l); + +/* common timestamp management */ +void peak_usb_init_time_ref(struct peak_time_ref *time_ref, +			    struct peak_usb_adapter *adapter); +void peak_usb_update_ts_now(struct peak_time_ref *time_ref, u32 ts_now); +void peak_usb_set_ts_now(struct peak_time_ref *time_ref, u32 ts_now); +void peak_usb_get_ts_tv(struct peak_time_ref *time_ref, u32 ts, +			struct timeval *tv); + +void peak_usb_async_complete(struct urb *urb); +void peak_usb_restart_complete(struct peak_usb_device *dev); +#endif diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c new file mode 100644 index 00000000000..263dd921edc --- /dev/null +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -0,0 +1,1064 @@ +/* + * CAN driver for PEAK System PCAN-USB Pro adapter + * Derived from the PCAN project file driver/src/pcan_usbpro.c + * + * Copyright (C) 2003-2011 PEAK System-Technik GmbH + * Copyright (C) 2011-2012 Stephane Grosjean <s.grosjean@peak-system.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#include <linux/netdevice.h> +#include <linux/usb.h> +#include <linux/module.h> + +#include <linux/can.h> +#include <linux/can/dev.h> +#include <linux/can/error.h> + +#include "pcan_usb_core.h" +#include "pcan_usb_pro.h" + +MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB Pro adapter"); + +/* PCAN-USB Pro Endpoints */ +#define PCAN_USBPRO_EP_CMDOUT		1 +#define PCAN_USBPRO_EP_CMDIN		(PCAN_USBPRO_EP_CMDOUT | USB_DIR_IN) +#define PCAN_USBPRO_EP_MSGOUT_0		2 +#define PCAN_USBPRO_EP_MSGIN		(PCAN_USBPRO_EP_MSGOUT_0 | USB_DIR_IN) +#define PCAN_USBPRO_EP_MSGOUT_1		3 +#define PCAN_USBPRO_EP_UNUSED		(PCAN_USBPRO_EP_MSGOUT_1 | USB_DIR_IN) + +#define PCAN_USBPRO_CHANNEL_COUNT	2 + +/* PCAN-USB Pro adapter internal clock (MHz) */ +#define PCAN_USBPRO_CRYSTAL_HZ		56000000 + +/* PCAN-USB Pro command timeout (ms.) */ +#define PCAN_USBPRO_COMMAND_TIMEOUT	1000 + +/* PCAN-USB Pro rx/tx buffers size */ +#define PCAN_USBPRO_RX_BUFFER_SIZE	1024 +#define PCAN_USBPRO_TX_BUFFER_SIZE	64 + +#define PCAN_USBPRO_MSG_HEADER_LEN	4 + +/* some commands responses need to be re-submitted */ +#define PCAN_USBPRO_RSP_SUBMIT_MAX	2 + +#define PCAN_USBPRO_RTR			0x01 +#define PCAN_USBPRO_EXT			0x02 + +#define PCAN_USBPRO_CMD_BUFFER_SIZE	512 + +/* handle device specific info used by the netdevices */ +struct pcan_usb_pro_interface { +	struct peak_usb_device *dev[PCAN_USBPRO_CHANNEL_COUNT]; +	struct peak_time_ref time_ref; +	int cm_ignore_count; +	int dev_opened_count; +}; + +/* device information */ +struct pcan_usb_pro_device { +	struct peak_usb_device dev; +	struct pcan_usb_pro_interface *usb_if; +	u32 cached_ccbt; +}; + +/* internal structure used to handle messages sent to bulk urb */ +struct pcan_usb_pro_msg { +	u8 *rec_ptr; +	int rec_buffer_size; +	int rec_buffer_len; +	union { +		u16 *rec_cnt_rd; +		u32 *rec_cnt; +		u8 *rec_buffer; +	} u; +}; + +/* records sizes table indexed on message id. (8-bits value) */ +static u16 pcan_usb_pro_sizeof_rec[256] = { +	[PCAN_USBPRO_SETBTR] = sizeof(struct pcan_usb_pro_btr), +	[PCAN_USBPRO_SETBUSACT] = sizeof(struct pcan_usb_pro_busact), +	[PCAN_USBPRO_SETSILENT] = sizeof(struct pcan_usb_pro_silent), +	[PCAN_USBPRO_SETFILTR] = sizeof(struct pcan_usb_pro_filter), +	[PCAN_USBPRO_SETTS] = sizeof(struct pcan_usb_pro_setts), +	[PCAN_USBPRO_GETDEVID] = sizeof(struct pcan_usb_pro_devid), +	[PCAN_USBPRO_SETLED] = sizeof(struct pcan_usb_pro_setled), +	[PCAN_USBPRO_RXMSG8] = sizeof(struct pcan_usb_pro_rxmsg), +	[PCAN_USBPRO_RXMSG4] = sizeof(struct pcan_usb_pro_rxmsg) - 4, +	[PCAN_USBPRO_RXMSG0] = sizeof(struct pcan_usb_pro_rxmsg) - 8, +	[PCAN_USBPRO_RXRTR] = sizeof(struct pcan_usb_pro_rxmsg) - 8, +	[PCAN_USBPRO_RXSTATUS] = sizeof(struct pcan_usb_pro_rxstatus), +	[PCAN_USBPRO_RXTS] = sizeof(struct pcan_usb_pro_rxts), +	[PCAN_USBPRO_TXMSG8] = sizeof(struct pcan_usb_pro_txmsg), +	[PCAN_USBPRO_TXMSG4] = sizeof(struct pcan_usb_pro_txmsg) - 4, +	[PCAN_USBPRO_TXMSG0] = sizeof(struct pcan_usb_pro_txmsg) - 8, +}; + +/* + * initialize PCAN-USB Pro message data structure + */ +static u8 *pcan_msg_init(struct pcan_usb_pro_msg *pm, void *buffer_addr, +			 int buffer_size) +{ +	if (buffer_size < PCAN_USBPRO_MSG_HEADER_LEN) +		return NULL; + +	pm->u.rec_buffer = (u8 *)buffer_addr; +	pm->rec_buffer_size = pm->rec_buffer_len = buffer_size; +	pm->rec_ptr = pm->u.rec_buffer + PCAN_USBPRO_MSG_HEADER_LEN; + +	return pm->rec_ptr; +} + +static u8 *pcan_msg_init_empty(struct pcan_usb_pro_msg *pm, +			       void *buffer_addr, int buffer_size) +{ +	u8 *pr = pcan_msg_init(pm, buffer_addr, buffer_size); + +	if (pr) { +		pm->rec_buffer_len = PCAN_USBPRO_MSG_HEADER_LEN; +		*pm->u.rec_cnt = 0; +	} +	return pr; +} + +/* + * add one record to a message being built + */ +static int pcan_msg_add_rec(struct pcan_usb_pro_msg *pm, u8 id, ...) +{ +	int len, i; +	u8 *pc; +	va_list ap; + +	va_start(ap, id); + +	pc = pm->rec_ptr + 1; + +	i = 0; +	switch (id) { +	case PCAN_USBPRO_TXMSG8: +		i += 4; +	case PCAN_USBPRO_TXMSG4: +		i += 4; +	case PCAN_USBPRO_TXMSG0: +		*pc++ = va_arg(ap, int); +		*pc++ = va_arg(ap, int); +		*pc++ = va_arg(ap, int); +		*(u32 *)pc = cpu_to_le32(va_arg(ap, u32)); +		pc += 4; +		memcpy(pc, va_arg(ap, int *), i); +		pc += i; +		break; + +	case PCAN_USBPRO_SETBTR: +	case PCAN_USBPRO_GETDEVID: +		*pc++ = va_arg(ap, int); +		pc += 2; +		*(u32 *)pc = cpu_to_le32(va_arg(ap, u32)); +		pc += 4; +		break; + +	case PCAN_USBPRO_SETFILTR: +	case PCAN_USBPRO_SETBUSACT: +	case PCAN_USBPRO_SETSILENT: +		*pc++ = va_arg(ap, int); +		*(u16 *)pc = cpu_to_le16(va_arg(ap, int)); +		pc += 2; +		break; + +	case PCAN_USBPRO_SETLED: +		*pc++ = va_arg(ap, int); +		*(u16 *)pc = cpu_to_le16(va_arg(ap, int)); +		pc += 2; +		*(u32 *)pc = cpu_to_le32(va_arg(ap, u32)); +		pc += 4; +		break; + +	case PCAN_USBPRO_SETTS: +		pc++; +		*(u16 *)pc = cpu_to_le16(va_arg(ap, int)); +		pc += 2; +		break; + +	default: +		pr_err("%s: %s(): unknown data type %02Xh (%d)\n", +			PCAN_USB_DRIVER_NAME, __func__, id, id); +		pc--; +		break; +	} + +	len = pc - pm->rec_ptr; +	if (len > 0) { +		*pm->u.rec_cnt = cpu_to_le32(*pm->u.rec_cnt+1); +		*pm->rec_ptr = id; + +		pm->rec_ptr = pc; +		pm->rec_buffer_len += len; +	} + +	va_end(ap); + +	return len; +} + +/* + * send PCAN-USB Pro command synchronously + */ +static int pcan_usb_pro_send_cmd(struct peak_usb_device *dev, +				 struct pcan_usb_pro_msg *pum) +{ +	int actual_length; +	int err; + +	/* usb device unregistered? */ +	if (!(dev->state & PCAN_USB_STATE_CONNECTED)) +		return 0; + +	err = usb_bulk_msg(dev->udev, +		usb_sndbulkpipe(dev->udev, PCAN_USBPRO_EP_CMDOUT), +		pum->u.rec_buffer, pum->rec_buffer_len, +		&actual_length, PCAN_USBPRO_COMMAND_TIMEOUT); +	if (err) +		netdev_err(dev->netdev, "sending command failure: %d\n", err); + +	return err; +} + +/* + * wait for PCAN-USB Pro command response + */ +static int pcan_usb_pro_wait_rsp(struct peak_usb_device *dev, +				 struct pcan_usb_pro_msg *pum) +{ +	u8 req_data_type, req_channel; +	int actual_length; +	int i, err = 0; + +	/* usb device unregistered? */ +	if (!(dev->state & PCAN_USB_STATE_CONNECTED)) +		return 0; + +	req_data_type = pum->u.rec_buffer[4]; +	req_channel = pum->u.rec_buffer[5]; + +	*pum->u.rec_cnt = 0; +	for (i = 0; !err && i < PCAN_USBPRO_RSP_SUBMIT_MAX; i++) { +		struct pcan_usb_pro_msg rsp; +		union pcan_usb_pro_rec *pr; +		u32 r, rec_cnt; +		u16 rec_len; +		u8 *pc; + +		err = usb_bulk_msg(dev->udev, +			usb_rcvbulkpipe(dev->udev, PCAN_USBPRO_EP_CMDIN), +			pum->u.rec_buffer, pum->rec_buffer_len, +			&actual_length, PCAN_USBPRO_COMMAND_TIMEOUT); +		if (err) { +			netdev_err(dev->netdev, "waiting rsp error %d\n", err); +			break; +		} + +		if (actual_length == 0) +			continue; + +		err = -EBADMSG; +		if (actual_length < PCAN_USBPRO_MSG_HEADER_LEN) { +			netdev_err(dev->netdev, +				   "got abnormal too small rsp (len=%d)\n", +				   actual_length); +			break; +		} + +		pc = pcan_msg_init(&rsp, pum->u.rec_buffer, +			actual_length); + +		rec_cnt = le32_to_cpu(*rsp.u.rec_cnt); + +		/* loop on records stored into message */ +		for (r = 0; r < rec_cnt; r++) { +			pr = (union pcan_usb_pro_rec *)pc; +			rec_len = pcan_usb_pro_sizeof_rec[pr->data_type]; +			if (!rec_len) { +				netdev_err(dev->netdev, +					   "got unprocessed record in msg\n"); +				pcan_dump_mem("rcvd rsp msg", pum->u.rec_buffer, +					      actual_length); +				break; +			} + +			/* check if response corresponds to request */ +			if (pr->data_type != req_data_type) +				netdev_err(dev->netdev, +					   "got unwanted rsp %xh: ignored\n", +					   pr->data_type); + +			/* check if channel in response corresponds too */ +			else if ((req_channel != 0xff) && \ +				(pr->bus_act.channel != req_channel)) +				netdev_err(dev->netdev, +					"got rsp %xh but on chan%u: ignored\n", +					req_data_type, pr->bus_act.channel); + +			/* got the response */ +			else +				return 0; + +			/* otherwise, go on with next record in message */ +			pc += rec_len; +		} +	} + +	return (i >= PCAN_USBPRO_RSP_SUBMIT_MAX) ? -ERANGE : err; +} + +static int pcan_usb_pro_send_req(struct peak_usb_device *dev, int req_id, +				 int req_value, void *req_addr, int req_size) +{ +	int err; +	u8 req_type; +	unsigned int p; + +	/* usb device unregistered? */ +	if (!(dev->state & PCAN_USB_STATE_CONNECTED)) +		return 0; + +	memset(req_addr, '\0', req_size); + +	req_type = USB_TYPE_VENDOR | USB_RECIP_OTHER; + +	switch (req_id) { +	case PCAN_USBPRO_REQ_FCT: +		p = usb_sndctrlpipe(dev->udev, 0); +		break; + +	default: +		p = usb_rcvctrlpipe(dev->udev, 0); +		req_type |= USB_DIR_IN; +		break; +	} + +	err = usb_control_msg(dev->udev, p, req_id, req_type, req_value, 0, +			      req_addr, req_size, 2 * USB_CTRL_GET_TIMEOUT); +	if (err < 0) { +		netdev_info(dev->netdev, +			    "unable to request usb[type=%d value=%d] err=%d\n", +			    req_id, req_value, err); +		return err; +	} + +	return 0; +} + +static int pcan_usb_pro_set_ts(struct peak_usb_device *dev, u16 onoff) +{ +	struct pcan_usb_pro_msg um; + +	pcan_msg_init_empty(&um, dev->cmd_buf, PCAN_USB_MAX_CMD_LEN); +	pcan_msg_add_rec(&um, PCAN_USBPRO_SETTS, onoff); + +	return pcan_usb_pro_send_cmd(dev, &um); +} + +static int pcan_usb_pro_set_bitrate(struct peak_usb_device *dev, u32 ccbt) +{ +	struct pcan_usb_pro_device *pdev = +			container_of(dev, struct pcan_usb_pro_device, dev); +	struct pcan_usb_pro_msg um; + +	pcan_msg_init_empty(&um, dev->cmd_buf, PCAN_USB_MAX_CMD_LEN); +	pcan_msg_add_rec(&um, PCAN_USBPRO_SETBTR, dev->ctrl_idx, ccbt); + +	/* cache the CCBT value to reuse it before next buson */ +	pdev->cached_ccbt = ccbt; + +	return pcan_usb_pro_send_cmd(dev, &um); +} + +static int pcan_usb_pro_set_bus(struct peak_usb_device *dev, u8 onoff) +{ +	struct pcan_usb_pro_msg um; + +	/* if bus=on, be sure the bitrate being set before! */ +	if (onoff) { +		struct pcan_usb_pro_device *pdev = +			     container_of(dev, struct pcan_usb_pro_device, dev); + +		pcan_usb_pro_set_bitrate(dev, pdev->cached_ccbt); +	} + +	pcan_msg_init_empty(&um, dev->cmd_buf, PCAN_USB_MAX_CMD_LEN); +	pcan_msg_add_rec(&um, PCAN_USBPRO_SETBUSACT, dev->ctrl_idx, onoff); + +	return pcan_usb_pro_send_cmd(dev, &um); +} + +static int pcan_usb_pro_set_silent(struct peak_usb_device *dev, u8 onoff) +{ +	struct pcan_usb_pro_msg um; + +	pcan_msg_init_empty(&um, dev->cmd_buf, PCAN_USB_MAX_CMD_LEN); +	pcan_msg_add_rec(&um, PCAN_USBPRO_SETSILENT, dev->ctrl_idx, onoff); + +	return pcan_usb_pro_send_cmd(dev, &um); +} + +static int pcan_usb_pro_set_filter(struct peak_usb_device *dev, u16 filter_mode) +{ +	struct pcan_usb_pro_msg um; + +	pcan_msg_init_empty(&um, dev->cmd_buf, PCAN_USB_MAX_CMD_LEN); +	pcan_msg_add_rec(&um, PCAN_USBPRO_SETFILTR, dev->ctrl_idx, filter_mode); + +	return pcan_usb_pro_send_cmd(dev, &um); +} + +static int pcan_usb_pro_set_led(struct peak_usb_device *dev, u8 mode, +				u32 timeout) +{ +	struct pcan_usb_pro_msg um; + +	pcan_msg_init_empty(&um, dev->cmd_buf, PCAN_USB_MAX_CMD_LEN); +	pcan_msg_add_rec(&um, PCAN_USBPRO_SETLED, dev->ctrl_idx, mode, timeout); + +	return pcan_usb_pro_send_cmd(dev, &um); +} + +static int pcan_usb_pro_get_device_id(struct peak_usb_device *dev, +				      u32 *device_id) +{ +	struct pcan_usb_pro_devid *pdn; +	struct pcan_usb_pro_msg um; +	int err; +	u8 *pc; + +	pc = pcan_msg_init_empty(&um, dev->cmd_buf, PCAN_USB_MAX_CMD_LEN); +	pcan_msg_add_rec(&um, PCAN_USBPRO_GETDEVID, dev->ctrl_idx); + +	err =  pcan_usb_pro_send_cmd(dev, &um); +	if (err) +		return err; + +	err = pcan_usb_pro_wait_rsp(dev, &um); +	if (err) +		return err; + +	pdn = (struct pcan_usb_pro_devid *)pc; +	if (device_id) +		*device_id = le32_to_cpu(pdn->serial_num); + +	return err; +} + +static int pcan_usb_pro_set_bittiming(struct peak_usb_device *dev, +				      struct can_bittiming *bt) +{ +	u32 ccbt; + +	ccbt = (dev->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) ? 0x00800000 : 0; +	ccbt |= (bt->sjw - 1) << 24; +	ccbt |= (bt->phase_seg2 - 1) << 20; +	ccbt |= (bt->prop_seg + bt->phase_seg1 - 1) << 16; /* = tseg1 */ +	ccbt |= bt->brp - 1; + +	netdev_info(dev->netdev, "setting ccbt=0x%08x\n", ccbt); + +	return pcan_usb_pro_set_bitrate(dev, ccbt); +} + +static void pcan_usb_pro_restart_complete(struct urb *urb) +{ +	/* can delete usb resources */ +	peak_usb_async_complete(urb); + +	/* notify candev and netdev */ +	peak_usb_restart_complete(urb->context); +} + +/* + * handle restart but in asynchronously way + */ +static int pcan_usb_pro_restart_async(struct peak_usb_device *dev, +				      struct urb *urb, u8 *buf) +{ +	struct pcan_usb_pro_msg um; + +	pcan_msg_init_empty(&um, buf, PCAN_USB_MAX_CMD_LEN); +	pcan_msg_add_rec(&um, PCAN_USBPRO_SETBUSACT, dev->ctrl_idx, 1); + +	usb_fill_bulk_urb(urb, dev->udev, +			usb_sndbulkpipe(dev->udev, PCAN_USBPRO_EP_CMDOUT), +			buf, PCAN_USB_MAX_CMD_LEN, +			pcan_usb_pro_restart_complete, dev); + +	return usb_submit_urb(urb, GFP_ATOMIC); +} + +static int pcan_usb_pro_drv_loaded(struct peak_usb_device *dev, int loaded) +{ +	u8 *buffer; +	int err; + +	buffer = kmalloc(PCAN_USBPRO_FCT_DRVLD_REQ_LEN, GFP_KERNEL); +	if (!buffer) +		return -ENOMEM; + +	buffer[0] = 0; +	buffer[1] = !!loaded; + +	err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_FCT, +				    PCAN_USBPRO_FCT_DRVLD, buffer, +				    PCAN_USBPRO_FCT_DRVLD_REQ_LEN); +	kfree(buffer); + +	return err; +} + +static inline +struct pcan_usb_pro_interface *pcan_usb_pro_dev_if(struct peak_usb_device *dev) +{ +	struct pcan_usb_pro_device *pdev = +			container_of(dev, struct pcan_usb_pro_device, dev); +	return pdev->usb_if; +} + +static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if, +				      struct pcan_usb_pro_rxmsg *rx) +{ +	const unsigned int ctrl_idx = (rx->len >> 4) & 0x0f; +	struct peak_usb_device *dev = usb_if->dev[ctrl_idx]; +	struct net_device *netdev = dev->netdev; +	struct can_frame *can_frame; +	struct sk_buff *skb; +	struct timeval tv; +	struct skb_shared_hwtstamps *hwts; + +	skb = alloc_can_skb(netdev, &can_frame); +	if (!skb) +		return -ENOMEM; + +	can_frame->can_id = le32_to_cpu(rx->id); +	can_frame->can_dlc = rx->len & 0x0f; + +	if (rx->flags & PCAN_USBPRO_EXT) +		can_frame->can_id |= CAN_EFF_FLAG; + +	if (rx->flags & PCAN_USBPRO_RTR) +		can_frame->can_id |= CAN_RTR_FLAG; +	else +		memcpy(can_frame->data, rx->data, can_frame->can_dlc); + +	peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(rx->ts32), &tv); +	hwts = skb_hwtstamps(skb); +	hwts->hwtstamp = timeval_to_ktime(tv); + +	netif_rx(skb); +	netdev->stats.rx_packets++; +	netdev->stats.rx_bytes += can_frame->can_dlc; + +	return 0; +} + +static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if, +				     struct pcan_usb_pro_rxstatus *er) +{ +	const u32 raw_status = le32_to_cpu(er->status); +	const unsigned int ctrl_idx = (er->channel >> 4) & 0x0f; +	struct peak_usb_device *dev = usb_if->dev[ctrl_idx]; +	struct net_device *netdev = dev->netdev; +	struct can_frame *can_frame; +	enum can_state new_state = CAN_STATE_ERROR_ACTIVE; +	u8 err_mask = 0; +	struct sk_buff *skb; +	struct timeval tv; +	struct skb_shared_hwtstamps *hwts; + +	/* nothing should be sent while in BUS_OFF state */ +	if (dev->can.state == CAN_STATE_BUS_OFF) +		return 0; + +	if (!raw_status) { +		/* no error bit (back to active state) */ +		dev->can.state = CAN_STATE_ERROR_ACTIVE; +		return 0; +	} + +	if (raw_status & (PCAN_USBPRO_STATUS_OVERRUN | +			  PCAN_USBPRO_STATUS_QOVERRUN)) { +		/* trick to bypass next comparison and process other errors */ +		new_state = CAN_STATE_MAX; +	} + +	if (raw_status & PCAN_USBPRO_STATUS_BUS) { +		new_state = CAN_STATE_BUS_OFF; +	} else if (raw_status & PCAN_USBPRO_STATUS_ERROR) { +		u32 rx_err_cnt = (le32_to_cpu(er->err_frm) & 0x00ff0000) >> 16; +		u32 tx_err_cnt = (le32_to_cpu(er->err_frm) & 0xff000000) >> 24; + +		if (rx_err_cnt > 127) +			err_mask |= CAN_ERR_CRTL_RX_PASSIVE; +		else if (rx_err_cnt > 96) +			err_mask |= CAN_ERR_CRTL_RX_WARNING; + +		if (tx_err_cnt > 127) +			err_mask |= CAN_ERR_CRTL_TX_PASSIVE; +		else if (tx_err_cnt > 96) +			err_mask |= CAN_ERR_CRTL_TX_WARNING; + +		if (err_mask & (CAN_ERR_CRTL_RX_WARNING | +				CAN_ERR_CRTL_TX_WARNING)) +			new_state = CAN_STATE_ERROR_WARNING; +		else if (err_mask & (CAN_ERR_CRTL_RX_PASSIVE | +				     CAN_ERR_CRTL_TX_PASSIVE)) +			new_state = CAN_STATE_ERROR_PASSIVE; +	} + +	/* donot post any error if current state didn't change */ +	if (dev->can.state == new_state) +		return 0; + +	/* allocate an skb to store the error frame */ +	skb = alloc_can_err_skb(netdev, &can_frame); +	if (!skb) +		return -ENOMEM; + +	switch (new_state) { +	case CAN_STATE_BUS_OFF: +		can_frame->can_id |= CAN_ERR_BUSOFF; +		can_bus_off(netdev); +		break; + +	case CAN_STATE_ERROR_PASSIVE: +		can_frame->can_id |= CAN_ERR_CRTL; +		can_frame->data[1] |= err_mask; +		dev->can.can_stats.error_passive++; +		break; + +	case CAN_STATE_ERROR_WARNING: +		can_frame->can_id |= CAN_ERR_CRTL; +		can_frame->data[1] |= err_mask; +		dev->can.can_stats.error_warning++; +		break; + +	case CAN_STATE_ERROR_ACTIVE: +		break; + +	default: +		/* CAN_STATE_MAX (trick to handle other errors) */ +		if (raw_status & PCAN_USBPRO_STATUS_OVERRUN) { +			can_frame->can_id |= CAN_ERR_PROT; +			can_frame->data[2] |= CAN_ERR_PROT_OVERLOAD; +			netdev->stats.rx_over_errors++; +			netdev->stats.rx_errors++; +		} + +		if (raw_status & PCAN_USBPRO_STATUS_QOVERRUN) { +			can_frame->can_id |= CAN_ERR_CRTL; +			can_frame->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; +			netdev->stats.rx_over_errors++; +			netdev->stats.rx_errors++; +		} + +		new_state = CAN_STATE_ERROR_ACTIVE; +		break; +	} + +	dev->can.state = new_state; + +	peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(er->ts32), &tv); +	hwts = skb_hwtstamps(skb); +	hwts->hwtstamp = timeval_to_ktime(tv); +	netif_rx(skb); +	netdev->stats.rx_packets++; +	netdev->stats.rx_bytes += can_frame->can_dlc; + +	return 0; +} + +static void pcan_usb_pro_handle_ts(struct pcan_usb_pro_interface *usb_if, +				   struct pcan_usb_pro_rxts *ts) +{ +	/* should wait until clock is stabilized */ +	if (usb_if->cm_ignore_count > 0) +		usb_if->cm_ignore_count--; +	else +		peak_usb_set_ts_now(&usb_if->time_ref, +				    le32_to_cpu(ts->ts64[1])); +} + +/* + * callback for bulk IN urb + */ +static int pcan_usb_pro_decode_buf(struct peak_usb_device *dev, struct urb *urb) +{ +	struct pcan_usb_pro_interface *usb_if = pcan_usb_pro_dev_if(dev); +	struct net_device *netdev = dev->netdev; +	struct pcan_usb_pro_msg usb_msg; +	u8 *rec_ptr, *msg_end; +	u16 rec_cnt; +	int err = 0; + +	rec_ptr = pcan_msg_init(&usb_msg, urb->transfer_buffer, +					urb->actual_length); +	if (!rec_ptr) { +		netdev_err(netdev, "bad msg hdr len %d\n", urb->actual_length); +		return -EINVAL; +	} + +	/* loop reading all the records from the incoming message */ +	msg_end = urb->transfer_buffer + urb->actual_length; +	rec_cnt = le16_to_cpu(*usb_msg.u.rec_cnt_rd); +	for (; rec_cnt > 0; rec_cnt--) { +		union pcan_usb_pro_rec *pr = (union pcan_usb_pro_rec *)rec_ptr; +		u16 sizeof_rec = pcan_usb_pro_sizeof_rec[pr->data_type]; + +		if (!sizeof_rec) { +			netdev_err(netdev, +				   "got unsupported rec in usb msg:\n"); +			err = -ENOTSUPP; +			break; +		} + +		/* check if the record goes out of current packet */ +		if (rec_ptr + sizeof_rec > msg_end) { +			netdev_err(netdev, +				"got frag rec: should inc usb rx buf size\n"); +			err = -EBADMSG; +			break; +		} + +		switch (pr->data_type) { +		case PCAN_USBPRO_RXMSG8: +		case PCAN_USBPRO_RXMSG4: +		case PCAN_USBPRO_RXMSG0: +		case PCAN_USBPRO_RXRTR: +			err = pcan_usb_pro_handle_canmsg(usb_if, &pr->rx_msg); +			if (err < 0) +				goto fail; +			break; + +		case PCAN_USBPRO_RXSTATUS: +			err = pcan_usb_pro_handle_error(usb_if, &pr->rx_status); +			if (err < 0) +				goto fail; +			break; + +		case PCAN_USBPRO_RXTS: +			pcan_usb_pro_handle_ts(usb_if, &pr->rx_ts); +			break; + +		default: +			netdev_err(netdev, +				   "unhandled rec type 0x%02x (%d): ignored\n", +				   pr->data_type, pr->data_type); +			break; +		} + +		rec_ptr += sizeof_rec; +	} + +fail: +	if (err) +		pcan_dump_mem("received msg", +			      urb->transfer_buffer, urb->actual_length); + +	return err; +} + +static int pcan_usb_pro_encode_msg(struct peak_usb_device *dev, +				   struct sk_buff *skb, u8 *obuf, size_t *size) +{ +	struct can_frame *cf = (struct can_frame *)skb->data; +	u8 data_type, len, flags; +	struct pcan_usb_pro_msg usb_msg; + +	pcan_msg_init_empty(&usb_msg, obuf, *size); + +	if ((cf->can_id & CAN_RTR_FLAG) || (cf->can_dlc == 0)) +		data_type = PCAN_USBPRO_TXMSG0; +	else if (cf->can_dlc <= 4) +		data_type = PCAN_USBPRO_TXMSG4; +	else +		data_type = PCAN_USBPRO_TXMSG8; + +	len = (dev->ctrl_idx << 4) | (cf->can_dlc & 0x0f); + +	flags = 0; +	if (cf->can_id & CAN_EFF_FLAG) +		flags |= 0x02; +	if (cf->can_id & CAN_RTR_FLAG) +		flags |= 0x01; + +	pcan_msg_add_rec(&usb_msg, data_type, 0, flags, len, cf->can_id, +			 cf->data); + +	*size = usb_msg.rec_buffer_len; + +	return 0; +} + +static int pcan_usb_pro_start(struct peak_usb_device *dev) +{ +	struct pcan_usb_pro_device *pdev = +			container_of(dev, struct pcan_usb_pro_device, dev); +	int err; + +	err = pcan_usb_pro_set_silent(dev, +				dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY); +	if (err) +		return err; + +	/* filter mode: 0-> All OFF; 1->bypass */ +	err = pcan_usb_pro_set_filter(dev, 1); +	if (err) +		return err; + +	/* opening first device: */ +	if (pdev->usb_if->dev_opened_count == 0) { +		/* reset time_ref */ +		peak_usb_init_time_ref(&pdev->usb_if->time_ref, &pcan_usb_pro); + +		/* ask device to send ts messages */ +		err = pcan_usb_pro_set_ts(dev, 1); +	} + +	pdev->usb_if->dev_opened_count++; + +	return err; +} + +/* + * stop interface + * (last chance before set bus off) + */ +static int pcan_usb_pro_stop(struct peak_usb_device *dev) +{ +	struct pcan_usb_pro_device *pdev = +			container_of(dev, struct pcan_usb_pro_device, dev); + +	/* turn off ts msgs for that interface if no other dev opened */ +	if (pdev->usb_if->dev_opened_count == 1) +		pcan_usb_pro_set_ts(dev, 0); + +	pdev->usb_if->dev_opened_count--; + +	return 0; +} + +/* + * called when probing to initialize a device object. + */ +static int pcan_usb_pro_init(struct peak_usb_device *dev) +{ +	struct pcan_usb_pro_device *pdev = +			container_of(dev, struct pcan_usb_pro_device, dev); +	struct pcan_usb_pro_interface *usb_if = NULL; +	struct pcan_usb_pro_fwinfo *fi = NULL; +	struct pcan_usb_pro_blinfo *bi = NULL; +	int err; + +	/* do this for 1st channel only */ +	if (!dev->prev_siblings) { +		/* allocate netdevices common structure attached to first one */ +		usb_if = kzalloc(sizeof(struct pcan_usb_pro_interface), +				 GFP_KERNEL); +		fi = kmalloc(sizeof(struct pcan_usb_pro_fwinfo), GFP_KERNEL); +		bi = kmalloc(sizeof(struct pcan_usb_pro_blinfo), GFP_KERNEL); +		if (!usb_if || !fi || !bi) { +			err = -ENOMEM; +			goto err_out; +		} + +		/* number of ts msgs to ignore before taking one into account */ +		usb_if->cm_ignore_count = 5; + +		/* +		 * explicit use of dev_xxx() instead of netdev_xxx() here: +		 * information displayed are related to the device itself, not +		 * to the canx netdevices. +		 */ +		err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO, +					    PCAN_USBPRO_INFO_FW, +					    fi, sizeof(*fi)); +		if (err) { +			dev_err(dev->netdev->dev.parent, +				"unable to read %s firmware info (err %d)\n", +				pcan_usb_pro.name, err); +			goto err_out; +		} + +		err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO, +					    PCAN_USBPRO_INFO_BL, +					    bi, sizeof(*bi)); +		if (err) { +			dev_err(dev->netdev->dev.parent, +				"unable to read %s bootloader info (err %d)\n", +				pcan_usb_pro.name, err); +			goto err_out; +		} + +		/* tell the device the can driver is running */ +		err = pcan_usb_pro_drv_loaded(dev, 1); +		if (err) +			goto err_out; + +		dev_info(dev->netdev->dev.parent, +		     "PEAK-System %s hwrev %u serial %08X.%08X (%u channels)\n", +		     pcan_usb_pro.name, +		     bi->hw_rev, bi->serial_num_hi, bi->serial_num_lo, +		     pcan_usb_pro.ctrl_count); +	} else { +		usb_if = pcan_usb_pro_dev_if(dev->prev_siblings); +	} + +	pdev->usb_if = usb_if; +	usb_if->dev[dev->ctrl_idx] = dev; + +	/* set LED in default state (end of init phase) */ +	pcan_usb_pro_set_led(dev, 0, 1); + +	kfree(bi); +	kfree(fi); + +	return 0; + + err_out: +	kfree(bi); +	kfree(fi); +	kfree(usb_if); + +	return err; +} + +static void pcan_usb_pro_exit(struct peak_usb_device *dev) +{ +	struct pcan_usb_pro_device *pdev = +			container_of(dev, struct pcan_usb_pro_device, dev); + +	/* +	 * when rmmod called before unplug and if down, should reset things +	 * before leaving +	 */ +	if (dev->can.state != CAN_STATE_STOPPED) { +		/* set bus off on the corresponding channel */ +		pcan_usb_pro_set_bus(dev, 0); +	} + +	/* if channel #0 (only) */ +	if (dev->ctrl_idx == 0) { +		/* turn off calibration message if any device were opened */ +		if (pdev->usb_if->dev_opened_count > 0) +			pcan_usb_pro_set_ts(dev, 0); + +		/* tell the PCAN-USB Pro device the driver is being unloaded */ +		pcan_usb_pro_drv_loaded(dev, 0); +	} +} + +/* + * called when PCAN-USB Pro adapter is unplugged + */ +static void pcan_usb_pro_free(struct peak_usb_device *dev) +{ +	/* last device: can free pcan_usb_pro_interface object now */ +	if (!dev->prev_siblings && !dev->next_siblings) +		kfree(pcan_usb_pro_dev_if(dev)); +} + +/* + * probe function for new PCAN-USB Pro usb interface + */ +static int pcan_usb_pro_probe(struct usb_interface *intf) +{ +	struct usb_host_interface *if_desc; +	int i; + +	if_desc = intf->altsetting; + +	/* check interface endpoint addresses */ +	for (i = 0; i < if_desc->desc.bNumEndpoints; i++) { +		struct usb_endpoint_descriptor *ep = &if_desc->endpoint[i].desc; + +		/* +		 * below is the list of valid ep addreses. Any other ep address +		 * is considered as not-CAN interface address => no dev created +		 */ +		switch (ep->bEndpointAddress) { +		case PCAN_USBPRO_EP_CMDOUT: +		case PCAN_USBPRO_EP_CMDIN: +		case PCAN_USBPRO_EP_MSGOUT_0: +		case PCAN_USBPRO_EP_MSGOUT_1: +		case PCAN_USBPRO_EP_MSGIN: +		case PCAN_USBPRO_EP_UNUSED: +			break; +		default: +			return -ENODEV; +		} +	} + +	return 0; +} + +/* + * describe the PCAN-USB Pro adapter + */ +struct peak_usb_adapter pcan_usb_pro = { +	.name = "PCAN-USB Pro", +	.device_id = PCAN_USBPRO_PRODUCT_ID, +	.ctrl_count = PCAN_USBPRO_CHANNEL_COUNT, +	.clock = { +		.freq = PCAN_USBPRO_CRYSTAL_HZ, +	}, +	.bittiming_const = { +		.name = "pcan_usb_pro", +		.tseg1_min = 1, +		.tseg1_max = 16, +		.tseg2_min = 1, +		.tseg2_max = 8, +		.sjw_max = 4, +		.brp_min = 1, +		.brp_max = 1024, +		.brp_inc = 1, +	}, + +	/* size of device private data */ +	.sizeof_dev_private = sizeof(struct pcan_usb_pro_device), + +	/* timestamps usage */ +	.ts_used_bits = 32, +	.ts_period = 1000000, /* calibration period in ts. */ +	.us_per_ts_scale = 1, /* us = (ts * scale) >> shift */ +	.us_per_ts_shift = 0, + +	/* give here messages in/out endpoints */ +	.ep_msg_in = PCAN_USBPRO_EP_MSGIN, +	.ep_msg_out = {PCAN_USBPRO_EP_MSGOUT_0, PCAN_USBPRO_EP_MSGOUT_1}, + +	/* size of rx/tx usb buffers */ +	.rx_buffer_size = PCAN_USBPRO_RX_BUFFER_SIZE, +	.tx_buffer_size = PCAN_USBPRO_TX_BUFFER_SIZE, + +	/* device callbacks */ +	.intf_probe = pcan_usb_pro_probe, +	.dev_init = pcan_usb_pro_init, +	.dev_exit = pcan_usb_pro_exit, +	.dev_free = pcan_usb_pro_free, +	.dev_set_bus = pcan_usb_pro_set_bus, +	.dev_set_bittiming = pcan_usb_pro_set_bittiming, +	.dev_get_device_id = pcan_usb_pro_get_device_id, +	.dev_decode_buf = pcan_usb_pro_decode_buf, +	.dev_encode_msg = pcan_usb_pro_encode_msg, +	.dev_start = pcan_usb_pro_start, +	.dev_stop = pcan_usb_pro_stop, +	.dev_restart_async = pcan_usb_pro_restart_async, +}; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h new file mode 100644 index 00000000000..32275af547e --- /dev/null +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h @@ -0,0 +1,179 @@ +/* + * CAN driver for PEAK System PCAN-USB Pro adapter + * Derived from the PCAN project file driver/src/pcan_usbpro_fw.h + * + * Copyright (C) 2003-2011 PEAK System-Technik GmbH + * Copyright (C) 2011-2012 Stephane Grosjean <s.grosjean@peak-system.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef PCAN_USB_PRO_H +#define PCAN_USB_PRO_H + +/* + * USB Vendor request data types + */ +#define PCAN_USBPRO_REQ_INFO		0 +#define PCAN_USBPRO_REQ_FCT		2 + +/* Vendor Request value for XXX_INFO */ +#define PCAN_USBPRO_INFO_BL		0 +#define PCAN_USBPRO_INFO_FW		1 + +/* Vendor Request value for XXX_FCT */ +#define PCAN_USBPRO_FCT_DRVLD		5 /* tell device driver is loaded */ +#define PCAN_USBPRO_FCT_DRVLD_REQ_LEN	16 + +/* PCAN_USBPRO_INFO_BL vendor request record type */ +struct __packed pcan_usb_pro_blinfo { +	u32 ctrl_type; +	u8  version[4]; +	u8  day; +	u8  month; +	u8  year; +	u8  dummy; +	u32 serial_num_hi; +	u32 serial_num_lo; +	u32 hw_type; +	u32 hw_rev; +}; + +/* PCAN_USBPRO_INFO_FW vendor request record type */ +struct __packed pcan_usb_pro_fwinfo { +	u32 ctrl_type; +	u8  version[4]; +	u8  day; +	u8  month; +	u8  year; +	u8  dummy; +	u32 fw_type; +}; + +/* + * USB Command record types + */ +#define PCAN_USBPRO_SETBTR	0x02 +#define PCAN_USBPRO_SETBUSACT	0x04 +#define PCAN_USBPRO_SETSILENT	0x05 +#define PCAN_USBPRO_SETFILTR	0x0a +#define PCAN_USBPRO_SETTS	0x10 +#define PCAN_USBPRO_GETDEVID	0x12 +#define PCAN_USBPRO_SETLED	0x1C +#define PCAN_USBPRO_RXMSG8	0x80 +#define PCAN_USBPRO_RXMSG4	0x81 +#define PCAN_USBPRO_RXMSG0	0x82 +#define PCAN_USBPRO_RXRTR	0x83 +#define PCAN_USBPRO_RXSTATUS	0x84 +#define PCAN_USBPRO_RXTS	0x85 +#define PCAN_USBPRO_TXMSG8	0x41 +#define PCAN_USBPRO_TXMSG4	0x42 +#define PCAN_USBPRO_TXMSG0	0x43 + +/* record structures */ +struct __packed pcan_usb_pro_btr { +	u8  data_type; +	u8  channel; +	u16 dummy; +	u32 CCBT; +}; + +struct __packed pcan_usb_pro_busact { +	u8  data_type; +	u8  channel; +	u16 onoff; +}; + +struct __packed pcan_usb_pro_silent { +	u8  data_type; +	u8  channel; +	u16 onoff; +}; + +struct __packed pcan_usb_pro_filter { +	u8  data_type; +	u8  dummy; +	u16 filter_mode; +}; + +struct __packed pcan_usb_pro_setts { +	u8  data_type; +	u8  dummy; +	u16 mode; +}; + +struct __packed pcan_usb_pro_devid { +	u8  data_type; +	u8  channel; +	u16 dummy; +	u32 serial_num; +}; + +struct __packed pcan_usb_pro_setled { +	u8  data_type; +	u8  channel; +	u16 mode; +	u32 timeout; +}; + +struct __packed pcan_usb_pro_rxmsg { +	u8  data_type; +	u8  client; +	u8  flags; +	u8  len; +	u32 ts32; +	u32 id; + +	u8  data[8]; +}; + +#define PCAN_USBPRO_STATUS_ERROR	0x0001 +#define PCAN_USBPRO_STATUS_BUS		0x0002 +#define PCAN_USBPRO_STATUS_OVERRUN	0x0004 +#define PCAN_USBPRO_STATUS_QOVERRUN	0x0008 + +struct __packed pcan_usb_pro_rxstatus { +	u8  data_type; +	u8  channel; +	u16 status; +	u32 ts32; +	u32 err_frm; +}; + +struct __packed pcan_usb_pro_rxts { +	u8  data_type; +	u8  dummy[3]; +	u32 ts64[2]; +}; + +struct __packed pcan_usb_pro_txmsg { +	u8  data_type; +	u8  client; +	u8  flags; +	u8  len; +	u32 id; +	u8  data[8]; +}; + +union pcan_usb_pro_rec { +	u8				data_type; +	struct pcan_usb_pro_btr		btr; +	struct pcan_usb_pro_busact	bus_act; +	struct pcan_usb_pro_silent	silent_mode; +	struct pcan_usb_pro_filter	filter_mode; +	struct pcan_usb_pro_setts	ts; +	struct pcan_usb_pro_devid	dev_id; +	struct pcan_usb_pro_setled	set_led; +	struct pcan_usb_pro_rxmsg	rx_msg; +	struct pcan_usb_pro_rxstatus	rx_status; +	struct pcan_usb_pro_rxts	rx_ts; +	struct pcan_usb_pro_txmsg	tx_msg; +}; + +#endif diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c new file mode 100644 index 00000000000..ef674ecb82f --- /dev/null +++ b/drivers/net/can/usb/usb_8dev.c @@ -0,0 +1,1035 @@ +/* + * CAN driver for "8 devices" USB2CAN converter + * + * Copyright (C) 2012 Bernd Krumboeck (krumboeck@universalnet.at) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. + * + * This driver is inspired by the 3.2.0 version of drivers/net/can/usb/ems_usb.c + * and drivers/net/can/usb/esd_usb2.c + * + * Many thanks to Gerhard Bertelsmann (info@gerhard-bertelsmann.de) + * for testing and fixing this driver. Also many thanks to "8 devices", + * who were very cooperative and answered my questions. + */ + +#include <linux/signal.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/usb.h> + +#include <linux/can.h> +#include <linux/can/dev.h> +#include <linux/can/error.h> +#include <linux/can/led.h> + +/* driver constants */ +#define MAX_RX_URBS			20 +#define MAX_TX_URBS			20 +#define RX_BUFFER_SIZE			64 + +/* vendor and product id */ +#define USB_8DEV_VENDOR_ID		0x0483 +#define USB_8DEV_PRODUCT_ID		0x1234 + +/* endpoints */ +enum usb_8dev_endpoint { +	USB_8DEV_ENDP_DATA_RX = 1, +	USB_8DEV_ENDP_DATA_TX, +	USB_8DEV_ENDP_CMD_RX, +	USB_8DEV_ENDP_CMD_TX +}; + +/* device CAN clock */ +#define USB_8DEV_ABP_CLOCK		32000000 + +/* setup flags */ +#define USB_8DEV_SILENT			0x01 +#define USB_8DEV_LOOPBACK		0x02 +#define USB_8DEV_DISABLE_AUTO_RESTRANS	0x04 +#define USB_8DEV_STATUS_FRAME		0x08 + +/* commands */ +enum usb_8dev_cmd { +	USB_8DEV_RESET = 1, +	USB_8DEV_OPEN, +	USB_8DEV_CLOSE, +	USB_8DEV_SET_SPEED, +	USB_8DEV_SET_MASK_FILTER, +	USB_8DEV_GET_STATUS, +	USB_8DEV_GET_STATISTICS, +	USB_8DEV_GET_SERIAL, +	USB_8DEV_GET_SOFTW_VER, +	USB_8DEV_GET_HARDW_VER, +	USB_8DEV_RESET_TIMESTAMP, +	USB_8DEV_GET_SOFTW_HARDW_VER +}; + +/* command options */ +#define USB_8DEV_BAUD_MANUAL		0x09 +#define USB_8DEV_CMD_START		0x11 +#define USB_8DEV_CMD_END		0x22 + +#define USB_8DEV_CMD_SUCCESS		0 +#define USB_8DEV_CMD_ERROR		255 + +#define USB_8DEV_CMD_TIMEOUT		1000 + +/* frames */ +#define USB_8DEV_DATA_START		0x55 +#define USB_8DEV_DATA_END		0xAA + +#define USB_8DEV_TYPE_CAN_FRAME		0 +#define USB_8DEV_TYPE_ERROR_FRAME	3 + +#define USB_8DEV_EXTID			0x01 +#define USB_8DEV_RTR			0x02 +#define USB_8DEV_ERR_FLAG		0x04 + +/* status */ +#define USB_8DEV_STATUSMSG_OK		0x00  /* Normal condition. */ +#define USB_8DEV_STATUSMSG_OVERRUN	0x01  /* Overrun occured when sending */ +#define USB_8DEV_STATUSMSG_BUSLIGHT	0x02  /* Error counter has reached 96 */ +#define USB_8DEV_STATUSMSG_BUSHEAVY	0x03  /* Error count. has reached 128 */ +#define USB_8DEV_STATUSMSG_BUSOFF	0x04  /* Device is in BUSOFF */ +#define USB_8DEV_STATUSMSG_STUFF	0x20  /* Stuff Error */ +#define USB_8DEV_STATUSMSG_FORM		0x21  /* Form Error */ +#define USB_8DEV_STATUSMSG_ACK		0x23  /* Ack Error */ +#define USB_8DEV_STATUSMSG_BIT0		0x24  /* Bit1 Error */ +#define USB_8DEV_STATUSMSG_BIT1		0x25  /* Bit0 Error */ +#define USB_8DEV_STATUSMSG_CRC		0x27  /* CRC Error */ + +#define USB_8DEV_RP_MASK		0x7F  /* Mask for Receive Error Bit */ + + +/* table of devices that work with this driver */ +static const struct usb_device_id usb_8dev_table[] = { +	{ USB_DEVICE(USB_8DEV_VENDOR_ID, USB_8DEV_PRODUCT_ID) }, +	{ }					/* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, usb_8dev_table); + +struct usb_8dev_tx_urb_context { +	struct usb_8dev_priv *priv; + +	u32 echo_index; +	u8 dlc; +}; + +/* Structure to hold all of our device specific stuff */ +struct usb_8dev_priv { +	struct can_priv can; /* must be the first member */ + +	struct sk_buff *echo_skb[MAX_TX_URBS]; + +	struct usb_device *udev; +	struct net_device *netdev; + +	atomic_t active_tx_urbs; +	struct usb_anchor tx_submitted; +	struct usb_8dev_tx_urb_context tx_contexts[MAX_TX_URBS]; + +	struct usb_anchor rx_submitted; + +	struct can_berr_counter bec; + +	u8 *cmd_msg_buffer; + +	struct mutex usb_8dev_cmd_lock; + +}; + +/* tx frame */ +struct __packed usb_8dev_tx_msg { +	u8 begin; +	u8 flags;	/* RTR and EXT_ID flag */ +	__be32 id;	/* upper 3 bits not used */ +	u8 dlc;		/* data length code 0-8 bytes */ +	u8 data[8];	/* 64-bit data */ +	u8 end; +}; + +/* rx frame */ +struct __packed usb_8dev_rx_msg { +	u8 begin; +	u8 type;		/* frame type */ +	u8 flags;		/* RTR and EXT_ID flag */ +	__be32 id;		/* upper 3 bits not used */ +	u8 dlc;			/* data length code 0-8 bytes */ +	u8 data[8];		/* 64-bit data */ +	__be32 timestamp;	/* 32-bit timestamp */ +	u8 end; +}; + +/* command frame */ +struct __packed usb_8dev_cmd_msg { +	u8 begin; +	u8 channel;	/* unkown - always 0 */ +	u8 command;	/* command to execute */ +	u8 opt1;	/* optional parameter / return value */ +	u8 opt2;	/* optional parameter 2 */ +	u8 data[10];	/* optional parameter and data */ +	u8 end; +}; + +static int usb_8dev_send_cmd_msg(struct usb_8dev_priv *priv, u8 *msg, int size) +{ +	int actual_length; + +	return usb_bulk_msg(priv->udev, +			    usb_sndbulkpipe(priv->udev, USB_8DEV_ENDP_CMD_TX), +			    msg, size, &actual_length, USB_8DEV_CMD_TIMEOUT); +} + +static int usb_8dev_wait_cmd_msg(struct usb_8dev_priv *priv, u8 *msg, int size, +				int *actual_length) +{ +	return usb_bulk_msg(priv->udev, +			    usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_CMD_RX), +			    msg, size, actual_length, USB_8DEV_CMD_TIMEOUT); +} + +/* Send command to device and receive result. + * Command was successful when opt1 = 0. + */ +static int usb_8dev_send_cmd(struct usb_8dev_priv *priv, +			     struct usb_8dev_cmd_msg *out, +			     struct usb_8dev_cmd_msg *in) +{ +	int err; +	int num_bytes_read; +	struct net_device *netdev; + +	netdev = priv->netdev; + +	out->begin = USB_8DEV_CMD_START; +	out->end = USB_8DEV_CMD_END; + +	mutex_lock(&priv->usb_8dev_cmd_lock); + +	memcpy(priv->cmd_msg_buffer, out, +		sizeof(struct usb_8dev_cmd_msg)); + +	err = usb_8dev_send_cmd_msg(priv, priv->cmd_msg_buffer, +				    sizeof(struct usb_8dev_cmd_msg)); +	if (err < 0) { +		netdev_err(netdev, "sending command message failed\n"); +		goto failed; +	} + +	err = usb_8dev_wait_cmd_msg(priv, priv->cmd_msg_buffer, +				    sizeof(struct usb_8dev_cmd_msg), +				    &num_bytes_read); +	if (err < 0) { +		netdev_err(netdev, "no command message answer\n"); +		goto failed; +	} + +	memcpy(in, priv->cmd_msg_buffer, sizeof(struct usb_8dev_cmd_msg)); + +	if (in->begin != USB_8DEV_CMD_START || in->end != USB_8DEV_CMD_END || +			num_bytes_read != 16 || in->opt1 != 0) +		err = -EPROTO; + +failed: +	mutex_unlock(&priv->usb_8dev_cmd_lock); +	return err; +} + +/* Send open command to device */ +static int usb_8dev_cmd_open(struct usb_8dev_priv *priv) +{ +	struct can_bittiming *bt = &priv->can.bittiming; +	struct usb_8dev_cmd_msg outmsg; +	struct usb_8dev_cmd_msg inmsg; +	u32 ctrlmode = priv->can.ctrlmode; +	u32 flags = USB_8DEV_STATUS_FRAME; +	__be32 beflags; +	__be16 bebrp; + +	memset(&outmsg, 0, sizeof(outmsg)); +	outmsg.command = USB_8DEV_OPEN; +	outmsg.opt1 = USB_8DEV_BAUD_MANUAL; +	outmsg.data[0] = bt->prop_seg + bt->phase_seg1; +	outmsg.data[1] = bt->phase_seg2; +	outmsg.data[2] = bt->sjw; + +	/* BRP */ +	bebrp = cpu_to_be16((u16)bt->brp); +	memcpy(&outmsg.data[3], &bebrp, sizeof(bebrp)); + +	/* flags */ +	if (ctrlmode & CAN_CTRLMODE_LOOPBACK) +		flags |= USB_8DEV_LOOPBACK; +	if (ctrlmode & CAN_CTRLMODE_LISTENONLY) +		flags |= USB_8DEV_SILENT; +	if (ctrlmode & CAN_CTRLMODE_ONE_SHOT) +		flags |= USB_8DEV_DISABLE_AUTO_RESTRANS; + +	beflags = cpu_to_be32(flags); +	memcpy(&outmsg.data[5], &beflags, sizeof(beflags)); + +	return usb_8dev_send_cmd(priv, &outmsg, &inmsg); +} + +/* Send close command to device */ +static int usb_8dev_cmd_close(struct usb_8dev_priv *priv) +{ +	struct usb_8dev_cmd_msg inmsg; +	struct usb_8dev_cmd_msg outmsg = { +		.channel = 0, +		.command = USB_8DEV_CLOSE, +		.opt1 = 0, +		.opt2 = 0 +	}; + +	return usb_8dev_send_cmd(priv, &outmsg, &inmsg); +} + +/* Get firmware and hardware version */ +static int usb_8dev_cmd_version(struct usb_8dev_priv *priv, u32 *res) +{ +	struct usb_8dev_cmd_msg	inmsg; +	struct usb_8dev_cmd_msg	outmsg = { +		.channel = 0, +		.command = USB_8DEV_GET_SOFTW_HARDW_VER, +		.opt1 = 0, +		.opt2 = 0 +	}; + +	int err = usb_8dev_send_cmd(priv, &outmsg, &inmsg); +	if (err) +		return err; + +	*res = be32_to_cpup((__be32 *)inmsg.data); + +	return err; +} + +/* Set network device mode + * + * Maybe we should leave this function empty, because the device + * set mode variable with open command. + */ +static int usb_8dev_set_mode(struct net_device *netdev, enum can_mode mode) +{ +	struct usb_8dev_priv *priv = netdev_priv(netdev); +	int err = 0; + +	switch (mode) { +	case CAN_MODE_START: +		err = usb_8dev_cmd_open(priv); +		if (err) +			netdev_warn(netdev, "couldn't start device"); +		break; + +	default: +		return -EOPNOTSUPP; +	} + +	return err; +} + +/* Read error/status frames */ +static void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv, +				struct usb_8dev_rx_msg *msg) +{ +	struct can_frame *cf; +	struct sk_buff *skb; +	struct net_device_stats *stats = &priv->netdev->stats; + +	/* Error message: +	 * byte 0: Status +	 * byte 1: bit   7: Receive Passive +	 * byte 1: bit 0-6: Receive Error Counter +	 * byte 2: Transmit Error Counter +	 * byte 3: Always 0 (maybe reserved for future use) +	 */ + +	u8 state = msg->data[0]; +	u8 rxerr = msg->data[1] & USB_8DEV_RP_MASK; +	u8 txerr = msg->data[2]; +	int rx_errors = 0; +	int tx_errors = 0; + +	skb = alloc_can_err_skb(priv->netdev, &cf); +	if (!skb) +		return; + +	switch (state) { +	case USB_8DEV_STATUSMSG_OK: +		priv->can.state = CAN_STATE_ERROR_ACTIVE; +		cf->can_id |= CAN_ERR_PROT; +		cf->data[2] = CAN_ERR_PROT_ACTIVE; +		break; +	case USB_8DEV_STATUSMSG_BUSOFF: +		priv->can.state = CAN_STATE_BUS_OFF; +		cf->can_id |= CAN_ERR_BUSOFF; +		can_bus_off(priv->netdev); +		break; +	case USB_8DEV_STATUSMSG_OVERRUN: +	case USB_8DEV_STATUSMSG_BUSLIGHT: +	case USB_8DEV_STATUSMSG_BUSHEAVY: +		cf->can_id |= CAN_ERR_CRTL; +		break; +	default: +		priv->can.state = CAN_STATE_ERROR_WARNING; +		cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; +		priv->can.can_stats.bus_error++; +		break; +	} + +	switch (state) { +	case USB_8DEV_STATUSMSG_OK: +	case USB_8DEV_STATUSMSG_BUSOFF: +		break; +	case USB_8DEV_STATUSMSG_ACK: +		cf->can_id |= CAN_ERR_ACK; +		tx_errors = 1; +		break; +	case USB_8DEV_STATUSMSG_CRC: +		cf->data[2] |= CAN_ERR_PROT_UNSPEC; +		cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ | +			       CAN_ERR_PROT_LOC_CRC_DEL; +		rx_errors = 1; +		break; +	case USB_8DEV_STATUSMSG_BIT0: +		cf->data[2] |= CAN_ERR_PROT_BIT0; +		tx_errors = 1; +		break; +	case USB_8DEV_STATUSMSG_BIT1: +		cf->data[2] |= CAN_ERR_PROT_BIT1; +		tx_errors = 1; +		break; +	case USB_8DEV_STATUSMSG_FORM: +		cf->data[2] |= CAN_ERR_PROT_FORM; +		rx_errors = 1; +		break; +	case USB_8DEV_STATUSMSG_STUFF: +		cf->data[2] |= CAN_ERR_PROT_STUFF; +		rx_errors = 1; +		break; +	case USB_8DEV_STATUSMSG_OVERRUN: +		cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; +		stats->rx_over_errors++; +		rx_errors = 1; +		break; +	case USB_8DEV_STATUSMSG_BUSLIGHT: +		priv->can.state = CAN_STATE_ERROR_WARNING; +		cf->data[1] = (txerr > rxerr) ? +			CAN_ERR_CRTL_TX_WARNING : +			CAN_ERR_CRTL_RX_WARNING; +		priv->can.can_stats.error_warning++; +		break; +	case USB_8DEV_STATUSMSG_BUSHEAVY: +		priv->can.state = CAN_STATE_ERROR_PASSIVE; +		cf->data[1] = (txerr > rxerr) ? +			CAN_ERR_CRTL_TX_PASSIVE : +			CAN_ERR_CRTL_RX_PASSIVE; +		priv->can.can_stats.error_passive++; +		break; +	default: +		netdev_warn(priv->netdev, +			    "Unknown status/error message (%d)\n", state); +		break; +	} + +	if (tx_errors) { +		cf->data[2] |= CAN_ERR_PROT_TX; +		stats->tx_errors++; +	} + +	if (rx_errors) +		stats->rx_errors++; + +	cf->data[6] = txerr; +	cf->data[7] = rxerr; + +	priv->bec.txerr = txerr; +	priv->bec.rxerr = rxerr; + +	netif_rx(skb); + +	stats->rx_packets++; +	stats->rx_bytes += cf->can_dlc; +} + +/* Read data and status frames */ +static void usb_8dev_rx_can_msg(struct usb_8dev_priv *priv, +				struct usb_8dev_rx_msg *msg) +{ +	struct can_frame *cf; +	struct sk_buff *skb; +	struct net_device_stats *stats = &priv->netdev->stats; + +	if (msg->type == USB_8DEV_TYPE_ERROR_FRAME && +		   msg->flags == USB_8DEV_ERR_FLAG) { +		usb_8dev_rx_err_msg(priv, msg); +	} else if (msg->type == USB_8DEV_TYPE_CAN_FRAME) { +		skb = alloc_can_skb(priv->netdev, &cf); +		if (!skb) +			return; + +		cf->can_id = be32_to_cpu(msg->id); +		cf->can_dlc = get_can_dlc(msg->dlc & 0xF); + +		if (msg->flags & USB_8DEV_EXTID) +			cf->can_id |= CAN_EFF_FLAG; + +		if (msg->flags & USB_8DEV_RTR) +			cf->can_id |= CAN_RTR_FLAG; +		else +			memcpy(cf->data, msg->data, cf->can_dlc); + +		netif_rx(skb); + +		stats->rx_packets++; +		stats->rx_bytes += cf->can_dlc; + +		can_led_event(priv->netdev, CAN_LED_EVENT_RX); +	} else { +		netdev_warn(priv->netdev, "frame type %d unknown", +			 msg->type); +	} + +} + +/* Callback for reading data from device + * + * Check urb status, call read function and resubmit urb read operation. + */ +static void usb_8dev_read_bulk_callback(struct urb *urb) +{ +	struct usb_8dev_priv *priv = urb->context; +	struct net_device *netdev; +	int retval; +	int pos = 0; + +	netdev = priv->netdev; + +	if (!netif_device_present(netdev)) +		return; + +	switch (urb->status) { +	case 0: /* success */ +		break; + +	case -ENOENT: +	case -ESHUTDOWN: +		return; + +	default: +		netdev_info(netdev, "Rx URB aborted (%d)\n", +			 urb->status); +		goto resubmit_urb; +	} + +	while (pos < urb->actual_length) { +		struct usb_8dev_rx_msg *msg; + +		if (pos + sizeof(struct usb_8dev_rx_msg) > urb->actual_length) { +			netdev_err(priv->netdev, "format error\n"); +			break; +		} + +		msg = (struct usb_8dev_rx_msg *)(urb->transfer_buffer + pos); +		usb_8dev_rx_can_msg(priv, msg); + +		pos += sizeof(struct usb_8dev_rx_msg); +	} + +resubmit_urb: +	usb_fill_bulk_urb(urb, priv->udev, +			  usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_RX), +			  urb->transfer_buffer, RX_BUFFER_SIZE, +			  usb_8dev_read_bulk_callback, priv); + +	retval = usb_submit_urb(urb, GFP_ATOMIC); + +	if (retval == -ENODEV) +		netif_device_detach(netdev); +	else if (retval) +		netdev_err(netdev, +			"failed resubmitting read bulk urb: %d\n", retval); +} + +/* Callback handler for write operations + * + * Free allocated buffers, check transmit status and + * calculate statistic. + */ +static void usb_8dev_write_bulk_callback(struct urb *urb) +{ +	struct usb_8dev_tx_urb_context *context = urb->context; +	struct usb_8dev_priv *priv; +	struct net_device *netdev; + +	BUG_ON(!context); + +	priv = context->priv; +	netdev = priv->netdev; + +	/* free up our allocated buffer */ +	usb_free_coherent(urb->dev, urb->transfer_buffer_length, +			  urb->transfer_buffer, urb->transfer_dma); + +	atomic_dec(&priv->active_tx_urbs); + +	if (!netif_device_present(netdev)) +		return; + +	if (urb->status) +		netdev_info(netdev, "Tx URB aborted (%d)\n", +			 urb->status); + +	netdev->stats.tx_packets++; +	netdev->stats.tx_bytes += context->dlc; + +	can_get_echo_skb(netdev, context->echo_index); + +	can_led_event(netdev, CAN_LED_EVENT_TX); + +	/* Release context */ +	context->echo_index = MAX_TX_URBS; + +	netif_wake_queue(netdev); +} + +/* Send data to device */ +static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb, +				      struct net_device *netdev) +{ +	struct usb_8dev_priv *priv = netdev_priv(netdev); +	struct net_device_stats *stats = &netdev->stats; +	struct can_frame *cf = (struct can_frame *) skb->data; +	struct usb_8dev_tx_msg *msg; +	struct urb *urb; +	struct usb_8dev_tx_urb_context *context = NULL; +	u8 *buf; +	int i, err; +	size_t size = sizeof(struct usb_8dev_tx_msg); + +	if (can_dropped_invalid_skb(netdev, skb)) +		return NETDEV_TX_OK; + +	/* create a URB, and a buffer for it, and copy the data to the URB */ +	urb = usb_alloc_urb(0, GFP_ATOMIC); +	if (!urb) { +		netdev_err(netdev, "No memory left for URBs\n"); +		goto nomem; +	} + +	buf = usb_alloc_coherent(priv->udev, size, GFP_ATOMIC, +				 &urb->transfer_dma); +	if (!buf) { +		netdev_err(netdev, "No memory left for USB buffer\n"); +		goto nomembuf; +	} + +	memset(buf, 0, size); + +	msg = (struct usb_8dev_tx_msg *)buf; +	msg->begin = USB_8DEV_DATA_START; +	msg->flags = 0x00; + +	if (cf->can_id & CAN_RTR_FLAG) +		msg->flags |= USB_8DEV_RTR; + +	if (cf->can_id & CAN_EFF_FLAG) +		msg->flags |= USB_8DEV_EXTID; + +	msg->id = cpu_to_be32(cf->can_id & CAN_ERR_MASK); +	msg->dlc = cf->can_dlc; +	memcpy(msg->data, cf->data, cf->can_dlc); +	msg->end = USB_8DEV_DATA_END; + +	for (i = 0; i < MAX_TX_URBS; i++) { +		if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) { +			context = &priv->tx_contexts[i]; +			break; +		} +	} + +	/* May never happen! When this happens we'd more URBs in flight as +	 * allowed (MAX_TX_URBS). +	 */ +	if (!context) +		goto nofreecontext; + +	context->priv = priv; +	context->echo_index = i; +	context->dlc = cf->can_dlc; + +	usb_fill_bulk_urb(urb, priv->udev, +			  usb_sndbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_TX), +			  buf, size, usb_8dev_write_bulk_callback, context); +	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; +	usb_anchor_urb(urb, &priv->tx_submitted); + +	can_put_echo_skb(skb, netdev, context->echo_index); + +	atomic_inc(&priv->active_tx_urbs); + +	err = usb_submit_urb(urb, GFP_ATOMIC); +	if (unlikely(err)) +		goto failed; +	else if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS) +		/* Slow down tx path */ +		netif_stop_queue(netdev); + +	/* Release our reference to this URB, the USB core will eventually free +	 * it entirely. +	 */ +	usb_free_urb(urb); + +	return NETDEV_TX_OK; + +nofreecontext: +	usb_free_coherent(priv->udev, size, buf, urb->transfer_dma); +	usb_free_urb(urb); + +	netdev_warn(netdev, "couldn't find free context"); + +	return NETDEV_TX_BUSY; + +failed: +	can_free_echo_skb(netdev, context->echo_index); + +	usb_unanchor_urb(urb); +	usb_free_coherent(priv->udev, size, buf, urb->transfer_dma); + +	atomic_dec(&priv->active_tx_urbs); + +	if (err == -ENODEV) +		netif_device_detach(netdev); +	else +		netdev_warn(netdev, "failed tx_urb %d\n", err); + +nomembuf: +	usb_free_urb(urb); + +nomem: +	dev_kfree_skb(skb); +	stats->tx_dropped++; + +	return NETDEV_TX_OK; +} + +static int usb_8dev_get_berr_counter(const struct net_device *netdev, +				     struct can_berr_counter *bec) +{ +	struct usb_8dev_priv *priv = netdev_priv(netdev); + +	bec->txerr = priv->bec.txerr; +	bec->rxerr = priv->bec.rxerr; + +	return 0; +} + +/* Start USB device */ +static int usb_8dev_start(struct usb_8dev_priv *priv) +{ +	struct net_device *netdev = priv->netdev; +	int err, i; + +	for (i = 0; i < MAX_RX_URBS; i++) { +		struct urb *urb = NULL; +		u8 *buf; + +		/* create a URB, and a buffer for it */ +		urb = usb_alloc_urb(0, GFP_KERNEL); +		if (!urb) { +			netdev_err(netdev, "No memory left for URBs\n"); +			err = -ENOMEM; +			break; +		} + +		buf = usb_alloc_coherent(priv->udev, RX_BUFFER_SIZE, GFP_KERNEL, +					 &urb->transfer_dma); +		if (!buf) { +			netdev_err(netdev, "No memory left for USB buffer\n"); +			usb_free_urb(urb); +			err = -ENOMEM; +			break; +		} + +		usb_fill_bulk_urb(urb, priv->udev, +				  usb_rcvbulkpipe(priv->udev, +						  USB_8DEV_ENDP_DATA_RX), +				  buf, RX_BUFFER_SIZE, +				  usb_8dev_read_bulk_callback, priv); +		urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; +		usb_anchor_urb(urb, &priv->rx_submitted); + +		err = usb_submit_urb(urb, GFP_KERNEL); +		if (err) { +			usb_unanchor_urb(urb); +			usb_free_coherent(priv->udev, RX_BUFFER_SIZE, buf, +					  urb->transfer_dma); +			usb_free_urb(urb); +			break; +		} + +		/* Drop reference, USB core will take care of freeing it */ +		usb_free_urb(urb); +	} + +	/* Did we submit any URBs */ +	if (i == 0) { +		netdev_warn(netdev, "couldn't setup read URBs\n"); +		return err; +	} + +	/* Warn if we've couldn't transmit all the URBs */ +	if (i < MAX_RX_URBS) +		netdev_warn(netdev, "rx performance may be slow\n"); + +	err = usb_8dev_cmd_open(priv); +	if (err) +		goto failed; + +	priv->can.state = CAN_STATE_ERROR_ACTIVE; + +	return 0; + +failed: +	if (err == -ENODEV) +		netif_device_detach(priv->netdev); + +	netdev_warn(netdev, "couldn't submit control: %d\n", err); + +	return err; +} + +/* Open USB device */ +static int usb_8dev_open(struct net_device *netdev) +{ +	struct usb_8dev_priv *priv = netdev_priv(netdev); +	int err; + +	/* common open */ +	err = open_candev(netdev); +	if (err) +		return err; + +	can_led_event(netdev, CAN_LED_EVENT_OPEN); + +	/* finally start device */ +	err = usb_8dev_start(priv); +	if (err) { +		if (err == -ENODEV) +			netif_device_detach(priv->netdev); + +		netdev_warn(netdev, "couldn't start device: %d\n", +			 err); + +		close_candev(netdev); + +		return err; +	} + +	netif_start_queue(netdev); + +	return 0; +} + +static void unlink_all_urbs(struct usb_8dev_priv *priv) +{ +	int i; + +	usb_kill_anchored_urbs(&priv->rx_submitted); + +	usb_kill_anchored_urbs(&priv->tx_submitted); +	atomic_set(&priv->active_tx_urbs, 0); + +	for (i = 0; i < MAX_TX_URBS; i++) +		priv->tx_contexts[i].echo_index = MAX_TX_URBS; +} + +/* Close USB device */ +static int usb_8dev_close(struct net_device *netdev) +{ +	struct usb_8dev_priv *priv = netdev_priv(netdev); +	int err = 0; + +	/* Send CLOSE command to CAN controller */ +	err = usb_8dev_cmd_close(priv); +	if (err) +		netdev_warn(netdev, "couldn't stop device"); + +	priv->can.state = CAN_STATE_STOPPED; + +	netif_stop_queue(netdev); + +	/* Stop polling */ +	unlink_all_urbs(priv); + +	close_candev(netdev); + +	can_led_event(netdev, CAN_LED_EVENT_STOP); + +	return err; +} + +static const struct net_device_ops usb_8dev_netdev_ops = { +	.ndo_open = usb_8dev_open, +	.ndo_stop = usb_8dev_close, +	.ndo_start_xmit = usb_8dev_start_xmit, +	.ndo_change_mtu = can_change_mtu, +}; + +static const struct can_bittiming_const usb_8dev_bittiming_const = { +	.name = "usb_8dev", +	.tseg1_min = 1, +	.tseg1_max = 16, +	.tseg2_min = 1, +	.tseg2_max = 8, +	.sjw_max = 4, +	.brp_min = 1, +	.brp_max = 1024, +	.brp_inc = 1, +}; + +/* Probe USB device + * + * Check device and firmware. + * Set supported modes and bittiming constants. + * Allocate some memory. + */ +static int usb_8dev_probe(struct usb_interface *intf, +			 const struct usb_device_id *id) +{ +	struct net_device *netdev; +	struct usb_8dev_priv *priv; +	int i, err = -ENOMEM; +	u32 version; +	char buf[18]; +	struct usb_device *usbdev = interface_to_usbdev(intf); + +	/* product id looks strange, better we also check iProduct string */ +	if (usb_string(usbdev, usbdev->descriptor.iProduct, buf, +		       sizeof(buf)) > 0 && strcmp(buf, "USB2CAN converter")) { +		dev_info(&usbdev->dev, "ignoring: not an USB2CAN converter\n"); +		return -ENODEV; +	} + +	netdev = alloc_candev(sizeof(struct usb_8dev_priv), MAX_TX_URBS); +	if (!netdev) { +		dev_err(&intf->dev, "Couldn't alloc candev\n"); +		return -ENOMEM; +	} + +	priv = netdev_priv(netdev); + +	priv->udev = usbdev; +	priv->netdev = netdev; + +	priv->can.state = CAN_STATE_STOPPED; +	priv->can.clock.freq = USB_8DEV_ABP_CLOCK; +	priv->can.bittiming_const = &usb_8dev_bittiming_const; +	priv->can.do_set_mode = usb_8dev_set_mode; +	priv->can.do_get_berr_counter = usb_8dev_get_berr_counter; +	priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | +				      CAN_CTRLMODE_LISTENONLY | +				      CAN_CTRLMODE_ONE_SHOT; + +	netdev->netdev_ops = &usb_8dev_netdev_ops; + +	netdev->flags |= IFF_ECHO; /* we support local echo */ + +	init_usb_anchor(&priv->rx_submitted); + +	init_usb_anchor(&priv->tx_submitted); +	atomic_set(&priv->active_tx_urbs, 0); + +	for (i = 0; i < MAX_TX_URBS; i++) +		priv->tx_contexts[i].echo_index = MAX_TX_URBS; + +	priv->cmd_msg_buffer = kzalloc(sizeof(struct usb_8dev_cmd_msg), +				      GFP_KERNEL); +	if (!priv->cmd_msg_buffer) +		goto cleanup_candev; + +	usb_set_intfdata(intf, priv); + +	SET_NETDEV_DEV(netdev, &intf->dev); + +	mutex_init(&priv->usb_8dev_cmd_lock); + +	err = register_candev(netdev); +	if (err) { +		netdev_err(netdev, +			"couldn't register CAN device: %d\n", err); +		goto cleanup_cmd_msg_buffer; +	} + +	err = usb_8dev_cmd_version(priv, &version); +	if (err) { +		netdev_err(netdev, "can't get firmware version\n"); +		goto cleanup_unregister_candev; +	} else { +		netdev_info(netdev, +			 "firmware: %d.%d, hardware: %d.%d\n", +			 (version>>24) & 0xff, (version>>16) & 0xff, +			 (version>>8) & 0xff, version & 0xff); +	} + +	devm_can_led_init(netdev); + +	return 0; + +cleanup_unregister_candev: +	unregister_netdev(priv->netdev); + +cleanup_cmd_msg_buffer: +	kfree(priv->cmd_msg_buffer); + +cleanup_candev: +	free_candev(netdev); + +	return err; + +} + +/* Called by the usb core when driver is unloaded or device is removed */ +static void usb_8dev_disconnect(struct usb_interface *intf) +{ +	struct usb_8dev_priv *priv = usb_get_intfdata(intf); + +	usb_set_intfdata(intf, NULL); + +	if (priv) { +		netdev_info(priv->netdev, "device disconnected\n"); + +		unregister_netdev(priv->netdev); +		free_candev(priv->netdev); + +		unlink_all_urbs(priv); +	} + +} + +static struct usb_driver usb_8dev_driver = { +	.name =		"usb_8dev", +	.probe =	usb_8dev_probe, +	.disconnect =	usb_8dev_disconnect, +	.id_table =	usb_8dev_table, +}; + +module_usb_driver(usb_8dev_driver); + +MODULE_AUTHOR("Bernd Krumboeck <krumboeck@universalnet.at>"); +MODULE_DESCRIPTION("CAN driver for 8 devices USB2CAN interfaces"); +MODULE_LICENSE("GPL v2");  | 
