pl2303.c 31.6 KB
Newer Older
Al Viro's avatar
Al Viro committed
1001
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1002
1003
}

1004
static void pl2303_set_break(struct usb_serial_port *port, bool enable)
Linus Torvalds's avatar
Linus Torvalds committed
1005
1006
1007
1008
1009
{
	struct usb_serial *serial = port->serial;
	u16 state;
	int result;

1010
	if (enable)
Linus Torvalds's avatar
Linus Torvalds committed
1011
		state = BREAK_ON;
1012
1013
	else
		state = BREAK_OFF;
1014

1015
	dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
Alan Cox's avatar
Alan Cox committed
1016
			state == BREAK_OFF ? "off" : "on");
Linus Torvalds's avatar
Linus Torvalds committed
1017

1018
1019
1020
	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
				 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
				 0, NULL, 0, 100);
Linus Torvalds's avatar
Linus Torvalds committed
1021
	if (result)
1022
		dev_err(&port->dev, "error sending break = %d\n", result);
Linus Torvalds's avatar
Linus Torvalds committed
1023
1024
}

1025
1026
1027
1028
1029
1030
1031
static void pl2303_break_ctl(struct tty_struct *tty, int state)
{
	struct usb_serial_port *port = tty->driver_data;

	pl2303_set_break(port, state);
}

Flavio Leitner's avatar
Flavio Leitner committed
1032
1033
1034
1035
static void pl2303_update_line_status(struct usb_serial_port *port,
				      unsigned char *data,
				      unsigned int actual_length)
{
1036
1037
	struct usb_serial *serial = port->serial;
	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
Flavio Leitner's avatar
Flavio Leitner committed
1038
	struct pl2303_private *priv = usb_get_serial_port_data(port);
1039
	struct tty_struct *tty;
Flavio Leitner's avatar
Flavio Leitner committed
1040
	unsigned long flags;
1041
	unsigned int status_idx = UART_STATE_INDEX;
1042
1043
	u8 status;
	u8 delta;
Flavio Leitner's avatar
Flavio Leitner committed
1044

1045
1046
	if (spriv->quirks & PL2303_QUIRK_UART_STATE_IDX0)
		status_idx = 0;
Flavio Leitner's avatar
Flavio Leitner committed
1047

1048
	if (actual_length < status_idx + 1)
1049
		return;
Flavio Leitner's avatar
Flavio Leitner committed
1050

1051
1052
	status = data[status_idx];

Alan Cox's avatar
Alan Cox committed
1053
	/* Save off the uart status for others to look at */
Flavio Leitner's avatar
Flavio Leitner committed
1054
	spin_lock_irqsave(&priv->lock, flags);
1055
1056
	delta = priv->line_status ^ status;
	priv->line_status = status;
Flavio Leitner's avatar
Flavio Leitner committed
1057
	spin_unlock_irqrestore(&priv->lock, flags);
1058

1059
	if (status & UART_BREAK_ERROR)
1060
		usb_serial_handle_break(port);
1061

1062
	if (delta & UART_STATE_MSR_MASK) {
1063
1064
1065
1066
1067
1068
		if (delta & UART_CTS)
			port->icount.cts++;
		if (delta & UART_DSR)
			port->icount.dsr++;
		if (delta & UART_RING)
			port->icount.rng++;
1069
		if (delta & UART_DCD) {
1070
			port->icount.dcd++;
1071
1072
1073
			tty = tty_port_tty_get(&port->port);
			if (tty) {
				usb_serial_handle_dcd_change(port, tty,
1074
							status & UART_DCD);
1075
1076
				tty_kref_put(tty);
			}
1077
		}
1078
1079

		wake_up_interruptible(&port->port.delta_msr_wait);
1080
	}
Flavio Leitner's avatar
Flavio Leitner committed
1081
}
Linus Torvalds's avatar
Linus Torvalds committed
1082

1083
static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds's avatar
Linus Torvalds committed
1084
{
1085
	struct usb_serial_port *port =  urb->context;
Linus Torvalds's avatar
Linus Torvalds committed
1086
	unsigned char *data = urb->transfer_buffer;
Flavio Leitner's avatar
Flavio Leitner committed
1087
	unsigned int actual_length = urb->actual_length;
1088
1089
	int status = urb->status;
	int retval;
Linus Torvalds's avatar
Linus Torvalds committed
1090

1091
	switch (status) {
Linus Torvalds's avatar
Linus Torvalds committed
1092
1093
1094
1095
1096
1097
1098
	case 0:
		/* success */
		break;
	case -ECONNRESET:
	case -ENOENT:
	case -ESHUTDOWN:
		/* this urb is terminated, clean up */
1099
1100
		dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
			__func__, status);
Linus Torvalds's avatar
Linus Torvalds committed
1101
1102
		return;
	default:
1103
1104
		dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
			__func__, status);
Linus Torvalds's avatar
Linus Torvalds committed
1105
1106
1107
		goto exit;
	}

1108
	usb_serial_debug_data(&port->dev, __func__,
1109
1110
			      urb->actual_length, urb->transfer_buffer);

Flavio Leitner's avatar
Flavio Leitner committed
1111
	pl2303_update_line_status(port, data, actual_length);
Linus Torvalds's avatar
Linus Torvalds committed
1112
1113

exit:
1114
	retval = usb_submit_urb(urb, GFP_ATOMIC);
1115
	if (retval) {
1116
		dev_err(&port->dev,
1117
			"%s - usb_submit_urb failed with result %d\n",
1118
			__func__, retval);
1119
	}
Linus Torvalds's avatar
Linus Torvalds committed
1120
1121
}

1122
static void pl2303_process_read_urb(struct urb *urb)
1123
{
1124
1125
	struct usb_serial_port *port = urb->context;
	struct pl2303_private *priv = usb_get_serial_port_data(port);
1126
1127
	unsigned char *data = urb->transfer_buffer;
	char tty_flag = TTY_NORMAL;
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
	unsigned long flags;
	u8 line_status;
	int i;

	/* update line status */
	spin_lock_irqsave(&priv->lock, flags);
	line_status = priv->line_status;
	priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
	spin_unlock_irqrestore(&priv->lock, flags);

	if (!urb->actual_length)
		return;

1141
1142
1143
1144
	/*
	 * Break takes precedence over parity, which takes precedence over
	 * framing errors.
	 */
1145
1146
1147
1148
1149
1150
1151
	if (line_status & UART_BREAK_ERROR)
		tty_flag = TTY_BREAK;
	else if (line_status & UART_PARITY_ERROR)
		tty_flag = TTY_PARITY;
	else if (line_status & UART_FRAME_ERROR)
		tty_flag = TTY_FRAME;

1152
1153
1154
	if (tty_flag != TTY_NORMAL)
		dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__,
								tty_flag);
1155
1156
	/* overrun is special, not associated with a char */
	if (line_status & UART_OVERRUN_ERROR)
Jiri Slaby's avatar
Jiri Slaby committed
1157
		tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
1158

1159
	if (port->sysrq) {
1160
		for (i = 0; i < urb->actual_length; ++i)
1161
			if (!usb_serial_handle_sysrq_char(port, data[i]))
Jiri Slaby's avatar
Jiri Slaby committed
1162
1163
				tty_insert_flip_char(&port->port, data[i],
						tty_flag);
1164
	} else {
1165
		tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
1166
							urb->actual_length);
1167
	}
Linus Torvalds's avatar
Linus Torvalds committed
1168

Jiri Slaby's avatar
Jiri Slaby committed
1169
	tty_flip_buffer_push(&port->port);
Linus Torvalds's avatar
Linus Torvalds committed
1170
1171
}

1172
1173
1174
1175
1176
1177
static struct usb_serial_driver pl2303_device = {
	.driver = {
		.owner =	THIS_MODULE,
		.name =		"pl2303",
	},
	.id_table =		id_table,
1178
1179
	.num_bulk_in =		1,
	.num_bulk_out =		1,
1180
	.num_interrupt_in =	0,	/* see pl2303_calc_num_ports */
1181
	.bulk_in_size =		256,
1182
	.bulk_out_size =	256,
1183
1184
	.open =			pl2303_open,
	.close =		pl2303_close,
1185
	.dtr_rts =		pl2303_dtr_rts,
1186
	.carrier_raised =	pl2303_carrier_raised,
Al Viro's avatar
Al Viro committed
1187
	.get_serial =		pl2303_get_serial,
1188
1189
1190
1191
	.break_ctl =		pl2303_break_ctl,
	.set_termios =		pl2303_set_termios,
	.tiocmget =		pl2303_tiocmget,
	.tiocmset =		pl2303_tiocmset,
1192
	.tiocmiwait =		usb_serial_generic_tiocmiwait,
1193
	.process_read_urb =	pl2303_process_read_urb,
1194
	.read_int_callback =	pl2303_read_int_callback,
1195
	.probe =		pl2303_probe,
1196
	.calc_num_ports =	pl2303_calc_num_ports,
1197
	.attach =		pl2303_startup,
1198
	.release =		pl2303_release,
1199
1200
	.port_probe =		pl2303_port_probe,
	.port_remove =		pl2303_port_remove,
1201
};
Linus Torvalds's avatar
Linus Torvalds committed
1202

1203
1204
1205
1206
static struct usb_serial_driver * const serial_drivers[] = {
	&pl2303_device, NULL
};

1207
module_usb_serial_driver(serial_drivers, id_table);
Linus Torvalds's avatar
Linus Torvalds committed
1208

1209
MODULE_DESCRIPTION("Prolific PL2303 USB to serial adaptor driver");
1210
MODULE_LICENSE("GPL v2");
For faster browsing, not all history is shown. View entire blame