Release 260111
This commit is contained in:
24
panda/drivers/linux/Makefile
Normal file
24
panda/drivers/linux/Makefile
Normal 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
|
||||
28
panda/drivers/linux/README.md
Normal file
28
panda/drivers/linux/README.md
Normal 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
|
||||
```
|
||||
6
panda/drivers/linux/dkms.conf
Normal file
6
panda/drivers/linux/dkms.conf
Normal 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"
|
||||
|
||||
2
panda/drivers/linux/test/Makefile
Normal file
2
panda/drivers/linux/test/Makefile
Normal file
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
gcc main.c -o cantest -pthread -lpthread
|
||||
4
panda/drivers/linux/test/run.sh
Executable file
4
panda/drivers/linux/test/run.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
sudo ifconfig can0 up
|
||||
make
|
||||
./cantest
|
||||
14
panda/drivers/spi/Makefile
Normal file
14
panda/drivers/spi/Makefile
Normal 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
27
panda/drivers/spi/load.sh
Executable 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
33
panda/drivers/spi/patch
Normal 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
12
panda/drivers/spi/pull-src.sh
Executable 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
|
||||
160
panda/drivers/spi/spi_panda.h
Normal file
160
panda/drivers/spi/spi_panda.h
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user