Release 260111

This commit is contained in:
Comma Device
2026-01-11 18:23:29 +08:00
commit 3721ecbf8a
2601 changed files with 855070 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
VERSION=0.0.1
obj-m+=panda.o
all: build install
build:
sudo dkms build panda/$(VERSION)
install:
sudo dkms install panda/$(VERSION)
remove:
sudo dkms remove panda/$(VERSION) --all
uninstall:
sudo dkms uninstall panda/$(VERSION)
clean: remove
link:
sudo dkms add `pwd`
unload:
sudo rmmod panda

View File

@@ -0,0 +1,28 @@
# Linux driver
Installs the panda linux kernel driver using DKMS.
This will allow the panda to work with tools such as `can-utils`
## Prerequisites
- `apt-get install dkms gcc linux-headers-$(uname -r) make sudo`
## Installation
- `make all`
- `make link` (optional, setup to build/install when kernel is updated)
## Uninstall
- `make clean`
## Usage
You will need to bring it up using `sudo ifconfig can0 up` or
`sudo ip link set dev can0 up`, depending on your platform.
Note that you may have to setup udev rules for Linux
``` bash
sudo tee /etc/udev/rules.d/11-panda.rules <<EOF
SUBSYSTEM=="usb", ATTRS{idVendor}=="3801", ATTRS{idProduct}=="ddcc", MODE="0666"
SUBSYSTEM=="usb", ATTRS{idVendor}=="3801", ATTRS{idProduct}=="ddee", MODE="0666"
EOF
sudo udevadm control --reload-rules && sudo udevadm trigger
```

View File

@@ -0,0 +1,6 @@
PACKAGE_NAME="panda"
PACKAGE_VERSION="0.0.1"
BUILT_MODULE_NAME[0]="panda"
DEST_MODULE_LOCATION[0]="/kernel/drivers/net/panda/"
AUTOINSTALL="yes"

View File

@@ -0,0 +1,2 @@
all:
gcc main.c -o cantest -pthread -lpthread

View File

@@ -0,0 +1,4 @@
#!/usr/bin/env bash
sudo ifconfig can0 up
make
./cantest

View File

@@ -0,0 +1,14 @@
obj-m += spidev_panda.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
# GCC9 bug, apply kernel patch instead?
# https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=0b999ae3614d09d97a1575936bcee884f912b10e
ccflags-y := -Wno-missing-attributes
default:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean

27
panda/drivers/spi/load.sh Executable file
View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -e
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
cd $DIR
make -j8
sudo su -c "echo spi0.0 > /sys/bus/spi/drivers/spidev/unbind" || true
sudo dmesg -C
#sudo rmmod -f spidev_panda
sudo rmmod spidev_panda || true
sudo insmod spidev_panda.ko
sudo su -c "echo 'file $DIR/spidev_panda.c +p' > /sys/kernel/debug/dynamic_debug/control"
sudo su -c "echo 'file $DIR/spi_panda.h +p' > /sys/kernel/debug/dynamic_debug/control"
sudo lsmod
echo "loaded"
ls -la /dev/spi*
sudo chmod 666 /dev/spi*
ipython -c "from panda import Panda; print(Panda.list())"
KERN=1 ipython -c "from panda import Panda; print(Panda.list())"
dmesg

33
panda/drivers/spi/patch Normal file
View File

@@ -0,0 +1,33 @@
53c53,54
< #define SPIDEV_MAJOR 153 /* assigned */
---
> int SPIDEV_MAJOR = 0;
> //#define SPIDEV_MAJOR 153 /* assigned */
354a356,358
>
> #include "spi_panda.h"
>
413,414c417,419
< retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0,
< (__u8 __user *)arg);
---
> retval = panda_transfer(spidev, spi, arg);
> //retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0,
> // (__u8 __user *)arg);
697,698d701
< { .compatible = "rohm,dh2228fv" },
< { .compatible = "lineartechnology,ltc2488" },
831c834
< .name = "spidev",
---
> .name = "spidev_panda",
856c859
< status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
---
> status = register_chrdev(0, "spi", &spidev_fops);
860c863,865
< spidev_class = class_create(THIS_MODULE, "spidev");
---
> SPIDEV_MAJOR = status;
>
> spidev_class = class_create(THIS_MODULE, "spidev_panda");

12
panda/drivers/spi/pull-src.sh Executable file
View File

@@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -e
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
cd $DIR
rm -f spidev.c
wget https://raw.githubusercontent.com/commaai/agnos-kernel-sdm845/master/drivers/spi/spidev.c
# diff spidev.c spidev_panda.c > patch
# git diff --no-index spidev.c spidev_panda.c
patch -o spidev_panda.c spidev.c -i patch

View File

@@ -0,0 +1,160 @@
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#define SPI_SYNC 0x5AU
#define SPI_HACK 0x79U
#define SPI_DACK 0x85U
#define SPI_NACK 0x1FU
#define SPI_CHECKSUM_START 0xABU
struct __attribute__((packed)) spi_header {
u8 sync;
u8 endpoint;
uint16_t tx_len;
uint16_t max_rx_len;
};
struct spi_panda_transfer {
__u64 rx_buf;
__u64 tx_buf;
__u32 tx_length;
__u32 rx_length_max;
__u32 timeout;
__u8 endpoint;
__u8 expect_disconnect;
};
static u8 panda_calc_checksum(u8 *buf, u16 length) {
int i;
u8 checksum = SPI_CHECKSUM_START;
for (i = 0U; i < length; i++) {
checksum ^= buf[i];
}
return checksum;
}
static long panda_wait_for_ack(struct spidev_data *spidev, u8 ack_val, u8 length) {
int i;
int ret;
for (i = 0; i < 1000; i++) {
ret = spidev_sync_read(spidev, length);
if (ret < 0) {
return ret;
}
if (spidev->rx_buffer[0] == ack_val) {
return 0;
} else if (spidev->rx_buffer[0] == SPI_NACK) {
return -2;
}
if (i > 20) usleep_range(10, 20);
}
return -1;
}
static long panda_transfer_raw(struct spidev_data *spidev, struct spi_device *spi, unsigned long arg) {
u16 rx_len;
long retval = -1;
struct spi_header header;
struct spi_panda_transfer pt;
struct spi_transfer t = {
.len = 0,
.tx_buf = spidev->tx_buffer,
.rx_buf = spidev->rx_buffer,
.speed_hz = spidev->spi->max_speed_hz,
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
// read struct from user
if (!access_ok(VERIFY_WRITE, arg, sizeof(pt))) {
return -1;
}
if (copy_from_user(&pt, (void __user *)arg, sizeof(pt))) {
return -1;
}
dev_dbg(&spi->dev, "ep: %d, tx len: %d\n", pt.endpoint, pt.tx_length);
// send header
header.sync = 0x5a;
header.endpoint = pt.endpoint;
header.tx_len = pt.tx_length;
header.max_rx_len = pt.rx_length_max;
memcpy(spidev->tx_buffer, &header, sizeof(header));
spidev->tx_buffer[sizeof(header)] = panda_calc_checksum(spidev->tx_buffer, sizeof(header));
t.len = sizeof(header) + 1;
retval = spidev_sync(spidev, &m);
if (retval < 0) {
dev_dbg(&spi->dev, "spi xfer failed %ld\n", retval);
return retval;
}
// wait for ACK
retval = panda_wait_for_ack(spidev, SPI_HACK, 1);
if (retval < 0) {
dev_dbg(&spi->dev, "no header ack %ld\n", retval);
return retval;
}
// send data
dev_dbg(&spi->dev, "sending data\n");
retval = copy_from_user(spidev->tx_buffer, (const u8 __user *)(uintptr_t)pt.tx_buf, pt.tx_length);
spidev->tx_buffer[pt.tx_length] = panda_calc_checksum(spidev->tx_buffer, pt.tx_length);
t.len = pt.tx_length + 1;
retval = spidev_sync(spidev, &m);
if (pt.expect_disconnect) {
return 0;
}
// wait for ACK
retval = panda_wait_for_ack(spidev, SPI_DACK, 3);
if (retval < 0) {
dev_dbg(&spi->dev, "no data ack\n");
return retval;
}
// get response
t.rx_buf = spidev->rx_buffer + 3;
rx_len = (spidev->rx_buffer[2] << 8) | (spidev->rx_buffer[1]);
dev_dbg(&spi->dev, "rx len %u\n", rx_len);
if (rx_len > pt.rx_length_max) {
dev_dbg(&spi->dev, "RX len greater than max\n");
return -1;
}
// do the read
t.len = rx_len + 1;
retval = spidev_sync(spidev, &m);
if (retval < 0) {
dev_dbg(&spi->dev, "spi xfer failed %ld\n", retval);
return retval;
}
if (panda_calc_checksum(spidev->rx_buffer, 3 + rx_len + 1) != 0) {
dev_dbg(&spi->dev, "bad checksum\n");
return -1;
}
retval = copy_to_user((u8 __user *)(uintptr_t)pt.rx_buf, spidev->rx_buffer + 3, rx_len);
return rx_len;
}
static long panda_transfer(struct spidev_data *spidev, struct spi_device *spi, unsigned long arg) {
int i;
int ret;
dev_dbg(&spi->dev, "=== XFER start ===\n");
for (i = 0; i < 20; i++) {
ret = panda_transfer_raw(spidev, spi, arg);
if (ret >= 0) {
break;
}
}
dev_dbg(&spi->dev, "took %d tries\n", i+1);
return ret;
}