diff options
| author | Konstantin Shkolnyy <konstantin.shkolnyy@gmail.com> | 2016-02-28 15:51:30 -0600 | 
|---|---|---|
| committer | Johan Hovold <johan@kernel.org> | 2016-02-29 19:04:49 +0100 | 
| commit | 19165b2b10a3b3d18b32a6add465379deade0736 (patch) | |
| tree | 77c1a9388726f3182118d597e82eff4860f0ce20 /drivers/usb/serial | |
| parent | 6424839ca194cf2497d2dfabf3586adf256f6754 (diff) | |
USB: serial: cp210x: add 16-bit register access functions
cp210x_get_config and cp210x_set_config are cumbersome to use. This change
introduces new register access functions for 16-bit values, instead of
the above functions.
Signed-off-by: Konstantin Shkolnyy <konstantin.shkolnyy@gmail.com>
Signed-off-by: Johan Hovold <johan@kernel.org>
Diffstat (limited to 'drivers/usb/serial')
| -rw-r--r-- | drivers/usb/serial/cp210x.c | 147 | 
1 files changed, 108 insertions, 39 deletions
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 987813b8a7f9..e9b2bddd719f 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -423,14 +423,88 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request,  }  /* - * cp210x_set_config_single - * Convenience function for calling cp210x_set_config on single data values - * without requiring an integer pointer + * Reads a variable-sized block of CP210X_ registers, identified by req. + * Returns data into buf in native USB byte order.   */ -static inline int cp210x_set_config_single(struct usb_serial_port *port, -		u8 request, unsigned int data) +static int cp210x_read_reg_block(struct usb_serial_port *port, u8 req, +		void *buf, int bufsize)  { -	return cp210x_set_config(port, request, &data, 2); +	struct usb_serial *serial = port->serial; +	struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); +	void *dmabuf; +	int result; + +	dmabuf = kmalloc(bufsize, GFP_KERNEL); +	if (!dmabuf) { +		/* +		 * FIXME Some callers don't bother to check for error, +		 * at least give them consistent junk until they are fixed +		 */ +		memset(buf, 0, bufsize); +		return -ENOMEM; +	} + +	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), +			req, REQTYPE_INTERFACE_TO_HOST, 0, +			port_priv->bInterfaceNumber, dmabuf, bufsize, +			USB_CTRL_SET_TIMEOUT); +	if (result == bufsize) { +		memcpy(buf, dmabuf, bufsize); +		result = 0; +	} else { +		dev_err(&port->dev, "failed get req 0x%x size %d status: %d\n", +				req, bufsize, result); +		if (result >= 0) +			result = -EPROTO; + +		/* +		 * FIXME Some callers don't bother to check for error, +		 * at least give them consistent junk until they are fixed +		 */ +		memset(buf, 0, bufsize); +	} + +	kfree(dmabuf); + +	return result; +} + +/* + * Reads any 16-bit CP210X_ register identified by req. + */ +static int cp210x_read_u16_reg(struct usb_serial_port *port, u8 req, u16 *val) +{ +	__le16 le16_val; +	int err; + +	err = cp210x_read_reg_block(port, req, &le16_val, sizeof(le16_val)); +	if (err) +		return err; + +	*val = le16_to_cpu(le16_val); +	return 0; +} + +/* + * Writes any 16-bit CP210X_ register (req) whose value is passed + * entirely in the wValue field of the USB request. + */ +static int cp210x_write_u16_reg(struct usb_serial_port *port, u8 req, u16 val) +{ +	struct usb_serial *serial = port->serial; +	struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); +	int result; + +	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), +			req, REQTYPE_HOST_TO_INTERFACE, val, +			port_priv->bInterfaceNumber, NULL, 0, +			USB_CTRL_SET_TIMEOUT); +	if (result < 0) { +		dev_err(&port->dev, "failed set request 0x%x status: %d\n", +				req, result); +	} + +	return result;  }  /* @@ -442,47 +516,46 @@ static inline int cp210x_set_config_single(struct usb_serial_port *port,  static int cp210x_detect_swapped_line_ctl(struct usb_serial_port *port)  {  	struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); -	unsigned int line_ctl_save; -	unsigned int line_ctl_test; +	u16 line_ctl_save; +	u16 line_ctl_test;  	int err; -	err = cp210x_get_config(port, CP210X_GET_LINE_CTL, &line_ctl_save, 2); +	err = cp210x_read_u16_reg(port, CP210X_GET_LINE_CTL, &line_ctl_save);  	if (err)  		return err; -	line_ctl_test = 0x800; -	err = cp210x_set_config(port, CP210X_SET_LINE_CTL, &line_ctl_test, 2); +	err = cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, 0x800);  	if (err)  		return err; -	err = cp210x_get_config(port, CP210X_GET_LINE_CTL, &line_ctl_test, 2); +	err = cp210x_read_u16_reg(port, CP210X_GET_LINE_CTL, &line_ctl_test);  	if (err)  		return err;  	if (line_ctl_test == 8) {  		port_priv->has_swapped_line_ctl = true; -		line_ctl_save = swab16((u16)line_ctl_save); +		line_ctl_save = swab16(line_ctl_save);  	} -	return cp210x_set_config(port, CP210X_SET_LINE_CTL, &line_ctl_save, 2); +	return cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, line_ctl_save);  }  /* - * Must always be called instead of cp210x_get_config(CP210X_GET_LINE_CTL) + * Must always be called instead of cp210x_read_u16_reg(CP210X_GET_LINE_CTL)   * to workaround cp2108 bug and get correct value.   */ -static int cp210x_get_line_ctl(struct usb_serial_port *port, unsigned int *ctl) +static int cp210x_get_line_ctl(struct usb_serial_port *port, u16 *ctl)  {  	struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);  	int err; -	err = cp210x_get_config(port, CP210X_GET_LINE_CTL, ctl, 2); +	err = cp210x_read_u16_reg(port, CP210X_GET_LINE_CTL, ctl);  	if (err)  		return err;  	/* Workaround swapped bytes in 16-bit value from CP210X_GET_LINE_CTL */  	if (port_priv->has_swapped_line_ctl) -		*ctl = swab16((u16)(*ctl)); +		*ctl = swab16(*ctl);  	return 0;  } @@ -533,8 +606,7 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)  {  	int result; -	result = cp210x_set_config_single(port, CP210X_IFC_ENABLE, -								UART_ENABLE); +	result = cp210x_write_u16_reg(port, CP210X_IFC_ENABLE, UART_ENABLE);  	if (result) {  		dev_err(&port->dev, "%s - Unable to enable UART\n", __func__);  		return result; @@ -552,15 +624,12 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)  static void cp210x_close(struct usb_serial_port *port)  { -	unsigned int purge_ctl; -  	usb_serial_generic_close(port);  	/* Clear both queues; cp2108 needs this to avoid an occasional hang */ -	purge_ctl = PURGE_ALL; -	cp210x_set_config(port, CP210X_PURGE, &purge_ctl, 2); +	cp210x_write_u16_reg(port, CP210X_PURGE, PURGE_ALL); -	cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE); +	cp210x_write_u16_reg(port, CP210X_IFC_ENABLE, UART_DISABLE);  }  /* @@ -640,7 +709,7 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,  	struct device *dev = &port->dev;  	unsigned int cflag, modem_ctl[4];  	unsigned int baud; -	unsigned int bits; +	u16 bits;  	cp210x_get_config(port, CP210X_GET_BAUDRATE, &baud, 4); @@ -673,14 +742,14 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,  		cflag |= CS8;  		bits &= ~BITS_DATA_MASK;  		bits |= BITS_DATA_8; -		cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); +		cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);  		break;  	default:  		dev_dbg(dev, "%s - Unknown number of data bits, using 8\n", __func__);  		cflag |= CS8;  		bits &= ~BITS_DATA_MASK;  		bits |= BITS_DATA_8; -		cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); +		cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);  		break;  	} @@ -711,7 +780,7 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,  		dev_dbg(dev, "%s - Unknown parity mode, disabling parity\n", __func__);  		cflag &= ~PARENB;  		bits &= ~BITS_PARITY_MASK; -		cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); +		cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);  		break;  	} @@ -723,7 +792,7 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,  	case BITS_STOP_1_5:  		dev_dbg(dev, "%s - stop bits = 1.5 (not supported, using 1 stop bit)\n", __func__);  		bits &= ~BITS_STOP_MASK; -		cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); +		cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);  		break;  	case BITS_STOP_2:  		dev_dbg(dev, "%s - stop bits = 2\n", __func__); @@ -732,7 +801,7 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,  	default:  		dev_dbg(dev, "%s - Unknown number of stop bits, using 1 stop bit\n", __func__);  		bits &= ~BITS_STOP_MASK; -		cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); +		cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);  		break;  	} @@ -806,7 +875,7 @@ static void cp210x_set_termios(struct tty_struct *tty,  {  	struct device *dev = &port->dev;  	unsigned int cflag, old_cflag; -	unsigned int bits; +	u16 bits;  	unsigned int modem_ctl[4];  	cflag = tty->termios.c_cflag; @@ -845,7 +914,7 @@ static void cp210x_set_termios(struct tty_struct *tty,  			bits |= BITS_DATA_8;  			break;  		} -		if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) +		if (cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits))  			dev_dbg(dev, "Number of data bits requested not supported by device\n");  	} @@ -872,7 +941,7 @@ static void cp210x_set_termios(struct tty_struct *tty,  				}  			}  		} -		if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) +		if (cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits))  			dev_dbg(dev, "Parity mode not supported by device\n");  	} @@ -886,7 +955,7 @@ static void cp210x_set_termios(struct tty_struct *tty,  			bits |= BITS_STOP_1;  			dev_dbg(dev, "%s - stop bits = 1\n", __func__);  		} -		if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) +		if (cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits))  			dev_dbg(dev, "Number of stop bits requested not supported by device\n");  	} @@ -926,7 +995,7 @@ static int cp210x_tiocmset(struct tty_struct *tty,  static int cp210x_tiocmset_port(struct usb_serial_port *port,  		unsigned int set, unsigned int clear)  { -	unsigned int control = 0; +	u16 control = 0;  	if (set & TIOCM_RTS) {  		control |= CONTROL_RTS; @@ -947,7 +1016,7 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port,  	dev_dbg(&port->dev, "%s - control = 0x%.4x\n", __func__, control); -	return cp210x_set_config(port, CP210X_SET_MHS, &control, 2); +	return cp210x_write_u16_reg(port, CP210X_SET_MHS, control);  }  static void cp210x_dtr_rts(struct usb_serial_port *p, int on) @@ -981,7 +1050,7 @@ static int cp210x_tiocmget(struct tty_struct *tty)  static void cp210x_break_ctl(struct tty_struct *tty, int break_state)  {  	struct usb_serial_port *port = tty->driver_data; -	unsigned int state; +	u16 state;  	if (break_state == 0)  		state = BREAK_OFF; @@ -989,7 +1058,7 @@ static void cp210x_break_ctl(struct tty_struct *tty, int break_state)  		state = BREAK_ON;  	dev_dbg(&port->dev, "%s - turning break %s\n", __func__,  		state == BREAK_OFF ? "off" : "on"); -	cp210x_set_config(port, CP210X_SET_BREAK, &state, 2); +	cp210x_write_u16_reg(port, CP210X_SET_BREAK, state);  }  static int cp210x_port_probe(struct usb_serial_port *port)  | 
