Commit 871f1f07 authored by Oleg Dzhimiev's avatar Oleg Dzhimiev
Browse files

updated drvier for kernels 4.9+ where usb_control_msg cannot be fed with...

updated drvier for kernels 4.9+ where usb_control_msg cannot be fed with statically allocated buffer
parent f71e5c8d
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -3,8 +3,6 @@
CP210X_NAME="cp210x.c"
CP210X_ADDRESS="https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/plain/drivers/usb/serial/cp210x.c?id=refs/tags/v"

PATCH_NAME="cp210x.patch"

LINUX_KERNEL_VERSION=$(uname -r | cut -f1 -d"-")
LKV_P1=$(echo $LINUX_KERNEL_VERSION | cut -f1 -d".")
LKV_P2=$(echo $LINUX_KERNEL_VERSION | cut -f2 -d".")
@@ -16,6 +14,14 @@ else
  CP210X_VERSION=$(echo "$LKV_P1.$LKV_P2.$LKV_P3")
fi

if [ $LKV_P1 -le 4 ] && [ $LKV_P2 -lt 9 ]; then
  echo "Selecting patch for kernel <4.9.0!"
  PATCH_NAME="cp210x.patch"
else
  echo "Selecting patch for kernel 4.9+!"
  PATCH_NAME="cp210x_kernel_4.9.x+.patch"
fi

#uncomment if patch doesn't work 
#CP210X_VERSION="3.8.0"

+97 −0
Original line number Diff line number Diff line
--- a/cp210x.c	2019-07-18 13:10:09.000000000 -0600
+++ b/cp210x.c	2019-07-18 13:06:25.000000000 -0600
@@ -31,6 +31,8 @@
  */
 static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *);
 static void cp210x_close(struct usb_serial_port *);
+static int cp210x_ioctl(struct tty_struct *tty,
+	unsigned int cmd, unsigned long arg);
 static void cp210x_get_termios(struct tty_struct *, struct usb_serial_port *);
 static void cp210x_get_termios_port(struct usb_serial_port *port,
 	tcflag_t *cflagp, unsigned int *baudp);
@@ -245,6 +247,7 @@
 	.bulk_out_size		= 256,
 	.open			= cp210x_open,
 	.close			= cp210x_close,
+        .ioctl			= cp210x_ioctl,
 	.break_ctl		= cp210x_break_ctl,
 	.set_termios		= cp210x_set_termios,
 	.tx_empty		= cp210x_tx_empty,
@@ -262,6 +265,10 @@
 	&cp210x_device, NULL
 };
 
+/* IOCTLs */
+#define IOCTL_GPIOGET	 0x8000
+#define IOCTL_GPIOSET	 0x8001
+
 /* Config request types */
 #define REQTYPE_HOST_TO_INTERFACE	0x41
 #define REQTYPE_INTERFACE_TO_HOST	0xc1
@@ -867,6 +874,66 @@
 	return !count;
 }
 
+// Elphel
+static int cp210x_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
+{
+	struct usb_serial_port *port = tty->driver_data;
+	struct usb_serial *serial = port->serial;
+
+	int result = 0;
+	unsigned int latch_setting = 0;
+        int bufsize = 1;
+
+	// usb_control_msg used to be able to read to statically allocated buffer
+	// now it does not, have to create this buffer
+	// https://stackoverflow.com/questions/52685669/usb-control-msg-returns-eagain
+	void *dmabuf;
+
+	dmabuf = kmalloc(bufsize, GFP_KERNEL);
+	if (!dmabuf)
+            return -ENOMEM;
+
+	switch (cmd) {
+	    case IOCTL_GPIOGET:
+		result = usb_control_msg(
+			      serial->dev,
+			      usb_rcvctrlpipe(serial->dev, 0),
+			      CP210X_VENDOR_SPECIFIC,
+			      REQTYPE_DEVICE_TO_HOST,
+			      CP210X_READ_LATCH,
+			      cp210x_interface_num(serial),
+			      dmabuf, bufsize,
+			      USB_CTRL_GET_TIMEOUT);
+		if (result != bufsize)
+		    return -EPROTO;
+                memcpy(&latch_setting, dmabuf, bufsize);
+		*(unsigned long *)arg = (unsigned long)latch_setting;
+		return 0;
+	    break;
+	    case IOCTL_GPIOSET:
+		latch_setting = *(unsigned int *)arg & 0x000000FF;
+		//why [23:16] bits are taken for value is unknown
+		latch_setting |= (*(unsigned int *)arg & 0x00FF0000) >> 8;
+
+		result = usb_control_msg(
+			      serial->dev,
+			      usb_sndctrlpipe(serial->dev, 0),
+			      CP210X_VENDOR_SPECIFIC,
+			      REQTYPE_HOST_TO_DEVICE,
+			      CP210X_WRITE_LATCH,
+			      latch_setting,
+			      NULL, 0,
+			      USB_CTRL_SET_TIMEOUT);
+		if (result != 0)
+		    return -EPROTO;
+		return 0;
+	    break;
+	    default:
+	    break;
+	}
+	return -ENOIOCTLCMD;
+}
+
 /*
  * cp210x_get_termios
  * Reads the baud rate, data bits, parity, stop bits and flow control mode