diff --git a/CMakeLists.txt b/CMakeLists.txt index e21429e..0900816 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ set(FAMILY "rp2040" CACHE STRING "Board/MCU family, decides which drivers to use set(BOARD "raspberry_pi_pico" CACHE STRING "Board used, determines the pinout. Defaults to the Raspberry Pi Pico.") # use directory name for project id # FIXME: use fixed project name -get_filename_component(PROJECT ${CMAKE_CURRENT_SOURCE_DIR} NAME) +get_filename_component(PROJECT "Dragon Probe" NAME) set(PROJECT ${BOARD}-${PROJECT}) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/README.md b/README.md index 04210d2..9ff2d11 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ -# DapperMime-JTAG - -(name is still WIP) +# Dragon Probe This project attempts to add Bus Pirate/...-like functionality to a number of MCUs, mainly the Raspberry Pi Pico. It was originally based on [Dapper @@ -81,7 +79,6 @@ projects. These respective licenses can be found in ## TODO -- [ ] **A name** - [ ] **A (VID and) PID, and maybe better subclass & protocol IDs for the vnd cfg itf** - [ ] GPL license headers on every file - [x] Debug interface to send printf stuff directly to USB, instead of having @@ -102,6 +99,8 @@ projects. These respective licenses can be found in - interface 2 ("C"): index 3, epin 0x06, epout 0x85 - interface 3 ("D"): index 4, epin 0x08, epout 0x87 - ~~or, FX2 emulation mode??? (useful links: https://sigrok.org/wiki/Fx2lafw ; https://sigrok.org/wiki/CWAV_USBee_SX/Info )~~ has a ROM/fw and everything, so, maybe not +- [ ] "Complex Trigger" mode for aiding with glitching triggers, by turning + UART/SPI/I2C/eMMC/... sequences into a GPIO toggle - [ ] Mode where you can define custom PIO stuff for custom pinouts/protocols?????? - Maybe also with code that auto-reacts to stuff from the environment? - [ ] Facedancer implementation by connecting two picos via GPIO, one doing host diff --git a/bsp/rp2040/m_default/dap_swo.c b/bsp/rp2040/m_default/dap_swo.c index f7429e4..8f61773 100644 --- a/bsp/rp2040/m_default/dap_swo.c +++ b/bsp/rp2040/m_default/dap_swo.c @@ -22,18 +22,24 @@ static bool mode_enabled = false; // enable: enable flag // return: 1 - Success, 0 - Error uint32_t SWO_Mode_UART(uint32_t enable) { + //for(;;);//printf("SWO mode %lu\n", enable); if (enable) { swo_sm = pio_claim_unused_sm(SWO_PIO, false); - if (swo_sm == -1) return 0; + if (swo_sm == -1) { + //for(;;);//printf("E: no PIO\n"); + return 0; + } swo_dmach = dma_claim_unused_channel(false); if (swo_dmach == -1) { + //for(;;);//printf("E: no DMA\n"); pio_sm_unclaim(SWO_PIO, swo_sm); swo_sm = -1; return 0; } if (!pio_can_add_program(SWO_PIO, &uart_rx_program)) { + //for(;;);//printf("E: no prg\n"); dma_channel_unclaim(swo_dmach); swo_dmach = -1; pio_sm_unclaim(SWO_PIO, swo_sm); @@ -75,6 +81,7 @@ uint32_t SWO_Mode_UART(uint32_t enable) { // baudrate: requested baudrate // return: actual baudrate or 0 when not configured uint32_t SWO_Baudrate_UART(uint32_t baudrate) { + //for(;;);//printf("SWO baudrate %lu\n", baudrate); if (!mode_enabled) return 0; uart_rx_program_init(SWO_PIO, swo_sm, swo_pio_off, PINOUT_SWO, baudrate); @@ -86,6 +93,7 @@ uint32_t SWO_Baudrate_UART(uint32_t baudrate) { // active: active flag // return: 1 - Success, 0 - Error uint32_t SWO_Control_UART(uint32_t active) { + //for(;;);//printf("SWO control %lu\n", active); if (!mode_enabled) return 0; if (active) { @@ -105,6 +113,7 @@ uint32_t SWO_Control_UART(uint32_t active) { // buf: pointer to buffer for capturing // num: number of bytes to capture void SWO_Capture_UART(uint8_t* buf, uint32_t num) { + //for(;;);//printf("SWO capture %p 0x%lx\n", buf, num); if (!mode_enabled) return; swo_num = num; @@ -128,6 +137,7 @@ uint32_t SWO_GetCount_UART(void) { if (!mode_enabled || swo_num == 0) return 0; // not initialized uint32_t remaining = dma_hw->ch[swo_dmach].transfer_count; + //for(;;);//printf("SWO getcount -> 0x%lx\n", swo_num - remaining); return swo_num - remaining; } diff --git a/host/42-dragonprobe.rules b/host/42-dragonprobe.rules new file mode 100644 index 0000000..2db13f6 --- /dev/null +++ b/host/42-dragonprobe.rules @@ -0,0 +1,10 @@ +SUBSYSTEMS=="usb", ATTRS{idVendor}=="cafe", ATTRS{idProduct}=="1312", MODE:="0666", ENV{IS_DRAGONPROBE}:="yes" + +# TODO: redo all this here once the interface has settled a bit more +# (it needs the regular UART, SUMP CDC, SPI2 CDC (to be implemented), ...) +#ENV{IS_DRAGONPROBE}=="yes", ATTRS{interface}=="stdio CDC interface (debug)", ENV{DRAGONPROBE_INTERFACE_TYPE}:="debug" +#ENV{IS_DRAGONPROBE}=="yes", ATTRS{interface}=="Serprog CDC interface", ENV{DRAGONPROBE_INTERFACE_TYPE}:="serprog" +#ENV{IS_DRAGONPROBE}=="yes", ATTRS{interface}=="CMSIS-DAP HID interface", ENV{DRAGONPROBE_INTERFACE_TYPE}:="dap" +#ENV{DRAGONPROBE_INTERFACE_TYPE}=="debug", SUBSYSTEM=="tty", SYMLINK+="dragnbus-dbg" +#ENV{DRAGONPROBE_INTERFACE_TYPE}=="serprog", SUBSYSTEM=="tty", SYMLINK+="dragnbus-serprog" +#ENV{DRAGONPROBE_INTERFACE_TYPE}=="dap", SUBSYSTEM=="usbmisc", SYMLINK+="dragnbus-dap" diff --git a/host/dmctl.sh b/host/dmctl.sh deleted file mode 100755 index ac65d16..0000000 --- a/host/dmctl.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -cd "$(dirname "$(realpath "$0")")" -exec python3 -m dmctl "$@" diff --git a/host/dpctl.sh b/host/dpctl.sh new file mode 100755 index 0000000..b08f495 --- /dev/null +++ b/host/dpctl.sh @@ -0,0 +1,3 @@ +#!/bin/sh +cd "$(dirname "$(realpath "$0")")" +exec python3 -m "$(basename -s .sh "$0")" "$@" diff --git a/host/dmctl/.gitignore b/host/dpctl/.gitignore similarity index 100% rename from host/dmctl/.gitignore rename to host/dpctl/.gitignore diff --git a/host/dmctl/__init__.py b/host/dpctl/__init__.py similarity index 93% rename from host/dmctl/__init__.py rename to host/dpctl/__init__.py index 93e1737..409c6a3 100644 --- a/host/dmctl/__init__.py +++ b/host/dpctl/__init__.py @@ -6,12 +6,12 @@ import traceback from typing import * -import dmctl.connection as devconn -import dmctl.protocol as devproto -import dmctl.commands as devcmds +import dpctl.connection as devconn +import dpctl.protocol as devproto +import dpctl.commands as devcmds -def dmctl_do(args: Any) -> int: +def dpctl_do(args: Any) -> int: def get_device_info(conn, args): return devcmds.get_device_info(conn) def get_mode_info(conn, args): return devcmds.get_mode_info(conn, args.mode) def set_mode(conn, args): return devcmds.set_mode(conn, args.mode) @@ -80,12 +80,12 @@ def dmctl_do(args: Any) -> int: print("Could not connect to a device: %s." % conn) return 1 - with devproto.DmjDevice(conn) as dev: + with devproto.DPDevice(conn) as dev: return subfn(dev, args) def main() -> int: - parser = argparse.ArgumentParser(prog="dmctl") + parser = argparse.ArgumentParser(prog="dpctl") def auto_int(x): return int(x, 0) @@ -114,10 +114,10 @@ def main() -> int: # * mode 5 (ftdi/fx2 emul): probably nothing parser.add_argument('--conn', type=str, default=None, - help="Connection string. Either a dmj-char device in"+\ - " /dev, a USB bus.device number, or a USB VID:PID " + \ - "pair. Defaults to trying /dev/dmj-* (if there is " + \ - "only one), and cafe:1312 otherwise.") + help="Connection string. Either a dragonprobe-char "+\ + "device in /dev, a USB bus.device number, or a USB " + \ + "VID:PID pair. Defaults to trying /dev/dragonprobe-* " + \ + "(if there is only one), and cafe:1312 otherwise.") #parser.descripiton = ... subcmds = parser.add_subparsers(required=True, metavar="subcommand", @@ -192,5 +192,5 @@ def main() -> int: help="Disable overclocking, short for --set 0") args = parser.parse_args() - return dmctl_do(args) + return dpctl_do(args) diff --git a/host/dmctl/__main__.py b/host/dpctl/__main__.py similarity index 69% rename from host/dmctl/__main__.py rename to host/dpctl/__main__.py index adb3c6b..496be3f 100755 --- a/host/dmctl/__main__.py +++ b/host/dpctl/__main__.py @@ -1,9 +1,9 @@ -import dmctl +import dpctl try: - exit(dmctl.main() or 0) + exit(dpctl.main() or 0) except Exception:# as e import traceback traceback.print_exc() diff --git a/host/dmctl/commands.py b/host/dpctl/commands.py similarity index 92% rename from host/dmctl/commands.py rename to host/dpctl/commands.py index 05ed2c0..580c8d3 100644 --- a/host/dmctl/commands.py +++ b/host/dpctl/commands.py @@ -15,7 +15,7 @@ FEATURES_OF_MODE = { } -def get_device_info(dev: DmjDevice) -> int: +def get_device_info(dev: DPDevice) -> int: print("%s: protocol version: %02x.%02x, currently in mode %d (%s)" % \ (dev.infotext, dev.protocol_version >> 8, dev.protocol_version & 0xff, dev.current_mode, dev.mode_info[dev.current_mode].infotext) @@ -31,7 +31,7 @@ def get_device_info(dev: DmjDevice) -> int: return 0 -def get_mode_info(dev: DmjDevice, mode: Optional[str]) -> int: +def get_mode_info(dev: DPDevice, mode: Optional[str]) -> int: def try_parse(s: str): try: return int(s) except ValueError: return None @@ -73,7 +73,7 @@ def get_mode_info(dev: DmjDevice, mode: Optional[str]) -> int: return 1 -def set_mode(dev: DmjDevice, mode: int) -> int: +def set_mode(dev: DPDevice, mode: int) -> int: try: dev.set_mode(mode) return 0 @@ -85,7 +85,7 @@ def set_mode(dev: DmjDevice, mode: int) -> int: # --- -def uart_hw_flowctl_get(dev: DmjDevice) -> int: +def uart_hw_flowctl_get(dev: DPDevice) -> int: try: res = dev.m1_usb_hw_flowctl_get() print("Flow control %sabled" % ("en" if res else "dis")) @@ -95,7 +95,7 @@ def uart_hw_flowctl_get(dev: DmjDevice) -> int: return 1 -def uart_hw_flowctl_set(dev: DmjDevice, v: bool) -> int: +def uart_hw_flowctl_set(dev: DPDevice, v: bool) -> int: try: dev.m1_usb_hw_flowctl_set(v) return 0 @@ -107,7 +107,7 @@ def uart_hw_flowctl_set(dev: DmjDevice, v: bool) -> int: # --- -def tempsensor_get(dev: DmjDevice) -> int: +def tempsensor_get(dev: DPDevice) -> int: try: res = dev.m1_tempsensor_i2cemul_get() if res is None: @@ -120,7 +120,7 @@ def tempsensor_get(dev: DmjDevice) -> int: return 1 -def tempsensor_set(dev: DmjDevice, v: int) -> int: +def tempsensor_set(dev: DPDevice, v: int) -> int: try: old, new = dev.m1_tempsensor_i2cemul_set(v) olds = "disabled" if old is None else ("0x%02x" % old) @@ -135,7 +135,7 @@ def tempsensor_set(dev: DmjDevice, v: int) -> int: # --- -def jtag_scan(dev: DmjDevice, typ: str, start_pin: int, end_pin: int) -> int: +def jtag_scan(dev: DPDevice, typ: str, start_pin: int, end_pin: int) -> int: SCAN_IDLE = 0x7f SCAN_DONE_F = 0x80 @@ -218,7 +218,7 @@ def jtag_scan(dev: DmjDevice, typ: str, start_pin: int, end_pin: int) -> int: # --- -def sump_overclock_get(dev: DmjDevice) -> int: +def sump_overclock_get(dev: DPDevice) -> int: try: stat = dev.m4_sump_overclock_get() print("SUMP overclocking mode: %d" % stat) @@ -228,7 +228,7 @@ def sump_overclock_get(dev: DmjDevice) -> int: return 1 -def sump_overclock_set(dev: DmjDevice, v: int) -> int: +def sump_overclock_set(dev: DPDevice, v: int) -> int: try: stat = dev.m4_sump_overclock_set(v) return 0 diff --git a/host/dmctl/connection.py b/host/dpctl/connection.py similarity index 99% rename from host/dmctl/connection.py rename to host/dpctl/connection.py index f93467d..4639dfa 100644 --- a/host/dmctl/connection.py +++ b/host/dpctl/connection.py @@ -179,7 +179,7 @@ class UsbConn(DevConn): class ChardevConn(DevConn): - _DEVCLASSNAME = "dmj" + _DEVCLASSNAME = "dragonprobe" def try_find() -> Optional[ChardevConn]: if sys.platform != 'linux': diff --git a/host/dmctl/protocol.py b/host/dpctl/protocol.py similarity index 99% rename from host/dmctl/protocol.py rename to host/dpctl/protocol.py index 9364eee..e73921e 100644 --- a/host/dmctl/protocol.py +++ b/host/dpctl/protocol.py @@ -104,7 +104,7 @@ class ModeInfo(NamedTuple): features: Set[int] -class DmjDevice: +class DPDevice: def __init__(self, conn: DevConn): self._conn = conn self._buf = array.array('B') diff --git a/host/i2c-tiny-usb-misc/i2c-tiny-usb.c b/host/i2c-tiny-usb-misc/i2c-tiny-usb.c index 9bfab3e..f1303ec 100644 --- a/host/i2c-tiny-usb-misc/i2c-tiny-usb.c +++ b/host/i2c-tiny-usb-misc/i2c-tiny-usb.c @@ -160,7 +160,7 @@ static const struct i2c_algorithm usb_algorithm = { static const struct usb_device_id i2c_tiny_usb_table[] = { { USB_DEVICE(0x0403, 0xc631) }, /* FTDI */ { USB_DEVICE(0x1c40, 0x0534) }, /* EZPrototypes */ - { /* TinyUSB DapperMime: we want the Vendor interface on I2C-enabled ones */ + { /* Dragon Probe: we want the Vendor interface on I2C-enabled ones */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | USB_DEVICE_ID_MATCH_INT_CLASS, .idVendor = 0xcafe, .idProduct = 0x1312, .bcdDevice_lo = 0x6000, .bcdDevice_hi = 0x6fff, diff --git a/host/modules/.gitignore b/host/modules/.gitignore new file mode 100644 index 0000000..9c7231e --- /dev/null +++ b/host/modules/.gitignore @@ -0,0 +1,8 @@ +modules.order +Module.symvers +*.ko +*.mod +*.o +*.mod.c +.*.cmd +.*.d diff --git a/host/modules/Makefile b/host/modules/Makefile index a95a6ec..f28bba6 100644 --- a/host/modules/Makefile +++ b/host/modules/Makefile @@ -1,5 +1,5 @@ -obj-m := dmj.o dmj-char.o i2c-dmj.o spi-dmj.o dmj-hwmon.o +obj-m := dragonprobe.o dragonprobe-char.o i2c-dragonprobe.o spi-dragonprobe.o dragonprobe-hwmon.o KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) @@ -9,18 +9,18 @@ default: $(MAKE) -C $(KDIR) M=$(PWD) modules clean: - $(RM) -v *.o *.ko *.mod *.mod.c Module.symvers modules.order + $(RM) -v *.o *.ko *.mod *.mod.c Module.symvers modules.order .*.cmd .*.d load: - sudo insmod ./dmj.ko - sudo insmod ./dmj-char.ko - sudo insmod ./i2c-dmj.ko - sudo insmod ./spi-dmj.ko - sudo insmod ./dmj-hwmon.ko + sudo insmod ./dragonprobe.ko + sudo insmod ./dragonprobe-char.ko + sudo insmod ./i2c-dragonprobe.ko + sudo insmod ./spi-dragonprobe.ko + sudo insmod ./dragonprobe-hwmon.ko unload: - sudo rmmod dmj-hwmon - sudo rmmod spi-dmj - sudo rmmod i2c-dmj - sudo rmmod dmj-char - sudo rmmod dmj + sudo rmmod dragonprobe-hwmon + sudo rmmod spi-dragonprobe + sudo rmmod i2c-dragonprobe + sudo rmmod dragonprobe-char + sudo rmmod dragonprobe diff --git a/host/modules/dmj.h b/host/modules/dmj.h deleted file mode 100644 index e5d1f15..0000000 --- a/host/modules/dmj.h +++ /dev/null @@ -1,89 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LINUX_USB_DAPPERMIMEJTAG_H -#define __LINUX_USB_DAPPERMIMEJTAG_H - -#define DMJ_USB_CFG_PROTO_VER 0x0010 - -#define DMJ_RESP_STAT_OK 0x00 -#define DMJ_RESP_STAT_ILLCMD 0x01 -#define DMJ_RESP_STAT_BADMODE 0x02 -#define DMJ_RESP_STAT_NOSUCHMODE 0x03 -#define DMJ_RESP_STAT_BADARG 0x04 -#define DMJ_RESP_STAT_ILLSTATE 0x05 - -#define DMJ_CMD_CFG_GET_VERSION 0x00 -#define DMJ_CMD_CFG_GET_MODES 0x01 -#define DMJ_CMD_CFG_GET_CUR_MODE 0x02 -#define DMJ_CMD_CFG_SET_CUR_MODE 0x03 -#define DMJ_CMD_CFG_GET_INFOSTR 0x04 - -#define DMJ_CMD_MODE_GET_NAME 0x00 -#define DMJ_CMD_MODE_GET_VERSION 0x01 -#define DMJ_CMD_MODE_GET_FEATURES 0x02 - -#define DMJ_CMD_MODE1_SPI 0x13 -#define DMJ_CMD_MODE1_I2C 0x14 -#define DMJ_CMD_MODE1_TEMPSENSOR 0x15 - -#define DMJ_FEATURE_MODE1_UART (1<<0) -#define DMJ_FEATURE_MODE1_CMSISDAP (1<<1) -#define DMJ_FEATURE_MODE1_SPI (1<<2) -#define DMJ_FEATURE_MODE1_I2C (1<<3) -#define DMJ_FEATURE_MODE1_TEMPSENSOR (1<<4) - -#define DMJ_XFER_FLAGS_PARSE_RESP (1<<0) -#define DMJ_XFER_FLAGS_FILL_RECVBUF (1<<1) - -inline static const char *dmj_get_protoerr(int err) -{ - switch (err) { - case DMJ_RESP_STAT_OK: return "ok"; - case DMJ_RESP_STAT_ILLCMD: return "unknown/unimplemented command"; - case DMJ_RESP_STAT_BADMODE: return "bad mode"; - case DMJ_RESP_STAT_NOSUCHMODE: return "no such mode available"; - case DMJ_RESP_STAT_BADARG: return "illegal argument"; - case DMJ_RESP_STAT_ILLSTATE: return "wrong state for command"; - default: return "???"; - } -} -inline static int dmj_check_retval(int ret, int len, struct device *dev, - const char *pfix, bool check_pos_val, int lmin, int lmax) -{ - if (ret < 0) { - dev_err(dev, "%s: USB fail: %d\n", pfix, ret); - return ret; - } - if (ret && check_pos_val) { - dev_err(dev, "%s: USB protocol fail: %s (%d)\n", pfix, dmj_get_protoerr(ret), ret); - return -EIO; - } - if (len < lmin && lmin >= 0) { - dev_err(dev, "%s: USB reply too short: %d\n", pfix, len); - return -EREMOTEIO; - } - if (len > lmax && lmax >= 0) { - dev_err(dev, "%s: USB reply too long: %d\n", pfix, len); - return -EMSGSIZE; - } - - return 0; -} - -/* TODO: split up in "raw" read & writes, and higher-level ones with cmd and - * repstat, because the way this is currently overloaded, is, bad */ -int dmj_transfer(struct platform_device *pdev, int cmd, int recvflags, - const void *wbuf, int wbufsize, void **rbuf, int *rbufsize); - -inline static int dmj_read(struct platform_device *pdev, int recvflags, - void **rbuf, int *rbufsize) -{ - return dmj_transfer(pdev, -1, recvflags, NULL, 0, rbuf, rbufsize); -} - -inline static int dmj_write(struct platform_device *pdev, int cmd, - const void *wbuf, int wbufsize) -{ - return dmj_transfer(pdev, cmd, DMJ_XFER_FLAGS_PARSE_RESP, wbuf, wbufsize, NULL, NULL); -} - -#endif diff --git a/host/modules/dmj-char.c b/host/modules/dragonprobe-char.c similarity index 53% rename from host/modules/dmj-char.c rename to host/modules/dragonprobe-char.c index b43d0ca..adb9829 100644 --- a/host/modules/dmj-char.c +++ b/host/modules/dragonprobe-char.c @@ -23,16 +23,16 @@ #include #if 0 -#include +#include #else -#include "dmj.h" +#include "dragonprobe.h" #endif -#define HARDWARE_NAME "DapperMime-JTAG" -#define DEVICE_NAME "dmj-char" -#define CLASS_NAME "dmj" +#define HARDWARE_NAME "Dragon Probe" +#define DEVICE_NAME "dragonprobe-char" +#define CLASS_NAME "dragonprobe" -struct dmj_char_dev { +struct dp_char_dev { struct cdev cdev; struct device *dev; struct platform_device *pdev; @@ -42,22 +42,22 @@ struct dmj_char_dev { static int n_cdevs = 0; static spinlock_t ndevs_lock; -static int dmj_char_major; -static struct class *dmj_char_class; +static int dp_char_major; +static struct class *dp_char_class; -static ssize_t dmj_char_read(struct file *file, char *buf, size_t len, loff_t *loff) +static ssize_t dp_char_read(struct file *file, char *buf, size_t len, loff_t *loff) { int res, ilen; unsigned long ret; - struct dmj_char_dev *dmjch = file->private_data; + struct dp_char_dev *dpch = file->private_data; void *kbuf = NULL; - struct device *dev = dmjch->dev; + struct device *dev = dpch->dev; if (len > INT_MAX) return -EINVAL; ilen = (int)len; /* no flags: act like libusb read */ - res = dmj_transfer(dmjch->pdev, -1, 0/*DMJ_XFER_FLAGS_FILL_RECVBUF*/, NULL, 0, &kbuf, &ilen); + res = dp_transfer(dpch->pdev, -1, 0/*DP_XFER_FLAGS_FILL_RECVBUF*/, NULL, 0, &kbuf, &ilen); if (res < 0 || ilen < 0 || !kbuf) { //dev_warn(dev, "err res=%d ilen=%d kbuf=%p\n", res, ilen, kbuf); if (kbuf) kfree(kbuf); @@ -71,11 +71,11 @@ static ssize_t dmj_char_read(struct file *file, char *buf, size_t len, loff_t *l return (ssize_t)ilen; } -static ssize_t dmj_char_write(struct file *file, const char *buf, size_t len, loff_t *off) +static ssize_t dp_char_write(struct file *file, const char *buf, size_t len, loff_t *off) { unsigned long ret; int res; - struct dmj_char_dev *dmjch = file->private_data; + struct dp_char_dev *dpch = file->private_data; void *kbuf; kbuf = kmalloc(len, GFP_KERNEL); @@ -87,47 +87,47 @@ static ssize_t dmj_char_write(struct file *file, const char *buf, size_t len, lo return -EFAULT; } - res = dmj_transfer(dmjch->pdev, -1, 0, kbuf, len, NULL, NULL); + res = dp_transfer(dpch->pdev, -1, 0, kbuf, len, NULL, NULL); kfree(kbuf); return (res < 0) ? res : len; } -static int dmj_char_open(struct inode *inode, struct file *file) +static int dp_char_open(struct inode *inode, struct file *file) { - struct dmj_char_dev *dmjch; + struct dp_char_dev *dpch; - dmjch = container_of(inode->i_cdev, struct dmj_char_dev, cdev); + dpch = container_of(inode->i_cdev, struct dp_char_dev, cdev); - file->private_data = dmjch; + file->private_data = dpch; return 0; } -static int dmj_char_release(struct inode *inode, struct file *file) +static int dp_char_release(struct inode *inode, struct file *file) { - struct dmj_char_dev *dmjch; + struct dp_char_dev *dpch; - dmjch = container_of(inode->i_cdev, struct dmj_char_dev, cdev); + dpch = container_of(inode->i_cdev, struct dp_char_dev, cdev); return 0; } -static const struct file_operations dmj_char_fops = { +static const struct file_operations dp_char_fops = { .owner = THIS_MODULE, .llseek = no_llseek, - .read = dmj_char_read, - .write = dmj_char_write, + .read = dp_char_read, + .write = dp_char_write, .unlocked_ioctl = NULL, - .open = dmj_char_open, - .release = dmj_char_release + .open = dp_char_open, + .release = dp_char_release }; -static int dmj_char_probe(struct platform_device *pdev) +static int dp_char_probe(struct platform_device *pdev) { int ret, minor; struct device *device; struct device *pd = &pdev->dev; - struct dmj_char_dev *dmjch; + struct dp_char_dev *dpch; spin_lock(&ndevs_lock); minor = n_cdevs; @@ -135,57 +135,57 @@ static int dmj_char_probe(struct platform_device *pdev) spin_unlock(&ndevs_lock); dev_info(pd, HARDWARE_NAME " /dev entries driver, major=%d, minor=%d\n", - dmj_char_major, minor); + dp_char_major, minor); - dmjch = devm_kzalloc(pd, sizeof(*dmjch), GFP_KERNEL); - if (!dmjch) return -ENOMEM; + dpch = devm_kzalloc(pd, sizeof(*dpch), GFP_KERNEL); + if (!dpch) return -ENOMEM; - platform_set_drvdata(pdev, dmjch); + platform_set_drvdata(pdev, dpch); - cdev_init(&dmjch->cdev, &dmj_char_fops); - ret = cdev_add(&dmjch->cdev, MKDEV(dmj_char_major, minor), 1); + cdev_init(&dpch->cdev, &dp_char_fops); + ret = cdev_add(&dpch->cdev, MKDEV(dp_char_major, minor), 1); if (ret < 0) { dev_err(pd, "failed to create cdev: %d\n", ret); return ret; } - device = device_create(dmj_char_class, pd, MKDEV(dmj_char_major, minor), dmjch, "dmj-%d", minor); + device = device_create(dp_char_class, pd, MKDEV(dp_char_major, minor), dpch, "dragonprobe-%d", minor); if (IS_ERR(device)) { ret = PTR_ERR(device); dev_err(pd, "failed to create device: %d\n", ret); - cdev_del(&dmjch->cdev); + cdev_del(&dpch->cdev); return ret; } - dev_notice(device, "created device /dev/dmj-%d\n", minor); + dev_notice(device, "created device /dev/dragonprobe-%d\n", minor); - dmjch->dev = device; - dmjch->minor = minor; - dmjch->pdev = pdev; + dpch->dev = device; + dpch->minor = minor; + dpch->pdev = pdev; return 0; } -static int dmj_char_remove(struct platform_device *pdev) +static int dp_char_remove(struct platform_device *pdev) { - struct dmj_char_dev *dmjch = platform_get_drvdata(pdev); + struct dp_char_dev *dpch = platform_get_drvdata(pdev); - device_destroy(dmj_char_class, MKDEV(dmj_char_major, dmjch->minor)); - cdev_del(&dmjch->cdev); - unregister_chrdev(MKDEV(dmj_char_major, dmjch->minor), CLASS_NAME); + device_destroy(dp_char_class, MKDEV(dp_char_major, dpch->minor)); + cdev_del(&dpch->cdev); + unregister_chrdev(MKDEV(dp_char_major, dpch->minor), CLASS_NAME); return 0; } -static struct platform_driver dmj_char_driver = { +static struct platform_driver dp_char_driver = { .driver = { - .name = "dmj-char" + .name = "dragonprobe-char" }, - .probe = dmj_char_probe, - .remove = dmj_char_remove + .probe = dp_char_probe, + .remove = dp_char_remove }; -/*module_platform_driver(dmj_char_driver);*/ +/*module_platform_driver(dp_char_driver);*/ -static int __init dmj_char_init(void) +static int __init dp_char_init(void) { int ret, major; struct class *class; @@ -213,33 +213,33 @@ static int __init dmj_char_init(void) } printk(KERN_DEBUG DEVICE_NAME " created class\n"); - dmj_char_major = major; - dmj_char_class = class; + dp_char_major = major; + dp_char_class = class; - platform_driver_register(&dmj_char_driver); + platform_driver_register(&dp_char_driver); return 0; } -static void __exit dmj_char_exit(void) +static void __exit dp_char_exit(void) { - platform_driver_unregister(&dmj_char_driver); + platform_driver_unregister(&dp_char_driver); spin_lock(&ndevs_lock); n_cdevs = 0; spin_unlock(&ndevs_lock); - class_destroy(dmj_char_class); - unregister_chrdev(dmj_char_major, CLASS_NAME); + class_destroy(dp_char_class); + unregister_chrdev(dp_char_major, CLASS_NAME); - dmj_char_major = -1; - dmj_char_class = NULL; + dp_char_major = -1; + dp_char_class = NULL; } -module_init(dmj_char_init); -module_exit(dmj_char_exit); +module_init(dp_char_init); +module_exit(dp_char_exit); MODULE_AUTHOR("sys64738 "); MODULE_AUTHOR("haskal "); MODULE_DESCRIPTION("Character device for the " HARDWARE_NAME " USB multitool"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:dmj-char"); +MODULE_ALIAS("platform:dragonprobe-char"); diff --git a/host/modules/dmj-hwmon.c b/host/modules/dragonprobe-hwmon.c similarity index 52% rename from host/modules/dmj-hwmon.c rename to host/modules/dragonprobe-hwmon.c index 333d75f..9083f3a 100644 --- a/host/modules/dmj-hwmon.c +++ b/host/modules/dragonprobe-hwmon.c @@ -19,27 +19,27 @@ #include #if 0 -#include +#include #else -#include "dmj.h" +#include "dragonprobe.h" #endif -#define HARDWARE_NAME "DapperMime-JTAG" -#define HWMON_NAME "dmj" +#define HARDWARE_NAME "Dragon Probe" +#define HWMON_NAME "dragonprobe" -#define DMJ_TEMP_CMD_GET_ADDR 0x00 -#define DMJ_TEMP_CMD_SET_ADDR 0x01 -#define DMJ_TEMP_CMD_GET_TEMP 0x02 -#define DMJ_TEMP_CMD_GET_MIN 0x03 -#define DMJ_TEMP_CMD_GET_MAX 0x04 -#define DMJ_TEMP_CMD_GET_CRIT 0x05 +#define DP_TEMP_CMD_GET_ADDR 0x00 +#define DP_TEMP_CMD_SET_ADDR 0x01 +#define DP_TEMP_CMD_GET_TEMP 0x02 +#define DP_TEMP_CMD_GET_MIN 0x03 +#define DP_TEMP_CMD_GET_MAX 0x04 +#define DP_TEMP_CMD_GET_CRIT 0x05 -struct dmj_hwmon { +struct dp_hwmon { struct platform_device *pdev; struct device *hwmon_dev; }; -static umode_t dmj_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, +static umode_t dp_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, uint32_t attr, int ch) { switch (attr) { @@ -53,10 +53,10 @@ static umode_t dmj_hwmon_is_visible(const void *data, enum hwmon_sensor_types ty return 0; } } -static int dmj_hwmon_read(struct device *dev, enum hwmon_sensor_types type, +static int dp_hwmon_read(struct device *dev, enum hwmon_sensor_types type, uint32_t attr, int ch, long *val) { - struct dmj_hwmon *dmjh = dev_get_drvdata(dev); + struct dp_hwmon *dph = dev_get_drvdata(dev); uint8_t subcmd, *rbuf; uint16_t rval; int ret, rlen; @@ -66,25 +66,25 @@ static int dmj_hwmon_read(struct device *dev, enum hwmon_sensor_types type, *val = 1; return 0; case hwmon_temp_input: - subcmd = DMJ_TEMP_CMD_GET_TEMP; + subcmd = DP_TEMP_CMD_GET_TEMP; break; case hwmon_temp_min: - subcmd = DMJ_TEMP_CMD_GET_MIN; + subcmd = DP_TEMP_CMD_GET_MIN; break; case hwmon_temp_max: - subcmd = DMJ_TEMP_CMD_GET_MAX; + subcmd = DP_TEMP_CMD_GET_MAX; break; case hwmon_temp_crit: - subcmd = DMJ_TEMP_CMD_GET_CRIT; + subcmd = DP_TEMP_CMD_GET_CRIT; break; default: return -ENOTSUPP; } - ret = dmj_transfer(dmjh->pdev, DMJ_CMD_MODE1_TEMPSENSOR, - DMJ_XFER_FLAGS_PARSE_RESP, &subcmd, sizeof(subcmd), + ret = dp_transfer(dph->pdev, DP_CMD_MODE1_TEMPSENSOR, + DP_XFER_FLAGS_PARSE_RESP, &subcmd, sizeof(subcmd), (void**)&rbuf, &rlen); - ret = dmj_check_retval(ret, rlen, dev, "hwmon read", true, 2, 2); + ret = dp_check_retval(ret, rlen, dev, "hwmon read", true, 2, 2); if (!ret) { /* rval is 8.4 fixed point, bit 0x1000 is the sign bit, 0xe000 are flags */ rval = (uint16_t)rbuf[0] | ((uint16_t)rbuf[1] << 8); @@ -98,22 +98,22 @@ static int dmj_hwmon_read(struct device *dev, enum hwmon_sensor_types type, return ret; } -static const struct hwmon_channel_info *dmj_hwmon_info[] = { +static const struct hwmon_channel_info *dp_hwmon_info[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_TYPE | HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | HWMON_T_CRIT), NULL }; -static const struct hwmon_ops dmj_hwmon_ops = { - .is_visible = dmj_hwmon_is_visible, - .read = dmj_hwmon_read, - .write = NULL/*dmj_hwmon_write*/ +static const struct hwmon_ops dp_hwmon_ops = { + .is_visible = dp_hwmon_is_visible, + .read = dp_hwmon_read, + .write = NULL/*dp_hwmon_write*/ }; -static const struct hwmon_chip_info dmj_chip_info = { - .ops = &dmj_hwmon_ops, - .info = dmj_hwmon_info +static const struct hwmon_chip_info dp_chip_info = { + .ops = &dp_hwmon_ops, + .info = dp_hwmon_info }; -static int dmj_hwmon_check_hw(struct platform_device *pdev) +static int dp_hwmon_check_hw(struct platform_device *pdev) { struct device *dev = &pdev->dev; uint16_t m1ver; @@ -122,9 +122,9 @@ static int dmj_hwmon_check_hw(struct platform_device *pdev) int ret = 0, len; uint8_t *buf = NULL; - ret = dmj_transfer(pdev, DMJ_CMD_CFG_GET_CUR_MODE, - DMJ_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); - ret = dmj_check_retval(ret, len, dev, "hwmon test 1", true, sizeof(curmode), sizeof(curmode)); + ret = dp_transfer(pdev, DP_CMD_CFG_GET_CUR_MODE, + DP_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); + ret = dp_check_retval(ret, len, dev, "hwmon test 1", true, sizeof(curmode), sizeof(curmode)); if (ret < 0 || !buf) goto out; curmode = buf[0]; @@ -135,9 +135,9 @@ static int dmj_hwmon_check_hw(struct platform_device *pdev) goto out; } - ret = dmj_transfer(pdev, (1<<4) | DMJ_CMD_MODE_GET_VERSION, - DMJ_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); - ret = dmj_check_retval(ret, len, dev, "hwmon test 2", true, sizeof(m1ver), sizeof(m1ver)); + ret = dp_transfer(pdev, (1<<4) | DP_CMD_MODE_GET_VERSION, + DP_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); + ret = dp_check_retval(ret, len, dev, "hwmon test 2", true, sizeof(m1ver), sizeof(m1ver)); if (ret < 0 || !buf) goto out; m1ver = (uint16_t)buf[0] | ((uint16_t)buf[1] << 8); @@ -149,13 +149,13 @@ static int dmj_hwmon_check_hw(struct platform_device *pdev) goto out; } - ret = dmj_transfer(pdev, (1<<4) | DMJ_CMD_MODE_GET_FEATURES, - DMJ_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); - ret = dmj_check_retval(ret, len, dev, "hwmon test 3", true, sizeof(m1feat), sizeof(m1feat)); + ret = dp_transfer(pdev, (1<<4) | DP_CMD_MODE_GET_FEATURES, + DP_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); + ret = dp_check_retval(ret, len, dev, "hwmon test 3", true, sizeof(m1feat), sizeof(m1feat)); if (ret < 0 || !buf) goto out; m1feat = buf[0]; kfree(buf); buf = NULL; - if (!(m1feat & DMJ_FEATURE_MODE1_I2C)) { + if (!(m1feat & DP_FEATURE_MODE1_I2C)) { dev_err(dev, "device's mode 1 does not support hwmon tempsensor\n"); ret = -EIO; goto out; @@ -167,55 +167,55 @@ out: return ret; } -static int dmj_hwmon_probe(struct platform_device *pdev) +static int dp_hwmon_probe(struct platform_device *pdev) { - struct dmj_hwmon *dmjh; + struct dp_hwmon *dph; struct device *dev = &pdev->dev; int ret; - ret = dmj_hwmon_check_hw(pdev); + ret = dp_hwmon_check_hw(pdev); if (ret) { dev_err(dev, "hw check failed: %d\n", ret); return -ENODEV; } - dmjh = devm_kzalloc(dev, sizeof(*dmjh), GFP_KERNEL); - if (!dmjh) return -ENOMEM; + dph = devm_kzalloc(dev, sizeof(*dph), GFP_KERNEL); + if (!dph) return -ENOMEM; - dmjh->pdev = pdev; + dph->pdev = pdev; - platform_set_drvdata(pdev, dmjh); + platform_set_drvdata(pdev, dph); - dmjh->hwmon_dev = hwmon_device_register_with_info(dev, HWMON_NAME, dmjh, - &dmj_chip_info, NULL); - if (IS_ERR(dmjh->hwmon_dev)) { - ret = PTR_ERR(dmjh->hwmon_dev); + dph->hwmon_dev = hwmon_device_register_with_info(dev, HWMON_NAME, dph, + &dp_chip_info, NULL); + if (IS_ERR(dph->hwmon_dev)) { + ret = PTR_ERR(dph->hwmon_dev); dev_err(dev, "hwmon device registration failed\n"); } return ret; } -static int dmj_hwmon_remove(struct platform_device *pdev) +static int dp_hwmon_remove(struct platform_device *pdev) { - struct dmj_hwmon *dmjh = platform_get_drvdata(pdev); + struct dp_hwmon *dph = platform_get_drvdata(pdev); - hwmon_device_unregister(dmjh->hwmon_dev); + hwmon_device_unregister(dph->hwmon_dev); return 0; } -static struct platform_driver dmj_hwmon_driver = { +static struct platform_driver dp_hwmon_driver = { .driver = { - "dmj-hwmon", + "dragonprobe-hwmon", }, - .probe = dmj_hwmon_probe, - .remove = dmj_hwmon_remove + .probe = dp_hwmon_probe, + .remove = dp_hwmon_remove }; -module_platform_driver(dmj_hwmon_driver); +module_platform_driver(dp_hwmon_driver); MODULE_AUTHOR("sys64738 "); MODULE_AUTHOR("haskal "); MODULE_DESCRIPTION("Hwmon driver for the " HARDWARE_NAME " USB multitool"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:dmj-hwmon"); +MODULE_ALIAS("platform:dragonprobe-hwmon"); diff --git a/host/modules/dmj.c b/host/modules/dragonprobe.c similarity index 59% rename from host/modules/dmj.c rename to host/modules/dragonprobe.c index be694b4..74ac0d6 100644 --- a/host/modules/dmj.c +++ b/host/modules/dragonprobe.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Driver for the DapperMime-JTAG USB multitool: base MFD driver + * Driver for the Dragon Probe USB multitool: base MFD driver * * Copyright (c) 2021 sys64738 and haskal * @@ -20,23 +20,23 @@ #include #if 0 -#include +#include #else -#include "dmj.h" +#include "dragonprobe.h" #endif -#define HARDWARE_NAME "DapperMime-JTAG" -#define HARDWARE_NAME_SYMBOLIC "dappermime-jtag" +#define HARDWARE_NAME "Dragon Probe" +#define HARDWARE_NAME_SYMBOLIC "dragonprobe" -#define DMJ_USB_TIMEOUT 500 +#define DP_USB_TIMEOUT 500 -#define DMJ_RESP_HDR_SIZE 4 +#define DP_RESP_HDR_SIZE 4 /* endpoint indices, not addresses */ -#define DMJ_VND_CFG_EP_OUT 0 -#define DMJ_VND_CFG_EP_IN 1 +#define DP_VND_CFG_EP_OUT 0 +#define DP_VND_CFG_EP_IN 1 -struct dmj_dev { +struct dp_dev { struct usb_device *usb_dev; struct usb_interface *interface; uint8_t ep_in; @@ -45,12 +45,12 @@ struct dmj_dev { spinlock_t disconnect_lock; bool disconnect; - uint8_t dmj_mode, dmj_m1feature; + uint8_t dp_mode, dp_m1feature; }; /* USB transfers */ -static void *dmj_prep_buf(int cmd, const void *wbuf, int *wbufsize, gfp_t gfp) +static void *dp_prep_buf(int cmd, const void *wbuf, int *wbufsize, gfp_t gfp) { int len; uint8_t *buf; @@ -79,41 +79,41 @@ static void *dmj_prep_buf(int cmd, const void *wbuf, int *wbufsize, gfp_t gfp) return buf; } -static int dmj_send_wait(struct dmj_dev *dmj, int cmd, const void *wbuf, int wbufsize) +static int dp_send_wait(struct dp_dev *dp, int cmd, const void *wbuf, int wbufsize) { int ret = 0; int len = wbufsize, actual; void *buf; - buf = dmj_prep_buf(cmd, wbuf, &len, GFP_KERNEL); + buf = dp_prep_buf(cmd, wbuf, &len, GFP_KERNEL); if (!buf) return -ENOMEM; - ret = usb_bulk_msg(dmj->usb_dev, usb_sndbulkpipe(dmj->usb_dev, dmj->ep_out), - buf, len, &actual, DMJ_USB_TIMEOUT); + ret = usb_bulk_msg(dp->usb_dev, usb_sndbulkpipe(dp->usb_dev, dp->ep_out), + buf, len, &actual, DP_USB_TIMEOUT); kfree(buf); return ret; } -int dmj_xfer_internal(struct dmj_dev *dmj, int cmd, int recvflags, +int dp_xfer_internal(struct dp_dev *dp, int cmd, int recvflags, const void *wbuf, int wbufsize, void **rbuf, int *rbufsize) { int ret = 0, actual, pl_off, todo; - struct device *dev = &dmj->interface->dev; + struct device *dev = &dp->interface->dev; uint32_t pl_len; void *tmpbuf = NULL, *longbuf = NULL; uint8_t *bbuf; uint8_t respstat; - spin_lock(&dmj->disconnect_lock); - if (dmj->disconnect) ret = -ENODEV; - spin_unlock(&dmj->disconnect_lock); + spin_lock(&dp->disconnect_lock); + if (dp->disconnect) ret = -ENODEV; + spin_unlock(&dp->disconnect_lock); if (ret) return ret; if ((cmd >= 0 && cmd <= 0xff) || (wbufsize && wbuf)) { - ret = dmj_send_wait(dmj, cmd, wbuf, wbufsize); + ret = dp_send_wait(dp, cmd, wbuf, wbufsize); if (ret < 0) { dev_err(dev, "USB write failed: %d\n", ret); return ret; @@ -122,7 +122,7 @@ int dmj_xfer_internal(struct dmj_dev *dmj, int cmd, int recvflags, if (rbuf) *rbuf = NULL; - if (recvflags & DMJ_XFER_FLAGS_PARSE_RESP) { + if (recvflags & DP_XFER_FLAGS_PARSE_RESP) { /* * if we do want to parse the response, we'll split the reads into * blocks of 64 bytes, first to read the response header, and then @@ -136,8 +136,8 @@ int dmj_xfer_internal(struct dmj_dev *dmj, int cmd, int recvflags, tmpbuf = kmalloc(64, GFP_KERNEL); if (!tmpbuf) return -ENOMEM; /* first read: 64b, with header data to parse */ - ret = usb_bulk_msg(dmj->usb_dev, usb_rcvbulkpipe(dmj->usb_dev, dmj->ep_in), - tmpbuf, 64, &actual, DMJ_USB_TIMEOUT); + ret = usb_bulk_msg(dp->usb_dev, usb_rcvbulkpipe(dp->usb_dev, dp->ep_in), + tmpbuf, 64, &actual, DP_USB_TIMEOUT); if (ret < 0) goto err_freetmp; if (actual < 0) { ret = -EREMOTEIO; goto err_freetmp; } @@ -195,8 +195,8 @@ int dmj_xfer_internal(struct dmj_dev *dmj, int cmd, int recvflags, actual = 64; if (todo < actual) actual = todo; - ret = usb_bulk_msg(dmj->usb_dev, usb_rcvbulkpipe(dmj->usb_dev, dmj->ep_in), - tmpbuf, actual, &actual, DMJ_USB_TIMEOUT); + ret = usb_bulk_msg(dp->usb_dev, usb_rcvbulkpipe(dp->usb_dev, dp->ep_in), + tmpbuf, actual, &actual, DP_USB_TIMEOUT); if (ret < 0) goto err_freelong; if (actual < 0) { ret = -EREMOTEIO; goto err_freelong; } if (actual > todo) { @@ -223,7 +223,7 @@ int dmj_xfer_internal(struct dmj_dev *dmj, int cmd, int recvflags, } else { /* * otherwise, read max. rbufsize bytes (if using - * DMJ_XFER_FLAGS_FILL_RECVBUF, will try to fill it exactly, but it + * DP_XFER_FLAGS_FILL_RECVBUF, will try to fill it exactly, but it * will error when going beyond!). also done in 64b chunks */ @@ -232,7 +232,7 @@ int dmj_xfer_internal(struct dmj_dev *dmj, int cmd, int recvflags, return 0; } - if (recvflags & DMJ_XFER_FLAGS_FILL_RECVBUF) { + if (recvflags & DP_XFER_FLAGS_FILL_RECVBUF) { tmpbuf = kmalloc(64, GFP_KERNEL); if (!tmpbuf) return -ENOMEM; longbuf = kmalloc(*rbufsize, GFP_KERNEL); @@ -244,8 +244,8 @@ int dmj_xfer_internal(struct dmj_dev *dmj, int cmd, int recvflags, actual = 64; if (todo < actual) actual = todo; - ret = usb_bulk_msg(dmj->usb_dev, usb_rcvbulkpipe(dmj->usb_dev, dmj->ep_in), - tmpbuf, actual, &actual, DMJ_USB_TIMEOUT); + ret = usb_bulk_msg(dp->usb_dev, usb_rcvbulkpipe(dp->usb_dev, dp->ep_in), + tmpbuf, actual, &actual, DP_USB_TIMEOUT); if (ret < 0) goto err_freelong; if (actual < 0) { ret = -EREMOTEIO; goto err_freelong; } if (actual > todo) { ret = -EMSGSIZE; goto err_freelong; } @@ -265,8 +265,8 @@ int dmj_xfer_internal(struct dmj_dev *dmj, int cmd, int recvflags, longbuf = kmalloc(*rbufsize, GFP_KERNEL); if (!longbuf) return -ENOMEM; - ret = usb_bulk_msg(dmj->usb_dev, usb_rcvbulkpipe(dmj->usb_dev, dmj->ep_in), - longbuf, *rbufsize, rbufsize, DMJ_USB_TIMEOUT); + ret = usb_bulk_msg(dp->usb_dev, usb_rcvbulkpipe(dp->usb_dev, dp->ep_in), + longbuf, *rbufsize, rbufsize, DP_USB_TIMEOUT); if (ret < 0) goto err_freelong; if (*rbufsize < 0) { //dev_warn(dev, "remoteio\n"); @@ -290,37 +290,37 @@ err_freetmp: return ret; } -int dmj_transfer(struct platform_device *pdev, int cmd, int recvflags, +int dp_transfer(struct platform_device *pdev, int cmd, int recvflags, const void *wbuf, int wbufsize, void **rbuf, int *rbufsize) { - struct dmj_dev *dmj; + struct dp_dev *dp; - dmj = dev_get_drvdata(pdev->dev.parent); + dp = dev_get_drvdata(pdev->dev.parent); - return dmj_xfer_internal(dmj, cmd, recvflags, wbuf, wbufsize, rbuf, rbufsize); + return dp_xfer_internal(dp, cmd, recvflags, wbuf, wbufsize, rbuf, rbufsize); } -EXPORT_SYMBOL(dmj_transfer); +EXPORT_SYMBOL(dp_transfer); /* stuff on init */ -static int dmj_check_hw(struct dmj_dev *dmj) +static int dp_check_hw(struct dp_dev *dp) { - struct device *dev = &dmj->interface->dev; + struct device *dev = &dp->interface->dev; int ret, len; uint16_t protover; uint8_t *buf = NULL; - ret = dmj_xfer_internal(dmj, DMJ_CMD_CFG_GET_VERSION, - DMJ_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); - ret = dmj_check_retval(ret, len, dev, "version check", true, sizeof(protover), sizeof(protover)); + ret = dp_xfer_internal(dp, DP_CMD_CFG_GET_VERSION, + DP_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); + ret = dp_check_retval(ret, len, dev, "version check", true, sizeof(protover), sizeof(protover)); if (ret < 0 || !buf) goto out; protover = (uint16_t)buf[0] | ((uint16_t)buf[1] << 8); - if (protover != DMJ_USB_CFG_PROTO_VER) { - dev_err(&dmj->interface->dev, HARDWARE_NAME " config protocol version 0x%04x too %s\n", - protover, (protover > DMJ_USB_CFG_PROTO_VER) ? "new" : "old"); + if (protover != DP_USB_CFG_PROTO_VER) { + dev_err(&dp->interface->dev, HARDWARE_NAME " config protocol version 0x%04x too %s\n", + protover, (protover > DP_USB_CFG_PROTO_VER) ? "new" : "old"); ret = -ENODEV; } else @@ -330,19 +330,19 @@ out: if (buf) kfree(buf); return ret; } -static int dmj_print_info(struct dmj_dev *dmj) +static int dp_print_info(struct dp_dev *dp) { int ret, i, j, len; uint16_t modes, mversion; uint8_t curmode, features; - struct device *dev = &dmj->interface->dev; + struct device *dev = &dp->interface->dev; uint8_t *buf; char modeinfo[16], namebuf[64]; /* info string */ - ret = dmj_xfer_internal(dmj, DMJ_CMD_CFG_GET_INFOSTR, - DMJ_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); - ret = dmj_check_retval(ret, len, dev, "get info", true, -1, sizeof(namebuf)-1); + ret = dp_xfer_internal(dp, DP_CMD_CFG_GET_INFOSTR, + DP_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); + ret = dp_check_retval(ret, len, dev, "get info", true, -1, sizeof(namebuf)-1); if (ret < 0 || !buf) goto out; memcpy(namebuf, buf, len); namebuf[len] = 0; @@ -350,17 +350,17 @@ static int dmj_print_info(struct dmj_dev *dmj) kfree(buf); buf = NULL; /* cur mode */ - ret = dmj_xfer_internal(dmj, DMJ_CMD_CFG_GET_CUR_MODE, - DMJ_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); - ret = dmj_check_retval(ret, len, dev, "get info", true, sizeof(curmode), sizeof(curmode)); + ret = dp_xfer_internal(dp, DP_CMD_CFG_GET_CUR_MODE, + DP_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); + ret = dp_check_retval(ret, len, dev, "get info", true, sizeof(curmode), sizeof(curmode)); if (ret < 0 || !buf) goto out; - dmj->dmj_mode = curmode = buf[0]; + dp->dp_mode = curmode = buf[0]; kfree(buf); buf = NULL; /* map of available modes */ - ret = dmj_xfer_internal(dmj, DMJ_CMD_CFG_GET_MODES, - DMJ_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); - ret = dmj_check_retval(ret, len, dev, "get info", true, sizeof(modes), sizeof(modes)); + ret = dp_xfer_internal(dp, DP_CMD_CFG_GET_MODES, + DP_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); + ret = dp_check_retval(ret, len, dev, "get info", true, sizeof(modes), sizeof(modes)); if (ret < 0 || !buf) goto out; modes = (uint16_t)buf[0] | ((uint16_t)buf[1] << 8); kfree(buf); buf = NULL; @@ -379,31 +379,31 @@ static int dmj_print_info(struct dmj_dev *dmj) if (!(modes & (1<dmj_m1feature = features; + if (i == 1) dp->dp_m1feature = features; for (j = 0; j < 8; ++j) { if (features & (1<cur_altsetting; struct usb_endpoint_descriptor *epin = NULL, *epout = NULL, *curep; struct device *dev = &itf->dev; - struct dmj_dev *dmj; + struct dp_dev *dp; int ret, i; if (hostitf->desc.bNumEndpoints < 2) { @@ -479,46 +479,46 @@ static int dmj_probe(struct usb_interface *itf, const struct usb_device_id *usb_ return -ENODEV; } - dmj = kzalloc(sizeof(*dmj), GFP_KERNEL); - if (!dmj) return -ENOMEM; + dp = kzalloc(sizeof(*dp), GFP_KERNEL); + if (!dp) return -ENOMEM; - dmj->ep_out = epout->bEndpointAddress; - dmj->ep_in = epin->bEndpointAddress; - dmj->usb_dev = usb_get_dev(interface_to_usbdev(itf)); - dmj->interface = itf; - usb_set_intfdata(itf, dmj); + dp->ep_out = epout->bEndpointAddress; + dp->ep_in = epin->bEndpointAddress; + dp->usb_dev = usb_get_dev(interface_to_usbdev(itf)); + dp->interface = itf; + usb_set_intfdata(itf, dp); - spin_lock_init(&dmj->disconnect_lock); + spin_lock_init(&dp->disconnect_lock); - ret = dmj_hw_init(dmj); + ret = dp_hw_init(dp); if (ret < 0) { dev_err(dev, "failed to initialize hardware\n"); goto out_free; } - ret = mfd_add_hotplug_devices(dev, dmj_mfd_char, ARRAY_SIZE(dmj_mfd_char)); + ret = mfd_add_hotplug_devices(dev, dp_mfd_char, ARRAY_SIZE(dp_mfd_char)); if (ret) { dev_err(dev, "failed to add MFD character devices\n"); goto out_free; } - if (dmj->dmj_mode == 1) { - if (dmj->dmj_m1feature & DMJ_FEATURE_MODE1_SPI) { - ret = mfd_add_hotplug_devices(dev, dmj_mfd_spi, ARRAY_SIZE(dmj_mfd_spi)); + if (dp->dp_mode == 1) { + if (dp->dp_m1feature & DP_FEATURE_MODE1_SPI) { + ret = mfd_add_hotplug_devices(dev, dp_mfd_spi, ARRAY_SIZE(dp_mfd_spi)); if (ret) { dev_err(dev, "failed to add MFD SPI devices\n"); goto out_free; } } - if (dmj->dmj_m1feature & DMJ_FEATURE_MODE1_I2C) { - ret = mfd_add_hotplug_devices(dev, dmj_mfd_i2c, ARRAY_SIZE(dmj_mfd_i2c)); + if (dp->dp_m1feature & DP_FEATURE_MODE1_I2C) { + ret = mfd_add_hotplug_devices(dev, dp_mfd_i2c, ARRAY_SIZE(dp_mfd_i2c)); if (ret) { dev_err(dev, "failed to add MFD I2C devices\n"); goto out_free; } } - if (dmj->dmj_m1feature & DMJ_FEATURE_MODE1_TEMPSENSOR) { - ret = mfd_add_hotplug_devices(dev, dmj_mfd_hwmon, ARRAY_SIZE(dmj_mfd_hwmon)); + if (dp->dp_m1feature & DP_FEATURE_MODE1_TEMPSENSOR) { + ret = mfd_add_hotplug_devices(dev, dp_mfd_hwmon, ARRAY_SIZE(dp_mfd_hwmon)); if (ret) { dev_err(dev, "failed to add MFD hwmon devices\n"); goto out_free; @@ -529,69 +529,69 @@ static int dmj_probe(struct usb_interface *itf, const struct usb_device_id *usb_ return 0; out_free: - usb_put_dev(dmj->usb_dev); - kfree(dmj); + usb_put_dev(dp->usb_dev); + kfree(dp); return ret; } -static void dmj_disconnect(struct usb_interface *itf) +static void dp_disconnect(struct usb_interface *itf) { - struct dmj_dev *dmj = usb_get_intfdata(itf); + struct dp_dev *dp = usb_get_intfdata(itf); - spin_lock(&dmj->disconnect_lock); - dmj->disconnect = true; - spin_unlock(&dmj->disconnect_lock); + spin_lock(&dp->disconnect_lock); + dp->disconnect = true; + spin_unlock(&dp->disconnect_lock); mfd_remove_devices(&itf->dev); - usb_put_dev(dmj->usb_dev); + usb_put_dev(dp->usb_dev); - kfree(dmj); + kfree(dp); } -static int dmj_suspend(struct usb_interface *itf, pm_message_t message) +static int dp_suspend(struct usb_interface *itf, pm_message_t message) { - struct dmj_dev *dmj = usb_get_intfdata(itf); + struct dp_dev *dp = usb_get_intfdata(itf); (void)message; - spin_lock(&dmj->disconnect_lock); - dmj->disconnect = true; - spin_unlock(&dmj->disconnect_lock); + spin_lock(&dp->disconnect_lock); + dp->disconnect = true; + spin_unlock(&dp->disconnect_lock); return 0; } -static int dmj_resume(struct usb_interface *itf) +static int dp_resume(struct usb_interface *itf) { - struct dmj_dev *dmj = usb_get_intfdata(itf); + struct dp_dev *dp = usb_get_intfdata(itf); - dmj->disconnect = false; + dp->disconnect = false; return 0; } -static const struct usb_device_id dmj_table[] = { +static const struct usb_device_id dp_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(0xcafe, 0x1312, USB_CLASS_VENDOR_SPEC, 42, 69) }, { } }; -MODULE_DEVICE_TABLE(usb, dmj_table); +MODULE_DEVICE_TABLE(usb, dp_table); -static struct usb_driver dmj_driver = { +static struct usb_driver dp_driver = { .name = HARDWARE_NAME_SYMBOLIC, - .probe = dmj_probe, - .disconnect = dmj_disconnect, - .id_table = dmj_table, - .suspend = dmj_suspend, - .resume = dmj_resume, + .probe = dp_probe, + .disconnect = dp_disconnect, + .id_table = dp_table, + .suspend = dp_suspend, + .resume = dp_resume, }; -module_usb_driver(dmj_driver); +module_usb_driver(dp_driver); MODULE_AUTHOR("sys64738 "); MODULE_AUTHOR("haskal "); MODULE_DESCRIPTION("Core driver for the " HARDWARE_NAME " USB multitool"); MODULE_LICENSE("GPL v2"); -MODULE_SOFTDEP("post: dmj-char"); -MODULE_SOFTDEP("post: i2c-dmj"); -MODULE_SOFTDEP("post: spi-dmj"); -MODULE_SOFTDEP("post: dmj-hwmon"); +MODULE_SOFTDEP("post: dragonprobe-char"); +MODULE_SOFTDEP("post: dragonprobe-i2c"); +MODULE_SOFTDEP("post: dragonprobe-spi"); +MODULE_SOFTDEP("post: dragonprobe-hwmon"); diff --git a/host/modules/dragonprobe.h b/host/modules/dragonprobe.h new file mode 100644 index 0000000..5116111 --- /dev/null +++ b/host/modules/dragonprobe.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LINUX_USB_DAPPERMIMEJTAG_H +#define __LINUX_USB_DAPPERMIMEJTAG_H + +#define DP_USB_CFG_PROTO_VER 0x0010 + +#define DP_RESP_STAT_OK 0x00 +#define DP_RESP_STAT_ILLCMD 0x01 +#define DP_RESP_STAT_BADMODE 0x02 +#define DP_RESP_STAT_NOSUCHMODE 0x03 +#define DP_RESP_STAT_BADARG 0x04 +#define DP_RESP_STAT_ILLSTATE 0x05 + +#define DP_CMD_CFG_GET_VERSION 0x00 +#define DP_CMD_CFG_GET_MODES 0x01 +#define DP_CMD_CFG_GET_CUR_MODE 0x02 +#define DP_CMD_CFG_SET_CUR_MODE 0x03 +#define DP_CMD_CFG_GET_INFOSTR 0x04 + +#define DP_CMD_MODE_GET_NAME 0x00 +#define DP_CMD_MODE_GET_VERSION 0x01 +#define DP_CMD_MODE_GET_FEATURES 0x02 + +#define DP_CMD_MODE1_SPI 0x13 +#define DP_CMD_MODE1_I2C 0x14 +#define DP_CMD_MODE1_TEMPSENSOR 0x15 + +#define DP_FEATURE_MODE1_UART (1<<0) +#define DP_FEATURE_MODE1_CMSISDAP (1<<1) +#define DP_FEATURE_MODE1_SPI (1<<2) +#define DP_FEATURE_MODE1_I2C (1<<3) +#define DP_FEATURE_MODE1_TEMPSENSOR (1<<4) + +#define DP_XFER_FLAGS_PARSE_RESP (1<<0) +#define DP_XFER_FLAGS_FILL_RECVBUF (1<<1) + +inline static const char *dp_get_protoerr(int err) +{ + switch (err) { + case DP_RESP_STAT_OK: return "ok"; + case DP_RESP_STAT_ILLCMD: return "unknown/unimplemented command"; + case DP_RESP_STAT_BADMODE: return "bad mode"; + case DP_RESP_STAT_NOSUCHMODE: return "no such mode available"; + case DP_RESP_STAT_BADARG: return "illegal argument"; + case DP_RESP_STAT_ILLSTATE: return "wrong state for command"; + default: return "???"; + } +} +inline static int dp_check_retval(int ret, int len, struct device *dev, + const char *pfix, bool check_pos_val, int lmin, int lmax) +{ + if (ret < 0) { + dev_err(dev, "%s: USB fail: %d\n", pfix, ret); + return ret; + } + if (ret && check_pos_val) { + dev_err(dev, "%s: USB protocol fail: %s (%d)\n", pfix, dp_get_protoerr(ret), ret); + return -EIO; + } + if (len < lmin && lmin >= 0) { + dev_err(dev, "%s: USB reply too short: %d\n", pfix, len); + return -EREMOTEIO; + } + if (len > lmax && lmax >= 0) { + dev_err(dev, "%s: USB reply too long: %d\n", pfix, len); + return -EMSGSIZE; + } + + return 0; +} + +/* TODO: split up in "raw" read & writes, and higher-level ones with cmd and + * repstat, because the way this is currently overloaded, is, bad */ +int dp_transfer(struct platform_device *pdev, int cmd, int recvflags, + const void *wbuf, int wbufsize, void **rbuf, int *rbufsize); + +inline static int dp_read(struct platform_device *pdev, int recvflags, + void **rbuf, int *rbufsize) +{ + return dp_transfer(pdev, -1, recvflags, NULL, 0, rbuf, rbufsize); +} + +inline static int dp_write(struct platform_device *pdev, int cmd, + const void *wbuf, int wbufsize) +{ + return dp_transfer(pdev, cmd, DP_XFER_FLAGS_PARSE_RESP, wbuf, wbufsize, NULL, NULL); +} + +#endif diff --git a/host/modules/i2c-dmj.c b/host/modules/i2c-dragonprobe.c similarity index 52% rename from host/modules/i2c-dmj.c rename to host/modules/i2c-dragonprobe.c index 0bdc866..652873d 100644 --- a/host/modules/i2c-dmj.c +++ b/host/modules/i2c-dragonprobe.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Driver for the DapperMime-JTAG USB multitool: USB-I2C adapter + * Driver for the Dragon Probe USB multitool: USB-I2C adapter * * Copyright (c) 2021 sys64738 and haskal * @@ -18,42 +18,42 @@ #include #if 0 -#include +#include #else -#include "dmj.h" +#include "dragonprobe.h" #endif -#define HARDWARE_NAME "DapperMime-JTAG" +#define HARDWARE_NAME "Dragon Probe" -#define DMJ_I2C_MAX_XFER_SIZE 64 +#define DP_I2C_MAX_XFER_SIZE 64 -#define DMJ_I2C_CMD_ECHO 0x00 -#define DMJ_I2C_CMD_GET_FUNC 0x01 -#define DMJ_I2C_CMD_SET_DELAY 0x02 -#define DMJ_I2C_CMD_GET_STATUS 0x03 -#define DMJ_I2C_CMD_DO_XFER 0x04 -#define DMJ_I2C_CMD_DO_XFER_B 0x05 -#define DMJ_I2C_CMD_DO_XFER_E 0x06 -#define DMJ_I2C_CMD_DO_XFER_BE 0x07 -#define DMJ_I2C_FLG_XFER_B 0x01 -#define DMJ_I2C_FLG_XFER_E 0x02 +#define DP_I2C_CMD_ECHO 0x00 +#define DP_I2C_CMD_GET_FUNC 0x01 +#define DP_I2C_CMD_SET_DELAY 0x02 +#define DP_I2C_CMD_GET_STATUS 0x03 +#define DP_I2C_CMD_DO_XFER 0x04 +#define DP_I2C_CMD_DO_XFER_B 0x05 +#define DP_I2C_CMD_DO_XFER_E 0x06 +#define DP_I2C_CMD_DO_XFER_BE 0x07 +#define DP_I2C_FLG_XFER_B 0x01 +#define DP_I2C_FLG_XFER_E 0x02 -#define DMJ_I2C_STAT_IDLE 0 -#define DMJ_I2C_STAT_ACK 1 -#define DMJ_I2C_STAT_NAK 2 +#define DP_I2C_STAT_IDLE 0 +#define DP_I2C_STAT_ACK 1 +#define DP_I2C_STAT_NAK 2 static uint16_t delay = 10; module_param(delay, ushort, 0); MODULE_PARM_DESC(delay, "bit delay in microseconds (default is 10us for 100kHz)"); -struct dmj_i2c { +struct dp_i2c { struct platform_device *pdev; struct i2c_adapter adapter; }; -static int dmj_i2c_read(struct dmj_i2c *dmji, struct i2c_msg *msg, int cmd) +static int dp_i2c_read(struct dp_i2c *dpi, struct i2c_msg *msg, int cmd) { - struct device *dev = &dmji->pdev->dev; + struct device *dev = &dpi->pdev->dev; void *respbuf = NULL; int ret, len; uint8_t cmdbuf[1+2+2+2]; /* cmd, flags, addr, len */ @@ -66,9 +66,9 @@ static int dmj_i2c_read(struct dmj_i2c *dmji, struct i2c_msg *msg, int cmd) cmdbuf[5] = (msg->len >> 0) & 0xff; cmdbuf[6] = (msg->len >> 8) & 0xff; - ret = dmj_transfer(dmji->pdev, DMJ_CMD_MODE1_I2C, DMJ_XFER_FLAGS_PARSE_RESP, + ret = dp_transfer(dpi->pdev, DP_CMD_MODE1_I2C, DP_XFER_FLAGS_PARSE_RESP, cmdbuf, sizeof(cmdbuf), &respbuf, &len); - ret = dmj_check_retval(ret, len, dev, "i2c read", true, -1, msg->len); + ret = dp_check_retval(ret, len, dev, "i2c read", true, -1, msg->len); if (ret < 0 || !respbuf) goto err_free; memcpy(msg->buf, respbuf, msg->len); @@ -78,9 +78,9 @@ err_free: if (respbuf) kfree(respbuf); return ret; } -static int dmj_i2c_write(struct dmj_i2c *dmji, struct i2c_msg *msg, int cmd) +static int dp_i2c_write(struct dp_i2c *dpi, struct i2c_msg *msg, int cmd) { - struct device *dev = &dmji->pdev->dev; + struct device *dev = &dpi->pdev->dev; uint8_t *cmdbuf; int ret, len; @@ -97,8 +97,8 @@ static int dmj_i2c_write(struct dmj_i2c *dmji, struct i2c_msg *msg, int cmd) cmdbuf[6] = (msg->len >> 8) & 0xff; memcpy(&cmdbuf[7], msg->buf, msg->len); - ret = dmj_write(dmji->pdev, DMJ_CMD_MODE1_I2C, cmdbuf, len); - ret = dmj_check_retval(ret, len, dev, "i2c write", true, -1, -1); + ret = dp_write(dpi->pdev, DP_CMD_MODE1_I2C, cmdbuf, len); + ret = dp_check_retval(ret, len, dev, "i2c write", true, -1, -1); if (ret < 0) goto err_free; ret = msg->len; @@ -108,18 +108,18 @@ err_free: return ret; } -static int dmj_i2c_xfer(struct i2c_adapter *a, struct i2c_msg *msgs, int nmsg) +static int dp_i2c_xfer(struct i2c_adapter *a, struct i2c_msg *msgs, int nmsg) { - struct dmj_i2c *dmji = i2c_get_adapdata(a); - struct device *dev = &dmji->pdev->dev; + struct dp_i2c *dpi = i2c_get_adapdata(a); + struct device *dev = &dpi->pdev->dev; struct i2c_msg *pmsg; int i, ret, cmd, stlen; uint8_t *status = NULL, i2ccmd; for (i = 0; i < nmsg; ++i) { - cmd = DMJ_I2C_CMD_DO_XFER; - if (i == 0) cmd |= DMJ_I2C_FLG_XFER_B; - if (i == nmsg-1) cmd |= DMJ_I2C_FLG_XFER_E; + cmd = DP_I2C_CMD_DO_XFER; + if (i == 0) cmd |= DP_I2C_FLG_XFER_B; + if (i == nmsg-1) cmd |= DP_I2C_FLG_XFER_E; pmsg = &msgs[i]; @@ -129,7 +129,7 @@ static int dmj_i2c_xfer(struct i2c_adapter *a, struct i2c_msg *msgs, int nmsg) pmsg->flags, pmsg->len, pmsg->addr); if (pmsg->flags & I2C_M_RD) { - ret = dmj_i2c_read(dmji, pmsg, cmd); + ret = dp_i2c_read(dpi, pmsg, cmd); if (ret < 0) goto err_ret; if (ret != pmsg->len) { dev_err(dev, "xfer rd: bad length %d vs %d\n", ret, pmsg->len); @@ -137,7 +137,7 @@ static int dmj_i2c_xfer(struct i2c_adapter *a, struct i2c_msg *msgs, int nmsg) goto err_ret; } } else { - ret = dmj_i2c_write(dmji, pmsg, cmd); + ret = dp_i2c_write(dpi, pmsg, cmd); if (ret < 0) goto err_ret; if (ret != pmsg->len) { dev_err(dev, "xfer wr: bad length %d vs %d\n", ret, pmsg->len); @@ -147,14 +147,14 @@ static int dmj_i2c_xfer(struct i2c_adapter *a, struct i2c_msg *msgs, int nmsg) } /* read status */ - i2ccmd = DMJ_I2C_CMD_GET_STATUS; - ret = dmj_transfer(dmji->pdev, DMJ_CMD_MODE1_I2C, DMJ_XFER_FLAGS_PARSE_RESP, + i2ccmd = DP_I2C_CMD_GET_STATUS; + ret = dp_transfer(dpi->pdev, DP_CMD_MODE1_I2C, DP_XFER_FLAGS_PARSE_RESP, &i2ccmd, sizeof(i2ccmd), (void**)&status, &stlen); - ret = dmj_check_retval(ret, stlen, dev, "i2c stat", true, sizeof(*status), sizeof(*status)); + ret = dp_check_retval(ret, stlen, dev, "i2c stat", true, sizeof(*status), sizeof(*status)); if (ret < 0 || !status) goto err_ret; dev_dbg(&a->dev, " status = %d\n", *status); - if (*status == DMJ_I2C_STAT_NAK) { + if (*status == DP_I2C_STAT_NAK) { ret = -ENXIO; goto err_ret; } @@ -166,19 +166,19 @@ err_ret: if (status) kfree(status); return ret; } -static uint32_t dmj_i2c_func(struct i2c_adapter *a) +static uint32_t dp_i2c_func(struct i2c_adapter *a) { - struct dmj_i2c *dmji = i2c_get_adapdata(a); - struct device *dev = /*&dmji->pdev->dev;*/ &a->dev; + struct dp_i2c *dpi = i2c_get_adapdata(a); + struct device *dev = /*&dpi->pdev->dev;*/ &a->dev; uint32_t func = 0; int len, ret; - uint8_t i2ccmd = DMJ_I2C_CMD_GET_FUNC; + uint8_t i2ccmd = DP_I2C_CMD_GET_FUNC; uint8_t *fbuf = NULL; - ret = dmj_transfer(dmji->pdev, DMJ_CMD_MODE1_I2C, DMJ_XFER_FLAGS_PARSE_RESP, + ret = dp_transfer(dpi->pdev, DP_CMD_MODE1_I2C, DP_XFER_FLAGS_PARSE_RESP, &i2ccmd, sizeof(i2ccmd), (void**)&fbuf, &len); - ret = dmj_check_retval(ret, len, dev, "i2c get_func", true, sizeof(func), sizeof(func)); + ret = dp_check_retval(ret, len, dev, "i2c get_func", true, sizeof(func), sizeof(func)); if (ret < 0 || !fbuf) return 0; func = (uint32_t)fbuf[0] | ((uint32_t)fbuf[1] << 8) @@ -190,16 +190,16 @@ static uint32_t dmj_i2c_func(struct i2c_adapter *a) return func; } -static const struct i2c_algorithm dmj_i2c_algo = { - .master_xfer = dmj_i2c_xfer, - .functionality = dmj_i2c_func +static const struct i2c_algorithm dp_i2c_algo = { + .master_xfer = dp_i2c_xfer, + .functionality = dp_i2c_func }; -static const struct i2c_adapter_quirks dmj_i2c_quirks = { - .max_read_len = DMJ_I2C_MAX_XFER_SIZE, - .max_write_len = DMJ_I2C_MAX_XFER_SIZE, +static const struct i2c_adapter_quirks dp_i2c_quirks = { + .max_read_len = DP_I2C_MAX_XFER_SIZE, + .max_write_len = DP_I2C_MAX_XFER_SIZE, }; -static int dmj_i2c_check_hw(struct platform_device *pdev) +static int dp_i2c_check_hw(struct platform_device *pdev) { /* * 1. check if mode 1 is available @@ -216,9 +216,9 @@ static int dmj_i2c_check_hw(struct platform_device *pdev) int ret = 0, len; uint8_t *buf = NULL; - ret = dmj_transfer(pdev, DMJ_CMD_CFG_GET_CUR_MODE, - DMJ_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); - ret = dmj_check_retval(ret, len, dev, "i2c test 1", true, sizeof(curmode), sizeof(curmode)); + ret = dp_transfer(pdev, DP_CMD_CFG_GET_CUR_MODE, + DP_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); + ret = dp_check_retval(ret, len, dev, "i2c test 1", true, sizeof(curmode), sizeof(curmode)); if (ret < 0 || !buf) goto out; curmode = buf[0]; @@ -229,9 +229,9 @@ static int dmj_i2c_check_hw(struct platform_device *pdev) goto out; } - ret = dmj_transfer(pdev, (1<<4) | DMJ_CMD_MODE_GET_VERSION, - DMJ_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); - ret = dmj_check_retval(ret, len, dev, "i2c test 2", true, sizeof(m1ver), sizeof(m1ver)); + ret = dp_transfer(pdev, (1<<4) | DP_CMD_MODE_GET_VERSION, + DP_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); + ret = dp_check_retval(ret, len, dev, "i2c test 2", true, sizeof(m1ver), sizeof(m1ver)); if (ret < 0 || !buf) goto out; m1ver = (uint16_t)buf[0] | ((uint16_t)buf[1] << 8); @@ -243,24 +243,24 @@ static int dmj_i2c_check_hw(struct platform_device *pdev) goto out; } - ret = dmj_transfer(pdev, (1<<4) | DMJ_CMD_MODE_GET_FEATURES, - DMJ_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); - ret = dmj_check_retval(ret, len, dev, "i2c test 3", true, sizeof(m1feat), sizeof(m1feat)); + ret = dp_transfer(pdev, (1<<4) | DP_CMD_MODE_GET_FEATURES, + DP_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); + ret = dp_check_retval(ret, len, dev, "i2c test 3", true, sizeof(m1feat), sizeof(m1feat)); if (ret < 0 || !buf) goto out; m1feat = buf[0]; kfree(buf); buf = NULL; - if (!(m1feat & DMJ_FEATURE_MODE1_I2C)) { + if (!(m1feat & DP_FEATURE_MODE1_I2C)) { dev_err(dev, "device's mode 1 does not support I2C\n"); ret = -EIO; goto out; } echoval = 0x42; - i2ccmd[0] = DMJ_I2C_CMD_ECHO; + i2ccmd[0] = DP_I2C_CMD_ECHO; i2ccmd[1] = ~echoval; - ret = dmj_transfer(pdev, (1<<4) | DMJ_CMD_MODE1_I2C, - DMJ_XFER_FLAGS_PARSE_RESP, i2ccmd, sizeof(i2ccmd), (void**)&buf, &len); - ret = dmj_check_retval(ret, len, dev, "i2c test", true, sizeof(echoval), sizeof(echoval)); + ret = dp_transfer(pdev, (1<<4) | DP_CMD_MODE1_I2C, + DP_XFER_FLAGS_PARSE_RESP, i2ccmd, sizeof(i2ccmd), (void**)&buf, &len); + ret = dp_check_retval(ret, len, dev, "i2c test", true, sizeof(echoval), sizeof(echoval)); if (ret < 0 || !buf) goto out; echoval = buf[0]; @@ -278,94 +278,94 @@ out: return ret; } -static int dmj_i2c_set_delay(struct platform_device *pdev, uint16_t us) +static int dp_i2c_set_delay(struct platform_device *pdev, uint16_t us) { struct device *dev = &pdev->dev; uint8_t i2ccmd[3]; int ret = 0; - i2ccmd[0] = DMJ_I2C_CMD_SET_DELAY; + i2ccmd[0] = DP_I2C_CMD_SET_DELAY; i2ccmd[1] = (us >> 0) & 0xff; i2ccmd[2] = (us >> 8) & 0xff; - ret = dmj_write(pdev, (1<<4) | DMJ_CMD_MODE1_I2C, i2ccmd, sizeof(i2ccmd)); + ret = dp_write(pdev, (1<<4) | DP_CMD_MODE1_I2C, i2ccmd, sizeof(i2ccmd)); dev_dbg(dev, "set delay to %hu us, result %d\n", us, ret); - ret = dmj_check_retval(ret, -1, dev, "i2c set delay", true, -1, -1); + ret = dp_check_retval(ret, -1, dev, "i2c set delay", true, -1, -1); return ret; } -static int dmj_i2c_probe(struct platform_device *pdev) +static int dp_i2c_probe(struct platform_device *pdev) { int ret, hwnlen; - struct dmj_i2c *dmji; + struct dp_i2c *dpi; struct device *dev = &pdev->dev; void *hwname; char namebuf[64]; - ret = dmj_i2c_check_hw(pdev); + ret = dp_i2c_check_hw(pdev); if (ret) return -ENODEV; - ret = dmj_i2c_set_delay(pdev, delay); + ret = dp_i2c_set_delay(pdev, delay); if (ret) { dev_err(dev, "failed to set I2C speed: %d\n", ret); return ret; } - dmji = devm_kzalloc(dev, sizeof(*dmji), GFP_KERNEL); - if (!dmji) return -ENOMEM; + dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL); + if (!dpi) return -ENOMEM; - dmji->pdev = pdev; + dpi->pdev = pdev; - dmji->adapter.owner = THIS_MODULE; - dmji->adapter.class = I2C_CLASS_HWMON; - dmji->adapter.algo = &dmj_i2c_algo; - dmji->adapter.quirks = &dmj_i2c_quirks; /* TODO: is this needed? probably... */ - dmji->adapter.dev.of_node = dev->of_node; - i2c_set_adapdata(&dmji->adapter, dmji); + dpi->adapter.owner = THIS_MODULE; + dpi->adapter.class = I2C_CLASS_HWMON; + dpi->adapter.algo = &dp_i2c_algo; + dpi->adapter.quirks = &dp_i2c_quirks; /* TODO: is this needed? probably... */ + dpi->adapter.dev.of_node = dev->of_node; + i2c_set_adapdata(&dpi->adapter, dpi); /* get device name, for adapter name */ - ret = dmj_transfer(pdev, DMJ_CMD_CFG_GET_INFOSTR, - DMJ_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&hwname, &hwnlen); - ret = dmj_check_retval(ret, hwnlen, dev, "probe: get name", true, -1, sizeof(namebuf)-1); + ret = dp_transfer(pdev, DP_CMD_CFG_GET_INFOSTR, + DP_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&hwname, &hwnlen); + ret = dp_check_retval(ret, hwnlen, dev, "probe: get name", true, -1, sizeof(namebuf)-1); if (ret < 0 || !hwname) return -EIO; memcpy(namebuf, hwname, hwnlen); namebuf[hwnlen] = 0; kfree(hwname); - snprintf(dmji->adapter.name, sizeof(dmji->adapter.name), + snprintf(dpi->adapter.name, sizeof(dpi->adapter.name), HARDWARE_NAME " '%s' at %s", namebuf, dev_name(pdev->dev.parent)); - platform_set_drvdata(pdev, dmji); + platform_set_drvdata(pdev, dpi); - ret = i2c_add_adapter(&dmji->adapter); + ret = i2c_add_adapter(&dpi->adapter); if (!ret) { dev_info(dev, HARDWARE_NAME " I2C device driver at i2c-%d, %s\n", - dmji->adapter.nr, dmji->adapter.name); + dpi->adapter.nr, dpi->adapter.name); } return ret; } -static int dmj_i2c_remove(struct platform_device *pdev) +static int dp_i2c_remove(struct platform_device *pdev) { - struct dmj_i2c *dmji = platform_get_drvdata(pdev); + struct dp_i2c *dpi = platform_get_drvdata(pdev); - i2c_del_adapter(&dmji->adapter); + i2c_del_adapter(&dpi->adapter); return 0; } -static struct platform_driver dmj_i2c_drv = { - .driver.name = "dmj-i2c", - .probe = dmj_i2c_probe, - .remove = dmj_i2c_remove +static struct platform_driver dp_i2c_drv = { + .driver.name = "dragonprobe-i2c", + .probe = dp_i2c_probe, + .remove = dp_i2c_remove }; -module_platform_driver(dmj_i2c_drv); +module_platform_driver(dp_i2c_drv); MODULE_AUTHOR("sys64738 "); MODULE_AUTHOR("haskal "); MODULE_DESCRIPTION("I2C interface driver for the " HARDWARE_NAME " USB multitool"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:dmj-i2c"); +MODULE_ALIAS("platform:dragonprobe-i2c"); diff --git a/host/modules/spi-dmj.c b/host/modules/spi-dmj.c deleted file mode 100644 index e96e05d..0000000 --- a/host/modules/spi-dmj.c +++ /dev/null @@ -1,984 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Driver for the DapperMime-JTAG USB multitool: USB-SPI adapter - * - * Copyright (c) 2021 sys64738 and haskal - * - * Adapted from: - * spi-dln2.c, Copyright (c) 2014 Intel Corporation - */ - -#include -#include -#include -#include -#include -#include - -#if 0 -#include -#else -#include "dmj.h" -#endif - -#define HARDWARE_NAME "DapperMime-JTAG" - -#define DMJ_SPI_CMD_NOP 0x00 -#define DMJ_SPI_CMD_Q_IFACE 0x01 -#define DMJ_SPI_CMD_Q_CMDMAP 0x02 -#define DMJ_SPI_CMD_Q_PGMNAME 0x03 -#define DMJ_SPI_CMD_Q_SERBUF 0x04 -#define DMJ_SPI_CMD_Q_BUSTYPE 0x05 -#define DMJ_SPI_CMD_Q_CHIPSIZE 0x06 -#define DMJ_SPI_CMD_Q_OPBUF 0x07 -#define DMJ_SPI_CMD_Q_WRNMAXLEN 0x08 -#define DMJ_SPI_CMD_R_BYTE 0x09 -#define DMJ_SPI_CMD_R_NBYTES 0x0a -#define DMJ_SPI_CMD_O_INIT 0x0b -#define DMJ_SPI_CMD_O_WRITEB 0x0c -#define DMJ_SPI_CMD_O_WRITEN 0x0d -#define DMJ_SPI_CMD_O_DELAY 0x0e -#define DMJ_SPI_CMD_O_EXEC 0x0f -#define DMJ_SPI_CMD_SYNCNOP 0x10 -#define DMJ_SPI_CMD_Q_RDNMAXLEN 0x11 -#define DMJ_SPI_CMD_S_BUSTYPE 0x12 -#define DMJ_SPI_CMD_SPIOP 0x13 -#define DMJ_SPI_CMD_S_SPI_FREQ 0x14 -#define DMJ_SPI_CMD_S_PINSTATE 0x15 - -#define DMJ_SPI_CMD_Q_SPI_CAPS 0x40 -#define DMJ_SPI_CMD_S_SPI_CHIPN 0x41 -#define DMJ_SPI_CMD_S_SPI_SETCS 0x42 -#define DMJ_SPI_CMD_S_SPI_FLAGS 0x43 -#define DMJ_SPI_CMD_S_SPI_BPW 0x44 -#define DMJ_SPI_CMD_SPI_READ 0x45 -#define DMJ_SPI_CMD_SPI_WRITE 0x46 -#define DMJ_SPI_CMD_SPI_RDWR 0x47 - -#define SERPROG_IFACE_VERSION 0x0001 - -static const uint8_t reqd_cmds[] = { - DMJ_SPI_CMD_NOP, DMJ_SPI_CMD_Q_IFACE, DMJ_SPI_CMD_Q_CMDMAP, - /*DMJ_SPI_CMD_Q_WRNMAXLEN, DMJ_SPI_CMD_Q_RDNMAXLEN,*/ - DMJ_SPI_CMD_S_SPI_FREQ, /*DMJ_SPI_CMD_S_PINSTATE,*/ /*DMJ_SPI_CMD_SPIOP,*/ - DMJ_SPI_CMD_Q_SPI_CAPS, DMJ_SPI_CMD_S_SPI_CHIPN, DMJ_SPI_CMD_S_SPI_FLAGS, - DMJ_SPI_CMD_S_SPI_BPW, DMJ_SPI_CMD_S_SPI_SETCS, - /*DMJ_SPI_CMD_SPI_READ, DMJ_SPI_CMD_SPI_WRITE, DMJ_SPI_CMD_SPI_RDWR,*/ -}; - -#define DMJ_SPI_ACK 0x06 -#define DMJ_SPI_NAK 0x15 - -#define DMJ_SPI_S_FLG_CPHA (1<<0) -#define DMJ_SPI_S_FLG_CPOL (1<<1) -#define DMJ_SPI_S_FLG_STDSPI (0<<2) -#define DMJ_SPI_S_FLG_TISSP (1<<2) -#define DMJ_SPI_S_FLG_MICROW (2<<2) -#define DMJ_SPI_S_FLG_MSBFST (0<<4) -#define DMJ_SPI_S_FLG_LSBFST (1<<4) -#define DMJ_SPI_S_FLG_CSACLO (0<<5) -#define DMJ_SPI_S_FLG_CSACHI (1<<5) -#define DMJ_SPI_S_FLG_3WIRE (1<<6) - -#define DMJ_SPI_S_CAP_CPHA_HI (1<<0) -#define DMJ_SPI_S_CAP_CPHA_LO (1<<1) -#define DMJ_SPI_S_CAP_CPOL_HI (1<<2) -#define DMJ_SPI_S_CAP_CPOL_LO (1<<3) -#define DMJ_SPI_S_CAP_STDSPI (1<<4) -#define DMJ_SPI_S_CAP_TISSP (1<<5) -#define DMJ_SPI_S_CAP_MICROW (1<<6) -#define DMJ_SPI_S_CAP_MSBFST (1<<7) -#define DMJ_SPI_S_CAP_LSBFST (1<<8) -#define DMJ_SPI_S_CAP_CSACHI (1<<9) -#define DMJ_SPI_S_CAP_3WIRE (1<<10) - -#define DMJ_PINST_AUTOSUSPEND_TIMEOUT 2000 - -struct dmj_spi_caps { - uint32_t freq_min, freq_max; - uint16_t flgcaps; - uint8_t num_cs, min_bpw, max_bpw; -}; -struct dmj_spi_dev_sett { - /* does not have to be guarded with a spinlock, as the kernel already - * serializes transfer_one/set_cs calls */ - uint32_t freq; - uint8_t flags, bpw; - uint8_t cs, pinst; -}; -struct dmj_spi { - struct platform_device *pdev; - struct spi_controller *spictl; - - uint8_t *txbuf; - struct dmj_spi_caps caps; - uint8_t csmask; - struct dmj_spi_dev_sett devsettings[8]; - uint32_t wrnmaxlen, rdnmaxlen; - uint8_t cmdmap[32]; - - spinlock_t csmap_lock; - - struct spi_board_info binfo[8]; -}; - -static int dmj_check_retval_sp(int ret, int len, struct device *dev, - const char *pfix, bool check_pos_val, int lmin, int lmax, const void* rbuf) -{ - ret = dmj_check_retval(ret, len, dev, pfix, check_pos_val, lmin, lmax); - if (ret >= 0 && ((const uint8_t *)rbuf)[0] != DMJ_SPI_ACK) { - dev_err(dev, "%s: did not receive ACK\n", pfix); - ret = -EIO; - } - - return ret; -} - -static bool has_cmd(struct dmj_spi *dmjs, int cmd) -{ - int byteind = cmd >> 3, bitind = cmd & 7; - - return dmjs->cmdmap[byteind] & (1 << bitind); -} - -static uint8_t kernmode_to_flags(uint16_t caps, int mode) -{ - uint8_t ret = mode & 3; /* bottom 2 bits are the SPI mode (CPHA & CPOL) */ - - if (mode & SPI_LSB_FIRST) ret |= DMJ_SPI_S_FLG_LSBFST; - else ret |= DMJ_SPI_S_FLG_MSBFST; - if (mode & SPI_CS_HIGH) ret |= DMJ_SPI_S_FLG_CSACHI; - else ret |= DMJ_SPI_S_FLG_CSACLO; - if (mode & SPI_3WIRE) ret |= DMJ_SPI_S_FLG_3WIRE; - - /* need some defaults for other stuff */ - if (caps & DMJ_SPI_S_CAP_STDSPI) ret |= DMJ_SPI_S_FLG_STDSPI; - else if (caps & DMJ_SPI_S_CAP_TISSP) ret |= DMJ_SPI_S_FLG_TISSP; - else if (caps & DMJ_SPI_S_CAP_MICROW) ret |= DMJ_SPI_S_FLG_MICROW; - else ret |= DMJ_SPI_S_FLG_STDSPI; /* shrug, also shouldn't happen (cf. get_caps) */ - - return ret; -} -static int devcaps_to_kernmode(uint16_t caps) -{ - int ret; - - ret = caps & 3; /* SPI mode (CPHA & CPOL) bits */ - - if (caps & DMJ_SPI_S_CAP_LSBFST) ret |= SPI_LSB_FIRST; - if (caps & DMJ_SPI_S_CAP_CSACHI) ret |= SPI_CS_HIGH; - if (caps & DMJ_SPI_S_CAP_3WIRE) ret |= SPI_3WIRE; - - return ret; -} -static void caps_to_binfo(struct dmj_spi *dmjs, int busnum) -{ - int i; - - for (i = 0; i < dmjs->caps.num_cs; ++i) { - snprintf(dmjs->binfo[i].modalias, SPI_NAME_SIZE, "spidev"); - dmjs->binfo[i].controller_data = dmjs; - dmjs->binfo[i].max_speed_hz = dmjs->caps.freq_max; - dmjs->binfo[i].bus_num = busnum; - dmjs->binfo[i].chip_select = i; - dmjs->binfo[i].mode = 0; /* shrug */ - } -} - -static void bufconv_to_le(void *dst, const void *src, size_t len_bytes, uint8_t bpw) -{ -#ifdef __LITTLE_ENDIAN - memcpy(dst, src, len_bytes); -#else - if (bpw > 16) { - __le32 *dst32 = (__le32 *)dst; - const uint32_t *src32 = (const uint32_t *)src; - - for (size_t i = 0; i < len_bytes; i += 4, ++dst32, ++src32) { - *dst32 = cpu_to_le32p(src32); - } - } else if (bpw > 8) { - __le16 *dst16 = (__le16 *)dst; - const uint16_t *src16 = (const uint16_t *)src; - - for (size_t i = 0; i < len_bytes; i += 2, ++dst16, ++src16) { - *dst16 = cpu_to_le16p(src16); - } - } else { - memcpy(dst, src, len_bytes); - } -#endif -} -static void bufconv_from_le(void *dst, const void *src, size_t len_bytes, uint8_t bpw) -{ -#ifdef __LITTLE_ENDIAN - memcpy(dst, src, len_bytes); -#else - if (bpw > 16) { - const __le32 *src32 = (const __le32 *)src; - uint32_t *dst32 = (uint32_t *)dst; - - for (size_t i = 0; i < len_bytes; i += 4, ++dst32, ++src32) { - *dst32 = get_unaligned_le32(src32); - } - } else if (bpw > 8) { - const __le16 *src16 = (const __le16 *)src; - uint16_t *dst16 = (uint16_t *)dst; - - for (size_t i = 0; i < len_bytes; i += 2, ++dst16, ++src16) { - *dst16 = le16_to_cpup(src16); - } - } else { - memcpy(dst, src, len_bytes); - } -#endif -} - -static int dmj_spi_csmask_set(struct dmj_spi *dmjs, uint8_t csmask) -{ - struct device *dev = &dmjs->pdev->dev; - uint8_t oldcm; - bool do_csmask = false; - uint8_t wbuf[] = { DMJ_SPI_CMD_S_SPI_CHIPN, csmask }; - uint8_t *rbuf; - int ret, rlen; - - spin_lock(&dmjs->csmap_lock); - oldcm = dmjs->csmask; - if (oldcm != csmask) { - dmjs->csmask = csmask; - do_csmask = true; - } - spin_unlock(&dmjs->csmap_lock); - - if (do_csmask) { - dev_dbg(dev, "set csmask %02x\n", csmask); - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "set CS mask", true, 1, 1, rbuf); - - if (rbuf) kfree(rbuf); - } - - return 0; -} -static int dmj_spi_csmask_set_one(struct dmj_spi *dmjs, uint8_t cs) -{ - return dmj_spi_csmask_set(dmjs, BIT(cs)); -} -static int dmj_spi_cs_set(struct dmj_spi *dmjs, int ind, bool lvl) -{ - struct device *dev = &dmjs->pdev->dev; - uint8_t wbuf[] = { DMJ_SPI_CMD_S_SPI_SETCS, lvl ? 1 : 0 }; - uint8_t *rbuf; - int ret, rlen; - - if (dmjs->devsettings[ind].cs == (lvl ? 1 : 0)) return 0; - - dev_dbg(dev, "set cs %s\n", lvl?"hi":"lo"); - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "set CS", true, 1, 1, rbuf); - - if (!ret) { - dmjs->devsettings[ind].cs = lvl ? 1 : 0; - } - if (rbuf) kfree(rbuf); - - return ret; -} -static int dmj_spi_get_caps(struct dmj_spi *dmjs) -{ - struct device *dev = &dmjs->pdev->dev; - uint8_t wbuf[] = { DMJ_SPI_CMD_Q_SPI_CAPS }; - uint8_t *rbuf; - int ret, rlen; - - dev_dbg(dev, "get caps\n"); - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "get caps", true, 14, 14, rbuf); - - if (!ret) { - dmjs->caps.freq_min = (uint32_t)rbuf[1] | ((uint32_t)rbuf[2] << 8) - | ((uint32_t)rbuf[3] << 16) | ((uint32_t)rbuf[4] << 24); - dmjs->caps.freq_max = (uint32_t)rbuf[5] | ((uint32_t)rbuf[6] << 8) - | ((uint32_t)rbuf[7] << 16) | ((uint32_t)rbuf[8] << 24); - dmjs->caps.flgcaps = (uint32_t)rbuf[9] | ((uint32_t)rbuf[10] << 8); - - dmjs->caps.num_cs = rbuf[11]; - dmjs->caps.min_bpw = rbuf[12]; - dmjs->caps.max_bpw = rbuf[13]; - - dev_info(dev, " capabilities: freq=%d..%d, flgcaps=%04hx, bpw=%d..%d, num cs=%d\n", - dmjs->caps.freq_min, dmjs->caps.freq_max, dmjs->caps.flgcaps, - dmjs->caps.min_bpw, dmjs->caps.max_bpw, dmjs->caps.num_cs); - - if (dmjs->caps.max_bpw == 0 || dmjs->caps.min_bpw == 0) { - dev_err(dev, "Device replied with max_bpw=0 or min_bpw=0, wtf?\n"); - ret = -EXDEV; - } - if (!(dmjs->caps.flgcaps & (DMJ_SPI_S_CAP_STDSPI - | DMJ_SPI_S_CAP_TISSP | DMJ_SPI_S_CAP_MICROW))) { - dev_err(dev, "Device does not support any SPI mode, wtf?\n"); - ret = -EXDEV; - } - - kfree(rbuf); - } - - return ret; -} -static int dmj_spi_set_freq(struct dmj_spi *dmjs, int ind, uint32_t freq) -{ - struct device *dev = &dmjs->pdev->dev; - uint8_t wbuf[] = { DMJ_SPI_CMD_S_SPI_FREQ, - freq, freq >> 8, freq >> 16, freq >> 24 }; - uint8_t *rbuf; - uint32_t freqret; - int ret, rlen; - - if (dmjs->devsettings[ind].freq == freq) return 0; - - dev_dbg(dev, "set freq to %u\n", freq); - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "set CS", true, 5, 5, rbuf); - - if (!ret) { - freqret = (uint32_t)rbuf[1] | ((uint32_t)rbuf[2] << 8) - | ((uint32_t)rbuf[3] << 16) | ((uint32_t)rbuf[4] << 24); - - if (freqret != freq) { - dev_warn(dev, "set frequency: couldn't provide exact freq %u Hz, %u Hz was applied instead.\n", - freq, freqret); - } - - /* not the returned one, to avoid resending */ - dmjs->devsettings[ind].freq = freq; - } - if (rbuf) kfree(rbuf); - - return ret; -} -static int dmj_spi_set_flags(struct dmj_spi *dmjs, int ind, uint8_t flags) -{ - struct device *dev = &dmjs->pdev->dev; - uint8_t wbuf[] = { DMJ_SPI_CMD_S_SPI_FLAGS, flags }; - uint8_t *rbuf, flagret; - int ret, rlen; - - if (dmjs->devsettings[ind].flags == flags) return 0; - - dev_dbg(dev, "set flags %08x\n", flags); - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "set flags", true, 2, 2, rbuf); - - if (!ret) { - flagret = rbuf[1]; - - if (flagret != flags) { - dev_warn(dev, "set flags: couldn't set exact flags %08x, was set to %08x instead\n", - flags, flagret); - } - - /* not the returned one, to avoid resending */ - dmjs->devsettings[ind].flags = flags; - } - if (rbuf) kfree(rbuf); - - return ret; -} -static int dmj_spi_set_bpw(struct dmj_spi *dmjs, int ind, uint8_t bpw) -{ - struct device *dev = &dmjs->pdev->dev; - uint8_t wbuf[] = { DMJ_SPI_CMD_S_SPI_BPW, bpw }; - uint8_t *rbuf, bpwret; - int ret, rlen; - - if (dmjs->devsettings[ind].bpw == bpw) return 0; - - dev_dbg(dev, "set bpw %hhu\n", bpw); - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "set bpw", true, 2, 2, rbuf); - - if (!ret) { - bpwret = rbuf[1]; - - if (bpwret != bpw) { - dev_warn(dev, "set flags: couldn't set exact bpw %hhu, was set to %hhu instead\n", - bpw, bpwret); - } - - /* not the returned one, to avoid resending */ - dmjs->devsettings[ind].bpw = bpw; - } - if (rbuf) kfree(rbuf); - - return ret; -} -static int dmj_spi_set_pinstate(struct dmj_spi *dmjs, bool pins) -{ - struct device *dev = &dmjs->pdev->dev; - uint8_t wbuf[] = { DMJ_SPI_CMD_S_PINSTATE, pins ? 1 : 0 }; - uint8_t *rbuf; - int ret, rlen; - - if (!has_cmd(dmjs, DMJ_SPI_CMD_S_PINSTATE)) return 0; - - dev_dbg(dev, "set pinstate %sabled\n", pins?"en":"dis"); - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "set pinstate", true, 2, 2, rbuf); - - /*if (!ret) { - dmjs->devsettings[ind].pinst = pins; - }*/ - if (rbuf) kfree(rbuf); - - return ret; -} - -static int dmj_spi_check_hw(struct dmj_spi *dmjs) -{ - struct device *dev = &dmjs->pdev->dev; - uint8_t wbuf[] = { DMJ_SPI_CMD_NOP }; - uint8_t *rbuf; - uint16_t iface; - int ret, rlen, i; - - dev_dbg(dev, "check hw: nop"); - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "check hw: nop", true, 1, 1, rbuf); - - if (rbuf) kfree(rbuf); - if (ret) return ret; - - dev_dbg(dev, "check hw: syncnop"); - wbuf[0] = DMJ_SPI_CMD_SYNCNOP; - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); - ret = dmj_check_retval(ret, rlen, dev, "check hw: nop", true, 2, 2); - if (!ret) { - if (rbuf[0] != DMJ_SPI_NAK || rbuf[1] != DMJ_SPI_ACK) { - dev_err(dev, "check hw: syncnop: bad response %02x %02x\n", - rbuf[0], rbuf[1]); - ret = -EIO; - } - } - if (rbuf) kfree(rbuf); - if (ret) return ret; - - dev_dbg(dev, "check hw: iface"); - wbuf[0] = DMJ_SPI_CMD_Q_IFACE; - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "check hw: iface", true, 3, 3, rbuf); - - if (!ret) { - iface = (uint16_t)rbuf[1] | ((uint16_t)rbuf[2] << 8); - - if (iface != SERPROG_IFACE_VERSION) { - dev_err(dev, "check hw: iface: bad serprog version: expected %hu, got %hu\n", - SERPROG_IFACE_VERSION, iface); - ret = -ENODEV; - } - } - if (rbuf) kfree(rbuf); - if (ret) return ret; - - dev_dbg(dev, "check hw: cmdmap"); - wbuf[0] = DMJ_SPI_CMD_Q_CMDMAP; - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "check hw: cmdmap", true, 33, 33, rbuf); - - if (!ret) { - memcpy(dmjs->cmdmap, &rbuf[1], 32); - } - if (rbuf) kfree(rbuf); - if (ret) return ret; - - for (i = 0; i < sizeof(reqd_cmds)/sizeof(*reqd_cmds); ++i) { - if (!has_cmd(dmjs, reqd_cmds[i])) { - dev_err(dev, "device does not have required serprog command %02x\n", reqd_cmds[i]); - ret = -ENODEV; - } - } - - if (has_cmd(dmjs, DMJ_SPI_CMD_Q_PGMNAME)) { - dev_dbg(dev, "check hw: pgmname"); - wbuf[0] = DMJ_SPI_CMD_Q_PGMNAME; - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "check hw: pgmname", true, 17, 17, rbuf); - - if (!ret) { - rbuf[16] = 0; - dev_info(dev, "Serprog pgmname: '%s'\n", &rbuf[1]); - } - if (rbuf) kfree(rbuf); - if (ret) return ret; - } - - if (has_cmd(dmjs, DMJ_SPI_CMD_Q_WRNMAXLEN)) { - dev_dbg(dev, "check hw: wrnmaxlen"); - wbuf[0] = DMJ_SPI_CMD_Q_WRNMAXLEN; - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "check hw: wrnmaxlen", true, 4, 4, rbuf); - - if (!ret) { - dmjs->wrnmaxlen = (uint32_t)rbuf[1] | ((uint32_t)rbuf[2] << 8) | ((uint32_t)rbuf[3] << 16); - } - if (rbuf) kfree(rbuf); - if (ret) return ret; - } else dmjs->rdnmaxlen = 512; - dev_info(dev, " wrnmaxlen = 0x%x\n", dmjs->wrnmaxlen); - - if (has_cmd(dmjs, DMJ_SPI_CMD_Q_RDNMAXLEN)) { - dev_dbg(dev, "check hw: rdnmaxlen"); - wbuf[0] = DMJ_SPI_CMD_Q_RDNMAXLEN; - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "check hw: rdnmaxlen", true, 4, 4, rbuf); - - if (!ret) { - dmjs->rdnmaxlen = (uint32_t)rbuf[1] | ((uint32_t)rbuf[2] << 8) | ((uint32_t)rbuf[3] << 16); - } - if (rbuf) kfree(rbuf); - if (ret) return ret; - } else dmjs->rdnmaxlen = 512; - dev_info(dev, " rdnmaxlen = 0x%x\n", dmjs->rdnmaxlen); - - return 0; -} - -static int dmj_spi_do_read(struct dmj_spi *dmjs, void *data, size_t len, uint8_t bpw) -{ - struct device *dev = &dmjs->pdev->dev; - uint8_t *rbuf; - int ret, rlen; - - if (len > INT_MAX-4) return -EINVAL; - - if (has_cmd(dmjs, DMJ_SPI_CMD_SPI_READ)) { - dev_dbg(dev, "do spi read len=0x%zx\n", len); - - dmjs->txbuf[0] = DMJ_SPI_CMD_SPI_READ; - dmjs->txbuf[1] = len & 0xff; - dmjs->txbuf[2] = (len >> 8) & 0xff; - dmjs->txbuf[3] = (len >> 16) & 0xff; - - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - dmjs->txbuf, 4, (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "do read", true, (int)len+1, (int)len+1, rbuf); - - if (!ret) bufconv_from_le(data, &rbuf[1], len, bpw); - - if (rbuf) kfree(rbuf); - } else if (has_cmd(dmjs, DMJ_SPI_CMD_SPIOP)) { - dev_dbg(dev, "do spiop read len=0x%zx\n", len); - - dmjs->txbuf[0] = DMJ_SPI_CMD_SPIOP; - dmjs->txbuf[1] = 0; - dmjs->txbuf[2] = 0; - dmjs->txbuf[3] = 0; - dmjs->txbuf[4] = len & 0xff; - dmjs->txbuf[5] = (len >> 8) & 0xff; - dmjs->txbuf[6] = (len >> 16) & 0xff; - - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - dmjs->txbuf, 7, (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "do spiop read", true, (int)len+1, (int)len+1, rbuf); - - if (!ret) bufconv_from_le(data, &rbuf[1], len, bpw); - - if (rbuf) kfree(rbuf); - } else if (has_cmd(dmjs, DMJ_SPI_CMD_SPI_RDWR)) { - dev_dbg(dev, "do rdwr read len=0x%zx\n", len); - - dmjs->txbuf[0] = DMJ_SPI_CMD_SPI_RDWR; - dmjs->txbuf[1] = len & 0xff; - dmjs->txbuf[2] = (len >> 8) & 0xff; - dmjs->txbuf[3] = (len >> 16) & 0xff; - - /* we need to fill the buffer with stuff bits to control the data - * that will get sent over the full duplex line. 0 is the default used - * in most places apparently? */ - memset(&dmjs->txbuf[4], 0, len); - - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - dmjs->txbuf, (int)len+4, (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "do rdwr read", true, (int)len+1, (int)len+1, rbuf); - - if (!ret) bufconv_from_le(data, &rbuf[1], len, bpw); - - if (rbuf) kfree(rbuf); - } else { - return -EXDEV; - } - - return 0; -} -static int dmj_spi_do_write(struct dmj_spi *dmjs, const void *data, size_t len, uint8_t bpw) -{ - struct device *dev = &dmjs->pdev->dev; - uint8_t *rbuf; - int ret, rlen; - - if (len > INT_MAX-7) return -EINVAL; - - if (has_cmd(dmjs, DMJ_SPI_CMD_SPI_WRITE)) { - dev_dbg(dev, "do spi write len=0x%zx\n", len); - - dmjs->txbuf[0] = DMJ_SPI_CMD_SPI_WRITE; - dmjs->txbuf[1] = len & 0xff; - dmjs->txbuf[2] = (len >> 8) & 0xff; - dmjs->txbuf[3] = (len >> 16) & 0xff; - - bufconv_to_le(&dmjs->txbuf[4], data, len, bpw); - - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - dmjs->txbuf, (int)len+4, (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "do write", true, 1, 1, rbuf); - - if (rbuf) kfree(rbuf); - } else if (has_cmd(dmjs, DMJ_SPI_CMD_SPIOP)) { - dev_dbg(dev, "do spiop write len=0x%zx\n", len); - - dmjs->txbuf[0] = DMJ_SPI_CMD_SPIOP; - dmjs->txbuf[1] = len & 0xff; - dmjs->txbuf[2] = (len >> 8) & 0xff; - dmjs->txbuf[3] = (len >> 16) & 0xff; - dmjs->txbuf[4] = 0; - dmjs->txbuf[5] = 0; - dmjs->txbuf[6] = 0; - - bufconv_to_le(&dmjs->txbuf[7], data, len, bpw); - - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - dmjs->txbuf, (int)len+7, (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "do spiop write", true, 1, 1, rbuf); - - if (rbuf) kfree(rbuf); - } else if (has_cmd(dmjs, DMJ_SPI_CMD_SPI_RDWR)) { - dev_dbg(dev, "do rdwr write len=0x%zx\n", len); - - dmjs->txbuf[0] = DMJ_SPI_CMD_SPI_RDWR; - dmjs->txbuf[1] = len & 0xff; - dmjs->txbuf[2] = (len >> 8) & 0xff; - dmjs->txbuf[3] = (len >> 16) & 0xff; - - bufconv_to_le(&dmjs->txbuf[4], data, len, bpw); - - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - dmjs->txbuf, (int)len+4, (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "do rdwr write", true, (int)len+1, (int)len+1, rbuf); - /* we just don't look at the returned bytes in this case */ - if (rbuf) kfree(rbuf); - } else { - return -EXDEV; - } - - return 0; -} -/* should only be called if it already has the cmd anyway (cf. spi_controller->flags) */ -static int dmj_spi_do_rdwr(struct dmj_spi *dmjs, void *rdata, const void *wdata, size_t len, uint8_t bpw) -{ - struct device *dev = &dmjs->pdev->dev; - uint8_t *rbuf; - int ret, rlen; - - if (len > INT_MAX-4) return -EINVAL; - if (!has_cmd(dmjs, DMJ_SPI_CMD_SPI_RDWR)) return -EXDEV; - - dev_dbg(dev, "do rdwr len=0x%zx\n", len); - - dmjs->txbuf[0] = DMJ_SPI_CMD_SPI_RDWR; - dmjs->txbuf[1] = len & 0xff; - dmjs->txbuf[2] = (len >> 8) & 0xff; - dmjs->txbuf[3] = (len >> 16) & 0xff; - - bufconv_to_le(&dmjs->txbuf[4], wdata, len, bpw); - - ret = dmj_transfer(dmjs->pdev, DMJ_CMD_MODE1_SPI, DMJ_XFER_FLAGS_PARSE_RESP, - dmjs->txbuf, (int)len+4, (void**)&rbuf, &rlen); - ret = dmj_check_retval_sp(ret, rlen, dev, "do rdwr", true, (int)len+1, -1, rbuf); - - if (!ret) bufconv_from_le(rdata, &rbuf[1], len, bpw); - - if (rbuf) kfree(rbuf); - - return ret; -} - -static int dmj_spi_prepare_message(struct spi_controller *spictl, struct spi_message *msg) -{ - struct dmj_spi *dmjs = spi_controller_get_devdata(spictl); - struct spi_device *spidev = msg->spi; - struct device *dev = &spidev->dev; - int ret; - - ret = dmj_spi_set_flags(dmjs, spidev->chip_select, - kernmode_to_flags(dmjs->caps.flgcaps, spidev->mode)); - if (ret < 0) { - dev_err(dev, "Failed to set SPI flags\n"); - return ret; - } - - /*ret = dmj_spi_csmask_set_one(dmjs, spidev->chip_select); - if (ret < 0) { - dev_err(dev, "Failed to set CS mask\n"); - return ret; - }*/ - - return ret; -} -static void dmj_spi_set_cs(struct spi_device *spidev, bool enable) -{ - struct spi_controller *spictl = spidev->controller; - struct dmj_spi *dmjs = spi_controller_get_devdata(spictl); - struct device *dev = &spidev->dev; - int ret; - - ret = dmj_spi_csmask_set_one(dmjs, spidev->chip_select); - if (ret < 0) { - dev_err(dev, "Failed to set CS mask\n"); - return; - } - - ret = dmj_spi_cs_set(dmjs, spidev->chip_select, enable); - if (ret < 0) { - dev_err(dev, "Failed to set chip select line\n"); - return; - } - - /*return 0;*/ -} -static int dmj_spi_transfer_one(struct spi_controller *spictl, struct spi_device *spidev, struct spi_transfer *xfer) -{ - struct dmj_spi *dmjs = spi_controller_get_devdata(spictl); - struct device *dev = &spidev->dev; - int ret; - uint32_t cksize, todo, off = 0; - - ret = dmj_spi_set_freq(dmjs, spidev->chip_select, xfer->speed_hz); - if (ret < 0) { - dev_err(dev, "Failed to set SPI frequency to %d Hz\n", xfer->speed_hz); - return ret; - } - - ret = dmj_spi_set_bpw(dmjs, spidev->chip_select, xfer->bits_per_word); - if (ret < 0) { - dev_err(dev, "Failed to set SPI bits-per-word to %d\n", xfer->bits_per_word); - return ret; - } - - if (xfer->tx_buf && xfer->rx_buf) { - cksize = dmjs->wrnmaxlen; - if (cksize > dmjs->rdnmaxlen) cksize = dmjs->rdnmaxlen; - } else if (xfer->tx_buf) { - cksize = dmjs->wrnmaxlen; - } else if (xfer->rx_buf) { - cksize = dmjs->rdnmaxlen; - } else return -EINVAL; - - todo = xfer->len; - do { - if (todo < cksize) cksize = todo; - - if (xfer->tx_buf && xfer->rx_buf) { - ret = dmj_spi_do_rdwr(dmjs, xfer->rx_buf + off, xfer->tx_buf + off, cksize, xfer->bits_per_word); - } else if (xfer->tx_buf) { - ret = dmj_spi_do_write(dmjs, xfer->tx_buf + off, cksize, xfer->bits_per_word); - } else /*if (xfer->rx_buf)*/ { - ret = dmj_spi_do_read(dmjs, xfer->rx_buf + off, cksize, xfer->bits_per_word); - } - - if (ret < 0) { - dev_err(dev, "SPI transfer failed! %d\n", ret); - return ret; - } - - todo -= cksize; - off += cksize; - } while (todo); - - return 0; -} - -static int dmj_spi_probe(struct platform_device *pdev) -{ - struct spi_controller *spictl; - struct dmj_spi *dmjs; - struct device *dev = &pdev->dev; - int ret, i; - - spictl = spi_alloc_master(dev, sizeof(*dmjs)); - if (!spictl ) return -ENOMEM; - - platform_set_drvdata(pdev, spictl); - - dmjs = spi_controller_get_devdata(spictl); - - dmjs->spictl = spictl; - dmjs->spictl->dev.of_node = dev->of_node; - dmjs->pdev = pdev; - dmjs->csmask = 0xff; - for (i = 0; i < 8; ++i) { - dmjs->devsettings[i].freq = 0; - dmjs->devsettings[i].flags = 0xff; - dmjs->devsettings[i].bpw = 0xff; - } - - spin_lock_init(&dmjs->csmap_lock); - - ret = dmj_spi_check_hw(dmjs); - if (ret < 0) { - dev_err(dev, "Hardware capabilities lacking\n"); - goto err_free_ctl; - } - - dmjs->txbuf = devm_kmalloc(&pdev->dev, dmjs->wrnmaxlen + 0x10, GFP_KERNEL); - if (!dmjs->txbuf) { - ret = -ENOMEM; - dev_err(dev, "No memory left for TX buffer of length 0x%x\n", dmjs->wrnmaxlen); - goto err_free_ctl; - } - - ret = dmj_spi_get_caps(dmjs); - if (ret < 0) { - dev_err(dev, "Failed to get device capabilities\n"); - goto err_free_ctl; - } - - spictl->min_speed_hz = dmjs->caps.freq_min; - spictl->max_speed_hz = dmjs->caps.freq_max; - spictl->bits_per_word_mask = SPI_BPW_RANGE_MASK(dmjs->caps.min_bpw, dmjs->caps.max_bpw); - spictl->num_chipselect = dmjs->caps.num_cs; - spictl->mode_bits = devcaps_to_kernmode(dmjs->caps.flgcaps); - - spictl->bus_num = -1; - spictl->prepare_message = dmj_spi_prepare_message; - spictl->transfer_one = dmj_spi_transfer_one; - spictl->set_cs = dmj_spi_set_cs; - - spictl->flags = 0; - if (!has_cmd(dmjs, DMJ_SPI_CMD_SPI_RDWR)) - spictl->flags |= SPI_CONTROLLER_HALF_DUPLEX; - - pm_runtime_set_autosuspend_delay(dev, DMJ_PINST_AUTOSUSPEND_TIMEOUT); - pm_runtime_use_autosuspend(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - - ret = devm_spi_register_controller(dev, spictl); - if (ret < 0) { - dev_err(dev, "Failed to register SPI controller\n"); - goto err_dereg; - } - - dev_info(dev, "SPI bus number is %d\n", spictl->bus_num); - - caps_to_binfo(dmjs, spictl->bus_num); - for (i = 0; i < dmjs->caps.num_cs; ++i) { - if (!spi_new_device(spictl, &dmjs->binfo[i])) { - dev_warn(dev, "failed to create %s device %d\n", dmjs->binfo[i].modalias, i); - } - } - - return dmj_spi_set_pinstate(dmjs, true); - -err_dereg: - pm_runtime_disable(dev); - pm_runtime_set_suspended(dev); -err_free_ctl: - spi_controller_put(spictl); - return ret; -} - -static int dmj_spi_remove(struct platform_device *pdev) -{ - struct spi_controller *spictl = platform_get_drvdata(pdev); - struct dmj_spi *dmjs = spi_controller_get_devdata(spictl); - - pm_runtime_disable(&pdev->dev); - - dmj_spi_set_pinstate(dmjs, false); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int dmj_spi_suspend(struct device *dev) -{ - struct spi_controller *spictl = dev_get_drvdata(dev); - struct dmj_spi *dmjs = spi_controller_get_devdata(spictl); - int ret, i; - - ret = spi_controller_suspend(spictl); - if (ret < 0) return ret; - - dmj_spi_set_pinstate(dmjs, false); - - for (i = 0; i < 8; ++i) { - dmjs->devsettings[i].freq = 0; - dmjs->devsettings[i].flags = 0xff; - dmjs->devsettings[i].bpw = 0xff; - } - - return 0; -} - -static int dmj_spi_resume(struct device *dev) -{ - struct spi_controller *spictl = dev_get_drvdata(dev); - struct dmj_spi *dmjs = spi_controller_get_devdata(spictl); - - dmj_spi_set_pinstate(dmjs, true); - - return spi_controller_resume(spictl); -} -#endif /* CONFIG_PM_SLEEP */ - -#ifdef CONFIG_PM -static int dmj_spi_runtime_suspend(struct device *dev) -{ - struct spi_controller *spictl = dev_get_drvdata(dev); - struct dmj_spi *dmjs = spi_controller_get_devdata(spictl); - - return dmj_spi_set_pinstate(dmjs, false); -} -static int dmj_spi_runtime_resume(struct device *dev) -{ - struct spi_controller *spictl = dev_get_drvdata(dev); - struct dmj_spi *dmjs = spi_controller_get_devdata(spictl); - - return dmj_spi_set_pinstate(dmjs, true); -} -#endif /* CONFIG_PM */ - -static const struct dev_pm_ops dmj_spi_pm = { - SET_SYSTEM_SLEEP_PM_OPS(dmj_spi_suspend, dmj_spi_resume) - SET_RUNTIME_PM_OPS(dmj_spi_runtime_suspend, dmj_spi_runtime_resume, NULL) -}; - -static struct platform_driver spi_dmj_driver = { - .driver = { - .name = "dmj-spi", - .pm = &dmj_spi_pm, - }, - .probe = dmj_spi_probe, - .remove = dmj_spi_remove -}; -module_platform_driver(spi_dmj_driver); - -MODULE_AUTHOR("sys64738 "); -MODULE_AUTHOR("haskal "); -MODULE_DESCRIPTION("SPI interface driver for the " HARDWARE_NAME " USB multitool"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:dmj-spi"); diff --git a/host/modules/spi-dragonprobe.c b/host/modules/spi-dragonprobe.c new file mode 100644 index 0000000..c5e015f --- /dev/null +++ b/host/modules/spi-dragonprobe.c @@ -0,0 +1,984 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for the Dragon Probe USB multitool: USB-SPI adapter + * + * Copyright (c) 2021 sys64738 and haskal + * + * Adapted from: + * spi-dln2.c, Copyright (c) 2014 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include + +#if 0 +#include +#else +#include "dragonprobe.h" +#endif + +#define HARDWARE_NAME "Dragon Probe" + +#define DP_SPI_CMD_NOP 0x00 +#define DP_SPI_CMD_Q_IFACE 0x01 +#define DP_SPI_CMD_Q_CMDMAP 0x02 +#define DP_SPI_CMD_Q_PGMNAME 0x03 +#define DP_SPI_CMD_Q_SERBUF 0x04 +#define DP_SPI_CMD_Q_BUSTYPE 0x05 +#define DP_SPI_CMD_Q_CHIPSIZE 0x06 +#define DP_SPI_CMD_Q_OPBUF 0x07 +#define DP_SPI_CMD_Q_WRNMAXLEN 0x08 +#define DP_SPI_CMD_R_BYTE 0x09 +#define DP_SPI_CMD_R_NBYTES 0x0a +#define DP_SPI_CMD_O_INIT 0x0b +#define DP_SPI_CMD_O_WRITEB 0x0c +#define DP_SPI_CMD_O_WRITEN 0x0d +#define DP_SPI_CMD_O_DELAY 0x0e +#define DP_SPI_CMD_O_EXEC 0x0f +#define DP_SPI_CMD_SYNCNOP 0x10 +#define DP_SPI_CMD_Q_RDNMAXLEN 0x11 +#define DP_SPI_CMD_S_BUSTYPE 0x12 +#define DP_SPI_CMD_SPIOP 0x13 +#define DP_SPI_CMD_S_SPI_FREQ 0x14 +#define DP_SPI_CMD_S_PINSTATE 0x15 + +#define DP_SPI_CMD_Q_SPI_CAPS 0x40 +#define DP_SPI_CMD_S_SPI_CHIPN 0x41 +#define DP_SPI_CMD_S_SPI_SETCS 0x42 +#define DP_SPI_CMD_S_SPI_FLAGS 0x43 +#define DP_SPI_CMD_S_SPI_BPW 0x44 +#define DP_SPI_CMD_SPI_READ 0x45 +#define DP_SPI_CMD_SPI_WRITE 0x46 +#define DP_SPI_CMD_SPI_RDWR 0x47 + +#define SERPROG_IFACE_VERSION 0x0001 + +static const uint8_t reqd_cmds[] = { + DP_SPI_CMD_NOP, DP_SPI_CMD_Q_IFACE, DP_SPI_CMD_Q_CMDMAP, + /*DP_SPI_CMD_Q_WRNMAXLEN, DP_SPI_CMD_Q_RDNMAXLEN,*/ + DP_SPI_CMD_S_SPI_FREQ, /*DP_SPI_CMD_S_PINSTATE,*/ /*DP_SPI_CMD_SPIOP,*/ + DP_SPI_CMD_Q_SPI_CAPS, DP_SPI_CMD_S_SPI_CHIPN, DP_SPI_CMD_S_SPI_FLAGS, + DP_SPI_CMD_S_SPI_BPW, DP_SPI_CMD_S_SPI_SETCS, + /*DP_SPI_CMD_SPI_READ, DP_SPI_CMD_SPI_WRITE, DP_SPI_CMD_SPI_RDWR,*/ +}; + +#define DP_SPI_ACK 0x06 +#define DP_SPI_NAK 0x15 + +#define DP_SPI_S_FLG_CPHA (1<<0) +#define DP_SPI_S_FLG_CPOL (1<<1) +#define DP_SPI_S_FLG_STDSPI (0<<2) +#define DP_SPI_S_FLG_TISSP (1<<2) +#define DP_SPI_S_FLG_MICROW (2<<2) +#define DP_SPI_S_FLG_MSBFST (0<<4) +#define DP_SPI_S_FLG_LSBFST (1<<4) +#define DP_SPI_S_FLG_CSACLO (0<<5) +#define DP_SPI_S_FLG_CSACHI (1<<5) +#define DP_SPI_S_FLG_3WIRE (1<<6) + +#define DP_SPI_S_CAP_CPHA_HI (1<<0) +#define DP_SPI_S_CAP_CPHA_LO (1<<1) +#define DP_SPI_S_CAP_CPOL_HI (1<<2) +#define DP_SPI_S_CAP_CPOL_LO (1<<3) +#define DP_SPI_S_CAP_STDSPI (1<<4) +#define DP_SPI_S_CAP_TISSP (1<<5) +#define DP_SPI_S_CAP_MICROW (1<<6) +#define DP_SPI_S_CAP_MSBFST (1<<7) +#define DP_SPI_S_CAP_LSBFST (1<<8) +#define DP_SPI_S_CAP_CSACHI (1<<9) +#define DP_SPI_S_CAP_3WIRE (1<<10) + +#define DP_PINST_AUTOSUSPEND_TIMEOUT 2000 + +struct dp_spi_caps { + uint32_t freq_min, freq_max; + uint16_t flgcaps; + uint8_t num_cs, min_bpw, max_bpw; +}; +struct dp_spi_dev_sett { + /* does not have to be guarded with a spinlock, as the kernel already + * serializes transfer_one/set_cs calls */ + uint32_t freq; + uint8_t flags, bpw; + uint8_t cs, pinst; +}; +struct dp_spi { + struct platform_device *pdev; + struct spi_controller *spictl; + + uint8_t *txbuf; + struct dp_spi_caps caps; + uint8_t csmask; + struct dp_spi_dev_sett devsettings[8]; + uint32_t wrnmaxlen, rdnmaxlen; + uint8_t cmdmap[32]; + + spinlock_t csmap_lock; + + struct spi_board_info binfo[8]; +}; + +static int dp_check_retval_sp(int ret, int len, struct device *dev, + const char *pfix, bool check_pos_val, int lmin, int lmax, const void* rbuf) +{ + ret = dp_check_retval(ret, len, dev, pfix, check_pos_val, lmin, lmax); + if (ret >= 0 && ((const uint8_t *)rbuf)[0] != DP_SPI_ACK) { + dev_err(dev, "%s: did not receive ACK\n", pfix); + ret = -EIO; + } + + return ret; +} + +static bool has_cmd(struct dp_spi *dps, int cmd) +{ + int byteind = cmd >> 3, bitind = cmd & 7; + + return dps->cmdmap[byteind] & (1 << bitind); +} + +static uint8_t kernmode_to_flags(uint16_t caps, int mode) +{ + uint8_t ret = mode & 3; /* bottom 2 bits are the SPI mode (CPHA & CPOL) */ + + if (mode & SPI_LSB_FIRST) ret |= DP_SPI_S_FLG_LSBFST; + else ret |= DP_SPI_S_FLG_MSBFST; + if (mode & SPI_CS_HIGH) ret |= DP_SPI_S_FLG_CSACHI; + else ret |= DP_SPI_S_FLG_CSACLO; + if (mode & SPI_3WIRE) ret |= DP_SPI_S_FLG_3WIRE; + + /* need some defaults for other stuff */ + if (caps & DP_SPI_S_CAP_STDSPI) ret |= DP_SPI_S_FLG_STDSPI; + else if (caps & DP_SPI_S_CAP_TISSP) ret |= DP_SPI_S_FLG_TISSP; + else if (caps & DP_SPI_S_CAP_MICROW) ret |= DP_SPI_S_FLG_MICROW; + else ret |= DP_SPI_S_FLG_STDSPI; /* shrug, also shouldn't happen (cf. get_caps) */ + + return ret; +} +static int devcaps_to_kernmode(uint16_t caps) +{ + int ret; + + ret = caps & 3; /* SPI mode (CPHA & CPOL) bits */ + + if (caps & DP_SPI_S_CAP_LSBFST) ret |= SPI_LSB_FIRST; + if (caps & DP_SPI_S_CAP_CSACHI) ret |= SPI_CS_HIGH; + if (caps & DP_SPI_S_CAP_3WIRE) ret |= SPI_3WIRE; + + return ret; +} +static void caps_to_binfo(struct dp_spi *dps, int busnum) +{ + int i; + + for (i = 0; i < dps->caps.num_cs; ++i) { + snprintf(dps->binfo[i].modalias, SPI_NAME_SIZE, "spidev"); + dps->binfo[i].controller_data = dps; + dps->binfo[i].max_speed_hz = dps->caps.freq_max; + dps->binfo[i].bus_num = busnum; + dps->binfo[i].chip_select = i; + dps->binfo[i].mode = 0; /* shrug */ + } +} + +static void bufconv_to_le(void *dst, const void *src, size_t len_bytes, uint8_t bpw) +{ +#ifdef __LITTLE_ENDIAN + memcpy(dst, src, len_bytes); +#else + if (bpw > 16) { + __le32 *dst32 = (__le32 *)dst; + const uint32_t *src32 = (const uint32_t *)src; + + for (size_t i = 0; i < len_bytes; i += 4, ++dst32, ++src32) { + *dst32 = cpu_to_le32p(src32); + } + } else if (bpw > 8) { + __le16 *dst16 = (__le16 *)dst; + const uint16_t *src16 = (const uint16_t *)src; + + for (size_t i = 0; i < len_bytes; i += 2, ++dst16, ++src16) { + *dst16 = cpu_to_le16p(src16); + } + } else { + memcpy(dst, src, len_bytes); + } +#endif +} +static void bufconv_from_le(void *dst, const void *src, size_t len_bytes, uint8_t bpw) +{ +#ifdef __LITTLE_ENDIAN + memcpy(dst, src, len_bytes); +#else + if (bpw > 16) { + const __le32 *src32 = (const __le32 *)src; + uint32_t *dst32 = (uint32_t *)dst; + + for (size_t i = 0; i < len_bytes; i += 4, ++dst32, ++src32) { + *dst32 = get_unaligned_le32(src32); + } + } else if (bpw > 8) { + const __le16 *src16 = (const __le16 *)src; + uint16_t *dst16 = (uint16_t *)dst; + + for (size_t i = 0; i < len_bytes; i += 2, ++dst16, ++src16) { + *dst16 = le16_to_cpup(src16); + } + } else { + memcpy(dst, src, len_bytes); + } +#endif +} + +static int dp_spi_csmask_set(struct dp_spi *dps, uint8_t csmask) +{ + struct device *dev = &dps->pdev->dev; + uint8_t oldcm; + bool do_csmask = false; + uint8_t wbuf[] = { DP_SPI_CMD_S_SPI_CHIPN, csmask }; + uint8_t *rbuf; + int ret, rlen; + + spin_lock(&dps->csmap_lock); + oldcm = dps->csmask; + if (oldcm != csmask) { + dps->csmask = csmask; + do_csmask = true; + } + spin_unlock(&dps->csmap_lock); + + if (do_csmask) { + dev_dbg(dev, "set csmask %02x\n", csmask); + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "set CS mask", true, 1, 1, rbuf); + + if (rbuf) kfree(rbuf); + } + + return 0; +} +static int dp_spi_csmask_set_one(struct dp_spi *dps, uint8_t cs) +{ + return dp_spi_csmask_set(dps, BIT(cs)); +} +static int dp_spi_cs_set(struct dp_spi *dps, int ind, bool lvl) +{ + struct device *dev = &dps->pdev->dev; + uint8_t wbuf[] = { DP_SPI_CMD_S_SPI_SETCS, lvl ? 1 : 0 }; + uint8_t *rbuf; + int ret, rlen; + + if (dps->devsettings[ind].cs == (lvl ? 1 : 0)) return 0; + + dev_dbg(dev, "set cs %s\n", lvl?"hi":"lo"); + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "set CS", true, 1, 1, rbuf); + + if (!ret) { + dps->devsettings[ind].cs = lvl ? 1 : 0; + } + if (rbuf) kfree(rbuf); + + return ret; +} +static int dp_spi_get_caps(struct dp_spi *dps) +{ + struct device *dev = &dps->pdev->dev; + uint8_t wbuf[] = { DP_SPI_CMD_Q_SPI_CAPS }; + uint8_t *rbuf; + int ret, rlen; + + dev_dbg(dev, "get caps\n"); + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "get caps", true, 14, 14, rbuf); + + if (!ret) { + dps->caps.freq_min = (uint32_t)rbuf[1] | ((uint32_t)rbuf[2] << 8) + | ((uint32_t)rbuf[3] << 16) | ((uint32_t)rbuf[4] << 24); + dps->caps.freq_max = (uint32_t)rbuf[5] | ((uint32_t)rbuf[6] << 8) + | ((uint32_t)rbuf[7] << 16) | ((uint32_t)rbuf[8] << 24); + dps->caps.flgcaps = (uint32_t)rbuf[9] | ((uint32_t)rbuf[10] << 8); + + dps->caps.num_cs = rbuf[11]; + dps->caps.min_bpw = rbuf[12]; + dps->caps.max_bpw = rbuf[13]; + + dev_info(dev, " capabilities: freq=%d..%d, flgcaps=%04hx, bpw=%d..%d, num cs=%d\n", + dps->caps.freq_min, dps->caps.freq_max, dps->caps.flgcaps, + dps->caps.min_bpw, dps->caps.max_bpw, dps->caps.num_cs); + + if (dps->caps.max_bpw == 0 || dps->caps.min_bpw == 0) { + dev_err(dev, "Device replied with max_bpw=0 or min_bpw=0, wtf?\n"); + ret = -EXDEV; + } + if (!(dps->caps.flgcaps & (DP_SPI_S_CAP_STDSPI + | DP_SPI_S_CAP_TISSP | DP_SPI_S_CAP_MICROW))) { + dev_err(dev, "Device does not support any SPI mode, wtf?\n"); + ret = -EXDEV; + } + + kfree(rbuf); + } + + return ret; +} +static int dp_spi_set_freq(struct dp_spi *dps, int ind, uint32_t freq) +{ + struct device *dev = &dps->pdev->dev; + uint8_t wbuf[] = { DP_SPI_CMD_S_SPI_FREQ, + freq, freq >> 8, freq >> 16, freq >> 24 }; + uint8_t *rbuf; + uint32_t freqret; + int ret, rlen; + + if (dps->devsettings[ind].freq == freq) return 0; + + dev_dbg(dev, "set freq to %u\n", freq); + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "set CS", true, 5, 5, rbuf); + + if (!ret) { + freqret = (uint32_t)rbuf[1] | ((uint32_t)rbuf[2] << 8) + | ((uint32_t)rbuf[3] << 16) | ((uint32_t)rbuf[4] << 24); + + if (freqret != freq) { + dev_warn(dev, "set frequency: couldn't provide exact freq %u Hz, %u Hz was applied instead.\n", + freq, freqret); + } + + /* not the returned one, to avoid resending */ + dps->devsettings[ind].freq = freq; + } + if (rbuf) kfree(rbuf); + + return ret; +} +static int dp_spi_set_flags(struct dp_spi *dps, int ind, uint8_t flags) +{ + struct device *dev = &dps->pdev->dev; + uint8_t wbuf[] = { DP_SPI_CMD_S_SPI_FLAGS, flags }; + uint8_t *rbuf, flagret; + int ret, rlen; + + if (dps->devsettings[ind].flags == flags) return 0; + + dev_dbg(dev, "set flags %08x\n", flags); + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "set flags", true, 2, 2, rbuf); + + if (!ret) { + flagret = rbuf[1]; + + if (flagret != flags) { + dev_warn(dev, "set flags: couldn't set exact flags %08x, was set to %08x instead\n", + flags, flagret); + } + + /* not the returned one, to avoid resending */ + dps->devsettings[ind].flags = flags; + } + if (rbuf) kfree(rbuf); + + return ret; +} +static int dp_spi_set_bpw(struct dp_spi *dps, int ind, uint8_t bpw) +{ + struct device *dev = &dps->pdev->dev; + uint8_t wbuf[] = { DP_SPI_CMD_S_SPI_BPW, bpw }; + uint8_t *rbuf, bpwret; + int ret, rlen; + + if (dps->devsettings[ind].bpw == bpw) return 0; + + dev_dbg(dev, "set bpw %hhu\n", bpw); + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "set bpw", true, 2, 2, rbuf); + + if (!ret) { + bpwret = rbuf[1]; + + if (bpwret != bpw) { + dev_warn(dev, "set flags: couldn't set exact bpw %hhu, was set to %hhu instead\n", + bpw, bpwret); + } + + /* not the returned one, to avoid resending */ + dps->devsettings[ind].bpw = bpw; + } + if (rbuf) kfree(rbuf); + + return ret; +} +static int dp_spi_set_pinstate(struct dp_spi *dps, bool pins) +{ + struct device *dev = &dps->pdev->dev; + uint8_t wbuf[] = { DP_SPI_CMD_S_PINSTATE, pins ? 1 : 0 }; + uint8_t *rbuf; + int ret, rlen; + + if (!has_cmd(dps, DP_SPI_CMD_S_PINSTATE)) return 0; + + dev_dbg(dev, "set pinstate %sabled\n", pins?"en":"dis"); + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "set pinstate", true, 2, 2, rbuf); + + /*if (!ret) { + dps->devsettings[ind].pinst = pins; + }*/ + if (rbuf) kfree(rbuf); + + return ret; +} + +static int dp_spi_check_hw(struct dp_spi *dps) +{ + struct device *dev = &dps->pdev->dev; + uint8_t wbuf[] = { DP_SPI_CMD_NOP }; + uint8_t *rbuf; + uint16_t iface; + int ret, rlen, i; + + dev_dbg(dev, "check hw: nop"); + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "check hw: nop", true, 1, 1, rbuf); + + if (rbuf) kfree(rbuf); + if (ret) return ret; + + dev_dbg(dev, "check hw: syncnop"); + wbuf[0] = DP_SPI_CMD_SYNCNOP; + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); + ret = dp_check_retval(ret, rlen, dev, "check hw: nop", true, 2, 2); + if (!ret) { + if (rbuf[0] != DP_SPI_NAK || rbuf[1] != DP_SPI_ACK) { + dev_err(dev, "check hw: syncnop: bad response %02x %02x\n", + rbuf[0], rbuf[1]); + ret = -EIO; + } + } + if (rbuf) kfree(rbuf); + if (ret) return ret; + + dev_dbg(dev, "check hw: iface"); + wbuf[0] = DP_SPI_CMD_Q_IFACE; + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "check hw: iface", true, 3, 3, rbuf); + + if (!ret) { + iface = (uint16_t)rbuf[1] | ((uint16_t)rbuf[2] << 8); + + if (iface != SERPROG_IFACE_VERSION) { + dev_err(dev, "check hw: iface: bad serprog version: expected %hu, got %hu\n", + SERPROG_IFACE_VERSION, iface); + ret = -ENODEV; + } + } + if (rbuf) kfree(rbuf); + if (ret) return ret; + + dev_dbg(dev, "check hw: cmdmap"); + wbuf[0] = DP_SPI_CMD_Q_CMDMAP; + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "check hw: cmdmap", true, 33, 33, rbuf); + + if (!ret) { + memcpy(dps->cmdmap, &rbuf[1], 32); + } + if (rbuf) kfree(rbuf); + if (ret) return ret; + + for (i = 0; i < sizeof(reqd_cmds)/sizeof(*reqd_cmds); ++i) { + if (!has_cmd(dps, reqd_cmds[i])) { + dev_err(dev, "device does not have required serprog command %02x\n", reqd_cmds[i]); + ret = -ENODEV; + } + } + + if (has_cmd(dps, DP_SPI_CMD_Q_PGMNAME)) { + dev_dbg(dev, "check hw: pgmname"); + wbuf[0] = DP_SPI_CMD_Q_PGMNAME; + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "check hw: pgmname", true, 17, 17, rbuf); + + if (!ret) { + rbuf[16] = 0; + dev_info(dev, "Serprog pgmname: '%s'\n", &rbuf[1]); + } + if (rbuf) kfree(rbuf); + if (ret) return ret; + } + + if (has_cmd(dps, DP_SPI_CMD_Q_WRNMAXLEN)) { + dev_dbg(dev, "check hw: wrnmaxlen"); + wbuf[0] = DP_SPI_CMD_Q_WRNMAXLEN; + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "check hw: wrnmaxlen", true, 4, 4, rbuf); + + if (!ret) { + dps->wrnmaxlen = (uint32_t)rbuf[1] | ((uint32_t)rbuf[2] << 8) | ((uint32_t)rbuf[3] << 16); + } + if (rbuf) kfree(rbuf); + if (ret) return ret; + } else dps->rdnmaxlen = 512; + dev_info(dev, " wrnmaxlen = 0x%x\n", dps->wrnmaxlen); + + if (has_cmd(dps, DP_SPI_CMD_Q_RDNMAXLEN)) { + dev_dbg(dev, "check hw: rdnmaxlen"); + wbuf[0] = DP_SPI_CMD_Q_RDNMAXLEN; + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + wbuf, sizeof(wbuf), (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "check hw: rdnmaxlen", true, 4, 4, rbuf); + + if (!ret) { + dps->rdnmaxlen = (uint32_t)rbuf[1] | ((uint32_t)rbuf[2] << 8) | ((uint32_t)rbuf[3] << 16); + } + if (rbuf) kfree(rbuf); + if (ret) return ret; + } else dps->rdnmaxlen = 512; + dev_info(dev, " rdnmaxlen = 0x%x\n", dps->rdnmaxlen); + + return 0; +} + +static int dp_spi_do_read(struct dp_spi *dps, void *data, size_t len, uint8_t bpw) +{ + struct device *dev = &dps->pdev->dev; + uint8_t *rbuf; + int ret, rlen; + + if (len > INT_MAX-4) return -EINVAL; + + if (has_cmd(dps, DP_SPI_CMD_SPI_READ)) { + dev_dbg(dev, "do spi read len=0x%zx\n", len); + + dps->txbuf[0] = DP_SPI_CMD_SPI_READ; + dps->txbuf[1] = len & 0xff; + dps->txbuf[2] = (len >> 8) & 0xff; + dps->txbuf[3] = (len >> 16) & 0xff; + + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + dps->txbuf, 4, (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "do read", true, (int)len+1, (int)len+1, rbuf); + + if (!ret) bufconv_from_le(data, &rbuf[1], len, bpw); + + if (rbuf) kfree(rbuf); + } else if (has_cmd(dps, DP_SPI_CMD_SPIOP)) { + dev_dbg(dev, "do spiop read len=0x%zx\n", len); + + dps->txbuf[0] = DP_SPI_CMD_SPIOP; + dps->txbuf[1] = 0; + dps->txbuf[2] = 0; + dps->txbuf[3] = 0; + dps->txbuf[4] = len & 0xff; + dps->txbuf[5] = (len >> 8) & 0xff; + dps->txbuf[6] = (len >> 16) & 0xff; + + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + dps->txbuf, 7, (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "do spiop read", true, (int)len+1, (int)len+1, rbuf); + + if (!ret) bufconv_from_le(data, &rbuf[1], len, bpw); + + if (rbuf) kfree(rbuf); + } else if (has_cmd(dps, DP_SPI_CMD_SPI_RDWR)) { + dev_dbg(dev, "do rdwr read len=0x%zx\n", len); + + dps->txbuf[0] = DP_SPI_CMD_SPI_RDWR; + dps->txbuf[1] = len & 0xff; + dps->txbuf[2] = (len >> 8) & 0xff; + dps->txbuf[3] = (len >> 16) & 0xff; + + /* we need to fill the buffer with stuff bits to control the data + * that will get sent over the full duplex line. 0 is the default used + * in most places apparently? */ + memset(&dps->txbuf[4], 0, len); + + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + dps->txbuf, (int)len+4, (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "do rdwr read", true, (int)len+1, (int)len+1, rbuf); + + if (!ret) bufconv_from_le(data, &rbuf[1], len, bpw); + + if (rbuf) kfree(rbuf); + } else { + return -EXDEV; + } + + return 0; +} +static int dp_spi_do_write(struct dp_spi *dps, const void *data, size_t len, uint8_t bpw) +{ + struct device *dev = &dps->pdev->dev; + uint8_t *rbuf; + int ret, rlen; + + if (len > INT_MAX-7) return -EINVAL; + + if (has_cmd(dps, DP_SPI_CMD_SPI_WRITE)) { + dev_dbg(dev, "do spi write len=0x%zx\n", len); + + dps->txbuf[0] = DP_SPI_CMD_SPI_WRITE; + dps->txbuf[1] = len & 0xff; + dps->txbuf[2] = (len >> 8) & 0xff; + dps->txbuf[3] = (len >> 16) & 0xff; + + bufconv_to_le(&dps->txbuf[4], data, len, bpw); + + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + dps->txbuf, (int)len+4, (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "do write", true, 1, 1, rbuf); + + if (rbuf) kfree(rbuf); + } else if (has_cmd(dps, DP_SPI_CMD_SPIOP)) { + dev_dbg(dev, "do spiop write len=0x%zx\n", len); + + dps->txbuf[0] = DP_SPI_CMD_SPIOP; + dps->txbuf[1] = len & 0xff; + dps->txbuf[2] = (len >> 8) & 0xff; + dps->txbuf[3] = (len >> 16) & 0xff; + dps->txbuf[4] = 0; + dps->txbuf[5] = 0; + dps->txbuf[6] = 0; + + bufconv_to_le(&dps->txbuf[7], data, len, bpw); + + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + dps->txbuf, (int)len+7, (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "do spiop write", true, 1, 1, rbuf); + + if (rbuf) kfree(rbuf); + } else if (has_cmd(dps, DP_SPI_CMD_SPI_RDWR)) { + dev_dbg(dev, "do rdwr write len=0x%zx\n", len); + + dps->txbuf[0] = DP_SPI_CMD_SPI_RDWR; + dps->txbuf[1] = len & 0xff; + dps->txbuf[2] = (len >> 8) & 0xff; + dps->txbuf[3] = (len >> 16) & 0xff; + + bufconv_to_le(&dps->txbuf[4], data, len, bpw); + + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + dps->txbuf, (int)len+4, (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "do rdwr write", true, (int)len+1, (int)len+1, rbuf); + /* we just don't look at the returned bytes in this case */ + if (rbuf) kfree(rbuf); + } else { + return -EXDEV; + } + + return 0; +} +/* should only be called if it already has the cmd anyway (cf. spi_controller->flags) */ +static int dp_spi_do_rdwr(struct dp_spi *dps, void *rdata, const void *wdata, size_t len, uint8_t bpw) +{ + struct device *dev = &dps->pdev->dev; + uint8_t *rbuf; + int ret, rlen; + + if (len > INT_MAX-4) return -EINVAL; + if (!has_cmd(dps, DP_SPI_CMD_SPI_RDWR)) return -EXDEV; + + dev_dbg(dev, "do rdwr len=0x%zx\n", len); + + dps->txbuf[0] = DP_SPI_CMD_SPI_RDWR; + dps->txbuf[1] = len & 0xff; + dps->txbuf[2] = (len >> 8) & 0xff; + dps->txbuf[3] = (len >> 16) & 0xff; + + bufconv_to_le(&dps->txbuf[4], wdata, len, bpw); + + ret = dp_transfer(dps->pdev, DP_CMD_MODE1_SPI, DP_XFER_FLAGS_PARSE_RESP, + dps->txbuf, (int)len+4, (void**)&rbuf, &rlen); + ret = dp_check_retval_sp(ret, rlen, dev, "do rdwr", true, (int)len+1, -1, rbuf); + + if (!ret) bufconv_from_le(rdata, &rbuf[1], len, bpw); + + if (rbuf) kfree(rbuf); + + return ret; +} + +static int dp_spi_prepare_message(struct spi_controller *spictl, struct spi_message *msg) +{ + struct dp_spi *dps = spi_controller_get_devdata(spictl); + struct spi_device *spidev = msg->spi; + struct device *dev = &spidev->dev; + int ret; + + ret = dp_spi_set_flags(dps, spidev->chip_select, + kernmode_to_flags(dps->caps.flgcaps, spidev->mode)); + if (ret < 0) { + dev_err(dev, "Failed to set SPI flags\n"); + return ret; + } + + /*ret = dp_spi_csmask_set_one(dps, spidev->chip_select); + if (ret < 0) { + dev_err(dev, "Failed to set CS mask\n"); + return ret; + }*/ + + return ret; +} +static void dp_spi_set_cs(struct spi_device *spidev, bool enable) +{ + struct spi_controller *spictl = spidev->controller; + struct dp_spi *dps = spi_controller_get_devdata(spictl); + struct device *dev = &spidev->dev; + int ret; + + ret = dp_spi_csmask_set_one(dps, spidev->chip_select); + if (ret < 0) { + dev_err(dev, "Failed to set CS mask\n"); + return; + } + + ret = dp_spi_cs_set(dps, spidev->chip_select, enable); + if (ret < 0) { + dev_err(dev, "Failed to set chip select line\n"); + return; + } + + /*return 0;*/ +} +static int dp_spi_transfer_one(struct spi_controller *spictl, struct spi_device *spidev, struct spi_transfer *xfer) +{ + struct dp_spi *dps = spi_controller_get_devdata(spictl); + struct device *dev = &spidev->dev; + int ret; + uint32_t cksize, todo, off = 0; + + ret = dp_spi_set_freq(dps, spidev->chip_select, xfer->speed_hz); + if (ret < 0) { + dev_err(dev, "Failed to set SPI frequency to %d Hz\n", xfer->speed_hz); + return ret; + } + + ret = dp_spi_set_bpw(dps, spidev->chip_select, xfer->bits_per_word); + if (ret < 0) { + dev_err(dev, "Failed to set SPI bits-per-word to %d\n", xfer->bits_per_word); + return ret; + } + + if (xfer->tx_buf && xfer->rx_buf) { + cksize = dps->wrnmaxlen; + if (cksize > dps->rdnmaxlen) cksize = dps->rdnmaxlen; + } else if (xfer->tx_buf) { + cksize = dps->wrnmaxlen; + } else if (xfer->rx_buf) { + cksize = dps->rdnmaxlen; + } else return -EINVAL; + + todo = xfer->len; + do { + if (todo < cksize) cksize = todo; + + if (xfer->tx_buf && xfer->rx_buf) { + ret = dp_spi_do_rdwr(dps, xfer->rx_buf + off, xfer->tx_buf + off, cksize, xfer->bits_per_word); + } else if (xfer->tx_buf) { + ret = dp_spi_do_write(dps, xfer->tx_buf + off, cksize, xfer->bits_per_word); + } else /*if (xfer->rx_buf)*/ { + ret = dp_spi_do_read(dps, xfer->rx_buf + off, cksize, xfer->bits_per_word); + } + + if (ret < 0) { + dev_err(dev, "SPI transfer failed! %d\n", ret); + return ret; + } + + todo -= cksize; + off += cksize; + } while (todo); + + return 0; +} + +static int dp_spi_probe(struct platform_device *pdev) +{ + struct spi_controller *spictl; + struct dp_spi *dps; + struct device *dev = &pdev->dev; + int ret, i; + + spictl = spi_alloc_master(dev, sizeof(*dps)); + if (!spictl ) return -ENOMEM; + + platform_set_drvdata(pdev, spictl); + + dps = spi_controller_get_devdata(spictl); + + dps->spictl = spictl; + dps->spictl->dev.of_node = dev->of_node; + dps->pdev = pdev; + dps->csmask = 0xff; + for (i = 0; i < 8; ++i) { + dps->devsettings[i].freq = 0; + dps->devsettings[i].flags = 0xff; + dps->devsettings[i].bpw = 0xff; + } + + spin_lock_init(&dps->csmap_lock); + + ret = dp_spi_check_hw(dps); + if (ret < 0) { + dev_err(dev, "Hardware capabilities lacking\n"); + goto err_free_ctl; + } + + dps->txbuf = devm_kmalloc(&pdev->dev, dps->wrnmaxlen + 0x10, GFP_KERNEL); + if (!dps->txbuf) { + ret = -ENOMEM; + dev_err(dev, "No memory left for TX buffer of length 0x%x\n", dps->wrnmaxlen); + goto err_free_ctl; + } + + ret = dp_spi_get_caps(dps); + if (ret < 0) { + dev_err(dev, "Failed to get device capabilities\n"); + goto err_free_ctl; + } + + spictl->min_speed_hz = dps->caps.freq_min; + spictl->max_speed_hz = dps->caps.freq_max; + spictl->bits_per_word_mask = SPI_BPW_RANGE_MASK(dps->caps.min_bpw, dps->caps.max_bpw); + spictl->num_chipselect = dps->caps.num_cs; + spictl->mode_bits = devcaps_to_kernmode(dps->caps.flgcaps); + + spictl->bus_num = -1; + spictl->prepare_message = dp_spi_prepare_message; + spictl->transfer_one = dp_spi_transfer_one; + spictl->set_cs = dp_spi_set_cs; + + spictl->flags = 0; + if (!has_cmd(dps, DP_SPI_CMD_SPI_RDWR)) + spictl->flags |= SPI_CONTROLLER_HALF_DUPLEX; + + pm_runtime_set_autosuspend_delay(dev, DP_PINST_AUTOSUSPEND_TIMEOUT); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + ret = devm_spi_register_controller(dev, spictl); + if (ret < 0) { + dev_err(dev, "Failed to register SPI controller\n"); + goto err_dereg; + } + + dev_info(dev, "SPI bus number is %d\n", spictl->bus_num); + + caps_to_binfo(dps, spictl->bus_num); + for (i = 0; i < dps->caps.num_cs; ++i) { + if (!spi_new_device(spictl, &dps->binfo[i])) { + dev_warn(dev, "failed to create %s device %d\n", dps->binfo[i].modalias, i); + } + } + + return dp_spi_set_pinstate(dps, true); + +err_dereg: + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); +err_free_ctl: + spi_controller_put(spictl); + return ret; +} + +static int dp_spi_remove(struct platform_device *pdev) +{ + struct spi_controller *spictl = platform_get_drvdata(pdev); + struct dp_spi *dps = spi_controller_get_devdata(spictl); + + pm_runtime_disable(&pdev->dev); + + dp_spi_set_pinstate(dps, false); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int dp_spi_suspend(struct device *dev) +{ + struct spi_controller *spictl = dev_get_drvdata(dev); + struct dp_spi *dps = spi_controller_get_devdata(spictl); + int ret, i; + + ret = spi_controller_suspend(spictl); + if (ret < 0) return ret; + + dp_spi_set_pinstate(dps, false); + + for (i = 0; i < 8; ++i) { + dps->devsettings[i].freq = 0; + dps->devsettings[i].flags = 0xff; + dps->devsettings[i].bpw = 0xff; + } + + return 0; +} + +static int dp_spi_resume(struct device *dev) +{ + struct spi_controller *spictl = dev_get_drvdata(dev); + struct dp_spi *dps = spi_controller_get_devdata(spictl); + + dp_spi_set_pinstate(dps, true); + + return spi_controller_resume(spictl); +} +#endif /* CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM +static int dp_spi_runtime_suspend(struct device *dev) +{ + struct spi_controller *spictl = dev_get_drvdata(dev); + struct dp_spi *dps = spi_controller_get_devdata(spictl); + + return dp_spi_set_pinstate(dps, false); +} +static int dp_spi_runtime_resume(struct device *dev) +{ + struct spi_controller *spictl = dev_get_drvdata(dev); + struct dp_spi *dps = spi_controller_get_devdata(spictl); + + return dp_spi_set_pinstate(dps, true); +} +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops dp_spi_pm = { + SET_SYSTEM_SLEEP_PM_OPS(dp_spi_suspend, dp_spi_resume) + SET_RUNTIME_PM_OPS(dp_spi_runtime_suspend, dp_spi_runtime_resume, NULL) +}; + +static struct platform_driver spi_dp_driver = { + .driver = { + .name = "dragonprobe-spi", + .pm = &dp_spi_pm, + }, + .probe = dp_spi_probe, + .remove = dp_spi_remove +}; +module_platform_driver(spi_dp_driver); + +MODULE_AUTHOR("sys64738 "); +MODULE_AUTHOR("haskal "); +MODULE_DESCRIPTION("SPI interface driver for the " HARDWARE_NAME " USB multitool"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:dragonprobe-spi"); diff --git a/host/setup.py b/host/setup.py index 2916031..2a84202 100644 --- a/host/setup.py +++ b/host/setup.py @@ -4,9 +4,9 @@ with open("../README.md", "r") as f: long_description = f.read() setup( - name='dmctl', + name='dpctl', version='0.1.0', - description='Tool for controlling a dmj device', + description='Tool for controlling a Dragon Probe device', long_description=long_description, long_description_content_type='text/markdown', url='', @@ -31,7 +31,7 @@ setup( include_package_data=True, entry_points={ 'console_scripts': [ - "dmctl=dmctl:main" + "dpctl=dpctl:main" ] }, zip_safe=False diff --git a/src/info.h b/src/info.h index 5059895..dbd076f 100644 --- a/src/info.h +++ b/src/info.h @@ -5,7 +5,7 @@ #include "bsp-info.h" #define INFO_MANUFACTURER "BLAHAJ CTF" -#define INFO_PRODUCT_BARE "CMSIS-DAP" +#define INFO_PRODUCT_BARE "DragonProbe" #define INFO_PRODUCT(board) INFO_PRODUCT_BARE " (" board ")" #endif diff --git a/src/m_default/_default.c b/src/m_default/_default.c index ad20b39..5bff079 100644 --- a/src/m_default/_default.c +++ b/src/m_default/_default.c @@ -304,11 +304,14 @@ static const uint8_t desc_configuration[] = { #endif }; static const char* string_desc_arr[] = { - /*[STRID_LANGID] = (const char[]){0x09, 0x04}, // supported language is English (0x0409) - [STRID_MANUFACTURER] = "BLAHAJ CTF", // Manufacturer - [STRID_PRODUCT] = "Dragnbus (RP2040 Pico)", // Product*/ NULL, + // no hw info here, or the name will be too long >__> + // CMSIS-DAP spec: + // "The Product String must contain 'CMSIS-DAP' somewhere in the string. + // This is used by the debuggers to identify a CMSIS-DAP compliant Debug + // Unit that is connected to a host computer." + [STRID_PRODUCT] = INFO_PRODUCT_BARE " CMSIS-DAP", [STRID_CONFIG] = "Configuration descriptor", // max string length check: ||||||||||||||||||||||||||||||| [STRID_IF_VND_CFG ] = "Device cfg/ctl interface", diff --git a/src/usb_descriptors.c b/src/usb_descriptors.c index d043a6e..5131525 100644 --- a/src/usb_descriptors.c +++ b/src/usb_descriptors.c @@ -185,15 +185,17 @@ const uint16_t* mode_std_descriptor_string_cb(uint8_t index, uint16_t langid) { chr_count = 1; } else if (index == STRID_SERIAL) { chr_count = get_unique_id_u16(_desc_str + 1); - } else if (index > STRID_CONFIG && mode_current != NULL && mode_current->string_desc != NULL) { - if (index >= mode_current->n_string_desc) return NULL; + } else if (mode_current != NULL && mode_current->string_desc != NULL) { + if (index >= mode_current->n_string_desc) goto fallback; const char* str = mode_current->string_desc[index]; + if (!str) goto fallback; chr_count = TU_MIN(strlen(str), 31); for (int i = 0; i < chr_count; i++) { _desc_str[1 + i] = str[i]; } } else { + fallback: // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors