blob: dff27e6b677adc7af3669d0b1cffa5db193466eb [file] [log] [blame]
Paul B Schroeder3f542972006-08-31 19:41:47 -05001/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 *
16 * Clean ups from Moschip version and a few ioctl implementations by:
17 * Paul B Schroeder <pschroeder "at" uplogix "dot" com>
18 *
19 * Originally based on drivers/usb/serial/io_edgeport.c which is:
20 * Copyright (C) 2000 Inside Out Networks, All rights reserved.
21 * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com>
22 *
23 */
24
25#include <linux/kernel.h>
26#include <linux/errno.h>
27#include <linux/init.h>
28#include <linux/slab.h>
29#include <linux/tty.h>
30#include <linux/tty_driver.h>
31#include <linux/tty_flip.h>
32#include <linux/module.h>
33#include <linux/serial.h>
34#include <linux/usb.h>
35#include <linux/usb/serial.h>
Alan Cox880af9d2008-07-22 11:16:12 +010036#include <linux/uaccess.h>
Paul B Schroeder3f542972006-08-31 19:41:47 -050037
Paul B Schroeder3f542972006-08-31 19:41:47 -050038#define DRIVER_DESC "Moschip 7840/7820 USB Serial Driver"
39
40/*
41 * 16C50 UART register defines
42 */
43
44#define LCR_BITS_5 0x00 /* 5 bits/char */
45#define LCR_BITS_6 0x01 /* 6 bits/char */
46#define LCR_BITS_7 0x02 /* 7 bits/char */
47#define LCR_BITS_8 0x03 /* 8 bits/char */
48#define LCR_BITS_MASK 0x03 /* Mask for bits/char field */
49
50#define LCR_STOP_1 0x00 /* 1 stop bit */
51#define LCR_STOP_1_5 0x04 /* 1.5 stop bits (if 5 bits/char) */
52#define LCR_STOP_2 0x04 /* 2 stop bits (if 6-8 bits/char) */
53#define LCR_STOP_MASK 0x04 /* Mask for stop bits field */
54
55#define LCR_PAR_NONE 0x00 /* No parity */
56#define LCR_PAR_ODD 0x08 /* Odd parity */
57#define LCR_PAR_EVEN 0x18 /* Even parity */
58#define LCR_PAR_MARK 0x28 /* Force parity bit to 1 */
59#define LCR_PAR_SPACE 0x38 /* Force parity bit to 0 */
60#define LCR_PAR_MASK 0x38 /* Mask for parity field */
61
62#define LCR_SET_BREAK 0x40 /* Set Break condition */
63#define LCR_DL_ENABLE 0x80 /* Enable access to divisor latch */
64
65#define MCR_DTR 0x01 /* Assert DTR */
66#define MCR_RTS 0x02 /* Assert RTS */
67#define MCR_OUT1 0x04 /* Loopback only: Sets state of RI */
68#define MCR_MASTER_IE 0x08 /* Enable interrupt outputs */
69#define MCR_LOOPBACK 0x10 /* Set internal (digital) loopback mode */
70#define MCR_XON_ANY 0x20 /* Enable any char to exit XOFF mode */
71
72#define MOS7840_MSR_CTS 0x10 /* Current state of CTS */
73#define MOS7840_MSR_DSR 0x20 /* Current state of DSR */
74#define MOS7840_MSR_RI 0x40 /* Current state of RI */
75#define MOS7840_MSR_CD 0x80 /* Current state of CD */
76
77/*
78 * Defines used for sending commands to port
79 */
80
Mark Ferrell1e658482012-07-24 13:38:31 -050081#define MOS_WDR_TIMEOUT 5000 /* default urb timeout */
Paul B Schroeder3f542972006-08-31 19:41:47 -050082
83#define MOS_PORT1 0x0200
84#define MOS_PORT2 0x0300
85#define MOS_VENREG 0x0000
86#define MOS_MAX_PORT 0x02
87#define MOS_WRITE 0x0E
88#define MOS_READ 0x0D
89
90/* Requests */
91#define MCS_RD_RTYPE 0xC0
92#define MCS_WR_RTYPE 0x40
93#define MCS_RDREQ 0x0D
94#define MCS_WRREQ 0x0E
95#define MCS_CTRL_TIMEOUT 500
96#define VENDOR_READ_LENGTH (0x01)
97
98#define MAX_NAME_LEN 64
99
Alan Cox880af9d2008-07-22 11:16:12 +0100100#define ZLP_REG1 0x3A /* Zero_Flag_Reg1 58 */
101#define ZLP_REG5 0x3E /* Zero_Flag_Reg5 62 */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500102
103/* For higher baud Rates use TIOCEXBAUD */
104#define TIOCEXBAUD 0x5462
105
106/* vendor id and device id defines */
107
David Ludlow11e1abb2008-02-25 17:30:52 -0500108/* The native mos7840/7820 component */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500109#define USB_VENDOR_ID_MOSCHIP 0x9710
110#define MOSCHIP_DEVICE_ID_7840 0x7840
111#define MOSCHIP_DEVICE_ID_7820 0x7820
Donald0eafe4d2012-04-19 15:00:45 +0800112#define MOSCHIP_DEVICE_ID_7810 0x7810
David Ludlow11e1abb2008-02-25 17:30:52 -0500113/* The native component can have its vendor/device id's overridden
114 * in vendor-specific implementations. Such devices can be handled
Greg Kroah-Hartman68e24112012-05-08 15:46:14 -0700115 * by making a change here, in id_table.
David Ludlow11e1abb2008-02-25 17:30:52 -0500116 */
Dave Ludlow870408c2010-09-01 12:33:30 -0400117#define USB_VENDOR_ID_BANDB 0x0856
118#define BANDB_DEVICE_ID_USO9ML2_2 0xAC22
119#define BANDB_DEVICE_ID_USO9ML2_2P 0xBC00
120#define BANDB_DEVICE_ID_USO9ML2_4 0xAC24
121#define BANDB_DEVICE_ID_USO9ML2_4P 0xBC01
122#define BANDB_DEVICE_ID_US9ML2_2 0xAC29
123#define BANDB_DEVICE_ID_US9ML2_4 0xAC30
124#define BANDB_DEVICE_ID_USPTL4_2 0xAC31
125#define BANDB_DEVICE_ID_USPTL4_4 0xAC32
126#define BANDB_DEVICE_ID_USOPTL4_2 0xAC42
127#define BANDB_DEVICE_ID_USOPTL4_2P 0xBC02
128#define BANDB_DEVICE_ID_USOPTL4_4 0xAC44
129#define BANDB_DEVICE_ID_USOPTL4_4P 0xBC03
130#define BANDB_DEVICE_ID_USOPTL2_4 0xAC24
Paul B Schroeder3f542972006-08-31 19:41:47 -0500131
Russell Lang9d498be2009-07-17 19:29:20 +1000132/* This driver also supports
133 * ATEN UC2324 device using Moschip MCS7840
134 * ATEN UC2322 device using Moschip MCS7820
135 */
Tony Cooke9b8cff2009-04-18 22:42:18 +0930136#define USB_VENDOR_ID_ATENINTL 0x0557
137#define ATENINTL_DEVICE_ID_UC2324 0x2011
Russell Lang9d498be2009-07-17 19:29:20 +1000138#define ATENINTL_DEVICE_ID_UC2322 0x7820
Tony Cooke9b8cff2009-04-18 22:42:18 +0930139
David Ludlow11e1abb2008-02-25 17:30:52 -0500140/* Interrupt Routine Defines */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500141
142#define SERIAL_IIR_RLS 0x06
143#define SERIAL_IIR_MS 0x00
144
145/*
146 * Emulation of the bit mask on the LINE STATUS REGISTER.
147 */
148#define SERIAL_LSR_DR 0x0001
149#define SERIAL_LSR_OE 0x0002
150#define SERIAL_LSR_PE 0x0004
151#define SERIAL_LSR_FE 0x0008
152#define SERIAL_LSR_BI 0x0010
153
154#define MOS_MSR_DELTA_CTS 0x10
155#define MOS_MSR_DELTA_DSR 0x20
156#define MOS_MSR_DELTA_RI 0x40
157#define MOS_MSR_DELTA_CD 0x80
158
Alan Cox880af9d2008-07-22 11:16:12 +0100159/* Serial Port register Address */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500160#define INTERRUPT_ENABLE_REGISTER ((__u16)(0x01))
161#define FIFO_CONTROL_REGISTER ((__u16)(0x02))
162#define LINE_CONTROL_REGISTER ((__u16)(0x03))
163#define MODEM_CONTROL_REGISTER ((__u16)(0x04))
164#define LINE_STATUS_REGISTER ((__u16)(0x05))
165#define MODEM_STATUS_REGISTER ((__u16)(0x06))
166#define SCRATCH_PAD_REGISTER ((__u16)(0x07))
167#define DIVISOR_LATCH_LSB ((__u16)(0x00))
168#define DIVISOR_LATCH_MSB ((__u16)(0x01))
169
170#define CLK_MULTI_REGISTER ((__u16)(0x02))
171#define CLK_START_VALUE_REGISTER ((__u16)(0x03))
Donald Lee093ea2d2012-03-14 15:26:33 +0800172#define GPIO_REGISTER ((__u16)(0x07))
Paul B Schroeder3f542972006-08-31 19:41:47 -0500173
174#define SERIAL_LCR_DLAB ((__u16)(0x0080))
175
176/*
177 * URB POOL related defines
178 */
179#define NUM_URBS 16 /* URB Count */
180#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */
181
Donald0eafe4d2012-04-19 15:00:45 +0800182/* LED on/off milliseconds*/
183#define LED_ON_MS 500
184#define LED_OFF_MS 500
185
186static int device_type;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500187
Tony Zelenoffb9c87662012-06-05 17:58:04 +0400188static const struct usb_device_id id_table[] = {
Paul B Schroeder3f542972006-08-31 19:41:47 -0500189 {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
190 {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
Donald0eafe4d2012-04-19 15:00:45 +0800191 {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7810)},
Cliff Brakeacf509a2009-12-01 09:53:43 -0500192 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)},
Dave Ludlow870408c2010-09-01 12:33:30 -0400193 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)},
Cliff Brakeacf509a2009-12-01 09:53:43 -0500194 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)},
Dave Ludlow870408c2010-09-01 12:33:30 -0400195 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4P)},
Cliff Brakeacf509a2009-12-01 09:53:43 -0500196 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)},
197 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)},
198 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)},
199 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)},
David Ludlow11e1abb2008-02-25 17:30:52 -0500200 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)},
Dave Ludlow870408c2010-09-01 12:33:30 -0400201 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2P)},
Cliff Brakeacf509a2009-12-01 09:53:43 -0500202 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)},
Dave Ludlow870408c2010-09-01 12:33:30 -0400203 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4P)},
Blaise Gassend27f12812009-12-18 15:23:38 -0800204 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)},
Tony Cooke9b8cff2009-04-18 22:42:18 +0930205 {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)},
Russell Lang9d498be2009-07-17 19:29:20 +1000206 {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},
Paul B Schroeder3f542972006-08-31 19:41:47 -0500207 {} /* terminating entry */
208};
Greg Kroah-Hartman68e24112012-05-08 15:46:14 -0700209MODULE_DEVICE_TABLE(usb, id_table);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500210
211/* This structure holds all of the local port information */
212
213struct moschip_port {
214 int port_num; /*Actual port number in the device(1,2,etc) */
215 struct urb *write_urb; /* write URB for this port */
216 struct urb *read_urb; /* read URB for this port */
217 __u8 shadowLCR; /* last LCR value received */
218 __u8 shadowMCR; /* last MCR value received */
219 char open;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100220 char open_ports;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500221 struct usb_serial_port *port; /* loop back to the owner of this object */
222
Alan Cox880af9d2008-07-22 11:16:12 +0100223 /* Offsets */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500224 __u8 SpRegOffset;
225 __u8 ControlRegOffset;
226 __u8 DcrRegOffset;
Alan Cox880af9d2008-07-22 11:16:12 +0100227 /* for processing control URBS in interrupt context */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500228 struct urb *control_urb;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100229 struct usb_ctrlrequest *dr;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500230 char *ctrl_buf;
231 int MsrLsr;
232
Oliver Neukum0de9a702007-03-16 20:28:28 +0100233 spinlock_t pool_lock;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500234 struct urb *write_urb_pool[NUM_URBS];
Oliver Neukum0de9a702007-03-16 20:28:28 +0100235 char busy[NUM_URBS];
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800236 bool read_urb_busy;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500237
Donald0eafe4d2012-04-19 15:00:45 +0800238 /* For device(s) with LED indicator */
239 bool has_led;
240 bool led_flag;
241 struct timer_list led_timer1; /* Timer for LED on */
242 struct timer_list led_timer2; /* Timer for LED off */
243};
Paul B Schroeder3f542972006-08-31 19:41:47 -0500244
Paul B Schroeder3f542972006-08-31 19:41:47 -0500245/*
246 * mos7840_set_reg_sync
247 * To set the Control register by calling usb_fill_control_urb function
248 * by passing usb_sndctrlpipe function as parameter.
249 */
250
251static int mos7840_set_reg_sync(struct usb_serial_port *port, __u16 reg,
252 __u16 val)
253{
254 struct usb_device *dev = port->serial->dev;
255 val = val & 0x00ff;
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700256 dev_dbg(&port->dev, "mos7840_set_reg_sync offset is %x, value %x\n", reg, val);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500257
258 return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ,
259 MCS_WR_RTYPE, val, reg, NULL, 0,
260 MOS_WDR_TIMEOUT);
261}
262
263/*
264 * mos7840_get_reg_sync
265 * To set the Uart register by calling usb_fill_control_urb function by
266 * passing usb_rcvctrlpipe function as parameter.
267 */
268
269static int mos7840_get_reg_sync(struct usb_serial_port *port, __u16 reg,
Alan Cox880af9d2008-07-22 11:16:12 +0100270 __u16 *val)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500271{
272 struct usb_device *dev = port->serial->dev;
273 int ret = 0;
Johan Hovold9e221a32009-12-28 23:01:55 +0100274 u8 *buf;
275
276 buf = kmalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
277 if (!buf)
278 return -ENOMEM;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500279
280 ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
Johan Hovold9e221a32009-12-28 23:01:55 +0100281 MCS_RD_RTYPE, 0, reg, buf, VENDOR_READ_LENGTH,
Paul B Schroeder3f542972006-08-31 19:41:47 -0500282 MOS_WDR_TIMEOUT);
Johan Hovold9e221a32009-12-28 23:01:55 +0100283 *val = buf[0];
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700284 dev_dbg(&port->dev, "%s offset is %x, return val %x\n", __func__, reg, *val);
Johan Hovold9e221a32009-12-28 23:01:55 +0100285
286 kfree(buf);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500287 return ret;
288}
289
290/*
291 * mos7840_set_uart_reg
292 * To set the Uart register by calling usb_fill_control_urb function by
293 * passing usb_sndctrlpipe function as parameter.
294 */
295
296static int mos7840_set_uart_reg(struct usb_serial_port *port, __u16 reg,
297 __u16 val)
298{
299
300 struct usb_device *dev = port->serial->dev;
301 val = val & 0x00ff;
Alan Cox880af9d2008-07-22 11:16:12 +0100302 /* For the UART control registers, the application number need
303 to be Or'ed */
Oliver Neukum0de9a702007-03-16 20:28:28 +0100304 if (port->serial->num_ports == 4) {
Greg Kroah-Hartman11438322013-06-06 10:32:00 -0700305 val |= ((__u16)port->port_number + 1) << 8;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500306 } else {
Greg Kroah-Hartman11438322013-06-06 10:32:00 -0700307 if (port->port_number == 0) {
308 val |= ((__u16)port->port_number + 1) << 8;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500309 } else {
Greg Kroah-Hartman11438322013-06-06 10:32:00 -0700310 val |= ((__u16)port->port_number + 2) << 8;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500311 }
312 }
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700313 dev_dbg(&port->dev, "%s application number is %x\n", __func__, val);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500314 return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ,
315 MCS_WR_RTYPE, val, reg, NULL, 0,
316 MOS_WDR_TIMEOUT);
317
318}
319
320/*
321 * mos7840_get_uart_reg
322 * To set the Control register by calling usb_fill_control_urb function
323 * by passing usb_rcvctrlpipe function as parameter.
324 */
325static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg,
Alan Cox880af9d2008-07-22 11:16:12 +0100326 __u16 *val)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500327{
328 struct usb_device *dev = port->serial->dev;
329 int ret = 0;
330 __u16 Wval;
Johan Hovold9e221a32009-12-28 23:01:55 +0100331 u8 *buf;
332
333 buf = kmalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
334 if (!buf)
335 return -ENOMEM;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500336
Alan Cox880af9d2008-07-22 11:16:12 +0100337 /* Wval is same as application number */
Oliver Neukum0de9a702007-03-16 20:28:28 +0100338 if (port->serial->num_ports == 4) {
Greg Kroah-Hartman11438322013-06-06 10:32:00 -0700339 Wval = ((__u16)port->port_number + 1) << 8;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500340 } else {
Greg Kroah-Hartman11438322013-06-06 10:32:00 -0700341 if (port->port_number == 0) {
342 Wval = ((__u16)port->port_number + 1) << 8;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500343 } else {
Greg Kroah-Hartman11438322013-06-06 10:32:00 -0700344 Wval = ((__u16)port->port_number + 2) << 8;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500345 }
346 }
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700347 dev_dbg(&port->dev, "%s application number is %x\n", __func__, Wval);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500348 ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
Johan Hovold9e221a32009-12-28 23:01:55 +0100349 MCS_RD_RTYPE, Wval, reg, buf, VENDOR_READ_LENGTH,
Paul B Schroeder3f542972006-08-31 19:41:47 -0500350 MOS_WDR_TIMEOUT);
Johan Hovold9e221a32009-12-28 23:01:55 +0100351 *val = buf[0];
352
353 kfree(buf);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500354 return ret;
355}
356
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700357static void mos7840_dump_serial_port(struct usb_serial_port *port,
358 struct moschip_port *mos7840_port)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500359{
360
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700361 dev_dbg(&port->dev, "SpRegOffset is %2x\n", mos7840_port->SpRegOffset);
362 dev_dbg(&port->dev, "ControlRegOffset is %2x\n", mos7840_port->ControlRegOffset);
363 dev_dbg(&port->dev, "DCRRegOffset is %2x\n", mos7840_port->DcrRegOffset);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500364
365}
366
367/************************************************************************/
368/************************************************************************/
369/* I N T E R F A C E F U N C T I O N S */
370/* I N T E R F A C E F U N C T I O N S */
371/************************************************************************/
372/************************************************************************/
373
374static inline void mos7840_set_port_private(struct usb_serial_port *port,
375 struct moschip_port *data)
376{
377 usb_set_serial_port_data(port, (void *)data);
378}
379
380static inline struct moschip_port *mos7840_get_port_private(struct
381 usb_serial_port
382 *port)
383{
384 return (struct moschip_port *)usb_get_serial_port_data(port);
385}
386
Oliver Neukum0de9a702007-03-16 20:28:28 +0100387static void mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500388{
389 struct moschip_port *mos7840_port;
390 struct async_icount *icount;
391 mos7840_port = port;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500392 if (new_msr &
393 (MOS_MSR_DELTA_CTS | MOS_MSR_DELTA_DSR | MOS_MSR_DELTA_RI |
394 MOS_MSR_DELTA_CD)) {
Johan Hovold8c1a07f2013-03-21 12:37:16 +0100395 icount = &mos7840_port->port->icount;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500396
397 /* update input line counters */
Johan Hovoldc9fac852013-03-21 12:37:15 +0100398 if (new_msr & MOS_MSR_DELTA_CTS)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500399 icount->cts++;
Johan Hovoldc9fac852013-03-21 12:37:15 +0100400 if (new_msr & MOS_MSR_DELTA_DSR)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500401 icount->dsr++;
Johan Hovoldc9fac852013-03-21 12:37:15 +0100402 if (new_msr & MOS_MSR_DELTA_CD)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500403 icount->dcd++;
Johan Hovoldc9fac852013-03-21 12:37:15 +0100404 if (new_msr & MOS_MSR_DELTA_RI)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500405 icount->rng++;
Johan Hovolde670c6a2013-03-19 09:21:19 +0100406
Johan Hovold0c613372013-03-21 12:37:17 +0100407 wake_up_interruptible(&port->port->port.delta_msr_wait);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500408 }
Paul B Schroeder3f542972006-08-31 19:41:47 -0500409}
410
Oliver Neukum0de9a702007-03-16 20:28:28 +0100411static void mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500412{
413 struct async_icount *icount;
414
Paul B Schroeder3f542972006-08-31 19:41:47 -0500415 if (new_lsr & SERIAL_LSR_BI) {
Alan Cox880af9d2008-07-22 11:16:12 +0100416 /*
417 * Parity and Framing errors only count if they
418 * occur exclusive of a break being
419 * received.
420 */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500421 new_lsr &= (__u8) (SERIAL_LSR_OE | SERIAL_LSR_BI);
422 }
423
424 /* update input line counters */
Johan Hovold8c1a07f2013-03-21 12:37:16 +0100425 icount = &port->port->icount;
Johan Hovoldc9fac852013-03-21 12:37:15 +0100426 if (new_lsr & SERIAL_LSR_BI)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500427 icount->brk++;
Johan Hovoldc9fac852013-03-21 12:37:15 +0100428 if (new_lsr & SERIAL_LSR_OE)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500429 icount->overrun++;
Johan Hovoldc9fac852013-03-21 12:37:15 +0100430 if (new_lsr & SERIAL_LSR_PE)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500431 icount->parity++;
Johan Hovoldc9fac852013-03-21 12:37:15 +0100432 if (new_lsr & SERIAL_LSR_FE)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500433 icount->frame++;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500434}
435
436/************************************************************************/
437/************************************************************************/
438/* U S B C A L L B A C K F U N C T I O N S */
439/* U S B C A L L B A C K F U N C T I O N S */
440/************************************************************************/
441/************************************************************************/
442
David Howells7d12e782006-10-05 14:55:46 +0100443static void mos7840_control_callback(struct urb *urb)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500444{
445 unsigned char *data;
446 struct moschip_port *mos7840_port;
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700447 struct device *dev = &urb->dev->dev;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500448 __u8 regval = 0x0;
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700449 int status = urb->status;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500450
Ming Leicdc97792008-02-24 18:41:47 +0800451 mos7840_port = urb->context;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100452
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700453 switch (status) {
Paul B Schroeder3f542972006-08-31 19:41:47 -0500454 case 0:
455 /* success */
456 break;
457 case -ECONNRESET:
458 case -ENOENT:
459 case -ESHUTDOWN:
460 /* this urb is terminated, clean up */
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700461 dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500462 return;
463 default:
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700464 dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status);
Johan Hovold28c3ae92012-10-25 18:56:32 +0200465 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500466 }
467
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700468 dev_dbg(dev, "%s urb buffer size is %d\n", __func__, urb->actual_length);
469 dev_dbg(dev, "%s mos7840_port->MsrLsr is %d port %d\n", __func__,
470 mos7840_port->MsrLsr, mos7840_port->port_num);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500471 data = urb->transfer_buffer;
472 regval = (__u8) data[0];
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700473 dev_dbg(dev, "%s data is %x\n", __func__, regval);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500474 if (mos7840_port->MsrLsr == 0)
475 mos7840_handle_new_msr(mos7840_port, regval);
476 else if (mos7840_port->MsrLsr == 1)
477 mos7840_handle_new_lsr(mos7840_port, regval);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500478}
479
480static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
Alan Cox880af9d2008-07-22 11:16:12 +0100481 __u16 *val)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500482{
483 struct usb_device *dev = mcs->port->serial->dev;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100484 struct usb_ctrlrequest *dr = mcs->dr;
485 unsigned char *buffer = mcs->ctrl_buf;
486 int ret;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500487
Paul B Schroeder3f542972006-08-31 19:41:47 -0500488 dr->bRequestType = MCS_RD_RTYPE;
489 dr->bRequest = MCS_RDREQ;
Alan Cox880af9d2008-07-22 11:16:12 +0100490 dr->wValue = cpu_to_le16(Wval); /* 0 */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500491 dr->wIndex = cpu_to_le16(reg);
492 dr->wLength = cpu_to_le16(2);
493
494 usb_fill_control_urb(mcs->control_urb, dev, usb_rcvctrlpipe(dev, 0),
495 (unsigned char *)dr, buffer, 2,
496 mos7840_control_callback, mcs);
497 mcs->control_urb->transfer_buffer_length = 2;
498 ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
499 return ret;
500}
501
Donald0eafe4d2012-04-19 15:00:45 +0800502static void mos7840_set_led_callback(struct urb *urb)
503{
504 switch (urb->status) {
505 case 0:
506 /* Success */
507 break;
508 case -ECONNRESET:
509 case -ENOENT:
510 case -ESHUTDOWN:
511 /* This urb is terminated, clean up */
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700512 dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d",
513 __func__, urb->status);
Donald0eafe4d2012-04-19 15:00:45 +0800514 break;
515 default:
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700516 dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d",
517 __func__, urb->status);
Donald0eafe4d2012-04-19 15:00:45 +0800518 }
519}
520
521static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval,
522 __u16 reg)
523{
524 struct usb_device *dev = mcs->port->serial->dev;
525 struct usb_ctrlrequest *dr = mcs->dr;
526
527 dr->bRequestType = MCS_WR_RTYPE;
528 dr->bRequest = MCS_WRREQ;
529 dr->wValue = cpu_to_le16(wval);
530 dr->wIndex = cpu_to_le16(reg);
531 dr->wLength = cpu_to_le16(0);
532
533 usb_fill_control_urb(mcs->control_urb, dev, usb_sndctrlpipe(dev, 0),
534 (unsigned char *)dr, NULL, 0, mos7840_set_led_callback, NULL);
535
536 usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
537}
538
539static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg,
540 __u16 val)
541{
542 struct usb_device *dev = port->serial->dev;
543
544 usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, MCS_WR_RTYPE,
545 val, reg, NULL, 0, MOS_WDR_TIMEOUT);
546}
547
548static void mos7840_led_off(unsigned long arg)
549{
550 struct moschip_port *mcs = (struct moschip_port *) arg;
551
552 /* Turn off LED */
553 mos7840_set_led_async(mcs, 0x0300, MODEM_CONTROL_REGISTER);
554 mod_timer(&mcs->led_timer2,
555 jiffies + msecs_to_jiffies(LED_OFF_MS));
556}
557
558static void mos7840_led_flag_off(unsigned long arg)
559{
560 struct moschip_port *mcs = (struct moschip_port *) arg;
561
562 mcs->led_flag = false;
563}
564
Paul B Schroeder3f542972006-08-31 19:41:47 -0500565/*****************************************************************************
566 * mos7840_interrupt_callback
567 * this is the callback function for when we have received data on the
568 * interrupt endpoint.
569 *****************************************************************************/
570
David Howells7d12e782006-10-05 14:55:46 +0100571static void mos7840_interrupt_callback(struct urb *urb)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500572{
573 int result;
574 int length;
575 struct moschip_port *mos7840_port;
576 struct usb_serial *serial;
577 __u16 Data;
578 unsigned char *data;
579 __u8 sp[5], st;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100580 int i, rv = 0;
581 __u16 wval, wreg = 0;
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700582 int status = urb->status;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500583
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700584 switch (status) {
Paul B Schroeder3f542972006-08-31 19:41:47 -0500585 case 0:
586 /* success */
587 break;
588 case -ECONNRESET:
589 case -ENOENT:
590 case -ESHUTDOWN:
591 /* this urb is terminated, clean up */
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700592 dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n",
593 __func__, status);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500594 return;
595 default:
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700596 dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n",
597 __func__, status);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500598 goto exit;
599 }
600
601 length = urb->actual_length;
602 data = urb->transfer_buffer;
603
Ming Leicdc97792008-02-24 18:41:47 +0800604 serial = urb->context;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500605
606 /* Moschip get 5 bytes
607 * Byte 1 IIR Port 1 (port.number is 0)
608 * Byte 2 IIR Port 2 (port.number is 1)
609 * Byte 3 IIR Port 3 (port.number is 2)
610 * Byte 4 IIR Port 4 (port.number is 3)
611 * Byte 5 FIFO status for both */
612
613 if (length && length > 5) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700614 dev_dbg(&urb->dev->dev, "%s", "Wrong data !!!\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500615 return;
616 }
617
618 sp[0] = (__u8) data[0];
619 sp[1] = (__u8) data[1];
620 sp[2] = (__u8) data[2];
621 sp[3] = (__u8) data[3];
622 st = (__u8) data[4];
623
624 for (i = 0; i < serial->num_ports; i++) {
625 mos7840_port = mos7840_get_port_private(serial->port[i]);
Greg Kroah-Hartman11438322013-06-06 10:32:00 -0700626 wval = ((__u16)serial->port[i]->port_number + 1) << 8;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500627 if (mos7840_port->open) {
628 if (sp[i] & 0x01) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700629 dev_dbg(&urb->dev->dev, "SP%d No Interrupt !!!\n", i);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500630 } else {
631 switch (sp[i] & 0x0f) {
632 case SERIAL_IIR_RLS:
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700633 dev_dbg(&urb->dev->dev, "Serial Port %d: Receiver status error or \n", i);
634 dev_dbg(&urb->dev->dev, "address bit detected in 9-bit mode\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500635 mos7840_port->MsrLsr = 1;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100636 wreg = LINE_STATUS_REGISTER;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500637 break;
638 case SERIAL_IIR_MS:
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700639 dev_dbg(&urb->dev->dev, "Serial Port %d: Modem status change\n", i);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500640 mos7840_port->MsrLsr = 0;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100641 wreg = MODEM_STATUS_REGISTER;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500642 break;
643 }
Johan Hovolde681b662012-10-25 18:56:33 +0200644 rv = mos7840_get_reg(mos7840_port, wval, wreg, &Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500645 }
646 }
647 }
Alan Cox880af9d2008-07-22 11:16:12 +0100648 if (!(rv < 0))
649 /* the completion handler for the control urb will resubmit */
Oliver Neukum0de9a702007-03-16 20:28:28 +0100650 return;
651exit:
Paul B Schroeder3f542972006-08-31 19:41:47 -0500652 result = usb_submit_urb(urb, GFP_ATOMIC);
653 if (result) {
654 dev_err(&urb->dev->dev,
655 "%s - Error %d submitting interrupt urb\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800656 __func__, result);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500657 }
Paul B Schroeder3f542972006-08-31 19:41:47 -0500658}
659
660static int mos7840_port_paranoia_check(struct usb_serial_port *port,
661 const char *function)
662{
663 if (!port) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700664 pr_debug("%s - port == NULL\n", function);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500665 return -1;
666 }
667 if (!port->serial) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700668 pr_debug("%s - port->serial == NULL\n", function);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500669 return -1;
670 }
671
672 return 0;
673}
674
675/* Inline functions to check the sanity of a pointer that is passed to us */
676static int mos7840_serial_paranoia_check(struct usb_serial *serial,
677 const char *function)
678{
679 if (!serial) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700680 pr_debug("%s - serial == NULL\n", function);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500681 return -1;
682 }
683 if (!serial->type) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700684 pr_debug("%s - serial->type == NULL!\n", function);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500685 return -1;
686 }
687
688 return 0;
689}
690
691static struct usb_serial *mos7840_get_usb_serial(struct usb_serial_port *port,
692 const char *function)
693{
694 /* if no port was specified, or it fails a paranoia check */
695 if (!port ||
696 mos7840_port_paranoia_check(port, function) ||
697 mos7840_serial_paranoia_check(port->serial, function)) {
Alan Cox880af9d2008-07-22 11:16:12 +0100698 /* then say that we don't have a valid usb_serial thing,
699 * which will end up genrating -ENODEV return values */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500700 return NULL;
701 }
702
703 return port->serial;
704}
705
706/*****************************************************************************
707 * mos7840_bulk_in_callback
708 * this is the callback function for when we have received data on the
709 * bulk in endpoint.
710 *****************************************************************************/
711
David Howells7d12e782006-10-05 14:55:46 +0100712static void mos7840_bulk_in_callback(struct urb *urb)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500713{
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700714 int retval;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500715 unsigned char *data;
716 struct usb_serial *serial;
717 struct usb_serial_port *port;
718 struct moschip_port *mos7840_port;
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700719 int status = urb->status;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500720
Ming Leicdc97792008-02-24 18:41:47 +0800721 mos7840_port = urb->context;
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700722 if (!mos7840_port)
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800723 return;
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800724
725 if (status) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700726 dev_dbg(&urb->dev->dev, "nonzero read bulk status received: %d\n", status);
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800727 mos7840_port->read_urb_busy = false;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500728 return;
729 }
730
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700731 port = mos7840_port->port;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800732 if (mos7840_port_paranoia_check(port, __func__)) {
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800733 mos7840_port->read_urb_busy = false;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500734 return;
735 }
736
Harvey Harrison441b62c2008-03-03 16:08:34 -0800737 serial = mos7840_get_usb_serial(port, __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500738 if (!serial) {
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800739 mos7840_port->read_urb_busy = false;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500740 return;
741 }
742
Paul B Schroeder3f542972006-08-31 19:41:47 -0500743 data = urb->transfer_buffer;
Greg Kroah-Hartman59d33f22012-09-18 09:58:57 +0100744 usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500745
Paul B Schroeder3f542972006-08-31 19:41:47 -0500746 if (urb->actual_length) {
Jiri Slaby05c7cd32013-01-03 15:53:04 +0100747 struct tty_port *tport = &mos7840_port->port->port;
Jiri Slaby2e124b42013-01-03 15:53:06 +0100748 tty_insert_flip_string(tport, data, urb->actual_length);
749 tty_flip_buffer_push(tport);
Johan Hovold8c1a07f2013-03-21 12:37:16 +0100750 port->icount.rx += urb->actual_length;
751 dev_dbg(&port->dev, "icount.rx is %d:\n", port->icount.rx);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500752 }
753
754 if (!mos7840_port->read_urb) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700755 dev_dbg(&port->dev, "%s", "URB KILLED !!!\n");
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800756 mos7840_port->read_urb_busy = false;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500757 return;
758 }
759
Donald0eafe4d2012-04-19 15:00:45 +0800760 /* Turn on LED */
761 if (mos7840_port->has_led && !mos7840_port->led_flag) {
762 mos7840_port->led_flag = true;
763 mos7840_set_led_async(mos7840_port, 0x0301,
764 MODEM_CONTROL_REGISTER);
765 mod_timer(&mos7840_port->led_timer1,
766 jiffies + msecs_to_jiffies(LED_ON_MS));
767 }
Paul B Schroeder3f542972006-08-31 19:41:47 -0500768
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800769 mos7840_port->read_urb_busy = true;
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700770 retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
Oliver Neukum0de9a702007-03-16 20:28:28 +0100771
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700772 if (retval) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700773 dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, retval = %d\n", retval);
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800774 mos7840_port->read_urb_busy = false;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500775 }
776}
777
778/*****************************************************************************
779 * mos7840_bulk_out_data_callback
Alan Cox880af9d2008-07-22 11:16:12 +0100780 * this is the callback function for when we have finished sending
781 * serial data on the bulk out endpoint.
Paul B Schroeder3f542972006-08-31 19:41:47 -0500782 *****************************************************************************/
783
David Howells7d12e782006-10-05 14:55:46 +0100784static void mos7840_bulk_out_data_callback(struct urb *urb)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500785{
786 struct moschip_port *mos7840_port;
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700787 struct usb_serial_port *port;
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700788 int status = urb->status;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100789 int i;
790
Ming Leicdc97792008-02-24 18:41:47 +0800791 mos7840_port = urb->context;
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700792 port = mos7840_port->port;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100793 spin_lock(&mos7840_port->pool_lock);
794 for (i = 0; i < NUM_URBS; i++) {
795 if (urb == mos7840_port->write_urb_pool[i]) {
796 mos7840_port->busy[i] = 0;
797 break;
798 }
799 }
800 spin_unlock(&mos7840_port->pool_lock);
801
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700802 if (status) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700803 dev_dbg(&port->dev, "nonzero write bulk status received:%d\n", status);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500804 return;
805 }
806
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700807 if (mos7840_port_paranoia_check(port, __func__))
Paul B Schroeder3f542972006-08-31 19:41:47 -0500808 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500809
Jiri Slaby6aad04f2013-03-07 13:12:29 +0100810 if (mos7840_port->open)
811 tty_port_tty_wakeup(&port->port);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500812
813}
814
815/************************************************************************/
816/* D R I V E R T T Y I N T E R F A C E F U N C T I O N S */
817/************************************************************************/
818#ifdef MCSSerialProbe
819static int mos7840_serial_probe(struct usb_serial *serial,
820 const struct usb_device_id *id)
821{
822
823 /*need to implement the mode_reg reading and updating\
824 structures usb_serial_ device_type\
825 (i.e num_ports, num_bulkin,bulkout etc) */
826 /* Also we can update the changes attach */
827 return 1;
828}
829#endif
830
831/*****************************************************************************
832 * mos7840_open
833 * this function is called by the tty driver when a port is opened
834 * If successful, we return 0
835 * Otherwise we return a negative error number.
836 *****************************************************************************/
837
Alan Coxa509a7e2009-09-19 13:13:26 -0700838static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500839{
840 int response;
841 int j;
842 struct usb_serial *serial;
843 struct urb *urb;
844 __u16 Data;
845 int status;
846 struct moschip_port *mos7840_port;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100847 struct moschip_port *port0;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500848
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700849 if (mos7840_port_paranoia_check(port, __func__))
Paul B Schroeder3f542972006-08-31 19:41:47 -0500850 return -ENODEV;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500851
Paul B Schroeder3f542972006-08-31 19:41:47 -0500852 serial = port->serial;
853
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700854 if (mos7840_serial_paranoia_check(serial, __func__))
Paul B Schroeder3f542972006-08-31 19:41:47 -0500855 return -ENODEV;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500856
857 mos7840_port = mos7840_get_port_private(port);
Oliver Neukum0de9a702007-03-16 20:28:28 +0100858 port0 = mos7840_get_port_private(serial->port[0]);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500859
Oliver Neukum0de9a702007-03-16 20:28:28 +0100860 if (mos7840_port == NULL || port0 == NULL)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500861 return -ENODEV;
862
863 usb_clear_halt(serial->dev, port->write_urb->pipe);
864 usb_clear_halt(serial->dev, port->read_urb->pipe);
Oliver Neukum0de9a702007-03-16 20:28:28 +0100865 port0->open_ports++;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500866
867 /* Initialising the write urb pool */
868 for (j = 0; j < NUM_URBS; ++j) {
Oliver Neukum0de9a702007-03-16 20:28:28 +0100869 urb = usb_alloc_urb(0, GFP_KERNEL);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500870 mos7840_port->write_urb_pool[j] = urb;
871
872 if (urb == NULL) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -0700873 dev_err(&port->dev, "No more urbs???\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500874 continue;
875 }
876
Alan Cox880af9d2008-07-22 11:16:12 +0100877 urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
878 GFP_KERNEL);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500879 if (!urb->transfer_buffer) {
Oliver Neukum0de9a702007-03-16 20:28:28 +0100880 usb_free_urb(urb);
881 mos7840_port->write_urb_pool[j] = NULL;
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -0700882 dev_err(&port->dev,
883 "%s-out of memory for urb buffers.\n",
884 __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500885 continue;
886 }
887 }
888
889/*****************************************************************************
890 * Initialize MCS7840 -- Write Init values to corresponding Registers
891 *
892 * Register Index
893 * 1 : IER
894 * 2 : FCR
895 * 3 : LCR
896 * 4 : MCR
897 *
898 * 0x08 : SP1/2 Control Reg
899 *****************************************************************************/
900
Alan Cox880af9d2008-07-22 11:16:12 +0100901 /* NEED to check the following Block */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500902
Paul B Schroeder3f542972006-08-31 19:41:47 -0500903 Data = 0x0;
904 status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data);
905 if (status < 0) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700906 dev_dbg(&port->dev, "Reading Spreg failed\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500907 return -1;
908 }
909 Data |= 0x80;
910 status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
911 if (status < 0) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700912 dev_dbg(&port->dev, "writing Spreg failed\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500913 return -1;
914 }
915
916 Data &= ~0x80;
917 status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
918 if (status < 0) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700919 dev_dbg(&port->dev, "writing Spreg failed\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500920 return -1;
921 }
Alan Cox880af9d2008-07-22 11:16:12 +0100922 /* End of block to be checked */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500923
Paul B Schroeder3f542972006-08-31 19:41:47 -0500924 Data = 0x0;
Alan Cox880af9d2008-07-22 11:16:12 +0100925 status = mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset,
926 &Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500927 if (status < 0) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700928 dev_dbg(&port->dev, "Reading Controlreg failed\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500929 return -1;
930 }
Alan Cox880af9d2008-07-22 11:16:12 +0100931 Data |= 0x08; /* Driver done bit */
932 Data |= 0x20; /* rx_disable */
933 status = mos7840_set_reg_sync(port,
934 mos7840_port->ControlRegOffset, Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500935 if (status < 0) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700936 dev_dbg(&port->dev, "writing Controlreg failed\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500937 return -1;
938 }
Alan Cox880af9d2008-07-22 11:16:12 +0100939 /* do register settings here */
940 /* Set all regs to the device default values. */
941 /***********************************
942 * First Disable all interrupts.
943 ***********************************/
Paul B Schroeder3f542972006-08-31 19:41:47 -0500944 Data = 0x00;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500945 status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
946 if (status < 0) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700947 dev_dbg(&port->dev, "disabling interrupts failed\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500948 return -1;
949 }
Alan Cox880af9d2008-07-22 11:16:12 +0100950 /* Set FIFO_CONTROL_REGISTER to the default value */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500951 Data = 0x00;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500952 status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
953 if (status < 0) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700954 dev_dbg(&port->dev, "Writing FIFO_CONTROL_REGISTER failed\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500955 return -1;
956 }
957
958 Data = 0xcf;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500959 status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
960 if (status < 0) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -0700961 dev_dbg(&port->dev, "Writing FIFO_CONTROL_REGISTER failed\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500962 return -1;
963 }
964
965 Data = 0x03;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500966 status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
967 mos7840_port->shadowLCR = Data;
968
969 Data = 0x0b;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500970 status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
971 mos7840_port->shadowMCR = Data;
972
973 Data = 0x00;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500974 status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
975 mos7840_port->shadowLCR = Data;
976
Alan Cox880af9d2008-07-22 11:16:12 +0100977 Data |= SERIAL_LCR_DLAB; /* data latch enable in LCR 0x80 */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500978 status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
979
980 Data = 0x0c;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500981 status = mos7840_set_uart_reg(port, DIVISOR_LATCH_LSB, Data);
982
983 Data = 0x0;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500984 status = mos7840_set_uart_reg(port, DIVISOR_LATCH_MSB, Data);
985
986 Data = 0x00;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500987 status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
988
989 Data = Data & ~SERIAL_LCR_DLAB;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500990 status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
991 mos7840_port->shadowLCR = Data;
992
Alan Cox880af9d2008-07-22 11:16:12 +0100993 /* clearing Bulkin and Bulkout Fifo */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500994 Data = 0x0;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500995 status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data);
996
997 Data = Data | 0x0c;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500998 status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
999
1000 Data = Data & ~0x0c;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001001 status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
Alan Cox880af9d2008-07-22 11:16:12 +01001002 /* Finally enable all interrupts */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001003 Data = 0x0c;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001004 status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
1005
Alan Cox880af9d2008-07-22 11:16:12 +01001006 /* clearing rx_disable */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001007 Data = 0x0;
Alan Cox880af9d2008-07-22 11:16:12 +01001008 status = mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset,
1009 &Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001010 Data = Data & ~0x20;
Alan Cox880af9d2008-07-22 11:16:12 +01001011 status = mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset,
1012 Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001013
Alan Cox880af9d2008-07-22 11:16:12 +01001014 /* rx_negate */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001015 Data = 0x0;
Alan Cox880af9d2008-07-22 11:16:12 +01001016 status = mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset,
1017 &Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001018 Data = Data | 0x10;
Alan Cox880af9d2008-07-22 11:16:12 +01001019 status = mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset,
1020 Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001021
Alan Cox880af9d2008-07-22 11:16:12 +01001022 /* Check to see if we've set up our endpoint info yet *
1023 * (can't set it up in mos7840_startup as the structures *
1024 * were not set up at that time.) */
Oliver Neukum0de9a702007-03-16 20:28:28 +01001025 if (port0->open_ports == 1) {
Paul B Schroeder3f542972006-08-31 19:41:47 -05001026 if (serial->port[0]->interrupt_in_buffer == NULL) {
Paul B Schroeder3f542972006-08-31 19:41:47 -05001027 /* set up interrupt urb */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001028 usb_fill_int_urb(serial->port[0]->interrupt_in_urb,
Alan Cox880af9d2008-07-22 11:16:12 +01001029 serial->dev,
1030 usb_rcvintpipe(serial->dev,
1031 serial->port[0]->interrupt_in_endpointAddress),
1032 serial->port[0]->interrupt_in_buffer,
1033 serial->port[0]->interrupt_in_urb->
1034 transfer_buffer_length,
1035 mos7840_interrupt_callback,
1036 serial,
1037 serial->port[0]->interrupt_in_urb->interval);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001038
1039 /* start interrupt read for mos7840 *
1040 * will continue as long as mos7840 is connected */
1041
1042 response =
1043 usb_submit_urb(serial->port[0]->interrupt_in_urb,
1044 GFP_KERNEL);
1045 if (response) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001046 dev_err(&port->dev, "%s - Error %d submitting "
1047 "interrupt urb\n", __func__, response);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001048 }
1049
1050 }
1051
1052 }
1053
1054 /* see if we've set up our endpoint info yet *
1055 * (can't set it up in mos7840_startup as the *
1056 * structures were not set up at that time.) */
1057
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001058 dev_dbg(&port->dev, "port number is %d\n", port->port_number);
Greg Kroah-Hartmane5b1e202013-06-07 11:04:28 -07001059 dev_dbg(&port->dev, "minor number is %d\n", port->minor);
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001060 dev_dbg(&port->dev, "Bulkin endpoint is %d\n", port->bulk_in_endpointAddress);
1061 dev_dbg(&port->dev, "BulkOut endpoint is %d\n", port->bulk_out_endpointAddress);
1062 dev_dbg(&port->dev, "Interrupt endpoint is %d\n", port->interrupt_in_endpointAddress);
1063 dev_dbg(&port->dev, "port's number in the device is %d\n", mos7840_port->port_num);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001064 mos7840_port->read_urb = port->read_urb;
1065
1066 /* set up our bulk in urb */
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001067 if ((serial->num_ports == 2) && (((__u16)port->port_number % 2) != 0)) {
Donald Lee093ea2d2012-03-14 15:26:33 +08001068 usb_fill_bulk_urb(mos7840_port->read_urb,
1069 serial->dev,
1070 usb_rcvbulkpipe(serial->dev,
1071 (port->bulk_in_endpointAddress) + 2),
1072 port->bulk_in_buffer,
1073 mos7840_port->read_urb->transfer_buffer_length,
1074 mos7840_bulk_in_callback, mos7840_port);
1075 } else {
1076 usb_fill_bulk_urb(mos7840_port->read_urb,
1077 serial->dev,
1078 usb_rcvbulkpipe(serial->dev,
1079 port->bulk_in_endpointAddress),
1080 port->bulk_in_buffer,
1081 mos7840_port->read_urb->transfer_buffer_length,
1082 mos7840_bulk_in_callback, mos7840_port);
1083 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05001084
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001085 dev_dbg(&port->dev, "%s: bulkin endpoint is %d\n", __func__, port->bulk_in_endpointAddress);
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -08001086 mos7840_port->read_urb_busy = true;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001087 response = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL);
1088 if (response) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001089 dev_err(&port->dev, "%s - Error %d submitting control urb\n",
1090 __func__, response);
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -08001091 mos7840_port->read_urb_busy = false;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001092 }
1093
Paul B Schroeder3f542972006-08-31 19:41:47 -05001094 /* initialize our port settings */
Alan Cox880af9d2008-07-22 11:16:12 +01001095 /* Must set to enable ints! */
1096 mos7840_port->shadowMCR = MCR_MASTER_IE;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001097 /* send a open port command */
1098 mos7840_port->open = 1;
Alan Cox880af9d2008-07-22 11:16:12 +01001099 /* mos7840_change_port_settings(mos7840_port,old_termios); */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001100
Paul B Schroeder3f542972006-08-31 19:41:47 -05001101 return 0;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001102}
1103
1104/*****************************************************************************
1105 * mos7840_chars_in_buffer
1106 * this function is called by the tty driver when it wants to know how many
1107 * bytes of data we currently have outstanding in the port (data that has
1108 * been written, but hasn't made it out the port yet)
1109 * If successful, we return the number of bytes left to be written in the
1110 * system,
Alan Cox95da3102008-07-22 11:09:07 +01001111 * Otherwise we return zero.
Paul B Schroeder3f542972006-08-31 19:41:47 -05001112 *****************************************************************************/
1113
Alan Cox95da3102008-07-22 11:09:07 +01001114static int mos7840_chars_in_buffer(struct tty_struct *tty)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001115{
Alan Cox95da3102008-07-22 11:09:07 +01001116 struct usb_serial_port *port = tty->driver_data;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001117 int i;
1118 int chars = 0;
Oliver Neukum0de9a702007-03-16 20:28:28 +01001119 unsigned long flags;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001120 struct moschip_port *mos7840_port;
1121
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001122 if (mos7840_port_paranoia_check(port, __func__))
Alan Cox95da3102008-07-22 11:09:07 +01001123 return 0;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001124
1125 mos7840_port = mos7840_get_port_private(port);
Greg Kroah-Hartman33631552012-05-03 16:44:33 -07001126 if (mos7840_port == NULL)
Alan Cox95da3102008-07-22 11:09:07 +01001127 return 0;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001128
Alan Cox880af9d2008-07-22 11:16:12 +01001129 spin_lock_irqsave(&mos7840_port->pool_lock, flags);
Mark Ferrell5c263b92012-07-24 14:15:13 -05001130 for (i = 0; i < NUM_URBS; ++i) {
1131 if (mos7840_port->busy[i]) {
1132 struct urb *urb = mos7840_port->write_urb_pool[i];
1133 chars += urb->transfer_buffer_length;
1134 }
1135 }
Alan Cox880af9d2008-07-22 11:16:12 +01001136 spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001137 dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
Oliver Neukum0de9a702007-03-16 20:28:28 +01001138 return chars;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001139
1140}
1141
Paul B Schroeder3f542972006-08-31 19:41:47 -05001142/*****************************************************************************
1143 * mos7840_close
1144 * this function is called by the tty driver when a port is closed
1145 *****************************************************************************/
1146
Alan Cox335f8512009-06-11 12:26:29 +01001147static void mos7840_close(struct usb_serial_port *port)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001148{
1149 struct usb_serial *serial;
1150 struct moschip_port *mos7840_port;
Oliver Neukum0de9a702007-03-16 20:28:28 +01001151 struct moschip_port *port0;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001152 int j;
1153 __u16 Data;
1154
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001155 if (mos7840_port_paranoia_check(port, __func__))
Paul B Schroeder3f542972006-08-31 19:41:47 -05001156 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001157
Harvey Harrison441b62c2008-03-03 16:08:34 -08001158 serial = mos7840_get_usb_serial(port, __func__);
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001159 if (!serial)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001160 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001161
1162 mos7840_port = mos7840_get_port_private(port);
Oliver Neukum0de9a702007-03-16 20:28:28 +01001163 port0 = mos7840_get_port_private(serial->port[0]);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001164
Oliver Neukum0de9a702007-03-16 20:28:28 +01001165 if (mos7840_port == NULL || port0 == NULL)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001166 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001167
1168 for (j = 0; j < NUM_URBS; ++j)
1169 usb_kill_urb(mos7840_port->write_urb_pool[j]);
1170
1171 /* Freeing Write URBs */
1172 for (j = 0; j < NUM_URBS; ++j) {
1173 if (mos7840_port->write_urb_pool[j]) {
1174 if (mos7840_port->write_urb_pool[j]->transfer_buffer)
1175 kfree(mos7840_port->write_urb_pool[j]->
1176 transfer_buffer);
1177
1178 usb_free_urb(mos7840_port->write_urb_pool[j]);
1179 }
1180 }
1181
Johan Hovoldbb3529c2013-03-21 12:36:35 +01001182 usb_kill_urb(mos7840_port->write_urb);
1183 usb_kill_urb(mos7840_port->read_urb);
1184 mos7840_port->read_urb_busy = false;
1185
Oliver Neukum0de9a702007-03-16 20:28:28 +01001186 port0->open_ports--;
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001187 dev_dbg(&port->dev, "%s in close%d\n", __func__, port0->open_ports);
Oliver Neukum0de9a702007-03-16 20:28:28 +01001188 if (port0->open_ports == 0) {
Paul B Schroeder3f542972006-08-31 19:41:47 -05001189 if (serial->port[0]->interrupt_in_urb) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001190 dev_dbg(&port->dev, "Shutdown interrupt_in_urb\n");
Oliver Neukum0de9a702007-03-16 20:28:28 +01001191 usb_kill_urb(serial->port[0]->interrupt_in_urb);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001192 }
1193 }
1194
1195 if (mos7840_port->write_urb) {
1196 /* if this urb had a transfer buffer already (old tx) free it */
Syam Sidhardhanae8d4872013-03-07 01:51:12 +05301197 kfree(mos7840_port->write_urb->transfer_buffer);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001198 usb_free_urb(mos7840_port->write_urb);
1199 }
1200
1201 Data = 0x0;
1202 mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
1203
1204 Data = 0x00;
1205 mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
1206
1207 mos7840_port->open = 0;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001208}
1209
Paul B Schroeder3f542972006-08-31 19:41:47 -05001210/*****************************************************************************
1211 * mos7840_break
1212 * this function sends a break to the port
1213 *****************************************************************************/
Alan Cox95da3102008-07-22 11:09:07 +01001214static void mos7840_break(struct tty_struct *tty, int break_state)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001215{
Alan Cox95da3102008-07-22 11:09:07 +01001216 struct usb_serial_port *port = tty->driver_data;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001217 unsigned char data;
1218 struct usb_serial *serial;
1219 struct moschip_port *mos7840_port;
1220
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001221 if (mos7840_port_paranoia_check(port, __func__))
Paul B Schroeder3f542972006-08-31 19:41:47 -05001222 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001223
Harvey Harrison441b62c2008-03-03 16:08:34 -08001224 serial = mos7840_get_usb_serial(port, __func__);
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001225 if (!serial)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001226 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001227
1228 mos7840_port = mos7840_get_port_private(port);
1229
Alan Cox880af9d2008-07-22 11:16:12 +01001230 if (mos7840_port == NULL)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001231 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001232
Alan Cox95da3102008-07-22 11:09:07 +01001233 if (break_state == -1)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001234 data = mos7840_port->shadowLCR | LCR_SET_BREAK;
Alan Cox95da3102008-07-22 11:09:07 +01001235 else
Paul B Schroeder3f542972006-08-31 19:41:47 -05001236 data = mos7840_port->shadowLCR & ~LCR_SET_BREAK;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001237
Alan Cox6b447f042009-01-02 13:48:56 +00001238 /* FIXME: no locking on shadowLCR anywhere in driver */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001239 mos7840_port->shadowLCR = data;
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001240 dev_dbg(&port->dev, "%s mos7840_port->shadowLCR is %x\n", __func__, mos7840_port->shadowLCR);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001241 mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER,
1242 mos7840_port->shadowLCR);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001243}
1244
1245/*****************************************************************************
1246 * mos7840_write_room
1247 * this function is called by the tty driver when it wants to know how many
1248 * bytes of data we can accept for a specific port.
1249 * If successful, we return the amount of room that we have for this port
1250 * Otherwise we return a negative error number.
1251 *****************************************************************************/
1252
Alan Cox95da3102008-07-22 11:09:07 +01001253static int mos7840_write_room(struct tty_struct *tty)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001254{
Alan Cox95da3102008-07-22 11:09:07 +01001255 struct usb_serial_port *port = tty->driver_data;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001256 int i;
1257 int room = 0;
Oliver Neukum0de9a702007-03-16 20:28:28 +01001258 unsigned long flags;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001259 struct moschip_port *mos7840_port;
1260
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001261 if (mos7840_port_paranoia_check(port, __func__))
Paul B Schroeder3f542972006-08-31 19:41:47 -05001262 return -1;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001263
1264 mos7840_port = mos7840_get_port_private(port);
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001265 if (mos7840_port == NULL)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001266 return -1;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001267
Oliver Neukum0de9a702007-03-16 20:28:28 +01001268 spin_lock_irqsave(&mos7840_port->pool_lock, flags);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001269 for (i = 0; i < NUM_URBS; ++i) {
Alan Cox880af9d2008-07-22 11:16:12 +01001270 if (!mos7840_port->busy[i])
Paul B Schroeder3f542972006-08-31 19:41:47 -05001271 room += URB_TRANSFER_BUFFER_SIZE;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001272 }
Oliver Neukum0de9a702007-03-16 20:28:28 +01001273 spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001274
Oliver Neukum0de9a702007-03-16 20:28:28 +01001275 room = (room == 0) ? 0 : room - URB_TRANSFER_BUFFER_SIZE + 1;
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001276 dev_dbg(&mos7840_port->port->dev, "%s - returns %d\n", __func__, room);
Oliver Neukum0de9a702007-03-16 20:28:28 +01001277 return room;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001278
1279}
1280
1281/*****************************************************************************
1282 * mos7840_write
1283 * this function is called by the tty driver when data should be written to
1284 * the port.
1285 * If successful, we return the number of bytes written, otherwise we
1286 * return a negative error number.
1287 *****************************************************************************/
1288
Alan Cox95da3102008-07-22 11:09:07 +01001289static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
Paul B Schroeder3f542972006-08-31 19:41:47 -05001290 const unsigned char *data, int count)
1291{
1292 int status;
1293 int i;
1294 int bytes_sent = 0;
1295 int transfer_size;
Oliver Neukum0de9a702007-03-16 20:28:28 +01001296 unsigned long flags;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001297
1298 struct moschip_port *mos7840_port;
1299 struct usb_serial *serial;
1300 struct urb *urb;
Alan Cox880af9d2008-07-22 11:16:12 +01001301 /* __u16 Data; */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001302 const unsigned char *current_position = data;
1303 unsigned char *data1;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001304
1305#ifdef NOTMOS7840
1306 Data = 0x00;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001307 status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
1308 mos7840_port->shadowLCR = Data;
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001309 dev_dbg(&port->dev, "%s: LINE_CONTROL_REGISTER is %x\n", __func__, Data);
1310 dev_dbg(&port->dev, "%s: mos7840_port->shadowLCR is %x\n", __func__, mos7840_port->shadowLCR);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001311
Alan Cox880af9d2008-07-22 11:16:12 +01001312 /* Data = 0x03; */
1313 /* status = mos7840_set_uart_reg(port,LINE_CONTROL_REGISTER,Data); */
1314 /* mos7840_port->shadowLCR=Data;//Need to add later */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001315
Alan Cox880af9d2008-07-22 11:16:12 +01001316 Data |= SERIAL_LCR_DLAB; /* data latch enable in LCR 0x80 */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001317 status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
1318
Alan Cox880af9d2008-07-22 11:16:12 +01001319 /* Data = 0x0c; */
1320 /* status = mos7840_set_uart_reg(port,DIVISOR_LATCH_LSB,Data); */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001321 Data = 0x00;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001322 status = mos7840_get_uart_reg(port, DIVISOR_LATCH_LSB, &Data);
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001323 dev_dbg(&port->dev, "%s: DLL value is %x\n", __func__, Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001324
1325 Data = 0x0;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001326 status = mos7840_get_uart_reg(port, DIVISOR_LATCH_MSB, &Data);
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001327 dev_dbg(&port->dev, "%s: DLM value is %x\n", __func__, Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001328
1329 Data = Data & ~SERIAL_LCR_DLAB;
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001330 dev_dbg(&port->dev, "%s: mos7840_port->shadowLCR is %x\n", __func__, mos7840_port->shadowLCR);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001331 status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
1332#endif
1333
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001334 if (mos7840_port_paranoia_check(port, __func__))
Paul B Schroeder3f542972006-08-31 19:41:47 -05001335 return -1;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001336
1337 serial = port->serial;
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001338 if (mos7840_serial_paranoia_check(serial, __func__))
Paul B Schroeder3f542972006-08-31 19:41:47 -05001339 return -1;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001340
1341 mos7840_port = mos7840_get_port_private(port);
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001342 if (mos7840_port == NULL)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001343 return -1;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001344
1345 /* try to find a free urb in the list */
1346 urb = NULL;
1347
Oliver Neukum0de9a702007-03-16 20:28:28 +01001348 spin_lock_irqsave(&mos7840_port->pool_lock, flags);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001349 for (i = 0; i < NUM_URBS; ++i) {
Oliver Neukum0de9a702007-03-16 20:28:28 +01001350 if (!mos7840_port->busy[i]) {
1351 mos7840_port->busy[i] = 1;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001352 urb = mos7840_port->write_urb_pool[i];
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001353 dev_dbg(&port->dev, "URB:%d\n", i);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001354 break;
1355 }
1356 }
Oliver Neukum0de9a702007-03-16 20:28:28 +01001357 spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001358
1359 if (urb == NULL) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001360 dev_dbg(&port->dev, "%s - no more free urbs\n", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001361 goto exit;
1362 }
1363
1364 if (urb->transfer_buffer == NULL) {
1365 urb->transfer_buffer =
1366 kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
1367
1368 if (urb->transfer_buffer == NULL) {
Johan Hovold22a416c2012-02-10 13:20:51 +01001369 dev_err_console(port, "%s no more kernel memory...\n",
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001370 __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001371 goto exit;
1372 }
1373 }
1374 transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
1375
Al Viro97c49652006-10-09 20:29:03 +01001376 memcpy(urb->transfer_buffer, current_position, transfer_size);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001377
1378 /* fill urb with data and submit */
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001379 if ((serial->num_ports == 2) && (((__u16)port->port_number % 2) != 0)) {
Donald Lee093ea2d2012-03-14 15:26:33 +08001380 usb_fill_bulk_urb(urb,
1381 serial->dev,
1382 usb_sndbulkpipe(serial->dev,
1383 (port->bulk_out_endpointAddress) + 2),
1384 urb->transfer_buffer,
1385 transfer_size,
1386 mos7840_bulk_out_data_callback, mos7840_port);
1387 } else {
1388 usb_fill_bulk_urb(urb,
1389 serial->dev,
1390 usb_sndbulkpipe(serial->dev,
1391 port->bulk_out_endpointAddress),
1392 urb->transfer_buffer,
1393 transfer_size,
1394 mos7840_bulk_out_data_callback, mos7840_port);
1395 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05001396
1397 data1 = urb->transfer_buffer;
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001398 dev_dbg(&port->dev, "bulkout endpoint is %d\n", port->bulk_out_endpointAddress);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001399
Donald0eafe4d2012-04-19 15:00:45 +08001400 /* Turn on LED */
1401 if (mos7840_port->has_led && !mos7840_port->led_flag) {
1402 mos7840_port->led_flag = true;
1403 mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0301);
1404 mod_timer(&mos7840_port->led_timer1,
1405 jiffies + msecs_to_jiffies(LED_ON_MS));
1406 }
1407
Paul B Schroeder3f542972006-08-31 19:41:47 -05001408 /* send it down the pipe */
1409 status = usb_submit_urb(urb, GFP_ATOMIC);
1410
1411 if (status) {
Oliver Neukum0de9a702007-03-16 20:28:28 +01001412 mos7840_port->busy[i] = 0;
Johan Hovold22a416c2012-02-10 13:20:51 +01001413 dev_err_console(port, "%s - usb_submit_urb(write bulk) failed "
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001414 "with status = %d\n", __func__, status);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001415 bytes_sent = status;
1416 goto exit;
1417 }
1418 bytes_sent = transfer_size;
Johan Hovold8c1a07f2013-03-21 12:37:16 +01001419 port->icount.tx += transfer_size;
1420 dev_dbg(&port->dev, "icount.tx is %d:\n", port->icount.tx);
Alan Cox95da3102008-07-22 11:09:07 +01001421exit:
Paul B Schroeder3f542972006-08-31 19:41:47 -05001422 return bytes_sent;
1423
1424}
1425
1426/*****************************************************************************
1427 * mos7840_throttle
1428 * this function is called by the tty driver when it wants to stop the data
1429 * being read from the port.
1430 *****************************************************************************/
1431
Alan Cox95da3102008-07-22 11:09:07 +01001432static void mos7840_throttle(struct tty_struct *tty)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001433{
Alan Cox95da3102008-07-22 11:09:07 +01001434 struct usb_serial_port *port = tty->driver_data;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001435 struct moschip_port *mos7840_port;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001436 int status;
1437
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001438 if (mos7840_port_paranoia_check(port, __func__))
Paul B Schroeder3f542972006-08-31 19:41:47 -05001439 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001440
1441 mos7840_port = mos7840_get_port_private(port);
1442
1443 if (mos7840_port == NULL)
1444 return;
1445
1446 if (!mos7840_port->open) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001447 dev_dbg(&port->dev, "%s", "port not opened\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001448 return;
1449 }
1450
Paul B Schroeder3f542972006-08-31 19:41:47 -05001451 /* if we are implementing XON/XOFF, send the stop character */
1452 if (I_IXOFF(tty)) {
1453 unsigned char stop_char = STOP_CHAR(tty);
Alan Cox95da3102008-07-22 11:09:07 +01001454 status = mos7840_write(tty, port, &stop_char, 1);
1455 if (status <= 0)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001456 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001457 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05001458 /* if we are implementing RTS/CTS, toggle that line */
Alan Coxadc8d742012-07-14 15:31:47 +01001459 if (tty->termios.c_cflag & CRTSCTS) {
Paul B Schroeder3f542972006-08-31 19:41:47 -05001460 mos7840_port->shadowMCR &= ~MCR_RTS;
Alan Cox95da3102008-07-22 11:09:07 +01001461 status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
Paul B Schroeder3f542972006-08-31 19:41:47 -05001462 mos7840_port->shadowMCR);
Alan Cox95da3102008-07-22 11:09:07 +01001463 if (status < 0)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001464 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001465 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05001466}
1467
1468/*****************************************************************************
1469 * mos7840_unthrottle
Alan Cox880af9d2008-07-22 11:16:12 +01001470 * this function is called by the tty driver when it wants to resume
1471 * the data being read from the port (called after mos7840_throttle is
1472 * called)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001473 *****************************************************************************/
Alan Cox95da3102008-07-22 11:09:07 +01001474static void mos7840_unthrottle(struct tty_struct *tty)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001475{
Alan Cox95da3102008-07-22 11:09:07 +01001476 struct usb_serial_port *port = tty->driver_data;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001477 int status;
1478 struct moschip_port *mos7840_port = mos7840_get_port_private(port);
1479
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001480 if (mos7840_port_paranoia_check(port, __func__))
Paul B Schroeder3f542972006-08-31 19:41:47 -05001481 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001482
1483 if (mos7840_port == NULL)
1484 return;
1485
1486 if (!mos7840_port->open) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001487 dev_dbg(&port->dev, "%s - port not opened\n", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001488 return;
1489 }
1490
Paul B Schroeder3f542972006-08-31 19:41:47 -05001491 /* if we are implementing XON/XOFF, send the start character */
1492 if (I_IXOFF(tty)) {
1493 unsigned char start_char = START_CHAR(tty);
Alan Cox95da3102008-07-22 11:09:07 +01001494 status = mos7840_write(tty, port, &start_char, 1);
1495 if (status <= 0)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001496 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001497 }
1498
1499 /* if we are implementing RTS/CTS, toggle that line */
Alan Coxadc8d742012-07-14 15:31:47 +01001500 if (tty->termios.c_cflag & CRTSCTS) {
Paul B Schroeder3f542972006-08-31 19:41:47 -05001501 mos7840_port->shadowMCR |= MCR_RTS;
Alan Cox95da3102008-07-22 11:09:07 +01001502 status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
Paul B Schroeder3f542972006-08-31 19:41:47 -05001503 mos7840_port->shadowMCR);
Alan Cox95da3102008-07-22 11:09:07 +01001504 if (status < 0)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001505 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001506 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05001507}
1508
Alan Cox60b33c12011-02-14 16:26:14 +00001509static int mos7840_tiocmget(struct tty_struct *tty)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001510{
Alan Cox95da3102008-07-22 11:09:07 +01001511 struct usb_serial_port *port = tty->driver_data;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001512 struct moschip_port *mos7840_port;
1513 unsigned int result;
1514 __u16 msr;
1515 __u16 mcr;
Alan Cox880af9d2008-07-22 11:16:12 +01001516 int status;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001517 mos7840_port = mos7840_get_port_private(port);
1518
Paul B Schroeder3f542972006-08-31 19:41:47 -05001519 if (mos7840_port == NULL)
1520 return -ENODEV;
1521
1522 status = mos7840_get_uart_reg(port, MODEM_STATUS_REGISTER, &msr);
1523 status = mos7840_get_uart_reg(port, MODEM_CONTROL_REGISTER, &mcr);
1524 result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0)
1525 | ((mcr & MCR_RTS) ? TIOCM_RTS : 0)
1526 | ((mcr & MCR_LOOPBACK) ? TIOCM_LOOP : 0)
1527 | ((msr & MOS7840_MSR_CTS) ? TIOCM_CTS : 0)
1528 | ((msr & MOS7840_MSR_CD) ? TIOCM_CAR : 0)
1529 | ((msr & MOS7840_MSR_RI) ? TIOCM_RI : 0)
1530 | ((msr & MOS7840_MSR_DSR) ? TIOCM_DSR : 0);
1531
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001532 dev_dbg(&port->dev, "%s - 0x%04X\n", __func__, result);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001533
1534 return result;
1535}
1536
Alan Cox20b9d172011-02-14 16:26:50 +00001537static int mos7840_tiocmset(struct tty_struct *tty,
Paul B Schroeder3f542972006-08-31 19:41:47 -05001538 unsigned int set, unsigned int clear)
1539{
Alan Cox95da3102008-07-22 11:09:07 +01001540 struct usb_serial_port *port = tty->driver_data;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001541 struct moschip_port *mos7840_port;
1542 unsigned int mcr;
Roel Kluin87521c42008-04-17 06:16:24 +02001543 int status;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001544
Paul B Schroeder3f542972006-08-31 19:41:47 -05001545 mos7840_port = mos7840_get_port_private(port);
1546
1547 if (mos7840_port == NULL)
1548 return -ENODEV;
1549
Alan Coxe2984492008-02-20 20:51:45 +00001550 /* FIXME: What locks the port registers ? */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001551 mcr = mos7840_port->shadowMCR;
1552 if (clear & TIOCM_RTS)
1553 mcr &= ~MCR_RTS;
1554 if (clear & TIOCM_DTR)
1555 mcr &= ~MCR_DTR;
1556 if (clear & TIOCM_LOOP)
1557 mcr &= ~MCR_LOOPBACK;
1558
1559 if (set & TIOCM_RTS)
1560 mcr |= MCR_RTS;
1561 if (set & TIOCM_DTR)
1562 mcr |= MCR_DTR;
1563 if (set & TIOCM_LOOP)
1564 mcr |= MCR_LOOPBACK;
1565
1566 mos7840_port->shadowMCR = mcr;
1567
Paul B Schroeder3f542972006-08-31 19:41:47 -05001568 status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr);
1569 if (status < 0) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001570 dev_dbg(&port->dev, "setting MODEM_CONTROL_REGISTER Failed\n");
Roel Kluin87521c42008-04-17 06:16:24 +02001571 return status;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001572 }
1573
1574 return 0;
1575}
1576
1577/*****************************************************************************
1578 * mos7840_calc_baud_rate_divisor
1579 * this function calculates the proper baud rate divisor for the specified
1580 * baud rate.
1581 *****************************************************************************/
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001582static int mos7840_calc_baud_rate_divisor(struct usb_serial_port *port,
1583 int baudRate, int *divisor,
Alan Cox880af9d2008-07-22 11:16:12 +01001584 __u16 *clk_sel_val)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001585{
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001586 dev_dbg(&port->dev, "%s - %d\n", __func__, baudRate);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001587
1588 if (baudRate <= 115200) {
1589 *divisor = 115200 / baudRate;
1590 *clk_sel_val = 0x0;
1591 }
1592 if ((baudRate > 115200) && (baudRate <= 230400)) {
1593 *divisor = 230400 / baudRate;
1594 *clk_sel_val = 0x10;
1595 } else if ((baudRate > 230400) && (baudRate <= 403200)) {
1596 *divisor = 403200 / baudRate;
1597 *clk_sel_val = 0x20;
1598 } else if ((baudRate > 403200) && (baudRate <= 460800)) {
1599 *divisor = 460800 / baudRate;
1600 *clk_sel_val = 0x30;
1601 } else if ((baudRate > 460800) && (baudRate <= 806400)) {
1602 *divisor = 806400 / baudRate;
1603 *clk_sel_val = 0x40;
1604 } else if ((baudRate > 806400) && (baudRate <= 921600)) {
1605 *divisor = 921600 / baudRate;
1606 *clk_sel_val = 0x50;
1607 } else if ((baudRate > 921600) && (baudRate <= 1572864)) {
1608 *divisor = 1572864 / baudRate;
1609 *clk_sel_val = 0x60;
1610 } else if ((baudRate > 1572864) && (baudRate <= 3145728)) {
1611 *divisor = 3145728 / baudRate;
1612 *clk_sel_val = 0x70;
1613 }
1614 return 0;
1615
1616#ifdef NOTMCS7840
1617
1618 for (i = 0; i < ARRAY_SIZE(mos7840_divisor_table); i++) {
1619 if (mos7840_divisor_table[i].BaudRate == baudrate) {
1620 *divisor = mos7840_divisor_table[i].Divisor;
1621 return 0;
1622 }
1623 }
1624
1625 /* After trying for all the standard baud rates *
1626 * Try calculating the divisor for this baud rate */
1627
1628 if (baudrate > 75 && baudrate < 230400) {
1629 /* get the divisor */
1630 custom = (__u16) (230400L / baudrate);
1631
1632 /* Check for round off */
1633 round1 = (__u16) (2304000L / baudrate);
1634 round = (__u16) (round1 - (custom * 10));
Alan Cox880af9d2008-07-22 11:16:12 +01001635 if (round > 4)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001636 custom++;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001637 *divisor = custom;
1638
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001639 dev_dbg(&port->dev, " Baud %d = %d\n", baudrate, custom);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001640 return 0;
1641 }
1642
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001643 dev_dbg(&port->dev, "%s", " Baud calculation Failed...\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001644 return -1;
1645#endif
1646}
1647
1648/*****************************************************************************
1649 * mos7840_send_cmd_write_baud_rate
1650 * this function sends the proper command to change the baud rate of the
1651 * specified port.
1652 *****************************************************************************/
1653
1654static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
1655 int baudRate)
1656{
1657 int divisor = 0;
1658 int status;
1659 __u16 Data;
1660 unsigned char number;
1661 __u16 clk_sel_val;
1662 struct usb_serial_port *port;
1663
1664 if (mos7840_port == NULL)
1665 return -1;
1666
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001667 port = mos7840_port->port;
1668 if (mos7840_port_paranoia_check(port, __func__))
Paul B Schroeder3f542972006-08-31 19:41:47 -05001669 return -1;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001670
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001671 if (mos7840_serial_paranoia_check(port->serial, __func__))
Paul B Schroeder3f542972006-08-31 19:41:47 -05001672 return -1;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001673
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001674 number = mos7840_port->port->port_number;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001675
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07001676 dev_dbg(&port->dev, "%s - baud = %d\n", __func__, baudRate);
Alan Cox880af9d2008-07-22 11:16:12 +01001677 /* reset clk_uart_sel in spregOffset */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001678 if (baudRate > 115200) {
1679#ifdef HW_flow_control
Alan Cox880af9d2008-07-22 11:16:12 +01001680 /* NOTE: need to see the pther register to modify */
1681 /* setting h/w flow control bit to 1 */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001682 Data = 0x2b;
1683 mos7840_port->shadowMCR = Data;
Alan Cox880af9d2008-07-22 11:16:12 +01001684 status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
1685 Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001686 if (status < 0) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001687 dev_dbg(&port->dev, "Writing spreg failed in set_serial_baud\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001688 return -1;
1689 }
1690#endif
1691
1692 } else {
1693#ifdef HW_flow_control
Donald Lee093ea2d2012-03-14 15:26:33 +08001694 /* setting h/w flow control bit to 0 */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001695 Data = 0xb;
1696 mos7840_port->shadowMCR = Data;
Alan Cox880af9d2008-07-22 11:16:12 +01001697 status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
1698 Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001699 if (status < 0) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001700 dev_dbg(&port->dev, "Writing spreg failed in set_serial_baud\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001701 return -1;
1702 }
1703#endif
1704
1705 }
1706
Alan Cox880af9d2008-07-22 11:16:12 +01001707 if (1) { /* baudRate <= 115200) */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001708 clk_sel_val = 0x0;
1709 Data = 0x0;
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001710 status = mos7840_calc_baud_rate_divisor(port, baudRate, &divisor,
Paul B Schroeder3f542972006-08-31 19:41:47 -05001711 &clk_sel_val);
Alan Cox880af9d2008-07-22 11:16:12 +01001712 status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset,
1713 &Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001714 if (status < 0) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001715 dev_dbg(&port->dev, "reading spreg failed in set_serial_baud\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001716 return -1;
1717 }
1718 Data = (Data & 0x8f) | clk_sel_val;
Alan Cox880af9d2008-07-22 11:16:12 +01001719 status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset,
1720 Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001721 if (status < 0) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001722 dev_dbg(&port->dev, "Writing spreg failed in set_serial_baud\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001723 return -1;
1724 }
1725 /* Calculate the Divisor */
1726
1727 if (status) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001728 dev_err(&port->dev, "%s - bad baud rate\n", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001729 return status;
1730 }
1731 /* Enable access to divisor latch */
1732 Data = mos7840_port->shadowLCR | SERIAL_LCR_DLAB;
1733 mos7840_port->shadowLCR = Data;
1734 mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
1735
1736 /* Write the divisor */
1737 Data = (unsigned char)(divisor & 0xff);
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001738 dev_dbg(&port->dev, "set_serial_baud Value to write DLL is %x\n", Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001739 mos7840_set_uart_reg(port, DIVISOR_LATCH_LSB, Data);
1740
1741 Data = (unsigned char)((divisor & 0xff00) >> 8);
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001742 dev_dbg(&port->dev, "set_serial_baud Value to write DLM is %x\n", Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001743 mos7840_set_uart_reg(port, DIVISOR_LATCH_MSB, Data);
1744
1745 /* Disable access to divisor latch */
1746 Data = mos7840_port->shadowLCR & ~SERIAL_LCR_DLAB;
1747 mos7840_port->shadowLCR = Data;
1748 mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
1749
1750 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05001751 return status;
1752}
1753
1754/*****************************************************************************
1755 * mos7840_change_port_settings
1756 * This routine is called to set the UART on the device to match
1757 * the specified new settings.
1758 *****************************************************************************/
1759
Alan Cox95da3102008-07-22 11:09:07 +01001760static void mos7840_change_port_settings(struct tty_struct *tty,
1761 struct moschip_port *mos7840_port, struct ktermios *old_termios)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001762{
Paul B Schroeder3f542972006-08-31 19:41:47 -05001763 int baud;
1764 unsigned cflag;
1765 unsigned iflag;
1766 __u8 lData;
1767 __u8 lParity;
1768 __u8 lStop;
1769 int status;
1770 __u16 Data;
1771 struct usb_serial_port *port;
1772 struct usb_serial *serial;
1773
1774 if (mos7840_port == NULL)
1775 return;
1776
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001777 port = mos7840_port->port;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001778
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001779 if (mos7840_port_paranoia_check(port, __func__))
Paul B Schroeder3f542972006-08-31 19:41:47 -05001780 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001781
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001782 if (mos7840_serial_paranoia_check(port->serial, __func__))
Paul B Schroeder3f542972006-08-31 19:41:47 -05001783 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001784
1785 serial = port->serial;
1786
Paul B Schroeder3f542972006-08-31 19:41:47 -05001787 if (!mos7840_port->open) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001788 dev_dbg(&port->dev, "%s - port not opened\n", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001789 return;
1790 }
1791
Paul B Schroeder3f542972006-08-31 19:41:47 -05001792 lData = LCR_BITS_8;
1793 lStop = LCR_STOP_1;
1794 lParity = LCR_PAR_NONE;
1795
Alan Coxadc8d742012-07-14 15:31:47 +01001796 cflag = tty->termios.c_cflag;
1797 iflag = tty->termios.c_iflag;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001798
1799 /* Change the number of bits */
1800 if (cflag & CSIZE) {
1801 switch (cflag & CSIZE) {
1802 case CS5:
1803 lData = LCR_BITS_5;
1804 break;
1805
1806 case CS6:
1807 lData = LCR_BITS_6;
1808 break;
1809
1810 case CS7:
1811 lData = LCR_BITS_7;
1812 break;
1813 default:
1814 case CS8:
1815 lData = LCR_BITS_8;
1816 break;
1817 }
1818 }
1819 /* Change the Parity bit */
1820 if (cflag & PARENB) {
1821 if (cflag & PARODD) {
1822 lParity = LCR_PAR_ODD;
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001823 dev_dbg(&port->dev, "%s - parity = odd\n", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001824 } else {
1825 lParity = LCR_PAR_EVEN;
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001826 dev_dbg(&port->dev, "%s - parity = even\n", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001827 }
1828
1829 } else {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001830 dev_dbg(&port->dev, "%s - parity = none\n", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001831 }
1832
Alan Cox880af9d2008-07-22 11:16:12 +01001833 if (cflag & CMSPAR)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001834 lParity = lParity | 0x20;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001835
1836 /* Change the Stop bit */
1837 if (cflag & CSTOPB) {
1838 lStop = LCR_STOP_2;
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001839 dev_dbg(&port->dev, "%s - stop bits = 2\n", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001840 } else {
1841 lStop = LCR_STOP_1;
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001842 dev_dbg(&port->dev, "%s - stop bits = 1\n", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001843 }
1844
1845 /* Update the LCR with the correct value */
1846 mos7840_port->shadowLCR &=
1847 ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
1848 mos7840_port->shadowLCR |= (lData | lParity | lStop);
1849
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001850 dev_dbg(&port->dev, "%s - mos7840_port->shadowLCR is %x\n", __func__,
1851 mos7840_port->shadowLCR);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001852 /* Disable Interrupts */
1853 Data = 0x00;
1854 mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
1855
1856 Data = 0x00;
1857 mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
1858
1859 Data = 0xcf;
1860 mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
1861
1862 /* Send the updated LCR value to the mos7840 */
1863 Data = mos7840_port->shadowLCR;
1864
1865 mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
1866
1867 Data = 0x00b;
1868 mos7840_port->shadowMCR = Data;
1869 mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
1870 Data = 0x00b;
1871 mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
1872
1873 /* set up the MCR register and send it to the mos7840 */
1874
1875 mos7840_port->shadowMCR = MCR_MASTER_IE;
Alan Cox880af9d2008-07-22 11:16:12 +01001876 if (cflag & CBAUD)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001877 mos7840_port->shadowMCR |= (MCR_DTR | MCR_RTS);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001878
Alan Cox880af9d2008-07-22 11:16:12 +01001879 if (cflag & CRTSCTS)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001880 mos7840_port->shadowMCR |= (MCR_XON_ANY);
Alan Cox880af9d2008-07-22 11:16:12 +01001881 else
Paul B Schroeder3f542972006-08-31 19:41:47 -05001882 mos7840_port->shadowMCR &= ~(MCR_XON_ANY);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001883
1884 Data = mos7840_port->shadowMCR;
1885 mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
1886
1887 /* Determine divisor based on baud rate */
1888 baud = tty_get_baud_rate(tty);
1889
1890 if (!baud) {
1891 /* pick a default, any default... */
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001892 dev_dbg(&port->dev, "%s", "Picked default baud...\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001893 baud = 9600;
1894 }
1895
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001896 dev_dbg(&port->dev, "%s - baud rate = %d\n", __func__, baud);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001897 status = mos7840_send_cmd_write_baud_rate(mos7840_port, baud);
1898
1899 /* Enable Interrupts */
1900 Data = 0x0c;
1901 mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
1902
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -08001903 if (mos7840_port->read_urb_busy == false) {
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -08001904 mos7840_port->read_urb_busy = true;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001905 status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001906 if (status) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001907 dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n",
Paul B Schroeder3f542972006-08-31 19:41:47 -05001908 status);
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -08001909 mos7840_port->read_urb_busy = false;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001910 }
1911 }
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001912 dev_dbg(&port->dev, "%s - mos7840_port->shadowLCR is End %x\n", __func__,
1913 mos7840_port->shadowLCR);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001914}
1915
1916/*****************************************************************************
1917 * mos7840_set_termios
1918 * this function is called by the tty driver when it wants to change
1919 * the termios structure
1920 *****************************************************************************/
1921
Alan Cox95da3102008-07-22 11:09:07 +01001922static void mos7840_set_termios(struct tty_struct *tty,
1923 struct usb_serial_port *port,
Alan Cox606d0992006-12-08 02:38:45 -08001924 struct ktermios *old_termios)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001925{
1926 int status;
1927 unsigned int cflag;
1928 struct usb_serial *serial;
1929 struct moschip_port *mos7840_port;
Greg Kroah-Hartman33631552012-05-03 16:44:33 -07001930
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001931 if (mos7840_port_paranoia_check(port, __func__))
Paul B Schroeder3f542972006-08-31 19:41:47 -05001932 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001933
1934 serial = port->serial;
1935
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001936 if (mos7840_serial_paranoia_check(serial, __func__))
Paul B Schroeder3f542972006-08-31 19:41:47 -05001937 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001938
1939 mos7840_port = mos7840_get_port_private(port);
1940
1941 if (mos7840_port == NULL)
1942 return;
1943
Paul B Schroeder3f542972006-08-31 19:41:47 -05001944 if (!mos7840_port->open) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001945 dev_dbg(&port->dev, "%s - port not opened\n", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001946 return;
1947 }
1948
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001949 dev_dbg(&port->dev, "%s", "setting termios - \n");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001950
Alan Coxadc8d742012-07-14 15:31:47 +01001951 cflag = tty->termios.c_cflag;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001952
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001953 dev_dbg(&port->dev, "%s - clfag %08x iflag %08x\n", __func__,
Linus Torvaldsd9a80742012-10-01 13:23:01 -07001954 tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag));
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001955 dev_dbg(&port->dev, "%s - old clfag %08x old iflag %08x\n", __func__,
1956 old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
Paul B Schroeder3f542972006-08-31 19:41:47 -05001957
1958 /* change the port settings to the new ones specified */
1959
Alan Cox95da3102008-07-22 11:09:07 +01001960 mos7840_change_port_settings(tty, mos7840_port, old_termios);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001961
1962 if (!mos7840_port->read_urb) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001963 dev_dbg(&port->dev, "%s", "URB KILLED !!!!!\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001964 return;
1965 }
1966
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -08001967 if (mos7840_port->read_urb_busy == false) {
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -08001968 mos7840_port->read_urb_busy = true;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001969 status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
1970 if (status) {
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001971 dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n",
Paul B Schroeder3f542972006-08-31 19:41:47 -05001972 status);
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -08001973 mos7840_port->read_urb_busy = false;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001974 }
1975 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05001976}
1977
1978/*****************************************************************************
1979 * mos7840_get_lsr_info - get line status register info
1980 *
1981 * Purpose: Let user call ioctl() to get info when the UART physically
1982 * is emptied. On bus types like RS485, the transmitter must
1983 * release the bus after transmitting. This must be done when
1984 * the transmit shift register is empty, not be done when the
1985 * transmit holding register is empty. This functionality
1986 * allows an RS485 driver to be written in user space.
1987 *****************************************************************************/
1988
Alan Cox95da3102008-07-22 11:09:07 +01001989static int mos7840_get_lsr_info(struct tty_struct *tty,
Al Viro97c49652006-10-09 20:29:03 +01001990 unsigned int __user *value)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001991{
1992 int count;
1993 unsigned int result = 0;
1994
Alan Cox95da3102008-07-22 11:09:07 +01001995 count = mos7840_chars_in_buffer(tty);
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07001996 if (count == 0)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001997 result = TIOCSER_TEMT;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001998
1999 if (copy_to_user(value, &result, sizeof(int)))
2000 return -EFAULT;
2001 return 0;
2002}
2003
2004/*****************************************************************************
Paul B Schroeder3f542972006-08-31 19:41:47 -05002005 * mos7840_get_serial_info
2006 * function to get information about serial port
2007 *****************************************************************************/
2008
2009static int mos7840_get_serial_info(struct moschip_port *mos7840_port,
Al Viro97c49652006-10-09 20:29:03 +01002010 struct serial_struct __user *retinfo)
Paul B Schroeder3f542972006-08-31 19:41:47 -05002011{
2012 struct serial_struct tmp;
2013
2014 if (mos7840_port == NULL)
2015 return -1;
2016
2017 if (!retinfo)
2018 return -EFAULT;
2019
2020 memset(&tmp, 0, sizeof(tmp));
2021
2022 tmp.type = PORT_16550A;
Greg Kroah-Hartmane5b1e202013-06-07 11:04:28 -07002023 tmp.line = mos7840_port->port->minor;
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07002024 tmp.port = mos7840_port->port->port_number;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002025 tmp.irq = 0;
2026 tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
2027 tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
2028 tmp.baud_base = 9600;
2029 tmp.close_delay = 5 * HZ;
2030 tmp.closing_wait = 30 * HZ;
2031
2032 if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
2033 return -EFAULT;
2034 return 0;
2035}
2036
2037/*****************************************************************************
2038 * SerialIoctl
2039 * this function handles any ioctl calls to the driver
2040 *****************************************************************************/
2041
Alan Cox00a0d0d2011-02-14 16:27:06 +00002042static int mos7840_ioctl(struct tty_struct *tty,
Paul B Schroeder3f542972006-08-31 19:41:47 -05002043 unsigned int cmd, unsigned long arg)
2044{
Alan Cox95da3102008-07-22 11:09:07 +01002045 struct usb_serial_port *port = tty->driver_data;
Al Viro97c49652006-10-09 20:29:03 +01002046 void __user *argp = (void __user *)arg;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002047 struct moschip_port *mos7840_port;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002048
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07002049 if (mos7840_port_paranoia_check(port, __func__))
Paul B Schroeder3f542972006-08-31 19:41:47 -05002050 return -1;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002051
2052 mos7840_port = mos7840_get_port_private(port);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002053
2054 if (mos7840_port == NULL)
2055 return -1;
2056
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07002057 dev_dbg(&port->dev, "%s - cmd = 0x%x\n", __func__, cmd);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002058
2059 switch (cmd) {
2060 /* return number of bytes available */
2061
Paul B Schroeder3f542972006-08-31 19:41:47 -05002062 case TIOCSERGETLSR:
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07002063 dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__);
Alan Cox95da3102008-07-22 11:09:07 +01002064 return mos7840_get_lsr_info(tty, argp);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002065
Paul B Schroeder3f542972006-08-31 19:41:47 -05002066 case TIOCGSERIAL:
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07002067 dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__);
Al Viro97c49652006-10-09 20:29:03 +01002068 return mos7840_get_serial_info(mos7840_port, argp);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002069
2070 case TIOCSSERIAL:
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07002071 dev_dbg(&port->dev, "%s TIOCSSERIAL\n", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002072 break;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002073 default:
2074 break;
2075 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05002076 return -ENOIOCTLCMD;
2077}
2078
Donald0eafe4d2012-04-19 15:00:45 +08002079static int mos7810_check(struct usb_serial *serial)
2080{
2081 int i, pass_count = 0;
Johan Hovold15ee89c332013-05-27 14:44:40 +02002082 u8 *buf;
Donald0eafe4d2012-04-19 15:00:45 +08002083 __u16 data = 0, mcr_data = 0;
2084 __u16 test_pattern = 0x55AA;
Johan Hovold15ee89c332013-05-27 14:44:40 +02002085 int res;
2086
2087 buf = kmalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
2088 if (!buf)
2089 return 0; /* failed to identify 7810 */
Donald0eafe4d2012-04-19 15:00:45 +08002090
2091 /* Store MCR setting */
Johan Hovold15ee89c332013-05-27 14:44:40 +02002092 res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
Donald0eafe4d2012-04-19 15:00:45 +08002093 MCS_RDREQ, MCS_RD_RTYPE, 0x0300, MODEM_CONTROL_REGISTER,
Johan Hovold15ee89c332013-05-27 14:44:40 +02002094 buf, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
2095 if (res == VENDOR_READ_LENGTH)
2096 mcr_data = *buf;
Donald0eafe4d2012-04-19 15:00:45 +08002097
2098 for (i = 0; i < 16; i++) {
2099 /* Send the 1-bit test pattern out to MCS7810 test pin */
2100 usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
2101 MCS_WRREQ, MCS_WR_RTYPE,
2102 (0x0300 | (((test_pattern >> i) & 0x0001) << 1)),
2103 MODEM_CONTROL_REGISTER, NULL, 0, MOS_WDR_TIMEOUT);
2104
2105 /* Read the test pattern back */
Johan Hovold15ee89c332013-05-27 14:44:40 +02002106 res = usb_control_msg(serial->dev,
2107 usb_rcvctrlpipe(serial->dev, 0), MCS_RDREQ,
2108 MCS_RD_RTYPE, 0, GPIO_REGISTER, buf,
2109 VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
2110 if (res == VENDOR_READ_LENGTH)
2111 data = *buf;
Donald0eafe4d2012-04-19 15:00:45 +08002112
2113 /* If this is a MCS7810 device, both test patterns must match */
2114 if (((test_pattern >> i) ^ (~data >> 1)) & 0x0001)
2115 break;
2116
2117 pass_count++;
2118 }
2119
2120 /* Restore MCR setting */
2121 usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), MCS_WRREQ,
2122 MCS_WR_RTYPE, 0x0300 | mcr_data, MODEM_CONTROL_REGISTER, NULL,
2123 0, MOS_WDR_TIMEOUT);
2124
Johan Hovold15ee89c332013-05-27 14:44:40 +02002125 kfree(buf);
2126
Donald0eafe4d2012-04-19 15:00:45 +08002127 if (pass_count == 16)
2128 return 1;
2129
2130 return 0;
2131}
2132
Paul B Schroeder3f542972006-08-31 19:41:47 -05002133static int mos7840_calc_num_ports(struct usb_serial *serial)
2134{
Donald0eafe4d2012-04-19 15:00:45 +08002135 __u16 data = 0x00;
Johan Hovold15ee89c332013-05-27 14:44:40 +02002136 u8 *buf;
Donald Lee093ea2d2012-03-14 15:26:33 +08002137 int mos7840_num_ports;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002138
Johan Hovold15ee89c332013-05-27 14:44:40 +02002139 buf = kzalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
2140 if (buf) {
2141 usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
2142 MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, buf,
2143 VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
2144 data = *buf;
2145 kfree(buf);
2146 }
Donald Lee093ea2d2012-03-14 15:26:33 +08002147
Donald0eafe4d2012-04-19 15:00:45 +08002148 if (serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7810 ||
2149 serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7820) {
2150 device_type = serial->dev->descriptor.idProduct;
Donald Lee093ea2d2012-03-14 15:26:33 +08002151 } else {
Donald0eafe4d2012-04-19 15:00:45 +08002152 /* For a MCS7840 device GPIO0 must be set to 1 */
2153 if ((data & 0x01) == 1)
2154 device_type = MOSCHIP_DEVICE_ID_7840;
2155 else if (mos7810_check(serial))
2156 device_type = MOSCHIP_DEVICE_ID_7810;
2157 else
2158 device_type = MOSCHIP_DEVICE_ID_7820;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002159 }
Donald Lee093ea2d2012-03-14 15:26:33 +08002160
Donald0eafe4d2012-04-19 15:00:45 +08002161 mos7840_num_ports = (device_type >> 4) & 0x000F;
2162 serial->num_bulk_in = mos7840_num_ports;
2163 serial->num_bulk_out = mos7840_num_ports;
2164 serial->num_ports = mos7840_num_ports;
2165
Paul B Schroeder3f542972006-08-31 19:41:47 -05002166 return mos7840_num_ports;
2167}
2168
Johan Hovold80c00752012-10-25 18:56:34 +02002169static int mos7840_port_probe(struct usb_serial_port *port)
Paul B Schroeder3f542972006-08-31 19:41:47 -05002170{
Johan Hovold80c00752012-10-25 18:56:34 +02002171 struct usb_serial *serial = port->serial;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002172 struct moschip_port *mos7840_port;
Johan Hovold80c00752012-10-25 18:56:34 +02002173 int status;
2174 int pnum;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002175 __u16 Data;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002176
Paul B Schroeder3f542972006-08-31 19:41:47 -05002177 /* we set up the pointers to the endpoints in the mos7840_open *
2178 * function, as the structures aren't created yet. */
2179
Greg Kroah-Hartman11438322013-06-06 10:32:00 -07002180 pnum = port->port_number;
Johan Hovold80c00752012-10-25 18:56:34 +02002181
Johan Hovoldae685ef2012-10-25 18:56:35 +02002182 dev_dbg(&port->dev, "mos7840_startup: configuring port %d\n", pnum);
2183 mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
2184 if (mos7840_port == NULL) {
2185 dev_err(&port->dev, "%s - Out of memory\n", __func__);
2186 return -ENOMEM;
2187 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05002188
Johan Hovoldae685ef2012-10-25 18:56:35 +02002189 /* Initialize all port interrupt end point to port 0 int
2190 * endpoint. Our device has only one interrupt end point
2191 * common to all port */
Paul B Schroeder3f542972006-08-31 19:41:47 -05002192
Johan Hovoldae685ef2012-10-25 18:56:35 +02002193 mos7840_port->port = port;
2194 mos7840_set_port_private(port, mos7840_port);
2195 spin_lock_init(&mos7840_port->pool_lock);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002196
Johan Hovoldae685ef2012-10-25 18:56:35 +02002197 /* minor is not initialised until later by
2198 * usb-serial.c:get_free_serial() and cannot therefore be used
2199 * to index device instances */
2200 mos7840_port->port_num = pnum + 1;
Greg Kroah-Hartmane5b1e202013-06-07 11:04:28 -07002201 dev_dbg(&port->dev, "port->minor = %d\n", port->minor);
Johan Hovoldae685ef2012-10-25 18:56:35 +02002202 dev_dbg(&port->dev, "mos7840_port->port_num = %d\n", mos7840_port->port_num);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002203
Johan Hovoldae685ef2012-10-25 18:56:35 +02002204 if (mos7840_port->port_num == 1) {
2205 mos7840_port->SpRegOffset = 0x0;
2206 mos7840_port->ControlRegOffset = 0x1;
2207 mos7840_port->DcrRegOffset = 0x4;
2208 } else if ((mos7840_port->port_num == 2) && (serial->num_ports == 4)) {
2209 mos7840_port->SpRegOffset = 0x8;
2210 mos7840_port->ControlRegOffset = 0x9;
2211 mos7840_port->DcrRegOffset = 0x16;
2212 } else if ((mos7840_port->port_num == 2) && (serial->num_ports == 2)) {
2213 mos7840_port->SpRegOffset = 0xa;
2214 mos7840_port->ControlRegOffset = 0xb;
2215 mos7840_port->DcrRegOffset = 0x19;
2216 } else if ((mos7840_port->port_num == 3) && (serial->num_ports == 4)) {
2217 mos7840_port->SpRegOffset = 0xa;
2218 mos7840_port->ControlRegOffset = 0xb;
2219 mos7840_port->DcrRegOffset = 0x19;
2220 } else if ((mos7840_port->port_num == 4) && (serial->num_ports == 4)) {
2221 mos7840_port->SpRegOffset = 0xc;
2222 mos7840_port->ControlRegOffset = 0xd;
2223 mos7840_port->DcrRegOffset = 0x1c;
2224 }
2225 mos7840_dump_serial_port(port, mos7840_port);
2226 mos7840_set_port_private(port, mos7840_port);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002227
Johan Hovoldae685ef2012-10-25 18:56:35 +02002228 /* enable rx_disable bit in control register */
2229 status = mos7840_get_reg_sync(port,
2230 mos7840_port->ControlRegOffset, &Data);
2231 if (status < 0) {
2232 dev_dbg(&port->dev, "Reading ControlReg failed status-0x%x\n", status);
2233 goto out;
2234 } else
2235 dev_dbg(&port->dev, "ControlReg Reading success val is %x, status%d\n", Data, status);
2236 Data |= 0x08; /* setting driver done bit */
2237 Data |= 0x04; /* sp1_bit to have cts change reflect in
2238 modem status reg */
Paul B Schroeder3f542972006-08-31 19:41:47 -05002239
Johan Hovoldae685ef2012-10-25 18:56:35 +02002240 /* Data |= 0x20; //rx_disable bit */
2241 status = mos7840_set_reg_sync(port,
2242 mos7840_port->ControlRegOffset, Data);
2243 if (status < 0) {
2244 dev_dbg(&port->dev, "Writing ControlReg failed(rx_disable) status-0x%x\n", status);
2245 goto out;
2246 } else
2247 dev_dbg(&port->dev, "ControlReg Writing success(rx_disable) status%d\n", status);
2248
2249 /* Write default values in DCR (i.e 0x01 in DCR0, 0x05 in DCR2
2250 and 0x24 in DCR3 */
2251 Data = 0x01;
2252 status = mos7840_set_reg_sync(port,
2253 (__u16) (mos7840_port->DcrRegOffset + 0), Data);
2254 if (status < 0) {
2255 dev_dbg(&port->dev, "Writing DCR0 failed status-0x%x\n", status);
2256 goto out;
2257 } else
2258 dev_dbg(&port->dev, "DCR0 Writing success status%d\n", status);
2259
2260 Data = 0x05;
2261 status = mos7840_set_reg_sync(port,
2262 (__u16) (mos7840_port->DcrRegOffset + 1), Data);
2263 if (status < 0) {
2264 dev_dbg(&port->dev, "Writing DCR1 failed status-0x%x\n", status);
2265 goto out;
2266 } else
2267 dev_dbg(&port->dev, "DCR1 Writing success status%d\n", status);
2268
2269 Data = 0x24;
2270 status = mos7840_set_reg_sync(port,
2271 (__u16) (mos7840_port->DcrRegOffset + 2), Data);
2272 if (status < 0) {
2273 dev_dbg(&port->dev, "Writing DCR2 failed status-0x%x\n", status);
2274 goto out;
2275 } else
2276 dev_dbg(&port->dev, "DCR2 Writing success status%d\n", status);
2277
2278 /* write values in clkstart0x0 and clkmulti 0x20 */
2279 Data = 0x0;
2280 status = mos7840_set_reg_sync(port, CLK_START_VALUE_REGISTER, Data);
2281 if (status < 0) {
2282 dev_dbg(&port->dev, "Writing CLK_START_VALUE_REGISTER failed status-0x%x\n", status);
2283 goto out;
2284 } else
2285 dev_dbg(&port->dev, "CLK_START_VALUE_REGISTER Writing success status%d\n", status);
2286
2287 Data = 0x20;
2288 status = mos7840_set_reg_sync(port, CLK_MULTI_REGISTER, Data);
2289 if (status < 0) {
2290 dev_dbg(&port->dev, "Writing CLK_MULTI_REGISTER failed status-0x%x\n", status);
2291 goto error;
2292 } else
2293 dev_dbg(&port->dev, "CLK_MULTI_REGISTER Writing success status%d\n", status);
2294
2295 /* write value 0x0 to scratchpad register */
2296 Data = 0x00;
2297 status = mos7840_set_uart_reg(port, SCRATCH_PAD_REGISTER, Data);
2298 if (status < 0) {
2299 dev_dbg(&port->dev, "Writing SCRATCH_PAD_REGISTER failed status-0x%x\n", status);
2300 goto out;
2301 } else
2302 dev_dbg(&port->dev, "SCRATCH_PAD_REGISTER Writing success status%d\n", status);
2303
2304 /* Zero Length flag register */
2305 if ((mos7840_port->port_num != 1) && (serial->num_ports == 2)) {
2306 Data = 0xff;
Johan Hovold80c00752012-10-25 18:56:34 +02002307 status = mos7840_set_reg_sync(port,
Johan Hovoldae685ef2012-10-25 18:56:35 +02002308 (__u16) (ZLP_REG1 +
2309 ((__u16)mos7840_port->port_num)), Data);
2310 dev_dbg(&port->dev, "ZLIP offset %x\n",
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07002311 (__u16)(ZLP_REG1 + ((__u16) mos7840_port->port_num)));
Johan Hovoldae685ef2012-10-25 18:56:35 +02002312 if (status < 0) {
2313 dev_dbg(&port->dev, "Writing ZLP_REG%d failed status-0x%x\n", pnum + 2, status);
2314 goto out;
2315 } else
2316 dev_dbg(&port->dev, "ZLP_REG%d Writing success status%d\n", pnum + 2, status);
2317 } else {
2318 Data = 0xff;
2319 status = mos7840_set_reg_sync(port,
2320 (__u16) (ZLP_REG1 +
2321 ((__u16)mos7840_port->port_num) - 0x1), Data);
2322 dev_dbg(&port->dev, "ZLIP offset %x\n",
Greg Kroah-Hartman9c134a12012-09-14 16:06:04 -07002323 (__u16)(ZLP_REG1 + ((__u16) mos7840_port->port_num) - 0x1));
Johan Hovoldae685ef2012-10-25 18:56:35 +02002324 if (status < 0) {
2325 dev_dbg(&port->dev, "Writing ZLP_REG%d failed status-0x%x\n", pnum + 1, status);
2326 goto out;
2327 } else
2328 dev_dbg(&port->dev, "ZLP_REG%d Writing success status%d\n", pnum + 1, status);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002329
Johan Hovoldae685ef2012-10-25 18:56:35 +02002330 }
2331 mos7840_port->control_urb = usb_alloc_urb(0, GFP_KERNEL);
2332 mos7840_port->ctrl_buf = kmalloc(16, GFP_KERNEL);
2333 mos7840_port->dr = kmalloc(sizeof(struct usb_ctrlrequest),
2334 GFP_KERNEL);
2335 if (!mos7840_port->control_urb || !mos7840_port->ctrl_buf ||
2336 !mos7840_port->dr) {
2337 status = -ENOMEM;
2338 goto error;
2339 }
Donald0eafe4d2012-04-19 15:00:45 +08002340
Johan Hovoldae685ef2012-10-25 18:56:35 +02002341 mos7840_port->has_led = false;
Donald0eafe4d2012-04-19 15:00:45 +08002342
Johan Hovoldae685ef2012-10-25 18:56:35 +02002343 /* Initialize LED timers */
2344 if (device_type == MOSCHIP_DEVICE_ID_7810) {
2345 mos7840_port->has_led = true;
Donald0eafe4d2012-04-19 15:00:45 +08002346
Johan Hovoldae685ef2012-10-25 18:56:35 +02002347 init_timer(&mos7840_port->led_timer1);
2348 mos7840_port->led_timer1.function = mos7840_led_off;
2349 mos7840_port->led_timer1.expires =
2350 jiffies + msecs_to_jiffies(LED_ON_MS);
2351 mos7840_port->led_timer1.data = (unsigned long)mos7840_port;
Donald0eafe4d2012-04-19 15:00:45 +08002352
Johan Hovoldae685ef2012-10-25 18:56:35 +02002353 init_timer(&mos7840_port->led_timer2);
2354 mos7840_port->led_timer2.function = mos7840_led_flag_off;
2355 mos7840_port->led_timer2.expires =
2356 jiffies + msecs_to_jiffies(LED_OFF_MS);
2357 mos7840_port->led_timer2.data = (unsigned long)mos7840_port;
Donald0eafe4d2012-04-19 15:00:45 +08002358
Johan Hovoldae685ef2012-10-25 18:56:35 +02002359 mos7840_port->led_flag = false;
Donald0eafe4d2012-04-19 15:00:45 +08002360
Johan Hovoldae685ef2012-10-25 18:56:35 +02002361 /* Turn off LED */
2362 mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0300);
2363 }
2364out:
Johan Hovold80c00752012-10-25 18:56:34 +02002365 if (pnum == serial->num_ports - 1) {
2366 /* Zero Length flag enable */
2367 Data = 0x0f;
2368 status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data);
2369 if (status < 0) {
2370 dev_dbg(&port->dev, "Writing ZLP_REG5 failed status-0x%x\n", status);
2371 goto error;
2372 } else
2373 dev_dbg(&port->dev, "ZLP_REG5 Writing success status%d\n", status);
2374
2375 /* setting configuration feature to one */
2376 usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
2377 0x03, 0x00, 0x01, 0x00, NULL, 0x00,
2378 MOS_WDR_TIMEOUT);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002379 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05002380 return 0;
Oliver Neukum0de9a702007-03-16 20:28:28 +01002381error:
Johan Hovold80c00752012-10-25 18:56:34 +02002382 kfree(mos7840_port->dr);
2383 kfree(mos7840_port->ctrl_buf);
2384 usb_free_urb(mos7840_port->control_urb);
2385 kfree(mos7840_port);
Oliver Neukum0de9a702007-03-16 20:28:28 +01002386
Oliver Neukum0de9a702007-03-16 20:28:28 +01002387 return status;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002388}
2389
Johan Hovold80c00752012-10-25 18:56:34 +02002390static int mos7840_port_remove(struct usb_serial_port *port)
Paul B Schroeder3f542972006-08-31 19:41:47 -05002391{
Paul B Schroeder3f542972006-08-31 19:41:47 -05002392 struct moschip_port *mos7840_port;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002393
Johan Hovold80c00752012-10-25 18:56:34 +02002394 mos7840_port = mos7840_get_port_private(port);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002395
Johan Hovold80c00752012-10-25 18:56:34 +02002396 if (mos7840_port->has_led) {
2397 /* Turn off LED */
2398 mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0300);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002399
Johan Hovold80c00752012-10-25 18:56:34 +02002400 del_timer_sync(&mos7840_port->led_timer1);
2401 del_timer_sync(&mos7840_port->led_timer2);
Alan Sternf9c99bb2009-06-02 11:53:55 -04002402 }
Johan Hovold80c00752012-10-25 18:56:34 +02002403 usb_kill_urb(mos7840_port->control_urb);
2404 usb_free_urb(mos7840_port->control_urb);
2405 kfree(mos7840_port->ctrl_buf);
2406 kfree(mos7840_port->dr);
2407 kfree(mos7840_port);
Alan Sternf9c99bb2009-06-02 11:53:55 -04002408
Johan Hovold80c00752012-10-25 18:56:34 +02002409 return 0;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002410}
2411
2412static struct usb_serial_driver moschip7840_4port_device = {
2413 .driver = {
2414 .owner = THIS_MODULE,
2415 .name = "mos7840",
2416 },
2417 .description = DRIVER_DESC,
Greg Kroah-Hartman68e24112012-05-08 15:46:14 -07002418 .id_table = id_table,
Paul B Schroeder3f542972006-08-31 19:41:47 -05002419 .num_ports = 4,
Paul B Schroeder3f542972006-08-31 19:41:47 -05002420 .open = mos7840_open,
2421 .close = mos7840_close,
2422 .write = mos7840_write,
2423 .write_room = mos7840_write_room,
2424 .chars_in_buffer = mos7840_chars_in_buffer,
2425 .throttle = mos7840_throttle,
2426 .unthrottle = mos7840_unthrottle,
2427 .calc_num_ports = mos7840_calc_num_ports,
2428#ifdef MCSSerialProbe
2429 .probe = mos7840_serial_probe,
2430#endif
2431 .ioctl = mos7840_ioctl,
2432 .set_termios = mos7840_set_termios,
2433 .break_ctl = mos7840_break,
2434 .tiocmget = mos7840_tiocmget,
2435 .tiocmset = mos7840_tiocmset,
Johan Hovold0c613372013-03-21 12:37:17 +01002436 .tiocmiwait = usb_serial_generic_tiocmiwait,
Johan Hovold8c1a07f2013-03-21 12:37:16 +01002437 .get_icount = usb_serial_generic_get_icount,
Johan Hovold80c00752012-10-25 18:56:34 +02002438 .port_probe = mos7840_port_probe,
2439 .port_remove = mos7840_port_remove,
Paul B Schroeder3f542972006-08-31 19:41:47 -05002440 .read_bulk_callback = mos7840_bulk_in_callback,
2441 .read_int_callback = mos7840_interrupt_callback,
2442};
2443
Alan Stern4d2a7af2012-02-23 14:57:09 -05002444static struct usb_serial_driver * const serial_drivers[] = {
2445 &moschip7840_4port_device, NULL
2446};
2447
Greg Kroah-Hartman68e24112012-05-08 15:46:14 -07002448module_usb_serial_driver(serial_drivers, id_table);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002449
Paul B Schroeder3f542972006-08-31 19:41:47 -05002450MODULE_DESCRIPTION(DRIVER_DESC);
2451MODULE_LICENSE("GPL");