metro-usb.c 10.0 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3 4
  Some of this code is credited to Linux USB open source files that are
  distributed with Linux.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

  Copyright:	2007 Metrologic Instruments. All rights reserved.
  Copyright:	2011 Azimut Ltd. <http://azimutrzn.ru/>
*/

#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
20
#include <linux/uaccess.h>
21 22 23 24
#include <linux/usb/serial.h>

#define DRIVER_DESC "Metrologic Instruments Inc. - USB-POS driver"

25 26
/* Product information. */
#define FOCUS_VENDOR_ID			0x0C2E
27 28
#define FOCUS_PRODUCT_ID_BI		0x0720
#define FOCUS_PRODUCT_ID_UNI		0x0700
29 30 31 32 33 34 35

#define METROUSB_SET_REQUEST_TYPE	0x40
#define METROUSB_SET_MODEM_CTRL_REQUEST	10
#define METROUSB_SET_BREAK_REQUEST	0x40
#define METROUSB_MCR_NONE		0x08	/* Deactivate DTR and RTS. */
#define METROUSB_MCR_RTS		0x0a	/* Activate RTS. */
#define METROUSB_MCR_DTR		0x09	/* Activate DTR. */
36
#define WDR_TIMEOUT			5000	/* default urb timeout. */
37 38 39 40 41 42 43 44

/* Private data structure. */
struct metrousb_private {
	spinlock_t lock;
	int throttled;
	unsigned long control_state;
};

45
/* Device table list. */
46
static const struct usb_device_id id_table[] = {
47
	{ USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_BI) },
48
	{ USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_UNI) },
49
	{ USB_DEVICE_INTERFACE_CLASS(0x0c2e, 0x0730, 0xff) },	/* MS7820 */
50 51 52 53
	{ }, /* Terminating entry. */
};
MODULE_DEVICE_TABLE(usb, id_table);

54 55 56 57
/* UNI-Directional mode commands for device configure */
#define UNI_CMD_OPEN	0x80
#define UNI_CMD_CLOSE	0xFF

58
static int metrousb_is_unidirectional_mode(struct usb_serial *serial)
59
{
60
	u16 product_id = le16_to_cpu(serial->dev->descriptor.idProduct);
61 62 63 64

	return product_id == FOCUS_PRODUCT_ID_UNI;
}

65 66 67 68 69 70 71 72 73 74 75 76 77
static int metrousb_calc_num_ports(struct usb_serial *serial,
				   struct usb_serial_endpoints *epds)
{
	if (metrousb_is_unidirectional_mode(serial)) {
		if (epds->num_interrupt_out == 0) {
			dev_err(&serial->interface->dev, "interrupt-out endpoint missing\n");
			return -ENODEV;
		}
	}

	return 1;
}

78 79 80 81 82 83
static int metrousb_send_unidirectional_cmd(u8 cmd, struct usb_serial_port *port)
{
	int ret;
	int actual_len;
	u8 *buffer_cmd = NULL;

84
	if (!metrousb_is_unidirectional_mode(port->serial))
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
		return 0;

	buffer_cmd = kzalloc(sizeof(cmd), GFP_KERNEL);
	if (!buffer_cmd)
		return -ENOMEM;

	*buffer_cmd = cmd;

	ret = usb_interrupt_msg(port->serial->dev,
		usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress),
		buffer_cmd, sizeof(cmd),
		&actual_len, USB_CTRL_SET_TIMEOUT);

	kfree(buffer_cmd);

	if (ret < 0)
		return ret;
	else if (actual_len != sizeof(cmd))
		return -EIO;
	return 0;
}

107
static void metrousb_read_int_callback(struct urb *urb)
108
{
109
	struct usb_serial_port *port = urb->context;
110 111 112 113 114 115
	struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
	unsigned char *data = urb->transfer_buffer;
	int throttled = 0;
	int result = 0;
	unsigned long flags = 0;

116
	dev_dbg(&port->dev, "%s\n", __func__);
117

118 119 120 121 122 123 124 125
	switch (urb->status) {
	case 0:
		/* Success status, read from the port. */
		break;
	case -ECONNRESET:
	case -ENOENT:
	case -ESHUTDOWN:
		/* urb has been terminated. */
126 127
		dev_dbg(&port->dev,
			"%s - urb shutting down, error code=%d\n",
128
			__func__, urb->status);
129 130
		return;
	default:
131 132
		dev_dbg(&port->dev,
			"%s - non-zero urb received, error code=%d\n",
133
			__func__, urb->status);
134 135 136 137 138
		goto exit;
	}


	/* Set the data read from the usb port into the serial port buffer. */
J
Jiri Slaby 已提交
139
	if (urb->actual_length) {
140
		/* Loop through the data copying each byte to the tty layer. */
J
Jiri Slaby 已提交
141
		tty_insert_flip_string(&port->port, data, urb->actual_length);
142 143

		/* Force the data to the tty layer. */
J
Jiri Slaby 已提交
144
		tty_flip_buffer_push(&port->port);
145 146 147 148 149 150 151
	}

	/* Set any port variables. */
	spin_lock_irqsave(&metro_priv->lock, flags);
	throttled = metro_priv->throttled;
	spin_unlock_irqrestore(&metro_priv->lock, flags);

152 153
	if (throttled)
		return;
154 155 156
exit:
	/* Try to resubmit the urb. */
	result = usb_submit_urb(urb, GFP_ATOMIC);
157
	if (result)
158
		dev_err(&port->dev,
159 160
			"%s - failed submitting interrupt in urb, error code=%d\n",
			__func__, result);
161 162
}

163
static void metrousb_cleanup(struct usb_serial_port *port)
164
{
165 166
	usb_kill_urb(port->interrupt_in_urb);

167
	metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port);
168 169
}

170
static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
{
	struct usb_serial *serial = port->serial;
	struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
	unsigned long flags = 0;
	int result = 0;

	/* Set the private data information for the port. */
	spin_lock_irqsave(&metro_priv->lock, flags);
	metro_priv->control_state = 0;
	metro_priv->throttled = 0;
	spin_unlock_irqrestore(&metro_priv->lock, flags);

	/* Clear the urb pipe. */
	usb_clear_halt(serial->dev, port->interrupt_in_urb->pipe);

	/* Start reading from the device */
187 188
	usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
			  usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress),
189 190 191 192 193 194
			   port->interrupt_in_urb->transfer_buffer,
			   port->interrupt_in_urb->transfer_buffer_length,
			   metrousb_read_int_callback, port, 1);
	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);

	if (result) {
195
		dev_err(&port->dev,
196 197
			"%s - failed submitting interrupt in urb, error code=%d\n",
			__func__, result);
198
		return result;
199 200
	}

201 202 203 204
	/* Send activate cmd to device */
	result = metrousb_send_unidirectional_cmd(UNI_CMD_OPEN, port);
	if (result) {
		dev_err(&port->dev,
205 206
			"%s - failed to configure device, error code=%d\n",
			__func__, result);
207
		goto err_kill_urb;
208
	}
209 210 211 212 213 214

	return 0;

err_kill_urb:
	usb_kill_urb(port->interrupt_in_urb);

215 216 217 218 219 220 221 222
	return result;
}

static int metrousb_set_modem_ctrl(struct usb_serial *serial, unsigned int control_state)
{
	int retval = 0;
	unsigned char mcr = METROUSB_MCR_NONE;

223 224
	dev_dbg(&serial->dev->dev, "%s - control state = %d\n",
		__func__, control_state);
225 226 227 228 229 230 231 232 233 234 235 236

	/* Set the modem control value. */
	if (control_state & TIOCM_DTR)
		mcr |= METROUSB_MCR_DTR;
	if (control_state & TIOCM_RTS)
		mcr |= METROUSB_MCR_RTS;

	/* Send the command to the usb port. */
	retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
				METROUSB_SET_REQUEST_TYPE, METROUSB_SET_MODEM_CTRL_REQUEST,
				control_state, 0, NULL, 0, WDR_TIMEOUT);
	if (retval < 0)
237
		dev_err(&serial->dev->dev,
238 239
			"%s - set modem ctrl=0x%x failed, error code=%d\n",
			__func__, mcr, retval);
240 241 242 243

	return retval;
}

244
static int metrousb_port_probe(struct usb_serial_port *port)
245
{
246
	struct metrousb_private *metro_priv;
247

248 249 250
	metro_priv = kzalloc(sizeof(*metro_priv), GFP_KERNEL);
	if (!metro_priv)
		return -ENOMEM;
251

252
	spin_lock_init(&metro_priv->lock);
253

254
	usb_set_serial_port_data(port, metro_priv);
255

256
	return 0;
257 258
}

259
static int metrousb_port_remove(struct usb_serial_port *port)
260 261 262
{
	struct metrousb_private *metro_priv;

263 264
	metro_priv = usb_get_serial_port_data(port);
	kfree(metro_priv);
265 266 267 268

	return 0;
}

269
static void metrousb_throttle(struct tty_struct *tty)
270 271 272 273 274 275 276 277 278 279 280
{
	struct usb_serial_port *port = tty->driver_data;
	struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
	unsigned long flags = 0;

	/* Set the private information for the port to stop reading data. */
	spin_lock_irqsave(&metro_priv->lock, flags);
	metro_priv->throttled = 1;
	spin_unlock_irqrestore(&metro_priv->lock, flags);
}

281
static int metrousb_tiocmget(struct tty_struct *tty)
282 283 284 285 286 287 288 289 290 291 292 293 294
{
	unsigned long control_state = 0;
	struct usb_serial_port *port = tty->driver_data;
	struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
	unsigned long flags = 0;

	spin_lock_irqsave(&metro_priv->lock, flags);
	control_state = metro_priv->control_state;
	spin_unlock_irqrestore(&metro_priv->lock, flags);

	return control_state;
}

295 296
static int metrousb_tiocmset(struct tty_struct *tty,
			     unsigned int set, unsigned int clear)
297 298 299 300 301 302 303
{
	struct usb_serial_port *port = tty->driver_data;
	struct usb_serial *serial = port->serial;
	struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
	unsigned long flags = 0;
	unsigned long control_state = 0;

304
	dev_dbg(tty->dev, "%s - set=%d, clear=%d\n", __func__, set, clear);
305 306 307 308

	spin_lock_irqsave(&metro_priv->lock, flags);
	control_state = metro_priv->control_state;

309
	/* Set the RTS and DTR values. */
310 311 312 313 314 315 316 317 318 319 320 321 322 323
	if (set & TIOCM_RTS)
		control_state |= TIOCM_RTS;
	if (set & TIOCM_DTR)
		control_state |= TIOCM_DTR;
	if (clear & TIOCM_RTS)
		control_state &= ~TIOCM_RTS;
	if (clear & TIOCM_DTR)
		control_state &= ~TIOCM_DTR;

	metro_priv->control_state = control_state;
	spin_unlock_irqrestore(&metro_priv->lock, flags);
	return metrousb_set_modem_ctrl(serial, control_state);
}

324
static void metrousb_unthrottle(struct tty_struct *tty)
325 326 327 328 329 330 331 332 333 334 335 336 337
{
	struct usb_serial_port *port = tty->driver_data;
	struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
	unsigned long flags = 0;
	int result = 0;

	/* Set the private information for the port to resume reading data. */
	spin_lock_irqsave(&metro_priv->lock, flags);
	metro_priv->throttled = 0;
	spin_unlock_irqrestore(&metro_priv->lock, flags);

	/* Submit the urb to read from the port. */
	result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
338
	if (result)
339
		dev_err(tty->dev,
340 341
			"failed submitting interrupt in urb error code=%d\n",
			result);
342 343
}

344 345 346 347 348
static struct usb_serial_driver metrousb_device = {
	.driver = {
		.owner =	THIS_MODULE,
		.name =		"metro-usb",
	},
349
	.description		= "Metrologic USB to Serial",
350
	.id_table		= id_table,
351
	.num_interrupt_in	= 1,
352
	.calc_num_ports		= metrousb_calc_num_ports,
353 354 355
	.open			= metrousb_open,
	.close			= metrousb_cleanup,
	.read_int_callback	= metrousb_read_int_callback,
356 357
	.port_probe		= metrousb_port_probe,
	.port_remove		= metrousb_port_remove,
358 359 360 361 362 363 364 365 366 367 368
	.throttle		= metrousb_throttle,
	.unthrottle		= metrousb_unthrottle,
	.tiocmget		= metrousb_tiocmget,
	.tiocmset		= metrousb_tiocmset,
};

static struct usb_serial_driver * const serial_drivers[] = {
	&metrousb_device,
	NULL,
};

369
module_usb_serial_driver(serial_drivers, id_table);
370

371
MODULE_LICENSE("GPL v2");
372 373 374
MODULE_AUTHOR("Philip Nicastro");
MODULE_AUTHOR("Aleksey Babahin <tamerlan311@gmail.com>");
MODULE_DESCRIPTION(DRIVER_DESC);