Files
dragonpilot/drivers/linux/panda.c
T
Vehicle Researcher bc7b9b38ae Squashed 'panda/' changes from 256d274e..a648ccae
a648ccae Add os import
042562dd Extracted wifi connect from test helpers
ac0fd5dd query fw versions example - use extended diagnostic session
4e9d788a Remove not-needed cadillac-init
f0a5d154 typo
c093286b Add bootkick after re-enabling phone power (#401)
eadb0dbb security upgrades (#397)
7c13bec0 Command to get signature (#399)
dad439a4 static assert on size of health packet (#398)
da9da466 Fix VERSION
df4159c8 Revert "Revert "Register readback on most modules. Still need to convert the other ones (#396)""
56ec2150 Revert "Register readback on most modules. Still need to convert the other ones (#396)"
893e4861 Register readback on most modules. Still need to convert the other ones (#396)
6bbae7be VW safety: allow cancel spam on both buses to be compatible with camera and gateway integration
d5f7a287 bump panda
1bcc351f ignition_can: set it to False after 2s of not seeing CAN msgs
96137f1a VW can based ignition not needed. it has ignition line at camera as well.
1b004a18 Same flake8 version as the one in openpilot
e82ba5f2 Same pylint version as the one in openpilot
656f99b0 Interrupt refactor (NVIC_SM_1: #334) and Fault handling (#377) (PR #373)
000282e5 Fix can_logger.py to run correctly on python3 (#392)
7f9b4a59 Fix USB device enumeration on Windows 8.1 and Windows 10 (#393)
dec565c7 Update Misra test coverage, which now includes rule 2.7
fb6bc3ba Fix Misra
878dd00a solve race condition is relay_malfunction right after changing the relay status by adding a counter
2d4cb05c add a safety mode counter
a6797a21 Implement USB power mode on uno
670f90cc Merge branch 'master' of github.com:commaai/panda
ca39a5d8 Added faults integer to health packet
e1c34a1a Panda Jungle testing (#394)
2a093a39 Added heartbeat to echo test
22464356 Fixed health struct size. We should really get an automated test for this
f458d67a Add uptime counter to the health packet (#391)
16624811 enable CAN transcievers outside the set_safety_mode function, which is not related
a7c98744 bump panda ver
1192d934 Power saving refactor (#389)
d58d08fb Fix Misra 17.8: can't mod function params
bc685ac9 Minor indent
a54b86c4 Failure of set_safety_mode falls back to SILENT. Failure to set silent results in hanging
597436d3 NOOUTPUT safety mode is now SILENT. NOOUTPUT still exists but keeps C… (#388)
d229f8dc ESP forced off in EON build. this prevents ESP to be turned on when e… (#387)
8a044b34 forgot Hyundai: now also using make_msg
4f9c8796 remove abunch of lines from safety regression tests by using common make_msg function
fb814143 mispelled word
57f5ef8c Fix misra: addr can't be more than 29 bits anyway
68ff5012 typo
d5c772b0 Fixe Toyota message white-list
48197a92 Better masking for ELM mode
b8fe78c3 VW is also tested for safety replay
212d336b Safety Chrysler: Added cancel spam button check
d44b5621 fix print in example
02d579a5 functional addr handling
6249a183 tx_hook shall have a white-list of messages (#381)
8138fc14 uds: handle function addrs and fw version query example
6626a542 Fixed python health api
b9b79e8b uds zero second timeout
e0de1a4f define ALLOW_DEBUG in safety tests
86dec4b8 Safety modes that violate ISO26262 requirements are not compiled in RELEASE build
e74ed936 safety tests a bit more simplified
2027765b relay malfunction test centralized
8af1a01a clean up safety tests
e8f7a3b2 upd panda
cfcce8f0 WIP: Relay malfunction (#384)
69d9d610 No tabs in mazda safety
a86418c1 insignificant changes
f239b996 single addr was better
d063a188 Hyundai safety: re-enable button spam safety check
4d1edc06 skip tx_hook if a message is forwarded (#379)
df2ff045 bump version
168461d5 added fault state to health packet
b3e1a133 uds: better debug prints
68c39fb3 uds: no need for threads if you always drain rx
91b7c5bb bump Panda Ver
26cb4dc4 Fixed pylint error
32725cc3 Fixed misra compliance
e33b4bea Added echo script
312ba62d minor comment cleanupo
e90897a8 Fix board detection on white
0e72c183 always stop executing if safety mode fails to be set (suggested by jyoung8607)
e8d7ed1d Rename function name to not confuse safety_set_mode and set_safety_mode
ff86db65 improve uds message processing
512ab3f2 except Exception
37ce507a py3 all
bac4d854 dos and python3
501db8d1 uds drain before send and use has_obd()
f2cbec16 Added has_obd() to python library
48e5b182 Add SDK downloading to the build step (#314)
e0762c2e Add Python & USB API for controlling phone power (#313)
ba9fb69f New health packet struct also in the python libs

git-subtree-dir: panda
git-subtree-split: a648ccae4b3661ca6de7a4ac199cc44a41442b74
2019-12-13 13:02:46 -08:00

617 lines
16 KiB
C

/**
* @file panda.c
* @author Jessy Diamond Exum
* @date 16 June 2017
* @version 0.1
* @brief Driver for the Comma.ai Panda CAN adapter to allow it to be controlled via
* the Linux SocketCAN interface.
* @see https://github.com/commaai/panda for the full project.
* @see Inspired by net/can/usb/mcba_usb.c from Linux Kernel 4.12-rc4.
*/
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/init.h> // Macros used to mark up functions e.g., __init __exit
#include <linux/kernel.h> // Contains types, macros, functions for the kernel
#include <linux/module.h> // Core header for loading LKMs into the kernel
#include <linux/netdevice.h>
#include <linux/usb.h>
/* vendor and product id */
#define PANDA_MODULE_NAME "panda"
#define PANDA_VENDOR_ID 0XBBAA
#define PANDA_PRODUCT_ID 0XDDCC
#define PANDA_MAX_TX_URBS 20
#define PANDA_CTX_FREE PANDA_MAX_TX_URBS
#define PANDA_USB_RX_BUFF_SIZE 0x40
#define PANDA_USB_TX_BUFF_SIZE (sizeof(struct panda_usb_can_msg))
#define PANDA_NUM_CAN_INTERFACES 3
#define PANDA_CAN_TRANSMIT 1
#define PANDA_CAN_EXTENDED 4
#define PANDA_BITRATE 500000
#define PANDA_DLC_MASK 0x0F
#define SAFETY_ALLOUTPUT 17
#define SAFETY_SILENT 0
struct panda_usb_ctx {
struct panda_inf_priv *priv;
u32 ndx;
u8 dlc;
};
struct panda_dev_priv;
struct panda_inf_priv {
struct can_priv can;
struct panda_usb_ctx tx_context[PANDA_MAX_TX_URBS];
struct net_device *netdev;
struct usb_anchor tx_submitted;
atomic_t free_ctx_cnt;
u8 interface_num;
u8 mcu_can_ifnum;
struct panda_dev_priv *priv_dev;
};
struct panda_dev_priv {
struct usb_device *udev;
struct device *dev;
struct usb_anchor rx_submitted;
struct panda_inf_priv *interfaces[PANDA_NUM_CAN_INTERFACES];
};
struct __packed panda_usb_can_msg {
u32 rir;
u32 bus_dat_len;
u8 data[8];
};
static const struct usb_device_id panda_usb_table[] = {
{ USB_DEVICE(PANDA_VENDOR_ID, PANDA_PRODUCT_ID) },
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, panda_usb_table);
// panda: CAN1 = 0 CAN2 = 1 CAN3 = 4
const int can_numbering[] = {0,1,4};
struct panda_inf_priv *
panda_get_inf_from_bus_id(struct panda_dev_priv *priv_dev, int bus_id){
int inf_num;
for(inf_num = 0; inf_num < PANDA_NUM_CAN_INTERFACES; inf_num++)
if(can_numbering[inf_num] == bus_id)
return priv_dev->interfaces[inf_num];
return NULL;
}
// CTX handling shamlessly ripped from mcba_usb.c linux driver
static inline void panda_init_ctx(struct panda_inf_priv *priv)
{
int i = 0;
for (i = 0; i < PANDA_MAX_TX_URBS; i++) {
priv->tx_context[i].ndx = PANDA_CTX_FREE;
priv->tx_context[i].priv = priv;
}
atomic_set(&priv->free_ctx_cnt, ARRAY_SIZE(priv->tx_context));
}
static inline struct panda_usb_ctx *panda_usb_get_free_ctx(struct panda_inf_priv *priv,
struct can_frame *cf)
{
int i = 0;
struct panda_usb_ctx *ctx = NULL;
for (i = 0; i < PANDA_MAX_TX_URBS; i++) {
if (priv->tx_context[i].ndx == PANDA_CTX_FREE) {
ctx = &priv->tx_context[i];
ctx->ndx = i;
ctx->dlc = cf->can_dlc;
atomic_dec(&priv->free_ctx_cnt);
break;
}
}
printk("CTX num %d\n", atomic_read(&priv->free_ctx_cnt));
if (!atomic_read(&priv->free_ctx_cnt)){
/* That was the last free ctx. Slow down tx path */
printk("SENDING TOO FAST\n");
netif_stop_queue(priv->netdev);
}
return ctx;
}
/* panda_usb_free_ctx and panda_usb_get_free_ctx are executed by different
* threads. The order of execution in below function is important.
*/
static inline void panda_usb_free_ctx(struct panda_usb_ctx *ctx)
{
/* Increase number of free ctxs before freeing ctx */
atomic_inc(&ctx->priv->free_ctx_cnt);
ctx->ndx = PANDA_CTX_FREE;
/* Wake up the queue once ctx is marked free */
netif_wake_queue(ctx->priv->netdev);
}
static void panda_urb_unlink(struct panda_inf_priv *priv)
{
usb_kill_anchored_urbs(&priv->priv_dev->rx_submitted);
usb_kill_anchored_urbs(&priv->tx_submitted);
}
static int panda_set_output_enable(struct panda_inf_priv* priv, bool enable){
return usb_control_msg(priv->priv_dev->udev,
usb_sndctrlpipe(priv->priv_dev->udev, 0),
0xDC, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
enable ? SAFETY_ALLOUTPUT : SAFETY_SILENT, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
}
static void panda_usb_write_bulk_callback(struct urb *urb)
{
struct panda_usb_ctx *ctx = urb->context;
struct net_device *netdev;
WARN_ON(!ctx);
netdev = ctx->priv->netdev;
/* free up our allocated buffer */
usb_free_coherent(urb->dev, urb->transfer_buffer_length,
urb->transfer_buffer, urb->transfer_dma);
if (!netif_device_present(netdev))
return;
netdev->stats.tx_packets++;
netdev->stats.tx_bytes += ctx->dlc;
can_get_echo_skb(netdev, ctx->ndx);
if (urb->status)
netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status);
/* Release the context */
panda_usb_free_ctx(ctx);
}
static netdev_tx_t panda_usb_xmit(struct panda_inf_priv *priv,
struct panda_usb_can_msg *usb_msg,
struct panda_usb_ctx *ctx)
{
struct urb *urb;
u8 *buf;
int err;
/* create a URB, and a buffer for it, and copy the data to the URB */
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb)
return -ENOMEM;
buf = usb_alloc_coherent(priv->priv_dev->udev,
PANDA_USB_TX_BUFF_SIZE, GFP_ATOMIC,
&urb->transfer_dma);
if (!buf) {
err = -ENOMEM;
goto nomembuf;
}
memcpy(buf, usb_msg, PANDA_USB_TX_BUFF_SIZE);
usb_fill_bulk_urb(urb, priv->priv_dev->udev,
usb_sndbulkpipe(priv->priv_dev->udev, 3), buf,
PANDA_USB_TX_BUFF_SIZE, panda_usb_write_bulk_callback,
ctx);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_anchor_urb(urb, &priv->tx_submitted);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (unlikely(err))
goto failed;
/* Release our reference to this URB, the USB core will eventually free it entirely. */
usb_free_urb(urb);
return 0;
failed:
usb_unanchor_urb(urb);
usb_free_coherent(priv->priv_dev->udev, PANDA_USB_TX_BUFF_SIZE, buf, urb->transfer_dma);
if (err == -ENODEV)
netif_device_detach(priv->netdev);
else
netdev_warn(priv->netdev, "failed tx_urb %d\n", err);
nomembuf:
usb_free_urb(urb);
return err;
}
static void panda_usb_process_can_rx(struct panda_dev_priv *priv_dev,
struct panda_usb_can_msg *msg)
{
struct can_frame *cf;
struct sk_buff *skb;
int bus_num;
struct panda_inf_priv *priv_inf;
struct net_device_stats *stats;
bus_num = (msg->bus_dat_len >> 4) & 0xf;
priv_inf = panda_get_inf_from_bus_id(priv_dev, bus_num);
if(!priv_inf){
printk("Got something on an unused interface %d\n", bus_num);
return;
}
printk("Recv bus %d\n", bus_num);
stats = &priv_inf->netdev->stats;
//u16 sid;
if (!netif_device_present(priv_inf->netdev))
return;
skb = alloc_can_skb(priv_inf->netdev, &cf);
if (!skb)
return;
if(msg->rir & PANDA_CAN_EXTENDED){
cf->can_id = (msg->rir >> 3) | CAN_EFF_FLAG;
}else{
cf->can_id = (msg->rir >> 21);
}
// TODO: Handle Remote Frames
//if (msg->dlc & MCBA_DLC_RTR_MASK)
// cf->can_id |= CAN_RTR_FLAG;
cf->can_dlc = get_can_dlc(msg->bus_dat_len & PANDA_DLC_MASK);
memcpy(cf->data, msg->data, cf->can_dlc);
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
netif_rx(skb);
}
static void panda_usb_read_int_callback(struct urb *urb)
{
struct panda_dev_priv *priv_dev = urb->context;
int retval;
int pos = 0;
int inf_num;
switch (urb->status) {
case 0: /* success */
break;
case -ENOENT:
case -ESHUTDOWN:
return;
default:
dev_info(priv_dev->dev, "Rx URB aborted (%d)\n", urb->status);
goto resubmit_urb;
}
while (pos < urb->actual_length) {
struct panda_usb_can_msg *msg;
if (pos + sizeof(struct panda_usb_can_msg) > urb->actual_length) {
dev_err(priv_dev->dev, "format error\n");
break;
}
msg = (struct panda_usb_can_msg *)(urb->transfer_buffer + pos);
panda_usb_process_can_rx(priv_dev, msg);
pos += sizeof(struct panda_usb_can_msg);
}
resubmit_urb:
usb_fill_int_urb(urb, priv_dev->udev,
usb_rcvintpipe(priv_dev->udev, 1),
urb->transfer_buffer, PANDA_USB_RX_BUFF_SIZE,
panda_usb_read_int_callback, priv_dev, 5);
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval == -ENODEV){
for(inf_num = 0; inf_num < PANDA_NUM_CAN_INTERFACES; inf_num++)
if(priv_dev->interfaces[inf_num])
netif_device_detach(priv_dev->interfaces[inf_num]->netdev);
}else if (retval)
dev_err(priv_dev->dev, "failed resubmitting read bulk urb: %d\n", retval);
}
static int panda_usb_start(struct panda_dev_priv *priv_dev)
{
int err;
struct urb *urb = NULL;
u8 *buf;
int inf_num;
for(inf_num = 0; inf_num < PANDA_NUM_CAN_INTERFACES; inf_num++)
panda_init_ctx(priv_dev->interfaces[inf_num]);
err = usb_set_interface(priv_dev->udev, 0, 1);
if (err) {
dev_err(priv_dev->dev, "Can not set alternate setting to 1, error: %i", err);
return err;
}
/* create a URB, and a buffer for it */
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
return -ENOMEM;
}
buf = usb_alloc_coherent(priv_dev->udev, PANDA_USB_RX_BUFF_SIZE,
GFP_KERNEL, &urb->transfer_dma);
if (!buf) {
dev_err(priv_dev->dev, "No memory left for USB buffer\n");
usb_free_urb(urb);
return -ENOMEM;
}
usb_fill_int_urb(urb, priv_dev->udev,
usb_rcvintpipe(priv_dev->udev, 1),
buf, PANDA_USB_RX_BUFF_SIZE,
panda_usb_read_int_callback, priv_dev, 5);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_anchor_urb(urb, &priv_dev->rx_submitted);
err = usb_submit_urb(urb, GFP_KERNEL);
if (err) {
usb_unanchor_urb(urb);
usb_free_coherent(priv_dev->udev, PANDA_USB_RX_BUFF_SIZE,
buf, urb->transfer_dma);
usb_free_urb(urb);
dev_err(priv_dev->dev, "Failed in start, while submitting urb.\n");
return err;
}
/* Drop reference, USB core will take care of freeing it */
usb_free_urb(urb);
return 0;
}
/* Open USB device */
static int panda_usb_open(struct net_device *netdev)
{
struct panda_inf_priv *priv = netdev_priv(netdev);
int err;
/* common open */
err = open_candev(netdev);
if (err)
return err;
//priv->can_speed_check = true;
priv->can.state = CAN_STATE_ERROR_ACTIVE;
netif_start_queue(netdev);
return 0;
}
/* Close USB device */
static int panda_usb_close(struct net_device *netdev)
{
struct panda_inf_priv *priv = netdev_priv(netdev);
priv->can.state = CAN_STATE_STOPPED;
netif_stop_queue(netdev);
/* Stop polling */
panda_urb_unlink(priv);
close_candev(netdev);
return 0;
}
static netdev_tx_t panda_usb_start_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
struct panda_inf_priv *priv_inf = netdev_priv(netdev);
struct can_frame *cf = (struct can_frame *)skb->data;
struct panda_usb_ctx *ctx = NULL;
struct net_device_stats *stats = &priv_inf->netdev->stats;
int err;
struct panda_usb_can_msg usb_msg = {};
int bus = priv_inf->mcu_can_ifnum;
if (can_dropped_invalid_skb(netdev, skb)){
printk("Invalid CAN packet");
return NETDEV_TX_OK;
}
ctx = panda_usb_get_free_ctx(priv_inf, cf);
//Warning: cargo cult. Can't tell what this is for, but it is
//everywhere and encouraged in the documentation.
can_put_echo_skb(skb, priv_inf->netdev, ctx->ndx);
if(cf->can_id & CAN_EFF_FLAG){
usb_msg.rir = cpu_to_le32(((cf->can_id & 0x1FFFFFFF) << 3) |
PANDA_CAN_TRANSMIT | PANDA_CAN_EXTENDED);
}else{
usb_msg.rir = cpu_to_le32(((cf->can_id & 0x7FF) << 21) | PANDA_CAN_TRANSMIT);
}
usb_msg.bus_dat_len = cpu_to_le32((cf->can_dlc & 0x0F) | (bus << 4));
memcpy(usb_msg.data, cf->data, cf->can_dlc);
//TODO Handle Remote Frames
//if (cf->can_id & CAN_RTR_FLAG)
// usb_msg.dlc |= PANDA_DLC_RTR_MASK;
netdev_err(netdev, "Received data from socket. canid: %x; len: %d\n", cf->can_id, cf->can_dlc);
err = panda_usb_xmit(priv_inf, &usb_msg, ctx);
if (err)
goto xmit_failed;
return NETDEV_TX_OK;
xmit_failed:
can_free_echo_skb(priv_inf->netdev, ctx->ndx);
panda_usb_free_ctx(ctx);
dev_kfree_skb(skb);
stats->tx_dropped++;
return NETDEV_TX_OK;
}
static const struct net_device_ops panda_netdev_ops = {
.ndo_open = panda_usb_open,
.ndo_stop = panda_usb_close,
.ndo_start_xmit = panda_usb_start_xmit,
};
static int panda_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct net_device *netdev;
struct panda_inf_priv *priv_inf;
int err = -ENOMEM;
int inf_num;
struct panda_dev_priv *priv_dev;
struct usb_device *usbdev = interface_to_usbdev(intf);
priv_dev = kzalloc(sizeof(struct panda_dev_priv), GFP_KERNEL);
if (!priv_dev) {
dev_err(&intf->dev, "Couldn't alloc priv_dev\n");
return -ENOMEM;
}
priv_dev->udev = usbdev;
priv_dev->dev = &intf->dev;
usb_set_intfdata(intf, priv_dev);
////// Interface privs
for(inf_num = 0; inf_num < PANDA_NUM_CAN_INTERFACES; inf_num++){
netdev = alloc_candev(sizeof(struct panda_inf_priv), PANDA_MAX_TX_URBS);
if (!netdev) {
dev_err(&intf->dev, "Couldn't alloc candev\n");
goto cleanup_candev;
}
netdev->netdev_ops = &panda_netdev_ops;
netdev->flags |= IFF_ECHO; /* we support local echo */
priv_inf = netdev_priv(netdev);
priv_inf->netdev = netdev;
priv_inf->priv_dev = priv_dev;
priv_inf->interface_num = inf_num;
priv_inf->mcu_can_ifnum = can_numbering[inf_num];
init_usb_anchor(&priv_dev->rx_submitted);
init_usb_anchor(&priv_inf->tx_submitted);
/* Init CAN device */
priv_inf->can.state = CAN_STATE_STOPPED;
priv_inf->can.bittiming.bitrate = PANDA_BITRATE;
SET_NETDEV_DEV(netdev, &intf->dev);
err = register_candev(netdev);
if (err) {
netdev_err(netdev, "couldn't register PANDA CAN device: %d\n", err);
free_candev(priv_inf->netdev);
goto cleanup_candev;
}
priv_dev->interfaces[inf_num] = priv_inf;
}
err = panda_usb_start(priv_dev);
if (err) {
dev_err(&intf->dev, "Failed to initialize Comma.ai Panda CAN controller\n");
goto cleanup_candev;
}
err = panda_set_output_enable(priv_inf, true);
if (err) {
dev_info(&intf->dev, "Failed to initialize send enable message to Panda.\n");
goto cleanup_candev;
}
dev_info(&intf->dev, "Comma.ai Panda CAN controller connected\n");
return 0;
cleanup_candev:
for(inf_num = 0; inf_num < PANDA_NUM_CAN_INTERFACES; inf_num++){
priv_inf = priv_dev->interfaces[inf_num];
if(priv_inf){
unregister_candev(priv_inf->netdev);
free_candev(priv_inf->netdev);
}else
break;
}
kfree(priv_dev);
return err;
}
/* Called by the usb core when driver is unloaded or device is removed */
static void panda_usb_disconnect(struct usb_interface *intf)
{
struct panda_dev_priv *priv_dev = usb_get_intfdata(intf);
struct panda_inf_priv *priv_inf;
int inf_num;
usb_set_intfdata(intf, NULL);
for(inf_num = 0; inf_num < PANDA_NUM_CAN_INTERFACES; inf_num++){
priv_inf = priv_dev->interfaces[inf_num];
if(priv_inf){
netdev_info(priv_inf->netdev, "device disconnected\n");
unregister_candev(priv_inf->netdev);
free_candev(priv_inf->netdev);
}else
break;
}
panda_urb_unlink(priv_inf);
kfree(priv_dev);
}
static struct usb_driver panda_usb_driver = {
.name = PANDA_MODULE_NAME,
.probe = panda_usb_probe,
.disconnect = panda_usb_disconnect,
.id_table = panda_usb_table,
};
module_usb_driver(panda_usb_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jessy Diamond Exum <jessy.diamondman@gmail.com>");
MODULE_DESCRIPTION("SocketCAN driver for Comma.ai's Panda Adapter.");
MODULE_VERSION("0.1");