USB-serial updates for v4.19-rc1
Here are the USB-serial updates for 4.19-rc1, including: - gpio support for CP2102N devices - improved line-speed handling for cp210x - conversion to spin_lock_irqsave() in completion handlers - dropped kl5kusb105 support from the kl5kusb105 driver (sic!) Included are also various lower-priority fixes and clean ups. All but the final commit have been in linux-next, and with no reported issues. Signed-off-by: Johan Hovold <johan@kernel.org> -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEEHszNKQClByu0A+9RQQ3kT97htJUFAltSEpQRHGpvaGFuQGtl cm5lbC5vcmcACgkQQQ3kT97htJUXJA//UaE1M6D5LefGKEitn1CMMqaCxc6M4U/y PyuGnGds22VXYgscQlur++bhetJ12qGWoo8r1IOl4QgZl5dWOISx19F5kgMXBMr7 GKEPraRCdxCvZ4RSKbjinlUIjFBij131doI2NIOP6lVdbnwA+z0fX5OH6zAf61p2 Tr/aNyJmN2eIJJx+ez7PszEB3pczWNpv7uP7tmoZ/cmyLdpRYYJzsaSv4I0KA4dz d87IQ9G2eG1BGbs3cYN7fUwwNhcsKG7wfonXMfQPEENdyPWdle7sh/EiubRlquv4 I7xs8+E5zDKChrwavbMQr4uCmXf3L1O7Ueev9718pHzYkQTfxiCvAqt6nhlmkyEx yZdo3DncTMGT3A8/MZk3C66I30xul8z7BH2X0DVXr8yeV4ZN17u7F65Qzyr5Tmni aUYPXaov6JuyLtIBNii3cXMtMuG9ghJoEbXZ2U9DcCFuYeDW6xJuTUd0sKmctTWa htXgW9lvndw0C3ojTXgp6dT2KQyEYhKDM6qdgVhoZV2x4M2XErEMSxTTIm0nlG7O dnrIT3q+iqarxU4vBC6doOq7vbQP5L7UPfpYJcD/AqMvjLX0ZEFInKz+eI2KLUg0 MM8DatTs6z80lClKfKmpNw/bWWcUdKyH9acFXvjrflwwMU2hqsJB9RcsN0d4ppNL QtaT/uY6zls= =0ukW -----END PGP SIGNATURE----- Merge tag 'usb-serial-4.19-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-next Johan writes: USB-serial updates for v4.19-rc1 Here are the USB-serial updates for 4.19-rc1, including: - gpio support for CP2102N devices - improved line-speed handling for cp210x - conversion to spin_lock_irqsave() in completion handlers - dropped kl5kusb105 support from the kl5kusb105 driver (sic!) Included are also various lower-priority fixes and clean ups. All but the final commit have been in linux-next, and with no reported issues. Signed-off-by: Johan Hovold <johan@kernel.org>
This commit is contained in:
		
						commit
						78fbe864c3
					
				| @ -418,15 +418,6 @@ Current status: | ||||
|   why it is wise to cut down on the rate used is wise for large | ||||
|   transfers until this is settled. | ||||
|    | ||||
| Options supported: | ||||
|   If this driver is compiled as a module you can pass the following | ||||
|   options to it: | ||||
|   debug			- extra verbose debugging info | ||||
|   			  (default: 0; nonzero enables) | ||||
|   use_lowlatency	- use low_latency flag to speed up tty layer | ||||
| 			  when reading from the device. | ||||
| 			  (default: 0; nonzero enables) | ||||
| 
 | ||||
|   See http://www.uuhaus.de/linux/palmconnect.html for up-to-date | ||||
|   information on this driver. | ||||
| 
 | ||||
|  | ||||
| @ -239,11 +239,14 @@ MODULE_DEVICE_TABLE(usb, id_table); | ||||
| struct cp210x_serial_private { | ||||
| #ifdef CONFIG_GPIOLIB | ||||
| 	struct gpio_chip	gc; | ||||
| 	u8			config; | ||||
| 	u8			gpio_mode; | ||||
| 	bool			gpio_registered; | ||||
| 	u8			gpio_pushpull; | ||||
| 	u8			gpio_altfunc; | ||||
| 	u8			gpio_input; | ||||
| #endif | ||||
| 	u8			partnum; | ||||
| 	speed_t			max_speed; | ||||
| 	bool			use_actual_rate; | ||||
| }; | ||||
| 
 | ||||
| struct cp210x_port_private { | ||||
| @ -356,6 +359,7 @@ static struct usb_serial_driver * const serial_drivers[] = { | ||||
| #define CONTROL_WRITE_RTS	0x0200 | ||||
| 
 | ||||
| /* CP210X_VENDOR_SPECIFIC values */ | ||||
| #define CP210X_READ_2NCONFIG	0x000E | ||||
| #define CP210X_READ_LATCH	0x00C2 | ||||
| #define CP210X_GET_PARTNUM	0x370B | ||||
| #define CP210X_GET_PORTCONFIG	0x370C | ||||
| @ -369,6 +373,9 @@ static struct usb_serial_driver * const serial_drivers[] = { | ||||
| #define CP210X_PARTNUM_CP2104	0x04 | ||||
| #define CP210X_PARTNUM_CP2105	0x05 | ||||
| #define CP210X_PARTNUM_CP2108	0x08 | ||||
| #define CP210X_PARTNUM_CP2102N_QFN28	0x20 | ||||
| #define CP210X_PARTNUM_CP2102N_QFN24	0x21 | ||||
| #define CP210X_PARTNUM_CP2102N_QFN20	0x22 | ||||
| #define CP210X_PARTNUM_UNKNOWN	0xFF | ||||
| 
 | ||||
| /* CP210X_GET_COMM_STATUS returns these 0x13 bytes */ | ||||
| @ -462,6 +469,12 @@ struct cp210x_config { | ||||
| #define CP2105_GPIO1_RXLED_MODE		BIT(1) | ||||
| #define CP2105_GPIO1_RS485_MODE		BIT(2) | ||||
| 
 | ||||
| /* CP2102N configuration array indices */ | ||||
| #define CP210X_2NCONFIG_CONFIG_VERSION_IDX	2 | ||||
| #define CP210X_2NCONFIG_GPIO_MODE_IDX		581 | ||||
| #define CP210X_2NCONFIG_GPIO_RSTLATCH_IDX	587 | ||||
| #define CP210X_2NCONFIG_GPIO_CONTROL_IDX	600 | ||||
| 
 | ||||
| /* CP210X_VENDOR_SPECIFIC, CP210X_WRITE_LATCH call writes these 0x2 bytes. */ | ||||
| struct cp210x_gpio_write { | ||||
| 	u8	mask; | ||||
| @ -767,48 +780,6 @@ static int cp210x_get_line_ctl(struct usb_serial_port *port, u16 *ctl) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * cp210x_quantise_baudrate | ||||
|  * Quantises the baud rate as per AN205 Table 1 | ||||
|  */ | ||||
| static unsigned int cp210x_quantise_baudrate(unsigned int baud) | ||||
| { | ||||
| 	if (baud <= 300) | ||||
| 		baud = 300; | ||||
| 	else if (baud <= 600)      baud = 600; | ||||
| 	else if (baud <= 1200)     baud = 1200; | ||||
| 	else if (baud <= 1800)     baud = 1800; | ||||
| 	else if (baud <= 2400)     baud = 2400; | ||||
| 	else if (baud <= 4000)     baud = 4000; | ||||
| 	else if (baud <= 4803)     baud = 4800; | ||||
| 	else if (baud <= 7207)     baud = 7200; | ||||
| 	else if (baud <= 9612)     baud = 9600; | ||||
| 	else if (baud <= 14428)    baud = 14400; | ||||
| 	else if (baud <= 16062)    baud = 16000; | ||||
| 	else if (baud <= 19250)    baud = 19200; | ||||
| 	else if (baud <= 28912)    baud = 28800; | ||||
| 	else if (baud <= 38601)    baud = 38400; | ||||
| 	else if (baud <= 51558)    baud = 51200; | ||||
| 	else if (baud <= 56280)    baud = 56000; | ||||
| 	else if (baud <= 58053)    baud = 57600; | ||||
| 	else if (baud <= 64111)    baud = 64000; | ||||
| 	else if (baud <= 77608)    baud = 76800; | ||||
| 	else if (baud <= 117028)   baud = 115200; | ||||
| 	else if (baud <= 129347)   baud = 128000; | ||||
| 	else if (baud <= 156868)   baud = 153600; | ||||
| 	else if (baud <= 237832)   baud = 230400; | ||||
| 	else if (baud <= 254234)   baud = 250000; | ||||
| 	else if (baud <= 273066)   baud = 256000; | ||||
| 	else if (baud <= 491520)   baud = 460800; | ||||
| 	else if (baud <= 567138)   baud = 500000; | ||||
| 	else if (baud <= 670254)   baud = 576000; | ||||
| 	else if (baud < 1000000) | ||||
| 		baud = 921600; | ||||
| 	else if (baud > 2000000) | ||||
| 		baud = 2000000; | ||||
| 	return baud; | ||||
| } | ||||
| 
 | ||||
| static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) | ||||
| { | ||||
| 	int result; | ||||
| @ -1028,6 +999,75 @@ static void cp210x_get_termios_port(struct usb_serial_port *port, | ||||
| 	*cflagp = cflag; | ||||
| } | ||||
| 
 | ||||
| struct cp210x_rate { | ||||
| 	speed_t rate; | ||||
| 	speed_t high; | ||||
| }; | ||||
| 
 | ||||
| static const struct cp210x_rate cp210x_an205_table1[] = { | ||||
| 	{ 300, 300 }, | ||||
| 	{ 600, 600 }, | ||||
| 	{ 1200, 1200 }, | ||||
| 	{ 1800, 1800 }, | ||||
| 	{ 2400, 2400 }, | ||||
| 	{ 4000, 4000 }, | ||||
| 	{ 4800, 4803 }, | ||||
| 	{ 7200, 7207 }, | ||||
| 	{ 9600, 9612 }, | ||||
| 	{ 14400, 14428 }, | ||||
| 	{ 16000, 16062 }, | ||||
| 	{ 19200, 19250 }, | ||||
| 	{ 28800, 28912 }, | ||||
| 	{ 38400, 38601 }, | ||||
| 	{ 51200, 51558 }, | ||||
| 	{ 56000, 56280 }, | ||||
| 	{ 57600, 58053 }, | ||||
| 	{ 64000, 64111 }, | ||||
| 	{ 76800, 77608 }, | ||||
| 	{ 115200, 117028 }, | ||||
| 	{ 128000, 129347 }, | ||||
| 	{ 153600, 156868 }, | ||||
| 	{ 230400, 237832 }, | ||||
| 	{ 250000, 254234 }, | ||||
| 	{ 256000, 273066 }, | ||||
| 	{ 460800, 491520 }, | ||||
| 	{ 500000, 567138 }, | ||||
| 	{ 576000, 670254 }, | ||||
| 	{ 921600, UINT_MAX } | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * Quantises the baud rate as per AN205 Table 1 | ||||
|  */ | ||||
| static speed_t cp210x_get_an205_rate(speed_t baud) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < ARRAY_SIZE(cp210x_an205_table1); ++i) { | ||||
| 		if (baud <= cp210x_an205_table1[i].high) | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	return cp210x_an205_table1[i].rate; | ||||
| } | ||||
| 
 | ||||
| static speed_t cp210x_get_actual_rate(struct usb_serial *serial, speed_t baud) | ||||
| { | ||||
| 	struct cp210x_serial_private *priv = usb_get_serial_data(serial); | ||||
| 	unsigned int prescale = 1; | ||||
| 	unsigned int div; | ||||
| 
 | ||||
| 	baud = clamp(baud, 300u, priv->max_speed); | ||||
| 
 | ||||
| 	if (baud <= 365) | ||||
| 		prescale = 4; | ||||
| 
 | ||||
| 	div = DIV_ROUND_CLOSEST(48000000, 2 * prescale * baud); | ||||
| 	baud = 48000000 / (2 * prescale * div); | ||||
| 
 | ||||
| 	return baud; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * CP2101 supports the following baud rates: | ||||
|  * | ||||
| @ -1057,16 +1097,24 @@ static void cp210x_get_termios_port(struct usb_serial_port *port, | ||||
| static void cp210x_change_speed(struct tty_struct *tty, | ||||
| 		struct usb_serial_port *port, struct ktermios *old_termios) | ||||
| { | ||||
| 	struct usb_serial *serial = port->serial; | ||||
| 	struct cp210x_serial_private *priv = usb_get_serial_data(serial); | ||||
| 	u32 baud; | ||||
| 
 | ||||
| 	baud = tty->termios.c_ospeed; | ||||
| 
 | ||||
| 	/* This maps the requested rate to a rate valid on cp2102 or cp2103,
 | ||||
| 	 * or to an arbitrary rate in [1M,2M]. | ||||
| 	/*
 | ||||
| 	 * This maps the requested rate to the actual rate, a valid rate on | ||||
| 	 * cp2102 or cp2103, or to an arbitrary rate in [1M, max_speed]. | ||||
| 	 * | ||||
| 	 * NOTE: B0 is not implemented. | ||||
| 	 */ | ||||
| 	baud = cp210x_quantise_baudrate(baud); | ||||
| 	if (priv->use_actual_rate) | ||||
| 		baud = cp210x_get_actual_rate(serial, baud); | ||||
| 	else if (baud < 1000000) | ||||
| 		baud = cp210x_get_an205_rate(baud); | ||||
| 	else if (baud > priv->max_speed) | ||||
| 		baud = priv->max_speed; | ||||
| 
 | ||||
| 	dev_dbg(&port->dev, "%s - setting baud rate to %u\n", __func__, baud); | ||||
| 	if (cp210x_write_u32_reg(port, CP210X_SET_BAUDRATE, baud)) { | ||||
| @ -1288,17 +1336,8 @@ static int cp210x_gpio_request(struct gpio_chip *gc, unsigned int offset) | ||||
| 	struct usb_serial *serial = gpiochip_get_data(gc); | ||||
| 	struct cp210x_serial_private *priv = usb_get_serial_data(serial); | ||||
| 
 | ||||
| 	switch (offset) { | ||||
| 	case 0: | ||||
| 		if (priv->config & CP2105_GPIO0_TXLED_MODE) | ||||
| 			return -ENODEV; | ||||
| 		break; | ||||
| 	case 1: | ||||
| 		if (priv->config & (CP2105_GPIO1_RXLED_MODE | | ||||
| 				    CP2105_GPIO1_RS485_MODE)) | ||||
| 			return -ENODEV; | ||||
| 		break; | ||||
| 	} | ||||
| 	if (priv->gpio_altfunc & BIT(offset)) | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| @ -1306,10 +1345,15 @@ static int cp210x_gpio_request(struct gpio_chip *gc, unsigned int offset) | ||||
| static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio) | ||||
| { | ||||
| 	struct usb_serial *serial = gpiochip_get_data(gc); | ||||
| 	struct cp210x_serial_private *priv = usb_get_serial_data(serial); | ||||
| 	u8 req_type = REQTYPE_DEVICE_TO_HOST; | ||||
| 	int result; | ||||
| 	u8 buf; | ||||
| 
 | ||||
| 	result = cp210x_read_vendor_block(serial, REQTYPE_INTERFACE_TO_HOST, | ||||
| 	if (priv->partnum == CP210X_PARTNUM_CP2105) | ||||
| 		req_type = REQTYPE_INTERFACE_TO_HOST; | ||||
| 
 | ||||
| 	result = cp210x_read_vendor_block(serial, req_type, | ||||
| 					  CP210X_READ_LATCH, &buf, sizeof(buf)); | ||||
| 	if (result < 0) | ||||
| 		return result; | ||||
| @ -1320,7 +1364,9 @@ static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio) | ||||
| static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) | ||||
| { | ||||
| 	struct usb_serial *serial = gpiochip_get_data(gc); | ||||
| 	struct cp210x_serial_private *priv = usb_get_serial_data(serial); | ||||
| 	struct cp210x_gpio_write buf; | ||||
| 	int result; | ||||
| 
 | ||||
| 	if (value == 1) | ||||
| 		buf.state = BIT(gpio); | ||||
| @ -1329,25 +1375,68 @@ static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) | ||||
| 
 | ||||
| 	buf.mask = BIT(gpio); | ||||
| 
 | ||||
| 	cp210x_write_vendor_block(serial, REQTYPE_HOST_TO_INTERFACE, | ||||
| 				  CP210X_WRITE_LATCH, &buf, sizeof(buf)); | ||||
| 	if (priv->partnum == CP210X_PARTNUM_CP2105) { | ||||
| 		result = cp210x_write_vendor_block(serial, | ||||
| 						   REQTYPE_HOST_TO_INTERFACE, | ||||
| 						   CP210X_WRITE_LATCH, &buf, | ||||
| 						   sizeof(buf)); | ||||
| 	} else { | ||||
| 		u16 wIndex = buf.state << 8 | buf.mask; | ||||
| 
 | ||||
| 		result = usb_control_msg(serial->dev, | ||||
| 					 usb_sndctrlpipe(serial->dev, 0), | ||||
| 					 CP210X_VENDOR_SPECIFIC, | ||||
| 					 REQTYPE_HOST_TO_DEVICE, | ||||
| 					 CP210X_WRITE_LATCH, | ||||
| 					 wIndex, | ||||
| 					 NULL, 0, USB_CTRL_SET_TIMEOUT); | ||||
| 	} | ||||
| 
 | ||||
| 	if (result < 0) { | ||||
| 		dev_err(&serial->interface->dev, "failed to set GPIO value: %d\n", | ||||
| 				result); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static int cp210x_gpio_direction_get(struct gpio_chip *gc, unsigned int gpio) | ||||
| { | ||||
| 	/* Hardware does not support an input mode */ | ||||
| 	return 0; | ||||
| 	struct usb_serial *serial = gpiochip_get_data(gc); | ||||
| 	struct cp210x_serial_private *priv = usb_get_serial_data(serial); | ||||
| 
 | ||||
| 	return priv->gpio_input & BIT(gpio); | ||||
| } | ||||
| 
 | ||||
| static int cp210x_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio) | ||||
| { | ||||
| 	/* Hardware does not support an input mode */ | ||||
| 	return -ENOTSUPP; | ||||
| 	struct usb_serial *serial = gpiochip_get_data(gc); | ||||
| 	struct cp210x_serial_private *priv = usb_get_serial_data(serial); | ||||
| 
 | ||||
| 	if (priv->partnum == CP210X_PARTNUM_CP2105) { | ||||
| 		/* hardware does not support an input mode */ | ||||
| 		return -ENOTSUPP; | ||||
| 	} | ||||
| 
 | ||||
| 	/* push-pull pins cannot be changed to be inputs */ | ||||
| 	if (priv->gpio_pushpull & BIT(gpio)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	/* make sure to release pin if it is being driven low */ | ||||
| 	cp210x_gpio_set(gc, gpio, 1); | ||||
| 
 | ||||
| 	priv->gpio_input |= BIT(gpio); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int cp210x_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio, | ||||
| 					int value) | ||||
| { | ||||
| 	struct usb_serial *serial = gpiochip_get_data(gc); | ||||
| 	struct cp210x_serial_private *priv = usb_get_serial_data(serial); | ||||
| 
 | ||||
| 	priv->gpio_input &= ~BIT(gpio); | ||||
| 	cp210x_gpio_set(gc, gpio, value); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -1360,11 +1449,11 @@ static int cp210x_gpio_set_config(struct gpio_chip *gc, unsigned int gpio, | ||||
| 
 | ||||
| 	/* Succeed only if in correct mode (this can't be set at runtime) */ | ||||
| 	if ((param == PIN_CONFIG_DRIVE_PUSH_PULL) && | ||||
| 	    (priv->gpio_mode & BIT(gpio))) | ||||
| 	    (priv->gpio_pushpull & BIT(gpio))) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if ((param == PIN_CONFIG_DRIVE_OPEN_DRAIN) && | ||||
| 	    !(priv->gpio_mode & BIT(gpio))) | ||||
| 	    !(priv->gpio_pushpull & BIT(gpio))) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	return -ENOTSUPP; | ||||
| @ -1377,12 +1466,13 @@ static int cp210x_gpio_set_config(struct gpio_chip *gc, unsigned int gpio, | ||||
|  * this driver that provide GPIO do so in a way that does not impact other | ||||
|  * signals and are thus expected to have very different initialisation. | ||||
|  */ | ||||
| static int cp2105_shared_gpio_init(struct usb_serial *serial) | ||||
| static int cp2105_gpioconf_init(struct usb_serial *serial) | ||||
| { | ||||
| 	struct cp210x_serial_private *priv = usb_get_serial_data(serial); | ||||
| 	struct cp210x_pin_mode mode; | ||||
| 	struct cp210x_config config; | ||||
| 	u8 intf_num = cp210x_interface_num(serial); | ||||
| 	u8 iface_config; | ||||
| 	int result; | ||||
| 
 | ||||
| 	result = cp210x_read_vendor_block(serial, REQTYPE_DEVICE_TO_HOST, | ||||
| @ -1399,20 +1489,26 @@ static int cp2105_shared_gpio_init(struct usb_serial *serial) | ||||
| 
 | ||||
| 	/*  2 banks of GPIO - One for the pins taken from each serial port */ | ||||
| 	if (intf_num == 0) { | ||||
| 		if (mode.eci == CP210X_PIN_MODE_MODEM) | ||||
| 		if (mode.eci == CP210X_PIN_MODE_MODEM) { | ||||
| 			/* mark all GPIOs of this interface as reserved */ | ||||
| 			priv->gpio_altfunc = 0xff; | ||||
| 			return 0; | ||||
| 		} | ||||
| 
 | ||||
| 		priv->config = config.eci_cfg; | ||||
| 		priv->gpio_mode = (u8)((le16_to_cpu(config.gpio_mode) & | ||||
| 		iface_config = config.eci_cfg; | ||||
| 		priv->gpio_pushpull = (u8)((le16_to_cpu(config.gpio_mode) & | ||||
| 						CP210X_ECI_GPIO_MODE_MASK) >> | ||||
| 						CP210X_ECI_GPIO_MODE_OFFSET); | ||||
| 		priv->gc.ngpio = 2; | ||||
| 	} else if (intf_num == 1) { | ||||
| 		if (mode.sci == CP210X_PIN_MODE_MODEM) | ||||
| 		if (mode.sci == CP210X_PIN_MODE_MODEM) { | ||||
| 			/* mark all GPIOs of this interface as reserved */ | ||||
| 			priv->gpio_altfunc = 0xff; | ||||
| 			return 0; | ||||
| 		} | ||||
| 
 | ||||
| 		priv->config = config.sci_cfg; | ||||
| 		priv->gpio_mode = (u8)((le16_to_cpu(config.gpio_mode) & | ||||
| 		iface_config = config.sci_cfg; | ||||
| 		priv->gpio_pushpull = (u8)((le16_to_cpu(config.gpio_mode) & | ||||
| 						CP210X_SCI_GPIO_MODE_MASK) >> | ||||
| 						CP210X_SCI_GPIO_MODE_OFFSET); | ||||
| 		priv->gc.ngpio = 3; | ||||
| @ -1420,6 +1516,125 @@ static int cp2105_shared_gpio_init(struct usb_serial *serial) | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| 
 | ||||
| 	/* mark all pins which are not in GPIO mode */ | ||||
| 	if (iface_config & CP2105_GPIO0_TXLED_MODE)	/* GPIO 0 */ | ||||
| 		priv->gpio_altfunc |= BIT(0); | ||||
| 	if (iface_config & (CP2105_GPIO1_RXLED_MODE |	/* GPIO 1 */ | ||||
| 			CP2105_GPIO1_RS485_MODE)) | ||||
| 		priv->gpio_altfunc |= BIT(1); | ||||
| 
 | ||||
| 	/* driver implementation for CP2105 only supports outputs */ | ||||
| 	priv->gpio_input = 0; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int cp2102n_gpioconf_init(struct usb_serial *serial) | ||||
| { | ||||
| 	struct cp210x_serial_private *priv = usb_get_serial_data(serial); | ||||
| 	const u16 config_size = 0x02a6; | ||||
| 	u8 gpio_rst_latch; | ||||
| 	u8 config_version; | ||||
| 	u8 gpio_pushpull; | ||||
| 	u8 *config_buf; | ||||
| 	u8 gpio_latch; | ||||
| 	u8 gpio_ctrl; | ||||
| 	int result; | ||||
| 	u8 i; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Retrieve device configuration from the device. | ||||
| 	 * The array received contains all customization settings done at the | ||||
| 	 * factory/manufacturer. Format of the array is documented at the | ||||
| 	 * time of writing at: | ||||
| 	 * https://www.silabs.com/community/interface/knowledge-base.entry.html/2017/03/31/cp2102n_setconfig-xsfa
 | ||||
| 	 */ | ||||
| 	config_buf = kmalloc(config_size, GFP_KERNEL); | ||||
| 	if (!config_buf) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	result = cp210x_read_vendor_block(serial, | ||||
| 					  REQTYPE_DEVICE_TO_HOST, | ||||
| 					  CP210X_READ_2NCONFIG, | ||||
| 					  config_buf, | ||||
| 					  config_size); | ||||
| 	if (result < 0) { | ||||
| 		kfree(config_buf); | ||||
| 		return result; | ||||
| 	} | ||||
| 
 | ||||
| 	config_version = config_buf[CP210X_2NCONFIG_CONFIG_VERSION_IDX]; | ||||
| 	gpio_pushpull = config_buf[CP210X_2NCONFIG_GPIO_MODE_IDX]; | ||||
| 	gpio_ctrl = config_buf[CP210X_2NCONFIG_GPIO_CONTROL_IDX]; | ||||
| 	gpio_rst_latch = config_buf[CP210X_2NCONFIG_GPIO_RSTLATCH_IDX]; | ||||
| 
 | ||||
| 	kfree(config_buf); | ||||
| 
 | ||||
| 	/* Make sure this is a config format we understand. */ | ||||
| 	if (config_version != 0x01) | ||||
| 		return -ENOTSUPP; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * We only support 4 GPIOs even on the QFN28 package, because | ||||
| 	 * config locations of GPIOs 4-6 determined using reverse | ||||
| 	 * engineering revealed conflicting offsets with other | ||||
| 	 * documented functions. So we'll just play it safe for now. | ||||
| 	 */ | ||||
| 	priv->gc.ngpio = 4; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Get default pin states after reset. Needed so we can determine | ||||
| 	 * the direction of an open-drain pin. | ||||
| 	 */ | ||||
| 	gpio_latch = (gpio_rst_latch >> 3) & 0x0f; | ||||
| 
 | ||||
| 	/* 0 indicates open-drain mode, 1 is push-pull */ | ||||
| 	priv->gpio_pushpull = (gpio_pushpull >> 3) & 0x0f; | ||||
| 
 | ||||
| 	/* 0 indicates GPIO mode, 1 is alternate function */ | ||||
| 	priv->gpio_altfunc = (gpio_ctrl >> 2) & 0x0f; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * The CP2102N does not strictly has input and output pin modes, | ||||
| 	 * it only knows open-drain and push-pull modes which is set at | ||||
| 	 * factory. An open-drain pin can function both as an | ||||
| 	 * input or an output. We emulate input mode for open-drain pins | ||||
| 	 * by making sure they are not driven low, and we do not allow | ||||
| 	 * push-pull pins to be set as an input. | ||||
| 	 */ | ||||
| 	for (i = 0; i < priv->gc.ngpio; ++i) { | ||||
| 		/*
 | ||||
| 		 * Set direction to "input" iff pin is open-drain and reset | ||||
| 		 * value is 1. | ||||
| 		 */ | ||||
| 		if (!(priv->gpio_pushpull & BIT(i)) && (gpio_latch & BIT(i))) | ||||
| 			priv->gpio_input |= BIT(i); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int cp210x_gpio_init(struct usb_serial *serial) | ||||
| { | ||||
| 	struct cp210x_serial_private *priv = usb_get_serial_data(serial); | ||||
| 	int result; | ||||
| 
 | ||||
| 	switch (priv->partnum) { | ||||
| 	case CP210X_PARTNUM_CP2105: | ||||
| 		result = cp2105_gpioconf_init(serial); | ||||
| 		break; | ||||
| 	case CP210X_PARTNUM_CP2102N_QFN28: | ||||
| 	case CP210X_PARTNUM_CP2102N_QFN24: | ||||
| 	case CP210X_PARTNUM_CP2102N_QFN20: | ||||
| 		result = cp2102n_gpioconf_init(serial); | ||||
| 		break; | ||||
| 	default: | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (result < 0) | ||||
| 		return result; | ||||
| 
 | ||||
| 	priv->gc.label = "cp210x"; | ||||
| 	priv->gc.request = cp210x_gpio_request; | ||||
| 	priv->gc.get_direction = cp210x_gpio_direction_get; | ||||
| @ -1452,7 +1667,7 @@ static void cp210x_gpio_remove(struct usb_serial *serial) | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| static int cp2105_shared_gpio_init(struct usb_serial *serial) | ||||
| static int cp210x_gpio_init(struct usb_serial *serial) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| @ -1497,6 +1712,50 @@ static int cp210x_port_remove(struct usb_serial_port *port) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void cp210x_init_max_speed(struct usb_serial *serial) | ||||
| { | ||||
| 	struct cp210x_serial_private *priv = usb_get_serial_data(serial); | ||||
| 	bool use_actual_rate = false; | ||||
| 	speed_t max; | ||||
| 
 | ||||
| 	switch (priv->partnum) { | ||||
| 	case CP210X_PARTNUM_CP2101: | ||||
| 		max = 921600; | ||||
| 		break; | ||||
| 	case CP210X_PARTNUM_CP2102: | ||||
| 	case CP210X_PARTNUM_CP2103: | ||||
| 		max = 1000000; | ||||
| 		break; | ||||
| 	case CP210X_PARTNUM_CP2104: | ||||
| 		use_actual_rate = true; | ||||
| 		max = 2000000; | ||||
| 		break; | ||||
| 	case CP210X_PARTNUM_CP2108: | ||||
| 		max = 2000000; | ||||
| 		break; | ||||
| 	case CP210X_PARTNUM_CP2105: | ||||
| 		if (cp210x_interface_num(serial) == 0) { | ||||
| 			use_actual_rate = true; | ||||
| 			max = 2000000;	/* ECI */ | ||||
| 		} else { | ||||
| 			max = 921600;	/* SCI */ | ||||
| 		} | ||||
| 		break; | ||||
| 	case CP210X_PARTNUM_CP2102N_QFN28: | ||||
| 	case CP210X_PARTNUM_CP2102N_QFN24: | ||||
| 	case CP210X_PARTNUM_CP2102N_QFN20: | ||||
| 		use_actual_rate = true; | ||||
| 		max = 3000000; | ||||
| 		break; | ||||
| 	default: | ||||
| 		max = 2000000; | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	priv->max_speed = max; | ||||
| 	priv->use_actual_rate = use_actual_rate; | ||||
| } | ||||
| 
 | ||||
| static int cp210x_attach(struct usb_serial *serial) | ||||
| { | ||||
| 	int result; | ||||
| @ -1517,12 +1776,12 @@ static int cp210x_attach(struct usb_serial *serial) | ||||
| 
 | ||||
| 	usb_set_serial_data(serial, priv); | ||||
| 
 | ||||
| 	if (priv->partnum == CP210X_PARTNUM_CP2105) { | ||||
| 		result = cp2105_shared_gpio_init(serial); | ||||
| 		if (result < 0) { | ||||
| 			dev_err(&serial->interface->dev, | ||||
| 				"GPIO initialisation failed, continuing without GPIO support\n"); | ||||
| 		} | ||||
| 	cp210x_init_max_speed(serial); | ||||
| 
 | ||||
| 	result = cp210x_gpio_init(serial); | ||||
| 	if (result < 0) { | ||||
| 		dev_err(&serial->interface->dev, "GPIO initialisation failed: %d\n", | ||||
| 				result); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
|  | ||||
| @ -255,6 +255,7 @@ static void cyberjack_read_int_callback(struct urb *urb) | ||||
| 	struct device *dev = &port->dev; | ||||
| 	unsigned char *data = urb->transfer_buffer; | ||||
| 	int status = urb->status; | ||||
| 	unsigned long flags; | ||||
| 	int result; | ||||
| 
 | ||||
| 	/* the urb might have been killed. */ | ||||
| @ -270,13 +271,13 @@ static void cyberjack_read_int_callback(struct urb *urb) | ||||
| 		/* This is a announcement of coming bulk_ins. */ | ||||
| 		unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3; | ||||
| 
 | ||||
| 		spin_lock(&priv->lock); | ||||
| 		spin_lock_irqsave(&priv->lock, flags); | ||||
| 
 | ||||
| 		old_rdtodo = priv->rdtodo; | ||||
| 
 | ||||
| 		if (old_rdtodo > SHRT_MAX - size) { | ||||
| 			dev_dbg(dev, "To many bulk_in urbs to do.\n"); | ||||
| 			spin_unlock(&priv->lock); | ||||
| 			spin_unlock_irqrestore(&priv->lock, flags); | ||||
| 			goto resubmit; | ||||
| 		} | ||||
| 
 | ||||
| @ -285,7 +286,7 @@ static void cyberjack_read_int_callback(struct urb *urb) | ||||
| 
 | ||||
| 		dev_dbg(dev, "%s - rdtodo: %d\n", __func__, priv->rdtodo); | ||||
| 
 | ||||
| 		spin_unlock(&priv->lock); | ||||
| 		spin_unlock_irqrestore(&priv->lock, flags); | ||||
| 
 | ||||
| 		if (!old_rdtodo) { | ||||
| 			result = usb_submit_urb(port->read_urb, GFP_ATOMIC); | ||||
| @ -309,6 +310,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb) | ||||
| 	struct cyberjack_private *priv = usb_get_serial_port_data(port); | ||||
| 	struct device *dev = &port->dev; | ||||
| 	unsigned char *data = urb->transfer_buffer; | ||||
| 	unsigned long flags; | ||||
| 	short todo; | ||||
| 	int result; | ||||
| 	int status = urb->status; | ||||
| @ -325,7 +327,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb) | ||||
| 		tty_flip_buffer_push(&port->port); | ||||
| 	} | ||||
| 
 | ||||
| 	spin_lock(&priv->lock); | ||||
| 	spin_lock_irqsave(&priv->lock, flags); | ||||
| 
 | ||||
| 	/* Reduce urbs to do by one. */ | ||||
| 	priv->rdtodo -= urb->actual_length; | ||||
| @ -334,7 +336,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb) | ||||
| 		priv->rdtodo = 0; | ||||
| 	todo = priv->rdtodo; | ||||
| 
 | ||||
| 	spin_unlock(&priv->lock); | ||||
| 	spin_unlock_irqrestore(&priv->lock, flags); | ||||
| 
 | ||||
| 	dev_dbg(dev, "%s - rdtodo: %d\n", __func__, todo); | ||||
| 
 | ||||
| @ -354,6 +356,7 @@ static void cyberjack_write_bulk_callback(struct urb *urb) | ||||
| 	struct cyberjack_private *priv = usb_get_serial_port_data(port); | ||||
| 	struct device *dev = &port->dev; | ||||
| 	int status = urb->status; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	set_bit(0, &port->write_urbs_free); | ||||
| 	if (status) { | ||||
| @ -362,7 +365,7 @@ static void cyberjack_write_bulk_callback(struct urb *urb) | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	spin_lock(&priv->lock); | ||||
| 	spin_lock_irqsave(&priv->lock, flags); | ||||
| 
 | ||||
| 	/* only do something if we have more data to send */ | ||||
| 	if (priv->wrfilled) { | ||||
| @ -406,7 +409,7 @@ static void cyberjack_write_bulk_callback(struct urb *urb) | ||||
| 	} | ||||
| 
 | ||||
| exit: | ||||
| 	spin_unlock(&priv->lock); | ||||
| 	spin_unlock_irqrestore(&priv->lock, flags); | ||||
| 	usb_serial_port_softint(port); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -984,6 +984,7 @@ static void digi_write_bulk_callback(struct urb *urb) | ||||
| 	struct usb_serial *serial; | ||||
| 	struct digi_port *priv; | ||||
| 	struct digi_serial *serial_priv; | ||||
| 	unsigned long flags; | ||||
| 	int ret = 0; | ||||
| 	int status = urb->status; | ||||
| 
 | ||||
| @ -1004,15 +1005,15 @@ static void digi_write_bulk_callback(struct urb *urb) | ||||
| 	/* handle oob callback */ | ||||
| 	if (priv->dp_port_num == serial_priv->ds_oob_port_num) { | ||||
| 		dev_dbg(&port->dev, "digi_write_bulk_callback: oob callback\n"); | ||||
| 		spin_lock(&priv->dp_port_lock); | ||||
| 		spin_lock_irqsave(&priv->dp_port_lock, flags); | ||||
| 		priv->dp_write_urb_in_use = 0; | ||||
| 		wake_up_interruptible(&port->write_wait); | ||||
| 		spin_unlock(&priv->dp_port_lock); | ||||
| 		spin_unlock_irqrestore(&priv->dp_port_lock, flags); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	/* try to send any buffered data on this port */ | ||||
| 	spin_lock(&priv->dp_port_lock); | ||||
| 	spin_lock_irqsave(&priv->dp_port_lock, flags); | ||||
| 	priv->dp_write_urb_in_use = 0; | ||||
| 	if (priv->dp_out_buf_len > 0) { | ||||
| 		*((unsigned char *)(port->write_urb->transfer_buffer)) | ||||
| @ -1035,7 +1036,7 @@ static void digi_write_bulk_callback(struct urb *urb) | ||||
| 	/* lost the race in write_chan(). */ | ||||
| 	schedule_work(&priv->dp_wakeup_work); | ||||
| 
 | ||||
| 	spin_unlock(&priv->dp_port_lock); | ||||
| 	spin_unlock_irqrestore(&priv->dp_port_lock, flags); | ||||
| 	if (ret && ret != -EPERM) | ||||
| 		dev_err_console(port, | ||||
| 			"%s: usb_submit_urb failed, ret=%d, port=%d\n", | ||||
| @ -1381,11 +1382,12 @@ static int digi_read_inb_callback(struct urb *urb) | ||||
| 	struct usb_serial_port *port = urb->context; | ||||
| 	struct digi_port *priv = usb_get_serial_port_data(port); | ||||
| 	unsigned char *buf = urb->transfer_buffer; | ||||
| 	unsigned long flags; | ||||
| 	int opcode; | ||||
| 	int len; | ||||
| 	int port_status; | ||||
| 	unsigned char *data; | ||||
| 	int flag, throttled; | ||||
| 	int tty_flag, throttled; | ||||
| 
 | ||||
| 	/* short/multiple packet check */ | ||||
| 	if (urb->actual_length < 2) { | ||||
| @ -1407,7 +1409,7 @@ static int digi_read_inb_callback(struct urb *urb) | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	spin_lock(&priv->dp_port_lock); | ||||
| 	spin_lock_irqsave(&priv->dp_port_lock, flags); | ||||
| 
 | ||||
| 	/* check for throttle; if set, do not resubmit read urb */ | ||||
| 	/* indicate the read chain needs to be restarted on unthrottle */ | ||||
| @ -1421,7 +1423,7 @@ static int digi_read_inb_callback(struct urb *urb) | ||||
| 		data = &buf[3]; | ||||
| 
 | ||||
| 		/* get flag from port_status */ | ||||
| 		flag = 0; | ||||
| 		tty_flag = 0; | ||||
| 
 | ||||
| 		/* overrun is special, not associated with a char */ | ||||
| 		if (port_status & DIGI_OVERRUN_ERROR) | ||||
| @ -1430,21 +1432,21 @@ static int digi_read_inb_callback(struct urb *urb) | ||||
| 		/* break takes precedence over parity, */ | ||||
| 		/* which takes precedence over framing errors */ | ||||
| 		if (port_status & DIGI_BREAK_ERROR) | ||||
| 			flag = TTY_BREAK; | ||||
| 			tty_flag = TTY_BREAK; | ||||
| 		else if (port_status & DIGI_PARITY_ERROR) | ||||
| 			flag = TTY_PARITY; | ||||
| 			tty_flag = TTY_PARITY; | ||||
| 		else if (port_status & DIGI_FRAMING_ERROR) | ||||
| 			flag = TTY_FRAME; | ||||
| 			tty_flag = TTY_FRAME; | ||||
| 
 | ||||
| 		/* data length is len-1 (one byte of len is port_status) */ | ||||
| 		--len; | ||||
| 		if (len > 0) { | ||||
| 			tty_insert_flip_string_fixed_flag(&port->port, data, | ||||
| 					flag, len); | ||||
| 					tty_flag, len); | ||||
| 			tty_flip_buffer_push(&port->port); | ||||
| 		} | ||||
| 	} | ||||
| 	spin_unlock(&priv->dp_port_lock); | ||||
| 	spin_unlock_irqrestore(&priv->dp_port_lock, flags); | ||||
| 
 | ||||
| 	if (opcode == DIGI_CMD_RECEIVE_DISABLE) | ||||
| 		dev_dbg(&port->dev, "%s: got RECEIVE_DISABLE\n", __func__); | ||||
| @ -1474,6 +1476,7 @@ static int digi_read_oob_callback(struct urb *urb) | ||||
| 	struct digi_port *priv = usb_get_serial_port_data(port); | ||||
| 	unsigned char *buf = urb->transfer_buffer; | ||||
| 	int opcode, line, status, val; | ||||
| 	unsigned long flags; | ||||
| 	int i; | ||||
| 	unsigned int rts; | ||||
| 
 | ||||
| @ -1506,7 +1509,7 @@ static int digi_read_oob_callback(struct urb *urb) | ||||
| 			rts = C_CRTSCTS(tty); | ||||
| 
 | ||||
| 		if (tty && opcode == DIGI_CMD_READ_INPUT_SIGNALS) { | ||||
| 			spin_lock(&priv->dp_port_lock); | ||||
| 			spin_lock_irqsave(&priv->dp_port_lock, flags); | ||||
| 			/* convert from digi flags to termiox flags */ | ||||
| 			if (val & DIGI_READ_INPUT_SIGNALS_CTS) { | ||||
| 				priv->dp_modem_signals |= TIOCM_CTS; | ||||
| @ -1530,12 +1533,12 @@ static int digi_read_oob_callback(struct urb *urb) | ||||
| 			else | ||||
| 				priv->dp_modem_signals &= ~TIOCM_CD; | ||||
| 
 | ||||
| 			spin_unlock(&priv->dp_port_lock); | ||||
| 			spin_unlock_irqrestore(&priv->dp_port_lock, flags); | ||||
| 		} else if (opcode == DIGI_CMD_TRANSMIT_IDLE) { | ||||
| 			spin_lock(&priv->dp_port_lock); | ||||
| 			spin_lock_irqsave(&priv->dp_port_lock, flags); | ||||
| 			priv->dp_transmit_idle = 1; | ||||
| 			wake_up_interruptible(&priv->dp_transmit_idle_wait); | ||||
| 			spin_unlock(&priv->dp_port_lock); | ||||
| 			spin_unlock_irqrestore(&priv->dp_port_lock, flags); | ||||
| 		} else if (opcode == DIGI_CMD_IFLUSH_FIFO) { | ||||
| 			wake_up_interruptible(&priv->dp_flush_wait); | ||||
| 		} | ||||
|  | ||||
| @ -648,6 +648,7 @@ static void edge_interrupt_callback(struct urb *urb) | ||||
| 	struct usb_serial_port *port; | ||||
| 	unsigned char *data = urb->transfer_buffer; | ||||
| 	int length = urb->actual_length; | ||||
| 	unsigned long flags; | ||||
| 	int bytes_avail; | ||||
| 	int position; | ||||
| 	int txCredits; | ||||
| @ -679,7 +680,7 @@ static void edge_interrupt_callback(struct urb *urb) | ||||
| 		if (length > 1) { | ||||
| 			bytes_avail = data[0] | (data[1] << 8); | ||||
| 			if (bytes_avail) { | ||||
| 				spin_lock(&edge_serial->es_lock); | ||||
| 				spin_lock_irqsave(&edge_serial->es_lock, flags); | ||||
| 				edge_serial->rxBytesAvail += bytes_avail; | ||||
| 				dev_dbg(dev, | ||||
| 					"%s - bytes_avail=%d, rxBytesAvail=%d, read_in_progress=%d\n", | ||||
| @ -702,7 +703,8 @@ static void edge_interrupt_callback(struct urb *urb) | ||||
| 						edge_serial->read_in_progress = false; | ||||
| 					} | ||||
| 				} | ||||
| 				spin_unlock(&edge_serial->es_lock); | ||||
| 				spin_unlock_irqrestore(&edge_serial->es_lock, | ||||
| 						       flags); | ||||
| 			} | ||||
| 		} | ||||
| 		/* grab the txcredits for the ports if available */ | ||||
| @ -715,9 +717,11 @@ static void edge_interrupt_callback(struct urb *urb) | ||||
| 				port = edge_serial->serial->port[portNumber]; | ||||
| 				edge_port = usb_get_serial_port_data(port); | ||||
| 				if (edge_port->open) { | ||||
| 					spin_lock(&edge_port->ep_lock); | ||||
| 					spin_lock_irqsave(&edge_port->ep_lock, | ||||
| 							  flags); | ||||
| 					edge_port->txCredits += txCredits; | ||||
| 					spin_unlock(&edge_port->ep_lock); | ||||
| 					spin_unlock_irqrestore(&edge_port->ep_lock, | ||||
| 							       flags); | ||||
| 					dev_dbg(dev, "%s - txcredits for port%d = %d\n", | ||||
| 						__func__, portNumber, | ||||
| 						edge_port->txCredits); | ||||
| @ -758,6 +762,7 @@ static void edge_bulk_in_callback(struct urb *urb) | ||||
| 	int			retval; | ||||
| 	__u16			raw_data_length; | ||||
| 	int status = urb->status; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	if (status) { | ||||
| 		dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n", | ||||
| @ -777,7 +782,7 @@ static void edge_bulk_in_callback(struct urb *urb) | ||||
| 
 | ||||
| 	usb_serial_debug_data(dev, __func__, raw_data_length, data); | ||||
| 
 | ||||
| 	spin_lock(&edge_serial->es_lock); | ||||
| 	spin_lock_irqsave(&edge_serial->es_lock, flags); | ||||
| 
 | ||||
| 	/* decrement our rxBytes available by the number that we just got */ | ||||
| 	edge_serial->rxBytesAvail -= raw_data_length; | ||||
| @ -801,7 +806,7 @@ static void edge_bulk_in_callback(struct urb *urb) | ||||
| 		edge_serial->read_in_progress = false; | ||||
| 	} | ||||
| 
 | ||||
| 	spin_unlock(&edge_serial->es_lock); | ||||
| 	spin_unlock_irqrestore(&edge_serial->es_lock, flags); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -1729,6 +1729,7 @@ static void edge_bulk_in_callback(struct urb *urb) | ||||
| 	struct edgeport_port *edge_port = urb->context; | ||||
| 	struct device *dev = &edge_port->port->dev; | ||||
| 	unsigned char *data = urb->transfer_buffer; | ||||
| 	unsigned long flags; | ||||
| 	int retval = 0; | ||||
| 	int port_number; | ||||
| 	int status = urb->status; | ||||
| @ -1780,13 +1781,13 @@ static void edge_bulk_in_callback(struct urb *urb) | ||||
| 
 | ||||
| exit: | ||||
| 	/* continue read unless stopped */ | ||||
| 	spin_lock(&edge_port->ep_lock); | ||||
| 	spin_lock_irqsave(&edge_port->ep_lock, flags); | ||||
| 	if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING) | ||||
| 		retval = usb_submit_urb(urb, GFP_ATOMIC); | ||||
| 	else if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPING) | ||||
| 		edge_port->ep_read_urb_state = EDGE_READ_URB_STOPPED; | ||||
| 
 | ||||
| 	spin_unlock(&edge_port->ep_lock); | ||||
| 	spin_unlock_irqrestore(&edge_port->ep_lock, flags); | ||||
| 	if (retval) | ||||
| 		dev_err(dev, "%s - usb_submit_urb failed with result %d\n", __func__, retval); | ||||
| } | ||||
|  | ||||
| @ -132,7 +132,7 @@ irda_usb_find_class_desc(struct usb_serial *serial, unsigned int ifnum) | ||||
| 			0, ifnum, desc, sizeof(*desc), 1000); | ||||
| 
 | ||||
| 	dev_dbg(&serial->dev->dev, "%s -  ret=%d\n", __func__, ret); | ||||
| 	if (ret < sizeof(*desc)) { | ||||
| 	if (ret < (int)sizeof(*desc)) { | ||||
| 		dev_dbg(&serial->dev->dev, | ||||
| 			"%s - class descriptor read %s (%d)\n", __func__, | ||||
| 			(ret < 0) ? "failed" : "too short", ret); | ||||
|  | ||||
| @ -58,7 +58,6 @@ struct iuu_private { | ||||
| 	u8 *buf;		/* used for initialize speed */ | ||||
| 	u8 len; | ||||
| 	int vcc;		/* vcc (either 3 or 5 V) */ | ||||
| 	u32 baud; | ||||
| 	u32 boost; | ||||
| 	u32 clk; | ||||
| }; | ||||
| @ -963,9 +962,6 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) | ||||
| 	struct iuu_private *priv = usb_get_serial_port_data(port); | ||||
| 
 | ||||
| 	baud = tty->termios.c_ospeed; | ||||
| 	tty->termios.c_ispeed = baud; | ||||
| 	/* Re-encode speed */ | ||||
| 	tty_encode_baud_rate(tty, baud, baud); | ||||
| 
 | ||||
| 	dev_dbg(dev, "%s - baud %d\n", __func__, baud); | ||||
| 	usb_clear_halt(serial->dev, port->write_urb->pipe); | ||||
| @ -991,7 +987,6 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) | ||||
| 	if (boost < 100) | ||||
| 		boost = 100; | ||||
| 	priv->boost = boost; | ||||
| 	priv->baud = baud; | ||||
| 	switch (clockmode) { | ||||
| 	case 2:		/*  3.680 Mhz */ | ||||
| 		priv->clk = IUU_CLK_3680000; | ||||
|  | ||||
| @ -67,7 +67,6 @@ static int klsi_105_prepare_write_buffer(struct usb_serial_port *port, | ||||
|  */ | ||||
| static const struct usb_device_id id_table[] = { | ||||
| 	{ USB_DEVICE(PALMCONNECT_VID, PALMCONNECT_PID) }, | ||||
| 	{ USB_DEVICE(KLSI_VID, KLSI_KL5KUSB105D_PID) }, | ||||
| 	{ }		/* Terminating entry */ | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -7,9 +7,6 @@ | ||||
| #define PALMCONNECT_VID		0x0830 | ||||
| #define PALMCONNECT_PID		0x0080 | ||||
| 
 | ||||
| #define KLSI_VID		0x05e9 | ||||
| #define KLSI_KL5KUSB105D_PID	0x00c0 | ||||
| 
 | ||||
| /* Vendor commands: */ | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -190,8 +190,10 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) | ||||
| 			  KOBIL_TIMEOUT | ||||
| 	); | ||||
| 	dev_dbg(dev, "%s - Send get_HW_version URB returns: %i\n", __func__, result); | ||||
| 	dev_dbg(dev, "Hardware version: %i.%i.%i\n", transfer_buffer[0], | ||||
| 		transfer_buffer[1], transfer_buffer[2]); | ||||
| 	if (result >= 3) { | ||||
| 		dev_dbg(dev, "Hardware version: %i.%i.%i\n", transfer_buffer[0], | ||||
| 				transfer_buffer[1], transfer_buffer[2]); | ||||
| 	} | ||||
| 
 | ||||
| 	/* get firmware version */ | ||||
| 	result = usb_control_msg(port->serial->dev, | ||||
| @ -205,8 +207,10 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) | ||||
| 			  KOBIL_TIMEOUT | ||||
| 	); | ||||
| 	dev_dbg(dev, "%s - Send get_FW_version URB returns: %i\n", __func__, result); | ||||
| 	dev_dbg(dev, "Firmware version: %i.%i.%i\n", transfer_buffer[0], | ||||
| 		transfer_buffer[1], transfer_buffer[2]); | ||||
| 	if (result >= 3) { | ||||
| 		dev_dbg(dev, "Firmware version: %i.%i.%i\n", transfer_buffer[0], | ||||
| 				transfer_buffer[1], transfer_buffer[2]); | ||||
| 	} | ||||
| 
 | ||||
| 	if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID || | ||||
| 			priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) { | ||||
| @ -393,12 +397,20 @@ static int kobil_tiocmget(struct tty_struct *tty) | ||||
| 			  transfer_buffer_length, | ||||
| 			  KOBIL_TIMEOUT); | ||||
| 
 | ||||
| 	dev_dbg(&port->dev, "%s - Send get_status_line_state URB returns: %i. Statusline: %02x\n", | ||||
| 		__func__, result, transfer_buffer[0]); | ||||
| 	dev_dbg(&port->dev, "Send get_status_line_state URB returns: %i\n", | ||||
| 			result); | ||||
| 	if (result < 1) { | ||||
| 		if (result >= 0) | ||||
| 			result = -EIO; | ||||
| 		goto out_free; | ||||
| 	} | ||||
| 
 | ||||
| 	dev_dbg(&port->dev, "Statusline: %02x\n", transfer_buffer[0]); | ||||
| 
 | ||||
| 	result = 0; | ||||
| 	if ((transfer_buffer[0] & SUSBCR_GSL_DSR) != 0) | ||||
| 		result = TIOCM_DSR; | ||||
| out_free: | ||||
| 	kfree(transfer_buffer); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| @ -340,14 +340,15 @@ static void async_complete(struct urb *urb) | ||||
| { | ||||
| 	struct urbtracker *urbtrack = urb->context; | ||||
| 	int status = urb->status; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	if (unlikely(status)) | ||||
| 		dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __func__, status); | ||||
| 
 | ||||
| 	/* remove the urbtracker from the active_urbs list */ | ||||
| 	spin_lock(&urbtrack->mos_parport->listlock); | ||||
| 	spin_lock_irqsave(&urbtrack->mos_parport->listlock, flags); | ||||
| 	list_del(&urbtrack->urblist_entry); | ||||
| 	spin_unlock(&urbtrack->mos_parport->listlock); | ||||
| 	spin_unlock_irqrestore(&urbtrack->mos_parport->listlock, flags); | ||||
| 	kref_put(&urbtrack->ref_count, destroy_urbtracker); | ||||
| } | ||||
| 
 | ||||
| @ -1526,8 +1527,6 @@ static void change_port_settings(struct tty_struct *tty, | ||||
| 	struct usb_serial *serial; | ||||
| 	int baud; | ||||
| 	unsigned cflag; | ||||
| 	unsigned iflag; | ||||
| 	__u8 mask = 0xff; | ||||
| 	__u8 lData; | ||||
| 	__u8 lParity; | ||||
| 	__u8 lStop; | ||||
| @ -1551,23 +1550,19 @@ static void change_port_settings(struct tty_struct *tty, | ||||
| 	lParity = 0x00;	/* No parity */ | ||||
| 
 | ||||
| 	cflag = tty->termios.c_cflag; | ||||
| 	iflag = tty->termios.c_iflag; | ||||
| 
 | ||||
| 	/* Change the number of bits */ | ||||
| 	switch (cflag & CSIZE) { | ||||
| 	case CS5: | ||||
| 		lData = UART_LCR_WLEN5; | ||||
| 		mask = 0x1f; | ||||
| 		break; | ||||
| 
 | ||||
| 	case CS6: | ||||
| 		lData = UART_LCR_WLEN6; | ||||
| 		mask = 0x3f; | ||||
| 		break; | ||||
| 
 | ||||
| 	case CS7: | ||||
| 		lData = UART_LCR_WLEN7; | ||||
| 		mask = 0x7f; | ||||
| 		break; | ||||
| 	default: | ||||
| 	case CS8: | ||||
| @ -1685,11 +1680,8 @@ static void mos7720_set_termios(struct tty_struct *tty, | ||||
| 		struct usb_serial_port *port, struct ktermios *old_termios) | ||||
| { | ||||
| 	int status; | ||||
| 	struct usb_serial *serial; | ||||
| 	struct moschip_port *mos7720_port; | ||||
| 
 | ||||
| 	serial = port->serial; | ||||
| 
 | ||||
| 	mos7720_port = usb_get_serial_port_data(port); | ||||
| 
 | ||||
| 	if (mos7720_port == NULL) | ||||
|  | ||||
| @ -805,18 +805,19 @@ static void mos7840_bulk_out_data_callback(struct urb *urb) | ||||
| 	struct moschip_port *mos7840_port; | ||||
| 	struct usb_serial_port *port; | ||||
| 	int status = urb->status; | ||||
| 	unsigned long flags; | ||||
| 	int i; | ||||
| 
 | ||||
| 	mos7840_port = urb->context; | ||||
| 	port = mos7840_port->port; | ||||
| 	spin_lock(&mos7840_port->pool_lock); | ||||
| 	spin_lock_irqsave(&mos7840_port->pool_lock, flags); | ||||
| 	for (i = 0; i < NUM_URBS; i++) { | ||||
| 		if (urb == mos7840_port->write_urb_pool[i]) { | ||||
| 			mos7840_port->busy[i] = 0; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	spin_unlock(&mos7840_port->pool_lock); | ||||
| 	spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); | ||||
| 
 | ||||
| 	if (status) { | ||||
| 		dev_dbg(&port->dev, "nonzero write bulk status received:%d\n", status); | ||||
|  | ||||
| @ -194,7 +194,7 @@ static inline int qt2_getregister(struct usb_device *dev, | ||||
| 	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), | ||||
| 			      QT_SET_GET_REGISTER, 0xc0, reg, | ||||
| 			      uart, data, sizeof(*data), QT2_USB_TIMEOUT); | ||||
| 	if (ret < sizeof(*data)) { | ||||
| 	if (ret < (int)sizeof(*data)) { | ||||
| 		if (ret >= 0) | ||||
| 			ret = -EIO; | ||||
| 	} | ||||
| @ -621,16 +621,17 @@ static void qt2_write_bulk_callback(struct urb *urb) | ||||
| { | ||||
| 	struct usb_serial_port *port; | ||||
| 	struct qt2_port_private *port_priv; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	port = urb->context; | ||||
| 	port_priv = usb_get_serial_port_data(port); | ||||
| 
 | ||||
| 	spin_lock(&port_priv->urb_lock); | ||||
| 	spin_lock_irqsave(&port_priv->urb_lock, flags); | ||||
| 
 | ||||
| 	port_priv->urb_in_use = false; | ||||
| 	usb_serial_port_softint(port); | ||||
| 
 | ||||
| 	spin_unlock(&port_priv->urb_lock); | ||||
| 	spin_unlock_irqrestore(&port_priv->urb_lock, flags); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -409,6 +409,7 @@ static void sierra_outdat_callback(struct urb *urb) | ||||
| 	struct sierra_port_private *portdata = usb_get_serial_port_data(port); | ||||
| 	struct sierra_intf_private *intfdata; | ||||
| 	int status = urb->status; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	intfdata = usb_get_serial_data(port->serial); | ||||
| 
 | ||||
| @ -419,12 +420,12 @@ static void sierra_outdat_callback(struct urb *urb) | ||||
| 		dev_dbg(&port->dev, "%s - nonzero write bulk status " | ||||
| 		    "received: %d\n", __func__, status); | ||||
| 
 | ||||
| 	spin_lock(&portdata->lock); | ||||
| 	spin_lock_irqsave(&portdata->lock, flags); | ||||
| 	--portdata->outstanding_urbs; | ||||
| 	spin_unlock(&portdata->lock); | ||||
| 	spin_lock(&intfdata->susp_lock); | ||||
| 	spin_unlock_irqrestore(&portdata->lock, flags); | ||||
| 	spin_lock_irqsave(&intfdata->susp_lock, flags); | ||||
| 	--intfdata->in_flight; | ||||
| 	spin_unlock(&intfdata->susp_lock); | ||||
| 	spin_unlock_irqrestore(&intfdata->susp_lock, flags); | ||||
| 
 | ||||
| 	usb_serial_port_softint(port); | ||||
| } | ||||
| @ -770,9 +771,9 @@ static void sierra_close(struct usb_serial_port *port) | ||||
| 		kfree(urb->transfer_buffer); | ||||
| 		usb_free_urb(urb); | ||||
| 		usb_autopm_put_interface_async(serial->interface); | ||||
| 		spin_lock(&portdata->lock); | ||||
| 		spin_lock_irq(&portdata->lock); | ||||
| 		portdata->outstanding_urbs--; | ||||
| 		spin_unlock(&portdata->lock); | ||||
| 		spin_unlock_irq(&portdata->lock); | ||||
| 	} | ||||
| 
 | ||||
| 	sierra_stop_rx_urbs(port); | ||||
|  | ||||
| @ -104,7 +104,7 @@ static inline int ssu100_getregister(struct usb_device *dev, | ||||
| 	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), | ||||
| 			      QT_SET_GET_REGISTER, 0xc0, reg, | ||||
| 			      uart, data, sizeof(*data), 300); | ||||
| 	if (ret < sizeof(*data)) { | ||||
| 	if (ret < (int)sizeof(*data)) { | ||||
| 		if (ret >= 0) | ||||
| 			ret = -EIO; | ||||
| 	} | ||||
|  | ||||
| @ -35,6 +35,7 @@ static void symbol_int_callback(struct urb *urb) | ||||
| 	struct symbol_private *priv = usb_get_serial_port_data(port); | ||||
| 	unsigned char *data = urb->transfer_buffer; | ||||
| 	int status = urb->status; | ||||
| 	unsigned long flags; | ||||
| 	int result; | ||||
| 	int data_length; | ||||
| 
 | ||||
| @ -73,7 +74,7 @@ static void symbol_int_callback(struct urb *urb) | ||||
| 	} | ||||
| 
 | ||||
| exit: | ||||
| 	spin_lock(&priv->lock); | ||||
| 	spin_lock_irqsave(&priv->lock, flags); | ||||
| 
 | ||||
| 	/* Continue trying to always read if we should */ | ||||
| 	if (!priv->throttled) { | ||||
| @ -84,7 +85,7 @@ exit: | ||||
| 							__func__, result); | ||||
| 	} else | ||||
| 		priv->actually_throttled = true; | ||||
| 	spin_unlock(&priv->lock); | ||||
| 	spin_unlock_irqrestore(&priv->lock, flags); | ||||
| } | ||||
| 
 | ||||
| static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port) | ||||
|  | ||||
| @ -1215,6 +1215,7 @@ static void ti_bulk_in_callback(struct urb *urb) | ||||
| 	struct usb_serial_port *port = tport->tp_port; | ||||
| 	struct device *dev = &urb->dev->dev; | ||||
| 	int status = urb->status; | ||||
| 	unsigned long flags; | ||||
| 	int retval = 0; | ||||
| 
 | ||||
| 	switch (status) { | ||||
| @ -1247,20 +1248,20 @@ static void ti_bulk_in_callback(struct urb *urb) | ||||
| 				__func__); | ||||
| 		else | ||||
| 			ti_recv(port, urb->transfer_buffer, urb->actual_length); | ||||
| 		spin_lock(&tport->tp_lock); | ||||
| 		spin_lock_irqsave(&tport->tp_lock, flags); | ||||
| 		port->icount.rx += urb->actual_length; | ||||
| 		spin_unlock(&tport->tp_lock); | ||||
| 		spin_unlock_irqrestore(&tport->tp_lock, flags); | ||||
| 	} | ||||
| 
 | ||||
| exit: | ||||
| 	/* continue to read unless stopping */ | ||||
| 	spin_lock(&tport->tp_lock); | ||||
| 	spin_lock_irqsave(&tport->tp_lock, flags); | ||||
| 	if (tport->tp_read_urb_state == TI_READ_URB_RUNNING) | ||||
| 		retval = usb_submit_urb(urb, GFP_ATOMIC); | ||||
| 	else if (tport->tp_read_urb_state == TI_READ_URB_STOPPING) | ||||
| 		tport->tp_read_urb_state = TI_READ_URB_STOPPED; | ||||
| 
 | ||||
| 	spin_unlock(&tport->tp_lock); | ||||
| 	spin_unlock_irqrestore(&tport->tp_lock, flags); | ||||
| 	if (retval) | ||||
| 		dev_err(dev, "%s - resubmit read urb failed, %d\n", | ||||
| 			__func__, retval); | ||||
|  | ||||
| @ -326,6 +326,7 @@ static void usb_wwan_outdat_callback(struct urb *urb) | ||||
| 	struct usb_serial_port *port; | ||||
| 	struct usb_wwan_port_private *portdata; | ||||
| 	struct usb_wwan_intf_private *intfdata; | ||||
| 	unsigned long flags; | ||||
| 	int i; | ||||
| 
 | ||||
| 	port = urb->context; | ||||
| @ -334,9 +335,9 @@ static void usb_wwan_outdat_callback(struct urb *urb) | ||||
| 	usb_serial_port_softint(port); | ||||
| 	usb_autopm_put_interface_async(port->serial->interface); | ||||
| 	portdata = usb_get_serial_port_data(port); | ||||
| 	spin_lock(&intfdata->susp_lock); | ||||
| 	spin_lock_irqsave(&intfdata->susp_lock, flags); | ||||
| 	intfdata->in_flight--; | ||||
| 	spin_unlock(&intfdata->susp_lock); | ||||
| 	spin_unlock_irqrestore(&intfdata->susp_lock, flags); | ||||
| 
 | ||||
| 	for (i = 0; i < N_OUT_URB; ++i) { | ||||
| 		if (portdata->out_urbs[i] == urb) { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user