Release 260111
This commit is contained in:
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