shithub: riscv

Download patch

ref: a3f3953ab2f245cd47aab3563014c04f1a70f9be
parent: 610071bb8b28fe8a871b97f0332e47c3d921f3cf
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Oct 9 08:12:13 EDT 2022

usbsdmux: Add program to control usb-sd-mux device

--- /dev/null
+++ b/sys/man/8/usbsdmux
@@ -1,0 +1,41 @@
+.TH USBSDMUX 8
+.SH NAME
+usbsdmux \- change mode of a usb-sd-mux device
+.SH SYNOPSIS
+.B aux/usbsdmux
+.I mode
+.B [
+.I /dev/sdUxxxxx/raw
+.B ]
+.SH DESCRIPTION
+The USB-SD-Mux from Linux Automation GmbH is a device
+that can programmatically attach and detach a sd-card
+from a device-under-test (DUT), allowing it to be 
+re-written from another machine (HOST) without the
+need to physically swap the sd-card.
+.PP
+The
+.I mode
+can be one of the following:
+.TP
+off
+The sd-card is disconnected from both the HOST and the DUT.
+.TP
+dut
+The sd-card is connected to the DUT and disconnected from
+the HOST.
+.TP
+host
+The sd-card is connected to the HOST and disconnected from
+the DUT.
+.PP
+This program uses a vendor-specific SCSI command to change
+the mode.
+When not specified, it opens
+.B /dev/sdUdca10/raw
+which is the first USB-SD-Mux device attached to the HOST.
+.SH SOURCE
+.B /sys/src/cmd/aux/usbsdmux.c
+.SH SEE ALSO
+.IR nusb (4)
+.B https://linux-automation.com/en/products/usb-sd-mux.html
--- a/sys/src/cmd/aux/mkfile
+++ b/sys/src/cmd/aux/mkfile
@@ -46,6 +46,7 @@
 	txt2uimage\
 	unbflz\
 	usage\
+	usbsdmux\
 	write\
 	wacom\
 	wikifmt\
--- /dev/null
+++ b/sys/src/cmd/aux/usbsdmux.c
@@ -1,0 +1,112 @@
+#include <u.h>
+#include <libc.h>
+
+enum {
+	I2C_ADDR = 0x41,
+
+	REG_INPUT = 0x00,
+	REG_OUTPUT = 0x01,
+	REG_POLARITY = 0x02,
+	REG_CONFIG = 0x03,
+
+	IO_DAT = 1<<0,
+	IO_PWR = 1<<1,
+	IO_DUT = 1<<2,
+	IO_CARD = 1<<3,
+};
+
+enum {
+	MODE_OFF,
+	MODE_DUT,
+	MODE_HOST,
+};
+
+int mode, fd;
+char *file = "/dev/sdUdca10/raw";
+
+void
+wr(int reg, int val)
+{
+	static uchar cmd[16], dat[512];
+	char status[32];
+	int n;
+
+	cmd[0] = 0xCF;
+	cmd[1] = 0x23;
+	cmd[2] = I2C_ADDR<<1;
+	cmd[3] = 0;
+	cmd[4] = 2>>8;
+	cmd[5] = 2;
+	cmd[6] = 0;
+
+	if(write(fd, cmd, sizeof(cmd)) != sizeof(cmd))
+		sysfatal("write command: %r");
+
+	dat[0] = reg;
+	dat[1] = val;
+	if(write(fd, dat, sizeof(dat)) < 0)
+		sysfatal("write data: %r");
+
+	if((n = pread(fd, status, sizeof(status)-1, 0)) < 0)
+		sysfatal("read status: %r");
+
+	status[n] = '\0';
+	if(atoi(status) != 0)
+		sysfatal("command error status: %s", status);
+}
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s off|dut|host [/dev/sdUxxxxx/raw]\n", argv0);
+	exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+	ARGBEGIN {
+	} ARGEND;
+
+	switch(argc){
+	case 2:
+		file = argv[1];
+		/* no break */
+	case 1:
+		break;
+	default:
+		usage();
+	}
+	
+	if(cistrcmp(argv[0], "off") == 0)
+		mode = MODE_OFF;
+	else if(cistrcmp(argv[0], "dut") == 0)
+		mode = MODE_DUT;
+	else if(cistrcmp(argv[0], "host") == 0)
+		mode = MODE_HOST;
+	else
+		usage();
+
+	if((fd = open(file, ORDWR)) < 0)
+		sysfatal("open: %r");
+
+	/* disconnect mode */
+	wr(REG_OUTPUT, IO_DAT|IO_PWR|IO_DUT|IO_CARD);
+	wr(REG_CONFIG, 0);
+	sleep(100);
+
+	/* apply mode */
+	switch(mode){
+	case MODE_OFF:
+		break;
+	case MODE_DUT:
+		wr(REG_OUTPUT, IO_DAT|IO_PWR|IO_CARD);
+		wr(REG_OUTPUT, IO_DUT|IO_CARD);
+		break;
+	case MODE_HOST:
+		wr(REG_OUTPUT, 0);
+		break;
+	}
+
+	exits(nil);
+}