blob: 4072caf37d426a2f5d3110da596ea45a5aa2a038 [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
38/*
39 * Version Information
40 */
Tony Cook37768ad2009-04-18 22:42:18 +093041#define DRIVER_VERSION "1.3.2"
Paul B Schroeder3f542972006-08-31 19:41:47 -050042#define DRIVER_DESC "Moschip 7840/7820 USB Serial Driver"
43
44/*
45 * 16C50 UART register defines
46 */
47
48#define LCR_BITS_5 0x00 /* 5 bits/char */
49#define LCR_BITS_6 0x01 /* 6 bits/char */
50#define LCR_BITS_7 0x02 /* 7 bits/char */
51#define LCR_BITS_8 0x03 /* 8 bits/char */
52#define LCR_BITS_MASK 0x03 /* Mask for bits/char field */
53
54#define LCR_STOP_1 0x00 /* 1 stop bit */
55#define LCR_STOP_1_5 0x04 /* 1.5 stop bits (if 5 bits/char) */
56#define LCR_STOP_2 0x04 /* 2 stop bits (if 6-8 bits/char) */
57#define LCR_STOP_MASK 0x04 /* Mask for stop bits field */
58
59#define LCR_PAR_NONE 0x00 /* No parity */
60#define LCR_PAR_ODD 0x08 /* Odd parity */
61#define LCR_PAR_EVEN 0x18 /* Even parity */
62#define LCR_PAR_MARK 0x28 /* Force parity bit to 1 */
63#define LCR_PAR_SPACE 0x38 /* Force parity bit to 0 */
64#define LCR_PAR_MASK 0x38 /* Mask for parity field */
65
66#define LCR_SET_BREAK 0x40 /* Set Break condition */
67#define LCR_DL_ENABLE 0x80 /* Enable access to divisor latch */
68
69#define MCR_DTR 0x01 /* Assert DTR */
70#define MCR_RTS 0x02 /* Assert RTS */
71#define MCR_OUT1 0x04 /* Loopback only: Sets state of RI */
72#define MCR_MASTER_IE 0x08 /* Enable interrupt outputs */
73#define MCR_LOOPBACK 0x10 /* Set internal (digital) loopback mode */
74#define MCR_XON_ANY 0x20 /* Enable any char to exit XOFF mode */
75
76#define MOS7840_MSR_CTS 0x10 /* Current state of CTS */
77#define MOS7840_MSR_DSR 0x20 /* Current state of DSR */
78#define MOS7840_MSR_RI 0x40 /* Current state of RI */
79#define MOS7840_MSR_CD 0x80 /* Current state of CD */
80
81/*
82 * Defines used for sending commands to port
83 */
84
Alan Cox880af9d2008-07-22 11:16:12 +010085#define WAIT_FOR_EVER (HZ * 0) /* timeout urb is wait for ever */
86#define MOS_WDR_TIMEOUT (HZ * 5) /* default urb timeout */
Paul B Schroeder3f542972006-08-31 19:41:47 -050087
88#define MOS_PORT1 0x0200
89#define MOS_PORT2 0x0300
90#define MOS_VENREG 0x0000
91#define MOS_MAX_PORT 0x02
92#define MOS_WRITE 0x0E
93#define MOS_READ 0x0D
94
95/* Requests */
96#define MCS_RD_RTYPE 0xC0
97#define MCS_WR_RTYPE 0x40
98#define MCS_RDREQ 0x0D
99#define MCS_WRREQ 0x0E
100#define MCS_CTRL_TIMEOUT 500
101#define VENDOR_READ_LENGTH (0x01)
102
103#define MAX_NAME_LEN 64
104
Alan Cox880af9d2008-07-22 11:16:12 +0100105#define ZLP_REG1 0x3A /* Zero_Flag_Reg1 58 */
106#define ZLP_REG5 0x3E /* Zero_Flag_Reg5 62 */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500107
108/* For higher baud Rates use TIOCEXBAUD */
109#define TIOCEXBAUD 0x5462
110
111/* vendor id and device id defines */
112
David Ludlow11e1abb2008-02-25 17:30:52 -0500113/* The native mos7840/7820 component */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500114#define USB_VENDOR_ID_MOSCHIP 0x9710
115#define MOSCHIP_DEVICE_ID_7840 0x7840
116#define MOSCHIP_DEVICE_ID_7820 0x7820
David Ludlow11e1abb2008-02-25 17:30:52 -0500117/* The native component can have its vendor/device id's overridden
118 * in vendor-specific implementations. Such devices can be handled
119 * by making a change here, in moschip_port_id_table, and in
120 * moschip_id_table_combined
121 */
Dave Ludlow870408c2010-09-01 12:33:30 -0400122#define USB_VENDOR_ID_BANDB 0x0856
123#define BANDB_DEVICE_ID_USO9ML2_2 0xAC22
124#define BANDB_DEVICE_ID_USO9ML2_2P 0xBC00
125#define BANDB_DEVICE_ID_USO9ML2_4 0xAC24
126#define BANDB_DEVICE_ID_USO9ML2_4P 0xBC01
127#define BANDB_DEVICE_ID_US9ML2_2 0xAC29
128#define BANDB_DEVICE_ID_US9ML2_4 0xAC30
129#define BANDB_DEVICE_ID_USPTL4_2 0xAC31
130#define BANDB_DEVICE_ID_USPTL4_4 0xAC32
131#define BANDB_DEVICE_ID_USOPTL4_2 0xAC42
132#define BANDB_DEVICE_ID_USOPTL4_2P 0xBC02
133#define BANDB_DEVICE_ID_USOPTL4_4 0xAC44
134#define BANDB_DEVICE_ID_USOPTL4_4P 0xBC03
135#define BANDB_DEVICE_ID_USOPTL2_4 0xAC24
Paul B Schroeder3f542972006-08-31 19:41:47 -0500136
Russell Lang9d498be2009-07-17 19:29:20 +1000137/* This driver also supports
138 * ATEN UC2324 device using Moschip MCS7840
139 * ATEN UC2322 device using Moschip MCS7820
140 */
Tony Cooke9b8cff2009-04-18 22:42:18 +0930141#define USB_VENDOR_ID_ATENINTL 0x0557
142#define ATENINTL_DEVICE_ID_UC2324 0x2011
Russell Lang9d498be2009-07-17 19:29:20 +1000143#define ATENINTL_DEVICE_ID_UC2322 0x7820
Tony Cooke9b8cff2009-04-18 22:42:18 +0930144
David Ludlow11e1abb2008-02-25 17:30:52 -0500145/* Interrupt Routine Defines */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500146
147#define SERIAL_IIR_RLS 0x06
148#define SERIAL_IIR_MS 0x00
149
150/*
151 * Emulation of the bit mask on the LINE STATUS REGISTER.
152 */
153#define SERIAL_LSR_DR 0x0001
154#define SERIAL_LSR_OE 0x0002
155#define SERIAL_LSR_PE 0x0004
156#define SERIAL_LSR_FE 0x0008
157#define SERIAL_LSR_BI 0x0010
158
159#define MOS_MSR_DELTA_CTS 0x10
160#define MOS_MSR_DELTA_DSR 0x20
161#define MOS_MSR_DELTA_RI 0x40
162#define MOS_MSR_DELTA_CD 0x80
163
Alan Cox880af9d2008-07-22 11:16:12 +0100164/* Serial Port register Address */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500165#define INTERRUPT_ENABLE_REGISTER ((__u16)(0x01))
166#define FIFO_CONTROL_REGISTER ((__u16)(0x02))
167#define LINE_CONTROL_REGISTER ((__u16)(0x03))
168#define MODEM_CONTROL_REGISTER ((__u16)(0x04))
169#define LINE_STATUS_REGISTER ((__u16)(0x05))
170#define MODEM_STATUS_REGISTER ((__u16)(0x06))
171#define SCRATCH_PAD_REGISTER ((__u16)(0x07))
172#define DIVISOR_LATCH_LSB ((__u16)(0x00))
173#define DIVISOR_LATCH_MSB ((__u16)(0x01))
174
175#define CLK_MULTI_REGISTER ((__u16)(0x02))
176#define CLK_START_VALUE_REGISTER ((__u16)(0x03))
Donald Lee093ea2d2012-03-14 15:26:33 +0800177#define GPIO_REGISTER ((__u16)(0x07))
Paul B Schroeder3f542972006-08-31 19:41:47 -0500178
179#define SERIAL_LCR_DLAB ((__u16)(0x0080))
180
181/*
182 * URB POOL related defines
183 */
184#define NUM_URBS 16 /* URB Count */
185#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */
186
187
Németh Márton7d40d7e2010-01-10 15:34:24 +0100188static const struct usb_device_id moschip_port_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)},
Cliff Brakeacf509a2009-12-01 09:53:43 -0500191 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)},
Dave Ludlow870408c2010-09-01 12:33:30 -0400192 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)},
Cliff Brakeacf509a2009-12-01 09:53:43 -0500193 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)},
Dave Ludlow870408c2010-09-01 12:33:30 -0400194 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4P)},
Cliff Brakeacf509a2009-12-01 09:53:43 -0500195 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)},
196 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)},
197 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)},
198 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)},
David Ludlow11e1abb2008-02-25 17:30:52 -0500199 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)},
Dave Ludlow870408c2010-09-01 12:33:30 -0400200 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2P)},
Cliff Brakeacf509a2009-12-01 09:53:43 -0500201 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)},
Dave Ludlow870408c2010-09-01 12:33:30 -0400202 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4P)},
Blaise Gassend27f12812009-12-18 15:23:38 -0800203 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)},
Tony Cooke9b8cff2009-04-18 22:42:18 +0930204 {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)},
Russell Lang9d498be2009-07-17 19:29:20 +1000205 {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},
Paul B Schroeder3f542972006-08-31 19:41:47 -0500206 {} /* terminating entry */
207};
208
Tony Zelenoff0fd47a32012-06-05 17:58:04 +0400209static const struct usb_device_id moschip_id_table_combined[] = {
Paul B Schroeder3f542972006-08-31 19:41:47 -0500210 {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
211 {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
Cliff Brakeacf509a2009-12-01 09:53:43 -0500212 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)},
Dave Ludlow870408c2010-09-01 12:33:30 -0400213 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)},
Cliff Brakeacf509a2009-12-01 09:53:43 -0500214 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)},
Dave Ludlow870408c2010-09-01 12:33:30 -0400215 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4P)},
Cliff Brakeacf509a2009-12-01 09:53:43 -0500216 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)},
217 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)},
218 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)},
219 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)},
David Ludlow11e1abb2008-02-25 17:30:52 -0500220 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)},
Dave Ludlow870408c2010-09-01 12:33:30 -0400221 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2P)},
Cliff Brakeacf509a2009-12-01 09:53:43 -0500222 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)},
Dave Ludlow870408c2010-09-01 12:33:30 -0400223 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4P)},
Blaise Gassend27f12812009-12-18 15:23:38 -0800224 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)},
Tony Cooke9b8cff2009-04-18 22:42:18 +0930225 {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)},
Russell Lang9d498be2009-07-17 19:29:20 +1000226 {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},
Paul B Schroeder3f542972006-08-31 19:41:47 -0500227 {} /* terminating entry */
228};
229
230MODULE_DEVICE_TABLE(usb, moschip_id_table_combined);
231
232/* This structure holds all of the local port information */
233
234struct moschip_port {
235 int port_num; /*Actual port number in the device(1,2,etc) */
236 struct urb *write_urb; /* write URB for this port */
237 struct urb *read_urb; /* read URB for this port */
238 __u8 shadowLCR; /* last LCR value received */
239 __u8 shadowMCR; /* last MCR value received */
240 char open;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100241 char open_ports;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500242 wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */
243 wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */
244 int delta_msr_cond;
245 struct async_icount icount;
246 struct usb_serial_port *port; /* loop back to the owner of this object */
247
Alan Cox880af9d2008-07-22 11:16:12 +0100248 /* Offsets */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500249 __u8 SpRegOffset;
250 __u8 ControlRegOffset;
251 __u8 DcrRegOffset;
Alan Cox880af9d2008-07-22 11:16:12 +0100252 /* for processing control URBS in interrupt context */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500253 struct urb *control_urb;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100254 struct usb_ctrlrequest *dr;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500255 char *ctrl_buf;
256 int MsrLsr;
257
Oliver Neukum0de9a702007-03-16 20:28:28 +0100258 spinlock_t pool_lock;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500259 struct urb *write_urb_pool[NUM_URBS];
Oliver Neukum0de9a702007-03-16 20:28:28 +0100260 char busy[NUM_URBS];
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800261 bool read_urb_busy;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500262};
263
264
Rusty Russell90ab5ee2012-01-13 09:32:20 +1030265static bool debug;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500266
267/*
268 * mos7840_set_reg_sync
269 * To set the Control register by calling usb_fill_control_urb function
270 * by passing usb_sndctrlpipe function as parameter.
271 */
272
273static int mos7840_set_reg_sync(struct usb_serial_port *port, __u16 reg,
274 __u16 val)
275{
276 struct usb_device *dev = port->serial->dev;
277 val = val & 0x00ff;
Tony Cook84fe6e72009-04-18 22:55:06 +0930278 dbg("mos7840_set_reg_sync offset is %x, value %x", reg, val);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500279
280 return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ,
281 MCS_WR_RTYPE, val, reg, NULL, 0,
282 MOS_WDR_TIMEOUT);
283}
284
285/*
286 * mos7840_get_reg_sync
287 * To set the Uart register by calling usb_fill_control_urb function by
288 * passing usb_rcvctrlpipe function as parameter.
289 */
290
291static int mos7840_get_reg_sync(struct usb_serial_port *port, __u16 reg,
Alan Cox880af9d2008-07-22 11:16:12 +0100292 __u16 *val)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500293{
294 struct usb_device *dev = port->serial->dev;
295 int ret = 0;
Johan Hovold9e221a32009-12-28 23:01:55 +0100296 u8 *buf;
297
298 buf = kmalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
299 if (!buf)
300 return -ENOMEM;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500301
302 ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
Johan Hovold9e221a32009-12-28 23:01:55 +0100303 MCS_RD_RTYPE, 0, reg, buf, VENDOR_READ_LENGTH,
Paul B Schroeder3f542972006-08-31 19:41:47 -0500304 MOS_WDR_TIMEOUT);
Johan Hovold9e221a32009-12-28 23:01:55 +0100305 *val = buf[0];
Tony Cook84fe6e72009-04-18 22:55:06 +0930306 dbg("mos7840_get_reg_sync offset is %x, return val %x", reg, *val);
Johan Hovold9e221a32009-12-28 23:01:55 +0100307
308 kfree(buf);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500309 return ret;
310}
311
312/*
313 * mos7840_set_uart_reg
314 * To set the Uart register by calling usb_fill_control_urb function by
315 * passing usb_sndctrlpipe function as parameter.
316 */
317
318static int mos7840_set_uart_reg(struct usb_serial_port *port, __u16 reg,
319 __u16 val)
320{
321
322 struct usb_device *dev = port->serial->dev;
323 val = val & 0x00ff;
Alan Cox880af9d2008-07-22 11:16:12 +0100324 /* For the UART control registers, the application number need
325 to be Or'ed */
Oliver Neukum0de9a702007-03-16 20:28:28 +0100326 if (port->serial->num_ports == 4) {
Alan Cox880af9d2008-07-22 11:16:12 +0100327 val |= (((__u16) port->number -
328 (__u16) (port->serial->minor)) + 1) << 8;
Tony Cook84fe6e72009-04-18 22:55:06 +0930329 dbg("mos7840_set_uart_reg application number is %x", val);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500330 } else {
331 if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) {
Alan Cox880af9d2008-07-22 11:16:12 +0100332 val |= (((__u16) port->number -
Paul B Schroeder3f542972006-08-31 19:41:47 -0500333 (__u16) (port->serial->minor)) + 1) << 8;
Tony Cook84fe6e72009-04-18 22:55:06 +0930334 dbg("mos7840_set_uart_reg application number is %x",
Paul B Schroeder3f542972006-08-31 19:41:47 -0500335 val);
336 } else {
337 val |=
338 (((__u16) port->number -
339 (__u16) (port->serial->minor)) + 2) << 8;
Tony Cook84fe6e72009-04-18 22:55:06 +0930340 dbg("mos7840_set_uart_reg application number is %x",
Paul B Schroeder3f542972006-08-31 19:41:47 -0500341 val);
342 }
343 }
344 return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ,
345 MCS_WR_RTYPE, val, reg, NULL, 0,
346 MOS_WDR_TIMEOUT);
347
348}
349
350/*
351 * mos7840_get_uart_reg
352 * To set the Control register by calling usb_fill_control_urb function
353 * by passing usb_rcvctrlpipe function as parameter.
354 */
355static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg,
Alan Cox880af9d2008-07-22 11:16:12 +0100356 __u16 *val)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500357{
358 struct usb_device *dev = port->serial->dev;
359 int ret = 0;
360 __u16 Wval;
Johan Hovold9e221a32009-12-28 23:01:55 +0100361 u8 *buf;
362
363 buf = kmalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
364 if (!buf)
365 return -ENOMEM;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500366
Tony Cook84fe6e72009-04-18 22:55:06 +0930367 /* dbg("application number is %4x",
Alan Cox880af9d2008-07-22 11:16:12 +0100368 (((__u16)port->number - (__u16)(port->serial->minor))+1)<<8); */
369 /* Wval is same as application number */
Oliver Neukum0de9a702007-03-16 20:28:28 +0100370 if (port->serial->num_ports == 4) {
Paul B Schroeder3f542972006-08-31 19:41:47 -0500371 Wval =
372 (((__u16) port->number - (__u16) (port->serial->minor)) +
373 1) << 8;
Tony Cook84fe6e72009-04-18 22:55:06 +0930374 dbg("mos7840_get_uart_reg application number is %x", Wval);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500375 } else {
376 if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) {
Alan Cox880af9d2008-07-22 11:16:12 +0100377 Wval = (((__u16) port->number -
Paul B Schroeder3f542972006-08-31 19:41:47 -0500378 (__u16) (port->serial->minor)) + 1) << 8;
Tony Cook84fe6e72009-04-18 22:55:06 +0930379 dbg("mos7840_get_uart_reg application number is %x",
Paul B Schroeder3f542972006-08-31 19:41:47 -0500380 Wval);
381 } else {
Alan Cox880af9d2008-07-22 11:16:12 +0100382 Wval = (((__u16) port->number -
Paul B Schroeder3f542972006-08-31 19:41:47 -0500383 (__u16) (port->serial->minor)) + 2) << 8;
Tony Cook84fe6e72009-04-18 22:55:06 +0930384 dbg("mos7840_get_uart_reg application number is %x",
Paul B Schroeder3f542972006-08-31 19:41:47 -0500385 Wval);
386 }
387 }
388 ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
Johan Hovold9e221a32009-12-28 23:01:55 +0100389 MCS_RD_RTYPE, Wval, reg, buf, VENDOR_READ_LENGTH,
Paul B Schroeder3f542972006-08-31 19:41:47 -0500390 MOS_WDR_TIMEOUT);
Johan Hovold9e221a32009-12-28 23:01:55 +0100391 *val = buf[0];
392
393 kfree(buf);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500394 return ret;
395}
396
397static void mos7840_dump_serial_port(struct moschip_port *mos7840_port)
398{
399
Tony Cook84fe6e72009-04-18 22:55:06 +0930400 dbg("***************************************");
401 dbg("SpRegOffset is %2x", mos7840_port->SpRegOffset);
402 dbg("ControlRegOffset is %2x", mos7840_port->ControlRegOffset);
403 dbg("DCRRegOffset is %2x", mos7840_port->DcrRegOffset);
404 dbg("***************************************");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500405
406}
407
408/************************************************************************/
409/************************************************************************/
410/* I N T E R F A C E F U N C T I O N S */
411/* I N T E R F A C E F U N C T I O N S */
412/************************************************************************/
413/************************************************************************/
414
415static inline void mos7840_set_port_private(struct usb_serial_port *port,
416 struct moschip_port *data)
417{
418 usb_set_serial_port_data(port, (void *)data);
419}
420
421static inline struct moschip_port *mos7840_get_port_private(struct
422 usb_serial_port
423 *port)
424{
425 return (struct moschip_port *)usb_get_serial_port_data(port);
426}
427
Oliver Neukum0de9a702007-03-16 20:28:28 +0100428static void mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500429{
430 struct moschip_port *mos7840_port;
431 struct async_icount *icount;
432 mos7840_port = port;
433 icount = &mos7840_port->icount;
434 if (new_msr &
435 (MOS_MSR_DELTA_CTS | MOS_MSR_DELTA_DSR | MOS_MSR_DELTA_RI |
436 MOS_MSR_DELTA_CD)) {
437 icount = &mos7840_port->icount;
438
439 /* update input line counters */
440 if (new_msr & MOS_MSR_DELTA_CTS) {
441 icount->cts++;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100442 smp_wmb();
Paul B Schroeder3f542972006-08-31 19:41:47 -0500443 }
444 if (new_msr & MOS_MSR_DELTA_DSR) {
445 icount->dsr++;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100446 smp_wmb();
Paul B Schroeder3f542972006-08-31 19:41:47 -0500447 }
448 if (new_msr & MOS_MSR_DELTA_CD) {
449 icount->dcd++;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100450 smp_wmb();
Paul B Schroeder3f542972006-08-31 19:41:47 -0500451 }
452 if (new_msr & MOS_MSR_DELTA_RI) {
453 icount->rng++;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100454 smp_wmb();
Paul B Schroeder3f542972006-08-31 19:41:47 -0500455 }
Johan Hovoldee2470d2013-03-19 09:21:19 +0100456
457 mos7840_port->delta_msr_cond = 1;
458 wake_up_interruptible(&mos7840_port->delta_msr_wait);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500459 }
Paul B Schroeder3f542972006-08-31 19:41:47 -0500460}
461
Oliver Neukum0de9a702007-03-16 20:28:28 +0100462static void mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500463{
464 struct async_icount *icount;
465
Harvey Harrison441b62c2008-03-03 16:08:34 -0800466 dbg("%s - %02x", __func__, new_lsr);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500467
468 if (new_lsr & SERIAL_LSR_BI) {
Alan Cox880af9d2008-07-22 11:16:12 +0100469 /*
470 * Parity and Framing errors only count if they
471 * occur exclusive of a break being
472 * received.
473 */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500474 new_lsr &= (__u8) (SERIAL_LSR_OE | SERIAL_LSR_BI);
475 }
476
477 /* update input line counters */
478 icount = &port->icount;
479 if (new_lsr & SERIAL_LSR_BI) {
480 icount->brk++;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100481 smp_wmb();
Paul B Schroeder3f542972006-08-31 19:41:47 -0500482 }
483 if (new_lsr & SERIAL_LSR_OE) {
484 icount->overrun++;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100485 smp_wmb();
Paul B Schroeder3f542972006-08-31 19:41:47 -0500486 }
487 if (new_lsr & SERIAL_LSR_PE) {
488 icount->parity++;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100489 smp_wmb();
Paul B Schroeder3f542972006-08-31 19:41:47 -0500490 }
491 if (new_lsr & SERIAL_LSR_FE) {
492 icount->frame++;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100493 smp_wmb();
Paul B Schroeder3f542972006-08-31 19:41:47 -0500494 }
Paul B Schroeder3f542972006-08-31 19:41:47 -0500495}
496
497/************************************************************************/
498/************************************************************************/
499/* U S B C A L L B A C K F U N C T I O N S */
500/* U S B C A L L B A C K F U N C T I O N S */
501/************************************************************************/
502/************************************************************************/
503
David Howells7d12e782006-10-05 14:55:46 +0100504static void mos7840_control_callback(struct urb *urb)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500505{
506 unsigned char *data;
507 struct moschip_port *mos7840_port;
508 __u8 regval = 0x0;
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700509 int status = urb->status;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500510
Ming Leicdc97792008-02-24 18:41:47 +0800511 mos7840_port = urb->context;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100512
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700513 switch (status) {
Paul B Schroeder3f542972006-08-31 19:41:47 -0500514 case 0:
515 /* success */
516 break;
517 case -ECONNRESET:
518 case -ENOENT:
519 case -ESHUTDOWN:
520 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800521 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700522 status);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500523 return;
524 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800525 dbg("%s - nonzero urb status received: %d", __func__,
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700526 status);
Johan Hovold380c05e2012-10-25 18:56:32 +0200527 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500528 }
529
Tony Cook84fe6e72009-04-18 22:55:06 +0930530 dbg("%s urb buffer size is %d", __func__, urb->actual_length);
531 dbg("%s mos7840_port->MsrLsr is %d port %d", __func__,
Paul B Schroeder3f542972006-08-31 19:41:47 -0500532 mos7840_port->MsrLsr, mos7840_port->port_num);
533 data = urb->transfer_buffer;
534 regval = (__u8) data[0];
Tony Cook84fe6e72009-04-18 22:55:06 +0930535 dbg("%s data is %x", __func__, regval);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500536 if (mos7840_port->MsrLsr == 0)
537 mos7840_handle_new_msr(mos7840_port, regval);
538 else if (mos7840_port->MsrLsr == 1)
539 mos7840_handle_new_lsr(mos7840_port, regval);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500540}
541
542static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
Alan Cox880af9d2008-07-22 11:16:12 +0100543 __u16 *val)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500544{
545 struct usb_device *dev = mcs->port->serial->dev;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100546 struct usb_ctrlrequest *dr = mcs->dr;
547 unsigned char *buffer = mcs->ctrl_buf;
548 int ret;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500549
Paul B Schroeder3f542972006-08-31 19:41:47 -0500550 dr->bRequestType = MCS_RD_RTYPE;
551 dr->bRequest = MCS_RDREQ;
Alan Cox880af9d2008-07-22 11:16:12 +0100552 dr->wValue = cpu_to_le16(Wval); /* 0 */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500553 dr->wIndex = cpu_to_le16(reg);
554 dr->wLength = cpu_to_le16(2);
555
556 usb_fill_control_urb(mcs->control_urb, dev, usb_rcvctrlpipe(dev, 0),
557 (unsigned char *)dr, buffer, 2,
558 mos7840_control_callback, mcs);
559 mcs->control_urb->transfer_buffer_length = 2;
560 ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
561 return ret;
562}
563
564/*****************************************************************************
565 * mos7840_interrupt_callback
566 * this is the callback function for when we have received data on the
567 * interrupt endpoint.
568 *****************************************************************************/
569
David Howells7d12e782006-10-05 14:55:46 +0100570static void mos7840_interrupt_callback(struct urb *urb)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500571{
572 int result;
573 int length;
574 struct moschip_port *mos7840_port;
575 struct usb_serial *serial;
576 __u16 Data;
577 unsigned char *data;
578 __u8 sp[5], st;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100579 int i, rv = 0;
580 __u16 wval, wreg = 0;
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700581 int status = urb->status;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500582
Tony Cook84fe6e72009-04-18 22:55:06 +0930583 dbg("%s", " : Entering");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500584
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700585 switch (status) {
Paul B Schroeder3f542972006-08-31 19:41:47 -0500586 case 0:
587 /* success */
588 break;
589 case -ECONNRESET:
590 case -ENOENT:
591 case -ESHUTDOWN:
592 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800593 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700594 status);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500595 return;
596 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -0800597 dbg("%s - nonzero urb status received: %d", __func__,
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700598 status);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500599 goto exit;
600 }
601
602 length = urb->actual_length;
603 data = urb->transfer_buffer;
604
Ming Leicdc97792008-02-24 18:41:47 +0800605 serial = urb->context;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500606
607 /* Moschip get 5 bytes
608 * Byte 1 IIR Port 1 (port.number is 0)
609 * Byte 2 IIR Port 2 (port.number is 1)
610 * Byte 3 IIR Port 3 (port.number is 2)
611 * Byte 4 IIR Port 4 (port.number is 3)
612 * Byte 5 FIFO status for both */
613
614 if (length && length > 5) {
Tony Cook84fe6e72009-04-18 22:55:06 +0930615 dbg("%s", "Wrong data !!!");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500616 return;
617 }
618
619 sp[0] = (__u8) data[0];
620 sp[1] = (__u8) data[1];
621 sp[2] = (__u8) data[2];
622 sp[3] = (__u8) data[3];
623 st = (__u8) data[4];
624
625 for (i = 0; i < serial->num_ports; i++) {
626 mos7840_port = mos7840_get_port_private(serial->port[i]);
627 wval =
628 (((__u16) serial->port[i]->number -
629 (__u16) (serial->minor)) + 1) << 8;
630 if (mos7840_port->open) {
631 if (sp[i] & 0x01) {
Tony Cook84fe6e72009-04-18 22:55:06 +0930632 dbg("SP%d No Interrupt !!!", i);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500633 } else {
634 switch (sp[i] & 0x0f) {
635 case SERIAL_IIR_RLS:
636 dbg("Serial Port %d: Receiver status error or ", i);
Tony Cook84fe6e72009-04-18 22:55:06 +0930637 dbg("address bit detected in 9-bit mode");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500638 mos7840_port->MsrLsr = 1;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100639 wreg = LINE_STATUS_REGISTER;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500640 break;
641 case SERIAL_IIR_MS:
Tony Cook84fe6e72009-04-18 22:55:06 +0930642 dbg("Serial Port %d: Modem status change", i);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500643 mos7840_port->MsrLsr = 0;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100644 wreg = MODEM_STATUS_REGISTER;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500645 break;
646 }
Johan Hovold8d649dd2012-10-25 18:56:33 +0200647 rv = mos7840_get_reg(mos7840_port, wval, wreg, &Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500648 }
649 }
650 }
Alan Cox880af9d2008-07-22 11:16:12 +0100651 if (!(rv < 0))
652 /* the completion handler for the control urb will resubmit */
Oliver Neukum0de9a702007-03-16 20:28:28 +0100653 return;
654exit:
Paul B Schroeder3f542972006-08-31 19:41:47 -0500655 result = usb_submit_urb(urb, GFP_ATOMIC);
656 if (result) {
657 dev_err(&urb->dev->dev,
658 "%s - Error %d submitting interrupt urb\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800659 __func__, result);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500660 }
Paul B Schroeder3f542972006-08-31 19:41:47 -0500661}
662
663static int mos7840_port_paranoia_check(struct usb_serial_port *port,
664 const char *function)
665{
666 if (!port) {
667 dbg("%s - port == NULL", function);
668 return -1;
669 }
670 if (!port->serial) {
671 dbg("%s - port->serial == NULL", function);
672 return -1;
673 }
674
675 return 0;
676}
677
678/* Inline functions to check the sanity of a pointer that is passed to us */
679static int mos7840_serial_paranoia_check(struct usb_serial *serial,
680 const char *function)
681{
682 if (!serial) {
683 dbg("%s - serial == NULL", function);
684 return -1;
685 }
686 if (!serial->type) {
687 dbg("%s - serial->type == NULL!", function);
688 return -1;
689 }
690
691 return 0;
692}
693
694static struct usb_serial *mos7840_get_usb_serial(struct usb_serial_port *port,
695 const char *function)
696{
697 /* if no port was specified, or it fails a paranoia check */
698 if (!port ||
699 mos7840_port_paranoia_check(port, function) ||
700 mos7840_serial_paranoia_check(port->serial, function)) {
Alan Cox880af9d2008-07-22 11:16:12 +0100701 /* then say that we don't have a valid usb_serial thing,
702 * which will end up genrating -ENODEV return values */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500703 return NULL;
704 }
705
706 return port->serial;
707}
708
709/*****************************************************************************
710 * mos7840_bulk_in_callback
711 * this is the callback function for when we have received data on the
712 * bulk in endpoint.
713 *****************************************************************************/
714
David Howells7d12e782006-10-05 14:55:46 +0100715static void mos7840_bulk_in_callback(struct urb *urb)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500716{
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700717 int retval;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500718 unsigned char *data;
719 struct usb_serial *serial;
720 struct usb_serial_port *port;
721 struct moschip_port *mos7840_port;
722 struct tty_struct *tty;
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700723 int status = urb->status;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500724
Ming Leicdc97792008-02-24 18:41:47 +0800725 mos7840_port = urb->context;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500726 if (!mos7840_port) {
Tony Cook84fe6e72009-04-18 22:55:06 +0930727 dbg("%s", "NULL mos7840_port pointer");
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800728 return;
729 }
730
731 if (status) {
732 dbg("nonzero read bulk status received: %d", status);
733 mos7840_port->read_urb_busy = false;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500734 return;
735 }
736
737 port = (struct usb_serial_port *)mos7840_port->port;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800738 if (mos7840_port_paranoia_check(port, __func__)) {
Tony Cook84fe6e72009-04-18 22:55:06 +0930739 dbg("%s", "Port Paranoia failed");
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800740 mos7840_port->read_urb_busy = false;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500741 return;
742 }
743
Harvey Harrison441b62c2008-03-03 16:08:34 -0800744 serial = mos7840_get_usb_serial(port, __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500745 if (!serial) {
Tony Cook84fe6e72009-04-18 22:55:06 +0930746 dbg("%s", "Bad serial pointer");
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800747 mos7840_port->read_urb_busy = false;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500748 return;
749 }
750
Tony Cook84fe6e72009-04-18 22:55:06 +0930751 dbg("%s", "Entering... ");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500752
753 data = urb->transfer_buffer;
754
Tony Cook84fe6e72009-04-18 22:55:06 +0930755 dbg("%s", "Entering ...........");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500756
757 if (urb->actual_length) {
Alan Cox4a90f092008-10-13 10:39:46 +0100758 tty = tty_port_tty_get(&mos7840_port->port->port);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500759 if (tty) {
Paul B Schroeder3f542972006-08-31 19:41:47 -0500760 tty_insert_flip_string(tty, data, urb->actual_length);
Tony Cook84fe6e72009-04-18 22:55:06 +0930761 dbg(" %s ", data);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500762 tty_flip_buffer_push(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100763 tty_kref_put(tty);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500764 }
765 mos7840_port->icount.rx += urb->actual_length;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100766 smp_wmb();
Tony Cook84fe6e72009-04-18 22:55:06 +0930767 dbg("mos7840_port->icount.rx is %d:",
Paul B Schroeder3f542972006-08-31 19:41:47 -0500768 mos7840_port->icount.rx);
769 }
770
771 if (!mos7840_port->read_urb) {
Tony Cook84fe6e72009-04-18 22:55:06 +0930772 dbg("%s", "URB KILLED !!!");
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800773 mos7840_port->read_urb_busy = false;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500774 return;
775 }
776
Paul B Schroeder3f542972006-08-31 19:41:47 -0500777
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800778 mos7840_port->read_urb_busy = true;
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700779 retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
Oliver Neukum0de9a702007-03-16 20:28:28 +0100780
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700781 if (retval) {
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800782 dbg("usb_submit_urb(read bulk) failed, retval = %d", retval);
783 mos7840_port->read_urb_busy = false;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500784 }
785}
786
787/*****************************************************************************
788 * mos7840_bulk_out_data_callback
Alan Cox880af9d2008-07-22 11:16:12 +0100789 * this is the callback function for when we have finished sending
790 * serial data on the bulk out endpoint.
Paul B Schroeder3f542972006-08-31 19:41:47 -0500791 *****************************************************************************/
792
David Howells7d12e782006-10-05 14:55:46 +0100793static void mos7840_bulk_out_data_callback(struct urb *urb)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500794{
795 struct moschip_port *mos7840_port;
796 struct tty_struct *tty;
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700797 int status = urb->status;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100798 int i;
799
Ming Leicdc97792008-02-24 18:41:47 +0800800 mos7840_port = urb->context;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100801 spin_lock(&mos7840_port->pool_lock);
802 for (i = 0; i < NUM_URBS; i++) {
803 if (urb == mos7840_port->write_urb_pool[i]) {
804 mos7840_port->busy[i] = 0;
805 break;
806 }
807 }
808 spin_unlock(&mos7840_port->pool_lock);
809
Greg Kroah-Hartman0643c722007-06-15 15:44:13 -0700810 if (status) {
Tony Cook84fe6e72009-04-18 22:55:06 +0930811 dbg("nonzero write bulk status received:%d", status);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500812 return;
813 }
814
Harvey Harrison441b62c2008-03-03 16:08:34 -0800815 if (mos7840_port_paranoia_check(mos7840_port->port, __func__)) {
Tony Cook84fe6e72009-04-18 22:55:06 +0930816 dbg("%s", "Port Paranoia failed");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500817 return;
818 }
819
Tony Cook84fe6e72009-04-18 22:55:06 +0930820 dbg("%s", "Entering .........");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500821
Alan Cox4a90f092008-10-13 10:39:46 +0100822 tty = tty_port_tty_get(&mos7840_port->port->port);
Jiri Slabyb963a842007-02-10 01:44:55 -0800823 if (tty && mos7840_port->open)
824 tty_wakeup(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100825 tty_kref_put(tty);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500826
827}
828
829/************************************************************************/
830/* 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 */
831/************************************************************************/
832#ifdef MCSSerialProbe
833static int mos7840_serial_probe(struct usb_serial *serial,
834 const struct usb_device_id *id)
835{
836
837 /*need to implement the mode_reg reading and updating\
838 structures usb_serial_ device_type\
839 (i.e num_ports, num_bulkin,bulkout etc) */
840 /* Also we can update the changes attach */
841 return 1;
842}
843#endif
844
845/*****************************************************************************
846 * mos7840_open
847 * this function is called by the tty driver when a port is opened
848 * If successful, we return 0
849 * Otherwise we return a negative error number.
850 *****************************************************************************/
851
Alan Coxa509a7e2009-09-19 13:13:26 -0700852static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500853{
854 int response;
855 int j;
856 struct usb_serial *serial;
857 struct urb *urb;
858 __u16 Data;
859 int status;
860 struct moschip_port *mos7840_port;
Oliver Neukum0de9a702007-03-16 20:28:28 +0100861 struct moschip_port *port0;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500862
Tony Cook84fe6e72009-04-18 22:55:06 +0930863 dbg ("%s enter", __func__);
864
Harvey Harrison441b62c2008-03-03 16:08:34 -0800865 if (mos7840_port_paranoia_check(port, __func__)) {
Tony Cook84fe6e72009-04-18 22:55:06 +0930866 dbg("%s", "Port Paranoia failed");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500867 return -ENODEV;
868 }
869
Paul B Schroeder3f542972006-08-31 19:41:47 -0500870 serial = port->serial;
871
Harvey Harrison441b62c2008-03-03 16:08:34 -0800872 if (mos7840_serial_paranoia_check(serial, __func__)) {
Tony Cook84fe6e72009-04-18 22:55:06 +0930873 dbg("%s", "Serial Paranoia failed");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500874 return -ENODEV;
875 }
876
877 mos7840_port = mos7840_get_port_private(port);
Oliver Neukum0de9a702007-03-16 20:28:28 +0100878 port0 = mos7840_get_port_private(serial->port[0]);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500879
Oliver Neukum0de9a702007-03-16 20:28:28 +0100880 if (mos7840_port == NULL || port0 == NULL)
Paul B Schroeder3f542972006-08-31 19:41:47 -0500881 return -ENODEV;
882
883 usb_clear_halt(serial->dev, port->write_urb->pipe);
884 usb_clear_halt(serial->dev, port->read_urb->pipe);
Oliver Neukum0de9a702007-03-16 20:28:28 +0100885 port0->open_ports++;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500886
887 /* Initialising the write urb pool */
888 for (j = 0; j < NUM_URBS; ++j) {
Oliver Neukum0de9a702007-03-16 20:28:28 +0100889 urb = usb_alloc_urb(0, GFP_KERNEL);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500890 mos7840_port->write_urb_pool[j] = urb;
891
892 if (urb == NULL) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -0700893 dev_err(&port->dev, "No more urbs???\n");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500894 continue;
895 }
896
Alan Cox880af9d2008-07-22 11:16:12 +0100897 urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
898 GFP_KERNEL);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500899 if (!urb->transfer_buffer) {
Oliver Neukum0de9a702007-03-16 20:28:28 +0100900 usb_free_urb(urb);
901 mos7840_port->write_urb_pool[j] = NULL;
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -0700902 dev_err(&port->dev,
903 "%s-out of memory for urb buffers.\n",
904 __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500905 continue;
906 }
907 }
908
909/*****************************************************************************
910 * Initialize MCS7840 -- Write Init values to corresponding Registers
911 *
912 * Register Index
913 * 1 : IER
914 * 2 : FCR
915 * 3 : LCR
916 * 4 : MCR
917 *
918 * 0x08 : SP1/2 Control Reg
919 *****************************************************************************/
920
Alan Cox880af9d2008-07-22 11:16:12 +0100921 /* NEED to check the following Block */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500922
Paul B Schroeder3f542972006-08-31 19:41:47 -0500923 Data = 0x0;
924 status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data);
925 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +0930926 dbg("Reading Spreg failed");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500927 return -1;
928 }
929 Data |= 0x80;
930 status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
931 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +0930932 dbg("writing Spreg failed");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500933 return -1;
934 }
935
936 Data &= ~0x80;
937 status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
938 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +0930939 dbg("writing Spreg failed");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500940 return -1;
941 }
Alan Cox880af9d2008-07-22 11:16:12 +0100942 /* End of block to be checked */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500943
Paul B Schroeder3f542972006-08-31 19:41:47 -0500944 Data = 0x0;
Alan Cox880af9d2008-07-22 11:16:12 +0100945 status = mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset,
946 &Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500947 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +0930948 dbg("Reading Controlreg failed");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500949 return -1;
950 }
Alan Cox880af9d2008-07-22 11:16:12 +0100951 Data |= 0x08; /* Driver done bit */
952 Data |= 0x20; /* rx_disable */
953 status = mos7840_set_reg_sync(port,
954 mos7840_port->ControlRegOffset, Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -0500955 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +0930956 dbg("writing Controlreg failed");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500957 return -1;
958 }
Alan Cox880af9d2008-07-22 11:16:12 +0100959 /* do register settings here */
960 /* Set all regs to the device default values. */
961 /***********************************
962 * First Disable all interrupts.
963 ***********************************/
Paul B Schroeder3f542972006-08-31 19:41:47 -0500964 Data = 0x00;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500965 status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
966 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +0930967 dbg("disabling interrupts failed");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500968 return -1;
969 }
Alan Cox880af9d2008-07-22 11:16:12 +0100970 /* Set FIFO_CONTROL_REGISTER to the default value */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500971 Data = 0x00;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500972 status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
973 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +0930974 dbg("Writing FIFO_CONTROL_REGISTER failed");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500975 return -1;
976 }
977
978 Data = 0xcf;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500979 status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
980 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +0930981 dbg("Writing FIFO_CONTROL_REGISTER failed");
Paul B Schroeder3f542972006-08-31 19:41:47 -0500982 return -1;
983 }
984
985 Data = 0x03;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500986 status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
987 mos7840_port->shadowLCR = Data;
988
989 Data = 0x0b;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500990 status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
991 mos7840_port->shadowMCR = Data;
992
993 Data = 0x00;
Paul B Schroeder3f542972006-08-31 19:41:47 -0500994 status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
995 mos7840_port->shadowLCR = Data;
996
Alan Cox880af9d2008-07-22 11:16:12 +0100997 Data |= SERIAL_LCR_DLAB; /* data latch enable in LCR 0x80 */
Paul B Schroeder3f542972006-08-31 19:41:47 -0500998 status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
999
1000 Data = 0x0c;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001001 status = mos7840_set_uart_reg(port, DIVISOR_LATCH_LSB, Data);
1002
1003 Data = 0x0;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001004 status = mos7840_set_uart_reg(port, DIVISOR_LATCH_MSB, Data);
1005
1006 Data = 0x00;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001007 status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
1008
1009 Data = Data & ~SERIAL_LCR_DLAB;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001010 status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
1011 mos7840_port->shadowLCR = Data;
1012
Alan Cox880af9d2008-07-22 11:16:12 +01001013 /* clearing Bulkin and Bulkout Fifo */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001014 Data = 0x0;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001015 status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data);
1016
1017 Data = Data | 0x0c;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001018 status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
1019
1020 Data = Data & ~0x0c;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001021 status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
Alan Cox880af9d2008-07-22 11:16:12 +01001022 /* Finally enable all interrupts */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001023 Data = 0x0c;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001024 status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
1025
Alan Cox880af9d2008-07-22 11:16:12 +01001026 /* clearing rx_disable */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001027 Data = 0x0;
Alan Cox880af9d2008-07-22 11:16:12 +01001028 status = mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset,
1029 &Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001030 Data = Data & ~0x20;
Alan Cox880af9d2008-07-22 11:16:12 +01001031 status = mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset,
1032 Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001033
Alan Cox880af9d2008-07-22 11:16:12 +01001034 /* rx_negate */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001035 Data = 0x0;
Alan Cox880af9d2008-07-22 11:16:12 +01001036 status = mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset,
1037 &Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001038 Data = Data | 0x10;
Alan Cox880af9d2008-07-22 11:16:12 +01001039 status = mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset,
1040 Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001041
Alan Cox880af9d2008-07-22 11:16:12 +01001042 /* Check to see if we've set up our endpoint info yet *
1043 * (can't set it up in mos7840_startup as the structures *
1044 * were not set up at that time.) */
Oliver Neukum0de9a702007-03-16 20:28:28 +01001045 if (port0->open_ports == 1) {
Paul B Schroeder3f542972006-08-31 19:41:47 -05001046 if (serial->port[0]->interrupt_in_buffer == NULL) {
Paul B Schroeder3f542972006-08-31 19:41:47 -05001047 /* set up interrupt urb */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001048 usb_fill_int_urb(serial->port[0]->interrupt_in_urb,
Alan Cox880af9d2008-07-22 11:16:12 +01001049 serial->dev,
1050 usb_rcvintpipe(serial->dev,
1051 serial->port[0]->interrupt_in_endpointAddress),
1052 serial->port[0]->interrupt_in_buffer,
1053 serial->port[0]->interrupt_in_urb->
1054 transfer_buffer_length,
1055 mos7840_interrupt_callback,
1056 serial,
1057 serial->port[0]->interrupt_in_urb->interval);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001058
1059 /* start interrupt read for mos7840 *
1060 * will continue as long as mos7840 is connected */
1061
1062 response =
1063 usb_submit_urb(serial->port[0]->interrupt_in_urb,
1064 GFP_KERNEL);
1065 if (response) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001066 dev_err(&port->dev, "%s - Error %d submitting "
1067 "interrupt urb\n", __func__, response);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001068 }
1069
1070 }
1071
1072 }
1073
1074 /* see if we've set up our endpoint info yet *
1075 * (can't set it up in mos7840_startup as the *
1076 * structures were not set up at that time.) */
1077
Tony Cook84fe6e72009-04-18 22:55:06 +09301078 dbg("port number is %d", port->number);
1079 dbg("serial number is %d", port->serial->minor);
1080 dbg("Bulkin endpoint is %d", port->bulk_in_endpointAddress);
1081 dbg("BulkOut endpoint is %d", port->bulk_out_endpointAddress);
1082 dbg("Interrupt endpoint is %d", port->interrupt_in_endpointAddress);
1083 dbg("port's number in the device is %d", mos7840_port->port_num);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001084 mos7840_port->read_urb = port->read_urb;
1085
1086 /* set up our bulk in urb */
Donald Lee093ea2d2012-03-14 15:26:33 +08001087 if ((serial->num_ports == 2)
1088 && ((((__u16)port->number -
1089 (__u16)(port->serial->minor)) % 2) != 0)) {
1090 usb_fill_bulk_urb(mos7840_port->read_urb,
1091 serial->dev,
1092 usb_rcvbulkpipe(serial->dev,
1093 (port->bulk_in_endpointAddress) + 2),
1094 port->bulk_in_buffer,
1095 mos7840_port->read_urb->transfer_buffer_length,
1096 mos7840_bulk_in_callback, mos7840_port);
1097 } else {
1098 usb_fill_bulk_urb(mos7840_port->read_urb,
1099 serial->dev,
1100 usb_rcvbulkpipe(serial->dev,
1101 port->bulk_in_endpointAddress),
1102 port->bulk_in_buffer,
1103 mos7840_port->read_urb->transfer_buffer_length,
1104 mos7840_bulk_in_callback, mos7840_port);
1105 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05001106
Tony Cook84fe6e72009-04-18 22:55:06 +09301107 dbg("mos7840_open: bulkin endpoint is %d",
Paul B Schroeder3f542972006-08-31 19:41:47 -05001108 port->bulk_in_endpointAddress);
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -08001109 mos7840_port->read_urb_busy = true;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001110 response = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL);
1111 if (response) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001112 dev_err(&port->dev, "%s - Error %d submitting control urb\n",
1113 __func__, response);
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -08001114 mos7840_port->read_urb_busy = false;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001115 }
1116
1117 /* initialize our wait queues */
1118 init_waitqueue_head(&mos7840_port->wait_chase);
1119 init_waitqueue_head(&mos7840_port->delta_msr_wait);
1120
1121 /* initialize our icount structure */
1122 memset(&(mos7840_port->icount), 0x00, sizeof(mos7840_port->icount));
1123
1124 /* initialize our port settings */
Alan Cox880af9d2008-07-22 11:16:12 +01001125 /* Must set to enable ints! */
1126 mos7840_port->shadowMCR = MCR_MASTER_IE;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001127 /* send a open port command */
1128 mos7840_port->open = 1;
Alan Cox880af9d2008-07-22 11:16:12 +01001129 /* mos7840_change_port_settings(mos7840_port,old_termios); */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001130 mos7840_port->icount.tx = 0;
1131 mos7840_port->icount.rx = 0;
1132
Tony Cook84fe6e72009-04-18 22:55:06 +09301133 dbg("usb_serial serial:%p mos7840_port:%p\n usb_serial_port port:%p",
Alan Cox880af9d2008-07-22 11:16:12 +01001134 serial, mos7840_port, port);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001135
Tony Cook84fe6e72009-04-18 22:55:06 +09301136 dbg ("%s leave", __func__);
1137
Paul B Schroeder3f542972006-08-31 19:41:47 -05001138 return 0;
1139
1140}
1141
1142/*****************************************************************************
1143 * mos7840_chars_in_buffer
1144 * this function is called by the tty driver when it wants to know how many
1145 * bytes of data we currently have outstanding in the port (data that has
1146 * been written, but hasn't made it out the port yet)
1147 * If successful, we return the number of bytes left to be written in the
1148 * system,
Alan Cox95da3102008-07-22 11:09:07 +01001149 * Otherwise we return zero.
Paul B Schroeder3f542972006-08-31 19:41:47 -05001150 *****************************************************************************/
1151
Alan Cox95da3102008-07-22 11:09:07 +01001152static int mos7840_chars_in_buffer(struct tty_struct *tty)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001153{
Alan Cox95da3102008-07-22 11:09:07 +01001154 struct usb_serial_port *port = tty->driver_data;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001155 int i;
1156 int chars = 0;
Oliver Neukum0de9a702007-03-16 20:28:28 +01001157 unsigned long flags;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001158 struct moschip_port *mos7840_port;
1159
Tony Cook84fe6e72009-04-18 22:55:06 +09301160 dbg("%s", " mos7840_chars_in_buffer:entering ...........");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001161
Harvey Harrison441b62c2008-03-03 16:08:34 -08001162 if (mos7840_port_paranoia_check(port, __func__)) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301163 dbg("%s", "Invalid port");
Alan Cox95da3102008-07-22 11:09:07 +01001164 return 0;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001165 }
1166
1167 mos7840_port = mos7840_get_port_private(port);
1168 if (mos7840_port == NULL) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301169 dbg("%s", "mos7840_break:leaving ...........");
Alan Cox95da3102008-07-22 11:09:07 +01001170 return 0;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001171 }
1172
Alan Cox880af9d2008-07-22 11:16:12 +01001173 spin_lock_irqsave(&mos7840_port->pool_lock, flags);
Mark Ferrell4893ce52012-07-24 14:15:13 -05001174 for (i = 0; i < NUM_URBS; ++i) {
1175 if (mos7840_port->busy[i]) {
1176 struct urb *urb = mos7840_port->write_urb_pool[i];
1177 chars += urb->transfer_buffer_length;
1178 }
1179 }
Alan Cox880af9d2008-07-22 11:16:12 +01001180 spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
Harvey Harrison441b62c2008-03-03 16:08:34 -08001181 dbg("%s - returns %d", __func__, chars);
Oliver Neukum0de9a702007-03-16 20:28:28 +01001182 return chars;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001183
1184}
1185
Paul B Schroeder3f542972006-08-31 19:41:47 -05001186/*****************************************************************************
1187 * mos7840_close
1188 * this function is called by the tty driver when a port is closed
1189 *****************************************************************************/
1190
Alan Cox335f8512009-06-11 12:26:29 +01001191static void mos7840_close(struct usb_serial_port *port)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001192{
1193 struct usb_serial *serial;
1194 struct moschip_port *mos7840_port;
Oliver Neukum0de9a702007-03-16 20:28:28 +01001195 struct moschip_port *port0;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001196 int j;
1197 __u16 Data;
1198
Tony Cook84fe6e72009-04-18 22:55:06 +09301199 dbg("%s", "mos7840_close:entering...");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001200
Harvey Harrison441b62c2008-03-03 16:08:34 -08001201 if (mos7840_port_paranoia_check(port, __func__)) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301202 dbg("%s", "Port Paranoia failed");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001203 return;
1204 }
1205
Harvey Harrison441b62c2008-03-03 16:08:34 -08001206 serial = mos7840_get_usb_serial(port, __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001207 if (!serial) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301208 dbg("%s", "Serial Paranoia failed");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001209 return;
1210 }
1211
1212 mos7840_port = mos7840_get_port_private(port);
Oliver Neukum0de9a702007-03-16 20:28:28 +01001213 port0 = mos7840_get_port_private(serial->port[0]);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001214
Oliver Neukum0de9a702007-03-16 20:28:28 +01001215 if (mos7840_port == NULL || port0 == NULL)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001216 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001217
1218 for (j = 0; j < NUM_URBS; ++j)
1219 usb_kill_urb(mos7840_port->write_urb_pool[j]);
1220
1221 /* Freeing Write URBs */
1222 for (j = 0; j < NUM_URBS; ++j) {
1223 if (mos7840_port->write_urb_pool[j]) {
1224 if (mos7840_port->write_urb_pool[j]->transfer_buffer)
1225 kfree(mos7840_port->write_urb_pool[j]->
1226 transfer_buffer);
1227
1228 usb_free_urb(mos7840_port->write_urb_pool[j]);
1229 }
1230 }
1231
Paul B Schroeder3f542972006-08-31 19:41:47 -05001232 /* While closing port, shutdown all bulk read, write *
1233 * and interrupt read if they exists */
1234 if (serial->dev) {
Paul B Schroeder3f542972006-08-31 19:41:47 -05001235 if (mos7840_port->write_urb) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301236 dbg("%s", "Shutdown bulk write");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001237 usb_kill_urb(mos7840_port->write_urb);
1238 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05001239 if (mos7840_port->read_urb) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301240 dbg("%s", "Shutdown bulk read");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001241 usb_kill_urb(mos7840_port->read_urb);
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -08001242 mos7840_port->read_urb_busy = false;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001243 }
1244 if ((&mos7840_port->control_urb)) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301245 dbg("%s", "Shutdown control read");
Alan Cox880af9d2008-07-22 11:16:12 +01001246 /*/ usb_kill_urb (mos7840_port->control_urb); */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001247 }
1248 }
Alan Cox880af9d2008-07-22 11:16:12 +01001249/* if(mos7840_port->ctrl_buf != NULL) */
1250/* kfree(mos7840_port->ctrl_buf); */
Oliver Neukum0de9a702007-03-16 20:28:28 +01001251 port0->open_ports--;
Tony Cook84fe6e72009-04-18 22:55:06 +09301252 dbg("mos7840_num_open_ports in close%d:in port%d",
Oliver Neukum0de9a702007-03-16 20:28:28 +01001253 port0->open_ports, port->number);
1254 if (port0->open_ports == 0) {
Paul B Schroeder3f542972006-08-31 19:41:47 -05001255 if (serial->port[0]->interrupt_in_urb) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301256 dbg("%s", "Shutdown interrupt_in_urb");
Oliver Neukum0de9a702007-03-16 20:28:28 +01001257 usb_kill_urb(serial->port[0]->interrupt_in_urb);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001258 }
1259 }
1260
1261 if (mos7840_port->write_urb) {
1262 /* if this urb had a transfer buffer already (old tx) free it */
Alan Cox880af9d2008-07-22 11:16:12 +01001263 if (mos7840_port->write_urb->transfer_buffer != NULL)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001264 kfree(mos7840_port->write_urb->transfer_buffer);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001265 usb_free_urb(mos7840_port->write_urb);
1266 }
1267
1268 Data = 0x0;
1269 mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
1270
1271 Data = 0x00;
1272 mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
1273
1274 mos7840_port->open = 0;
1275
Tony Cook84fe6e72009-04-18 22:55:06 +09301276 dbg("%s", "Leaving ............");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001277}
1278
1279/************************************************************************
1280 *
1281 * mos7840_block_until_chase_response
1282 *
1283 * This function will block the close until one of the following:
1284 * 1. Response to our Chase comes from mos7840
Joe Perchesdc0d5c12007-12-17 11:40:18 -08001285 * 2. A timeout of 10 seconds without activity has expired
Paul B Schroeder3f542972006-08-31 19:41:47 -05001286 * (1K of mos7840 data @ 2400 baud ==> 4 sec to empty)
1287 *
1288 ************************************************************************/
1289
Alan Cox95da3102008-07-22 11:09:07 +01001290static void mos7840_block_until_chase_response(struct tty_struct *tty,
1291 struct moschip_port *mos7840_port)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001292{
1293 int timeout = 1 * HZ;
1294 int wait = 10;
1295 int count;
1296
1297 while (1) {
Alan Cox95da3102008-07-22 11:09:07 +01001298 count = mos7840_chars_in_buffer(tty);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001299
1300 /* Check for Buffer status */
Alan Cox880af9d2008-07-22 11:16:12 +01001301 if (count <= 0)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001302 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001303
1304 /* Block the thread for a while */
1305 interruptible_sleep_on_timeout(&mos7840_port->wait_chase,
1306 timeout);
1307 /* No activity.. count down section */
1308 wait--;
1309 if (wait == 0) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001310 dbg("%s - TIMEOUT", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001311 return;
1312 } else {
Joe Perchesdc0d5c12007-12-17 11:40:18 -08001313 /* Reset timeout value back to seconds */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001314 wait = 10;
1315 }
1316 }
1317
1318}
1319
1320/*****************************************************************************
1321 * mos7840_break
1322 * this function sends a break to the port
1323 *****************************************************************************/
Alan Cox95da3102008-07-22 11:09:07 +01001324static void mos7840_break(struct tty_struct *tty, int break_state)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001325{
Alan Cox95da3102008-07-22 11:09:07 +01001326 struct usb_serial_port *port = tty->driver_data;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001327 unsigned char data;
1328 struct usb_serial *serial;
1329 struct moschip_port *mos7840_port;
1330
Tony Cook84fe6e72009-04-18 22:55:06 +09301331 dbg("%s", "Entering ...........");
1332 dbg("mos7840_break: Start");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001333
Harvey Harrison441b62c2008-03-03 16:08:34 -08001334 if (mos7840_port_paranoia_check(port, __func__)) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301335 dbg("%s", "Port Paranoia failed");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001336 return;
1337 }
1338
Harvey Harrison441b62c2008-03-03 16:08:34 -08001339 serial = mos7840_get_usb_serial(port, __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001340 if (!serial) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301341 dbg("%s", "Serial Paranoia failed");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001342 return;
1343 }
1344
1345 mos7840_port = mos7840_get_port_private(port);
1346
Alan Cox880af9d2008-07-22 11:16:12 +01001347 if (mos7840_port == NULL)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001348 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001349
Alan Cox95da3102008-07-22 11:09:07 +01001350 if (serial->dev)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001351 /* flush and block until tx is empty */
Alan Cox95da3102008-07-22 11:09:07 +01001352 mos7840_block_until_chase_response(tty, mos7840_port);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001353
Alan Cox95da3102008-07-22 11:09:07 +01001354 if (break_state == -1)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001355 data = mos7840_port->shadowLCR | LCR_SET_BREAK;
Alan Cox95da3102008-07-22 11:09:07 +01001356 else
Paul B Schroeder3f542972006-08-31 19:41:47 -05001357 data = mos7840_port->shadowLCR & ~LCR_SET_BREAK;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001358
Alan Cox6b447f042009-01-02 13:48:56 +00001359 /* FIXME: no locking on shadowLCR anywhere in driver */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001360 mos7840_port->shadowLCR = data;
Tony Cook84fe6e72009-04-18 22:55:06 +09301361 dbg("mcs7840_break mos7840_port->shadowLCR is %x",
Paul B Schroeder3f542972006-08-31 19:41:47 -05001362 mos7840_port->shadowLCR);
1363 mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER,
1364 mos7840_port->shadowLCR);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001365}
1366
1367/*****************************************************************************
1368 * mos7840_write_room
1369 * this function is called by the tty driver when it wants to know how many
1370 * bytes of data we can accept for a specific port.
1371 * If successful, we return the amount of room that we have for this port
1372 * Otherwise we return a negative error number.
1373 *****************************************************************************/
1374
Alan Cox95da3102008-07-22 11:09:07 +01001375static int mos7840_write_room(struct tty_struct *tty)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001376{
Alan Cox95da3102008-07-22 11:09:07 +01001377 struct usb_serial_port *port = tty->driver_data;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001378 int i;
1379 int room = 0;
Oliver Neukum0de9a702007-03-16 20:28:28 +01001380 unsigned long flags;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001381 struct moschip_port *mos7840_port;
1382
Tony Cook84fe6e72009-04-18 22:55:06 +09301383 dbg("%s", " mos7840_write_room:entering ...........");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001384
Harvey Harrison441b62c2008-03-03 16:08:34 -08001385 if (mos7840_port_paranoia_check(port, __func__)) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301386 dbg("%s", "Invalid port");
1387 dbg("%s", " mos7840_write_room:leaving ...........");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001388 return -1;
1389 }
1390
1391 mos7840_port = mos7840_get_port_private(port);
1392 if (mos7840_port == NULL) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301393 dbg("%s", "mos7840_break:leaving ...........");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001394 return -1;
1395 }
1396
Oliver Neukum0de9a702007-03-16 20:28:28 +01001397 spin_lock_irqsave(&mos7840_port->pool_lock, flags);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001398 for (i = 0; i < NUM_URBS; ++i) {
Alan Cox880af9d2008-07-22 11:16:12 +01001399 if (!mos7840_port->busy[i])
Paul B Schroeder3f542972006-08-31 19:41:47 -05001400 room += URB_TRANSFER_BUFFER_SIZE;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001401 }
Oliver Neukum0de9a702007-03-16 20:28:28 +01001402 spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001403
Oliver Neukum0de9a702007-03-16 20:28:28 +01001404 room = (room == 0) ? 0 : room - URB_TRANSFER_BUFFER_SIZE + 1;
Harvey Harrison441b62c2008-03-03 16:08:34 -08001405 dbg("%s - returns %d", __func__, room);
Oliver Neukum0de9a702007-03-16 20:28:28 +01001406 return room;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001407
1408}
1409
1410/*****************************************************************************
1411 * mos7840_write
1412 * this function is called by the tty driver when data should be written to
1413 * the port.
1414 * If successful, we return the number of bytes written, otherwise we
1415 * return a negative error number.
1416 *****************************************************************************/
1417
Alan Cox95da3102008-07-22 11:09:07 +01001418static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
Paul B Schroeder3f542972006-08-31 19:41:47 -05001419 const unsigned char *data, int count)
1420{
1421 int status;
1422 int i;
1423 int bytes_sent = 0;
1424 int transfer_size;
Oliver Neukum0de9a702007-03-16 20:28:28 +01001425 unsigned long flags;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001426
1427 struct moschip_port *mos7840_port;
1428 struct usb_serial *serial;
1429 struct urb *urb;
Alan Cox880af9d2008-07-22 11:16:12 +01001430 /* __u16 Data; */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001431 const unsigned char *current_position = data;
1432 unsigned char *data1;
Tony Cook84fe6e72009-04-18 22:55:06 +09301433 dbg("%s", "entering ...........");
1434 /* dbg("mos7840_write: mos7840_port->shadowLCR is %x",
Alan Cox880af9d2008-07-22 11:16:12 +01001435 mos7840_port->shadowLCR); */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001436
1437#ifdef NOTMOS7840
1438 Data = 0x00;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001439 status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
1440 mos7840_port->shadowLCR = Data;
Tony Cook84fe6e72009-04-18 22:55:06 +09301441 dbg("mos7840_write: LINE_CONTROL_REGISTER is %x", Data);
1442 dbg("mos7840_write: mos7840_port->shadowLCR is %x",
Paul B Schroeder3f542972006-08-31 19:41:47 -05001443 mos7840_port->shadowLCR);
1444
Alan Cox880af9d2008-07-22 11:16:12 +01001445 /* Data = 0x03; */
1446 /* status = mos7840_set_uart_reg(port,LINE_CONTROL_REGISTER,Data); */
1447 /* mos7840_port->shadowLCR=Data;//Need to add later */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001448
Alan Cox880af9d2008-07-22 11:16:12 +01001449 Data |= SERIAL_LCR_DLAB; /* data latch enable in LCR 0x80 */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001450 status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
1451
Alan Cox880af9d2008-07-22 11:16:12 +01001452 /* Data = 0x0c; */
1453 /* status = mos7840_set_uart_reg(port,DIVISOR_LATCH_LSB,Data); */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001454 Data = 0x00;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001455 status = mos7840_get_uart_reg(port, DIVISOR_LATCH_LSB, &Data);
Tony Cook84fe6e72009-04-18 22:55:06 +09301456 dbg("mos7840_write:DLL value is %x", Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001457
1458 Data = 0x0;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001459 status = mos7840_get_uart_reg(port, DIVISOR_LATCH_MSB, &Data);
Tony Cook84fe6e72009-04-18 22:55:06 +09301460 dbg("mos7840_write:DLM value is %x", Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001461
1462 Data = Data & ~SERIAL_LCR_DLAB;
Tony Cook84fe6e72009-04-18 22:55:06 +09301463 dbg("mos7840_write: mos7840_port->shadowLCR is %x",
Paul B Schroeder3f542972006-08-31 19:41:47 -05001464 mos7840_port->shadowLCR);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001465 status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
1466#endif
1467
Harvey Harrison441b62c2008-03-03 16:08:34 -08001468 if (mos7840_port_paranoia_check(port, __func__)) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301469 dbg("%s", "Port Paranoia failed");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001470 return -1;
1471 }
1472
1473 serial = port->serial;
Harvey Harrison441b62c2008-03-03 16:08:34 -08001474 if (mos7840_serial_paranoia_check(serial, __func__)) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301475 dbg("%s", "Serial Paranoia failed");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001476 return -1;
1477 }
1478
1479 mos7840_port = mos7840_get_port_private(port);
1480 if (mos7840_port == NULL) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301481 dbg("%s", "mos7840_port is NULL");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001482 return -1;
1483 }
1484
1485 /* try to find a free urb in the list */
1486 urb = NULL;
1487
Oliver Neukum0de9a702007-03-16 20:28:28 +01001488 spin_lock_irqsave(&mos7840_port->pool_lock, flags);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001489 for (i = 0; i < NUM_URBS; ++i) {
Oliver Neukum0de9a702007-03-16 20:28:28 +01001490 if (!mos7840_port->busy[i]) {
1491 mos7840_port->busy[i] = 1;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001492 urb = mos7840_port->write_urb_pool[i];
Tony Cook84fe6e72009-04-18 22:55:06 +09301493 dbg("URB:%d", i);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001494 break;
1495 }
1496 }
Oliver Neukum0de9a702007-03-16 20:28:28 +01001497 spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001498
1499 if (urb == NULL) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001500 dbg("%s - no more free urbs", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001501 goto exit;
1502 }
1503
1504 if (urb->transfer_buffer == NULL) {
1505 urb->transfer_buffer =
1506 kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
1507
1508 if (urb->transfer_buffer == NULL) {
Johan Hovold22a416c2012-02-10 13:20:51 +01001509 dev_err_console(port, "%s no more kernel memory...\n",
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001510 __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001511 goto exit;
1512 }
1513 }
1514 transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
1515
Al Viro97c49652006-10-09 20:29:03 +01001516 memcpy(urb->transfer_buffer, current_position, transfer_size);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001517
1518 /* fill urb with data and submit */
Donald Lee093ea2d2012-03-14 15:26:33 +08001519 if ((serial->num_ports == 2)
1520 && ((((__u16)port->number -
1521 (__u16)(port->serial->minor)) % 2) != 0)) {
1522 usb_fill_bulk_urb(urb,
1523 serial->dev,
1524 usb_sndbulkpipe(serial->dev,
1525 (port->bulk_out_endpointAddress) + 2),
1526 urb->transfer_buffer,
1527 transfer_size,
1528 mos7840_bulk_out_data_callback, mos7840_port);
1529 } else {
1530 usb_fill_bulk_urb(urb,
1531 serial->dev,
1532 usb_sndbulkpipe(serial->dev,
1533 port->bulk_out_endpointAddress),
1534 urb->transfer_buffer,
1535 transfer_size,
1536 mos7840_bulk_out_data_callback, mos7840_port);
1537 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05001538
1539 data1 = urb->transfer_buffer;
Tony Cook84fe6e72009-04-18 22:55:06 +09301540 dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001541
1542 /* send it down the pipe */
1543 status = usb_submit_urb(urb, GFP_ATOMIC);
1544
1545 if (status) {
Oliver Neukum0de9a702007-03-16 20:28:28 +01001546 mos7840_port->busy[i] = 0;
Johan Hovold22a416c2012-02-10 13:20:51 +01001547 dev_err_console(port, "%s - usb_submit_urb(write bulk) failed "
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001548 "with status = %d\n", __func__, status);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001549 bytes_sent = status;
1550 goto exit;
1551 }
1552 bytes_sent = transfer_size;
1553 mos7840_port->icount.tx += transfer_size;
Oliver Neukum0de9a702007-03-16 20:28:28 +01001554 smp_wmb();
Tony Cook84fe6e72009-04-18 22:55:06 +09301555 dbg("mos7840_port->icount.tx is %d:", mos7840_port->icount.tx);
Alan Cox95da3102008-07-22 11:09:07 +01001556exit:
Paul B Schroeder3f542972006-08-31 19:41:47 -05001557 return bytes_sent;
1558
1559}
1560
1561/*****************************************************************************
1562 * mos7840_throttle
1563 * this function is called by the tty driver when it wants to stop the data
1564 * being read from the port.
1565 *****************************************************************************/
1566
Alan Cox95da3102008-07-22 11:09:07 +01001567static void mos7840_throttle(struct tty_struct *tty)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001568{
Alan Cox95da3102008-07-22 11:09:07 +01001569 struct usb_serial_port *port = tty->driver_data;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001570 struct moschip_port *mos7840_port;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001571 int status;
1572
Harvey Harrison441b62c2008-03-03 16:08:34 -08001573 if (mos7840_port_paranoia_check(port, __func__)) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301574 dbg("%s", "Invalid port");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001575 return;
1576 }
1577
Tony Cook84fe6e72009-04-18 22:55:06 +09301578 dbg("- port %d", port->number);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001579
1580 mos7840_port = mos7840_get_port_private(port);
1581
1582 if (mos7840_port == NULL)
1583 return;
1584
1585 if (!mos7840_port->open) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301586 dbg("%s", "port not opened");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001587 return;
1588 }
1589
Tony Cook84fe6e72009-04-18 22:55:06 +09301590 dbg("%s", "Entering ..........");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001591
Paul B Schroeder3f542972006-08-31 19:41:47 -05001592 /* if we are implementing XON/XOFF, send the stop character */
1593 if (I_IXOFF(tty)) {
1594 unsigned char stop_char = STOP_CHAR(tty);
Alan Cox95da3102008-07-22 11:09:07 +01001595 status = mos7840_write(tty, port, &stop_char, 1);
1596 if (status <= 0)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001597 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001598 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05001599 /* if we are implementing RTS/CTS, toggle that line */
1600 if (tty->termios->c_cflag & CRTSCTS) {
1601 mos7840_port->shadowMCR &= ~MCR_RTS;
Alan Cox95da3102008-07-22 11:09:07 +01001602 status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
Paul B Schroeder3f542972006-08-31 19:41:47 -05001603 mos7840_port->shadowMCR);
Alan Cox95da3102008-07-22 11:09:07 +01001604 if (status < 0)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001605 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001606 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05001607}
1608
1609/*****************************************************************************
1610 * mos7840_unthrottle
Alan Cox880af9d2008-07-22 11:16:12 +01001611 * this function is called by the tty driver when it wants to resume
1612 * the data being read from the port (called after mos7840_throttle is
1613 * called)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001614 *****************************************************************************/
Alan Cox95da3102008-07-22 11:09:07 +01001615static void mos7840_unthrottle(struct tty_struct *tty)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001616{
Alan Cox95da3102008-07-22 11:09:07 +01001617 struct usb_serial_port *port = tty->driver_data;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001618 int status;
1619 struct moschip_port *mos7840_port = mos7840_get_port_private(port);
1620
Harvey Harrison441b62c2008-03-03 16:08:34 -08001621 if (mos7840_port_paranoia_check(port, __func__)) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301622 dbg("%s", "Invalid port");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001623 return;
1624 }
1625
1626 if (mos7840_port == NULL)
1627 return;
1628
1629 if (!mos7840_port->open) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001630 dbg("%s - port not opened", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001631 return;
1632 }
1633
Tony Cook84fe6e72009-04-18 22:55:06 +09301634 dbg("%s", "Entering ..........");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001635
Paul B Schroeder3f542972006-08-31 19:41:47 -05001636 /* if we are implementing XON/XOFF, send the start character */
1637 if (I_IXOFF(tty)) {
1638 unsigned char start_char = START_CHAR(tty);
Alan Cox95da3102008-07-22 11:09:07 +01001639 status = mos7840_write(tty, port, &start_char, 1);
1640 if (status <= 0)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001641 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001642 }
1643
1644 /* if we are implementing RTS/CTS, toggle that line */
1645 if (tty->termios->c_cflag & CRTSCTS) {
1646 mos7840_port->shadowMCR |= MCR_RTS;
Alan Cox95da3102008-07-22 11:09:07 +01001647 status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
Paul B Schroeder3f542972006-08-31 19:41:47 -05001648 mos7840_port->shadowMCR);
Alan Cox95da3102008-07-22 11:09:07 +01001649 if (status < 0)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001650 return;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001651 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05001652}
1653
Alan Cox60b33c12011-02-14 16:26:14 +00001654static int mos7840_tiocmget(struct tty_struct *tty)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001655{
Alan Cox95da3102008-07-22 11:09:07 +01001656 struct usb_serial_port *port = tty->driver_data;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001657 struct moschip_port *mos7840_port;
1658 unsigned int result;
1659 __u16 msr;
1660 __u16 mcr;
Alan Cox880af9d2008-07-22 11:16:12 +01001661 int status;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001662 mos7840_port = mos7840_get_port_private(port);
1663
Harvey Harrison441b62c2008-03-03 16:08:34 -08001664 dbg("%s - port %d", __func__, port->number);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001665
1666 if (mos7840_port == NULL)
1667 return -ENODEV;
1668
1669 status = mos7840_get_uart_reg(port, MODEM_STATUS_REGISTER, &msr);
Johan Hovolda4f40862013-10-09 17:01:09 +02001670 if (status != 1)
1671 return -EIO;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001672 status = mos7840_get_uart_reg(port, MODEM_CONTROL_REGISTER, &mcr);
Johan Hovolda4f40862013-10-09 17:01:09 +02001673 if (status != 1)
1674 return -EIO;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001675 result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0)
1676 | ((mcr & MCR_RTS) ? TIOCM_RTS : 0)
1677 | ((mcr & MCR_LOOPBACK) ? TIOCM_LOOP : 0)
1678 | ((msr & MOS7840_MSR_CTS) ? TIOCM_CTS : 0)
1679 | ((msr & MOS7840_MSR_CD) ? TIOCM_CAR : 0)
1680 | ((msr & MOS7840_MSR_RI) ? TIOCM_RI : 0)
1681 | ((msr & MOS7840_MSR_DSR) ? TIOCM_DSR : 0);
1682
Harvey Harrison441b62c2008-03-03 16:08:34 -08001683 dbg("%s - 0x%04X", __func__, result);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001684
1685 return result;
1686}
1687
Alan Cox20b9d172011-02-14 16:26:50 +00001688static int mos7840_tiocmset(struct tty_struct *tty,
Paul B Schroeder3f542972006-08-31 19:41:47 -05001689 unsigned int set, unsigned int clear)
1690{
Alan Cox95da3102008-07-22 11:09:07 +01001691 struct usb_serial_port *port = tty->driver_data;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001692 struct moschip_port *mos7840_port;
1693 unsigned int mcr;
Roel Kluin87521c42008-04-17 06:16:24 +02001694 int status;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001695
Harvey Harrison441b62c2008-03-03 16:08:34 -08001696 dbg("%s - port %d", __func__, port->number);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001697
1698 mos7840_port = mos7840_get_port_private(port);
1699
1700 if (mos7840_port == NULL)
1701 return -ENODEV;
1702
Alan Coxe2984492008-02-20 20:51:45 +00001703 /* FIXME: What locks the port registers ? */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001704 mcr = mos7840_port->shadowMCR;
1705 if (clear & TIOCM_RTS)
1706 mcr &= ~MCR_RTS;
1707 if (clear & TIOCM_DTR)
1708 mcr &= ~MCR_DTR;
1709 if (clear & TIOCM_LOOP)
1710 mcr &= ~MCR_LOOPBACK;
1711
1712 if (set & TIOCM_RTS)
1713 mcr |= MCR_RTS;
1714 if (set & TIOCM_DTR)
1715 mcr |= MCR_DTR;
1716 if (set & TIOCM_LOOP)
1717 mcr |= MCR_LOOPBACK;
1718
1719 mos7840_port->shadowMCR = mcr;
1720
Paul B Schroeder3f542972006-08-31 19:41:47 -05001721 status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr);
1722 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301723 dbg("setting MODEM_CONTROL_REGISTER Failed");
Roel Kluin87521c42008-04-17 06:16:24 +02001724 return status;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001725 }
1726
1727 return 0;
1728}
1729
1730/*****************************************************************************
1731 * mos7840_calc_baud_rate_divisor
1732 * this function calculates the proper baud rate divisor for the specified
1733 * baud rate.
1734 *****************************************************************************/
1735static int mos7840_calc_baud_rate_divisor(int baudRate, int *divisor,
Alan Cox880af9d2008-07-22 11:16:12 +01001736 __u16 *clk_sel_val)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001737{
1738
Harvey Harrison441b62c2008-03-03 16:08:34 -08001739 dbg("%s - %d", __func__, baudRate);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001740
1741 if (baudRate <= 115200) {
1742 *divisor = 115200 / baudRate;
1743 *clk_sel_val = 0x0;
1744 }
1745 if ((baudRate > 115200) && (baudRate <= 230400)) {
1746 *divisor = 230400 / baudRate;
1747 *clk_sel_val = 0x10;
1748 } else if ((baudRate > 230400) && (baudRate <= 403200)) {
1749 *divisor = 403200 / baudRate;
1750 *clk_sel_val = 0x20;
1751 } else if ((baudRate > 403200) && (baudRate <= 460800)) {
1752 *divisor = 460800 / baudRate;
1753 *clk_sel_val = 0x30;
1754 } else if ((baudRate > 460800) && (baudRate <= 806400)) {
1755 *divisor = 806400 / baudRate;
1756 *clk_sel_val = 0x40;
1757 } else if ((baudRate > 806400) && (baudRate <= 921600)) {
1758 *divisor = 921600 / baudRate;
1759 *clk_sel_val = 0x50;
1760 } else if ((baudRate > 921600) && (baudRate <= 1572864)) {
1761 *divisor = 1572864 / baudRate;
1762 *clk_sel_val = 0x60;
1763 } else if ((baudRate > 1572864) && (baudRate <= 3145728)) {
1764 *divisor = 3145728 / baudRate;
1765 *clk_sel_val = 0x70;
1766 }
1767 return 0;
1768
1769#ifdef NOTMCS7840
1770
1771 for (i = 0; i < ARRAY_SIZE(mos7840_divisor_table); i++) {
1772 if (mos7840_divisor_table[i].BaudRate == baudrate) {
1773 *divisor = mos7840_divisor_table[i].Divisor;
1774 return 0;
1775 }
1776 }
1777
1778 /* After trying for all the standard baud rates *
1779 * Try calculating the divisor for this baud rate */
1780
1781 if (baudrate > 75 && baudrate < 230400) {
1782 /* get the divisor */
1783 custom = (__u16) (230400L / baudrate);
1784
1785 /* Check for round off */
1786 round1 = (__u16) (2304000L / baudrate);
1787 round = (__u16) (round1 - (custom * 10));
Alan Cox880af9d2008-07-22 11:16:12 +01001788 if (round > 4)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001789 custom++;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001790 *divisor = custom;
1791
Tony Cook84fe6e72009-04-18 22:55:06 +09301792 dbg(" Baud %d = %d", baudrate, custom);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001793 return 0;
1794 }
1795
Tony Cook84fe6e72009-04-18 22:55:06 +09301796 dbg("%s", " Baud calculation Failed...");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001797 return -1;
1798#endif
1799}
1800
1801/*****************************************************************************
1802 * mos7840_send_cmd_write_baud_rate
1803 * this function sends the proper command to change the baud rate of the
1804 * specified port.
1805 *****************************************************************************/
1806
1807static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
1808 int baudRate)
1809{
1810 int divisor = 0;
1811 int status;
1812 __u16 Data;
1813 unsigned char number;
1814 __u16 clk_sel_val;
1815 struct usb_serial_port *port;
1816
1817 if (mos7840_port == NULL)
1818 return -1;
1819
1820 port = (struct usb_serial_port *)mos7840_port->port;
Harvey Harrison441b62c2008-03-03 16:08:34 -08001821 if (mos7840_port_paranoia_check(port, __func__)) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301822 dbg("%s", "Invalid port");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001823 return -1;
1824 }
1825
Harvey Harrison441b62c2008-03-03 16:08:34 -08001826 if (mos7840_serial_paranoia_check(port->serial, __func__)) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301827 dbg("%s", "Invalid Serial");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001828 return -1;
1829 }
1830
Tony Cook84fe6e72009-04-18 22:55:06 +09301831 dbg("%s", "Entering ..........");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001832
1833 number = mos7840_port->port->number - mos7840_port->port->serial->minor;
1834
Harvey Harrison441b62c2008-03-03 16:08:34 -08001835 dbg("%s - port = %d, baud = %d", __func__,
Paul B Schroeder3f542972006-08-31 19:41:47 -05001836 mos7840_port->port->number, baudRate);
Alan Cox880af9d2008-07-22 11:16:12 +01001837 /* reset clk_uart_sel in spregOffset */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001838 if (baudRate > 115200) {
1839#ifdef HW_flow_control
Alan Cox880af9d2008-07-22 11:16:12 +01001840 /* NOTE: need to see the pther register to modify */
1841 /* setting h/w flow control bit to 1 */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001842 Data = 0x2b;
1843 mos7840_port->shadowMCR = Data;
Alan Cox880af9d2008-07-22 11:16:12 +01001844 status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
1845 Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001846 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301847 dbg("Writing spreg failed in set_serial_baud");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001848 return -1;
1849 }
1850#endif
1851
1852 } else {
1853#ifdef HW_flow_control
Donald Lee093ea2d2012-03-14 15:26:33 +08001854 /* setting h/w flow control bit to 0 */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001855 Data = 0xb;
1856 mos7840_port->shadowMCR = Data;
Alan Cox880af9d2008-07-22 11:16:12 +01001857 status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
1858 Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001859 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301860 dbg("Writing spreg failed in set_serial_baud");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001861 return -1;
1862 }
1863#endif
1864
1865 }
1866
Alan Cox880af9d2008-07-22 11:16:12 +01001867 if (1) { /* baudRate <= 115200) */
Paul B Schroeder3f542972006-08-31 19:41:47 -05001868 clk_sel_val = 0x0;
1869 Data = 0x0;
Alan Cox880af9d2008-07-22 11:16:12 +01001870 status = mos7840_calc_baud_rate_divisor(baudRate, &divisor,
Paul B Schroeder3f542972006-08-31 19:41:47 -05001871 &clk_sel_val);
Alan Cox880af9d2008-07-22 11:16:12 +01001872 status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset,
1873 &Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001874 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301875 dbg("reading spreg failed in set_serial_baud");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001876 return -1;
1877 }
1878 Data = (Data & 0x8f) | clk_sel_val;
Alan Cox880af9d2008-07-22 11:16:12 +01001879 status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset,
1880 Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001881 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301882 dbg("Writing spreg failed in set_serial_baud");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001883 return -1;
1884 }
1885 /* Calculate the Divisor */
1886
1887 if (status) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001888 dev_err(&port->dev, "%s - bad baud rate\n", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001889 return status;
1890 }
1891 /* Enable access to divisor latch */
1892 Data = mos7840_port->shadowLCR | SERIAL_LCR_DLAB;
1893 mos7840_port->shadowLCR = Data;
1894 mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
1895
1896 /* Write the divisor */
1897 Data = (unsigned char)(divisor & 0xff);
Tony Cook84fe6e72009-04-18 22:55:06 +09301898 dbg("set_serial_baud Value to write DLL is %x", Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001899 mos7840_set_uart_reg(port, DIVISOR_LATCH_LSB, Data);
1900
1901 Data = (unsigned char)((divisor & 0xff00) >> 8);
Tony Cook84fe6e72009-04-18 22:55:06 +09301902 dbg("set_serial_baud Value to write DLM is %x", Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001903 mos7840_set_uart_reg(port, DIVISOR_LATCH_MSB, Data);
1904
1905 /* Disable access to divisor latch */
1906 Data = mos7840_port->shadowLCR & ~SERIAL_LCR_DLAB;
1907 mos7840_port->shadowLCR = Data;
1908 mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
1909
1910 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05001911 return status;
1912}
1913
1914/*****************************************************************************
1915 * mos7840_change_port_settings
1916 * This routine is called to set the UART on the device to match
1917 * the specified new settings.
1918 *****************************************************************************/
1919
Alan Cox95da3102008-07-22 11:09:07 +01001920static void mos7840_change_port_settings(struct tty_struct *tty,
1921 struct moschip_port *mos7840_port, struct ktermios *old_termios)
Paul B Schroeder3f542972006-08-31 19:41:47 -05001922{
Paul B Schroeder3f542972006-08-31 19:41:47 -05001923 int baud;
1924 unsigned cflag;
1925 unsigned iflag;
1926 __u8 lData;
1927 __u8 lParity;
1928 __u8 lStop;
1929 int status;
1930 __u16 Data;
1931 struct usb_serial_port *port;
1932 struct usb_serial *serial;
1933
1934 if (mos7840_port == NULL)
1935 return;
1936
1937 port = (struct usb_serial_port *)mos7840_port->port;
1938
Harvey Harrison441b62c2008-03-03 16:08:34 -08001939 if (mos7840_port_paranoia_check(port, __func__)) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301940 dbg("%s", "Invalid port");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001941 return;
1942 }
1943
Harvey Harrison441b62c2008-03-03 16:08:34 -08001944 if (mos7840_serial_paranoia_check(port->serial, __func__)) {
Tony Cook84fe6e72009-04-18 22:55:06 +09301945 dbg("%s", "Invalid Serial");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001946 return;
1947 }
1948
1949 serial = port->serial;
1950
Harvey Harrison441b62c2008-03-03 16:08:34 -08001951 dbg("%s - port %d", __func__, mos7840_port->port->number);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001952
1953 if (!mos7840_port->open) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001954 dbg("%s - port not opened", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001955 return;
1956 }
1957
Tony Cook84fe6e72009-04-18 22:55:06 +09301958 dbg("%s", "Entering ..........");
Paul B Schroeder3f542972006-08-31 19:41:47 -05001959
1960 lData = LCR_BITS_8;
1961 lStop = LCR_STOP_1;
1962 lParity = LCR_PAR_NONE;
1963
1964 cflag = tty->termios->c_cflag;
1965 iflag = tty->termios->c_iflag;
1966
1967 /* Change the number of bits */
Colin Leitner7069fd02013-11-08 22:52:34 +01001968 switch (cflag & CSIZE) {
1969 case CS5:
1970 lData = LCR_BITS_5;
1971 break;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001972
Colin Leitner7069fd02013-11-08 22:52:34 +01001973 case CS6:
1974 lData = LCR_BITS_6;
1975 break;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001976
Colin Leitner7069fd02013-11-08 22:52:34 +01001977 case CS7:
1978 lData = LCR_BITS_7;
1979 break;
1980
1981 default:
1982 case CS8:
1983 lData = LCR_BITS_8;
1984 break;
Paul B Schroeder3f542972006-08-31 19:41:47 -05001985 }
Colin Leitner7069fd02013-11-08 22:52:34 +01001986
Paul B Schroeder3f542972006-08-31 19:41:47 -05001987 /* Change the Parity bit */
1988 if (cflag & PARENB) {
1989 if (cflag & PARODD) {
1990 lParity = LCR_PAR_ODD;
Harvey Harrison441b62c2008-03-03 16:08:34 -08001991 dbg("%s - parity = odd", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001992 } else {
1993 lParity = LCR_PAR_EVEN;
Harvey Harrison441b62c2008-03-03 16:08:34 -08001994 dbg("%s - parity = even", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001995 }
1996
1997 } else {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001998 dbg("%s - parity = none", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05001999 }
2000
Alan Cox880af9d2008-07-22 11:16:12 +01002001 if (cflag & CMSPAR)
Paul B Schroeder3f542972006-08-31 19:41:47 -05002002 lParity = lParity | 0x20;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002003
2004 /* Change the Stop bit */
2005 if (cflag & CSTOPB) {
2006 lStop = LCR_STOP_2;
Harvey Harrison441b62c2008-03-03 16:08:34 -08002007 dbg("%s - stop bits = 2", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002008 } else {
2009 lStop = LCR_STOP_1;
Harvey Harrison441b62c2008-03-03 16:08:34 -08002010 dbg("%s - stop bits = 1", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002011 }
2012
2013 /* Update the LCR with the correct value */
2014 mos7840_port->shadowLCR &=
2015 ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
2016 mos7840_port->shadowLCR |= (lData | lParity | lStop);
2017
Tony Cook84fe6e72009-04-18 22:55:06 +09302018 dbg("mos7840_change_port_settings mos7840_port->shadowLCR is %x",
Paul B Schroeder3f542972006-08-31 19:41:47 -05002019 mos7840_port->shadowLCR);
2020 /* Disable Interrupts */
2021 Data = 0x00;
2022 mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
2023
2024 Data = 0x00;
2025 mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
2026
2027 Data = 0xcf;
2028 mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
2029
2030 /* Send the updated LCR value to the mos7840 */
2031 Data = mos7840_port->shadowLCR;
2032
2033 mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
2034
2035 Data = 0x00b;
2036 mos7840_port->shadowMCR = Data;
2037 mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
2038 Data = 0x00b;
2039 mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
2040
2041 /* set up the MCR register and send it to the mos7840 */
2042
2043 mos7840_port->shadowMCR = MCR_MASTER_IE;
Alan Cox880af9d2008-07-22 11:16:12 +01002044 if (cflag & CBAUD)
Paul B Schroeder3f542972006-08-31 19:41:47 -05002045 mos7840_port->shadowMCR |= (MCR_DTR | MCR_RTS);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002046
Alan Cox880af9d2008-07-22 11:16:12 +01002047 if (cflag & CRTSCTS)
Paul B Schroeder3f542972006-08-31 19:41:47 -05002048 mos7840_port->shadowMCR |= (MCR_XON_ANY);
Alan Cox880af9d2008-07-22 11:16:12 +01002049 else
Paul B Schroeder3f542972006-08-31 19:41:47 -05002050 mos7840_port->shadowMCR &= ~(MCR_XON_ANY);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002051
2052 Data = mos7840_port->shadowMCR;
2053 mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
2054
2055 /* Determine divisor based on baud rate */
2056 baud = tty_get_baud_rate(tty);
2057
2058 if (!baud) {
2059 /* pick a default, any default... */
Tony Cook84fe6e72009-04-18 22:55:06 +09302060 dbg("%s", "Picked default baud...");
Paul B Schroeder3f542972006-08-31 19:41:47 -05002061 baud = 9600;
2062 }
2063
Harvey Harrison441b62c2008-03-03 16:08:34 -08002064 dbg("%s - baud rate = %d", __func__, baud);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002065 status = mos7840_send_cmd_write_baud_rate(mos7840_port, baud);
2066
2067 /* Enable Interrupts */
2068 Data = 0x0c;
2069 mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
2070
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -08002071 if (mos7840_port->read_urb_busy == false) {
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -08002072 mos7840_port->read_urb_busy = true;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002073 status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002074 if (status) {
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -08002075 dbg("usb_submit_urb(read bulk) failed, status = %d",
Paul B Schroeder3f542972006-08-31 19:41:47 -05002076 status);
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -08002077 mos7840_port->read_urb_busy = false;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002078 }
2079 }
Tony Cook84fe6e72009-04-18 22:55:06 +09302080 dbg("mos7840_change_port_settings mos7840_port->shadowLCR is End %x",
Paul B Schroeder3f542972006-08-31 19:41:47 -05002081 mos7840_port->shadowLCR);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002082}
2083
2084/*****************************************************************************
2085 * mos7840_set_termios
2086 * this function is called by the tty driver when it wants to change
2087 * the termios structure
2088 *****************************************************************************/
2089
Alan Cox95da3102008-07-22 11:09:07 +01002090static void mos7840_set_termios(struct tty_struct *tty,
2091 struct usb_serial_port *port,
Alan Cox606d0992006-12-08 02:38:45 -08002092 struct ktermios *old_termios)
Paul B Schroeder3f542972006-08-31 19:41:47 -05002093{
2094 int status;
2095 unsigned int cflag;
2096 struct usb_serial *serial;
2097 struct moschip_port *mos7840_port;
Tony Cook84fe6e72009-04-18 22:55:06 +09302098 dbg("mos7840_set_termios: START");
Harvey Harrison441b62c2008-03-03 16:08:34 -08002099 if (mos7840_port_paranoia_check(port, __func__)) {
Tony Cook84fe6e72009-04-18 22:55:06 +09302100 dbg("%s", "Invalid port");
Paul B Schroeder3f542972006-08-31 19:41:47 -05002101 return;
2102 }
2103
2104 serial = port->serial;
2105
Harvey Harrison441b62c2008-03-03 16:08:34 -08002106 if (mos7840_serial_paranoia_check(serial, __func__)) {
Tony Cook84fe6e72009-04-18 22:55:06 +09302107 dbg("%s", "Invalid Serial");
Paul B Schroeder3f542972006-08-31 19:41:47 -05002108 return;
2109 }
2110
2111 mos7840_port = mos7840_get_port_private(port);
2112
2113 if (mos7840_port == NULL)
2114 return;
2115
Paul B Schroeder3f542972006-08-31 19:41:47 -05002116 if (!mos7840_port->open) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002117 dbg("%s - port not opened", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002118 return;
2119 }
2120
Tony Cook84fe6e72009-04-18 22:55:06 +09302121 dbg("%s", "setting termios - ");
Paul B Schroeder3f542972006-08-31 19:41:47 -05002122
2123 cflag = tty->termios->c_cflag;
2124
Harvey Harrison441b62c2008-03-03 16:08:34 -08002125 dbg("%s - clfag %08x iflag %08x", __func__,
Paul B Schroeder3f542972006-08-31 19:41:47 -05002126 tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag));
Harvey Harrison441b62c2008-03-03 16:08:34 -08002127 dbg("%s - old clfag %08x old iflag %08x", __func__,
Alan Cox3d3ddce2007-10-15 20:53:35 +01002128 old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
Harvey Harrison441b62c2008-03-03 16:08:34 -08002129 dbg("%s - port %d", __func__, port->number);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002130
2131 /* change the port settings to the new ones specified */
2132
Alan Cox95da3102008-07-22 11:09:07 +01002133 mos7840_change_port_settings(tty, mos7840_port, old_termios);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002134
2135 if (!mos7840_port->read_urb) {
Tony Cook84fe6e72009-04-18 22:55:06 +09302136 dbg("%s", "URB KILLED !!!!!");
Paul B Schroeder3f542972006-08-31 19:41:47 -05002137 return;
2138 }
2139
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -08002140 if (mos7840_port->read_urb_busy == false) {
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -08002141 mos7840_port->read_urb_busy = true;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002142 status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
2143 if (status) {
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -08002144 dbg("usb_submit_urb(read bulk) failed, status = %d",
Paul B Schroeder3f542972006-08-31 19:41:47 -05002145 status);
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -08002146 mos7840_port->read_urb_busy = false;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002147 }
2148 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05002149}
2150
2151/*****************************************************************************
2152 * mos7840_get_lsr_info - get line status register info
2153 *
2154 * Purpose: Let user call ioctl() to get info when the UART physically
2155 * is emptied. On bus types like RS485, the transmitter must
2156 * release the bus after transmitting. This must be done when
2157 * the transmit shift register is empty, not be done when the
2158 * transmit holding register is empty. This functionality
2159 * allows an RS485 driver to be written in user space.
2160 *****************************************************************************/
2161
Alan Cox95da3102008-07-22 11:09:07 +01002162static int mos7840_get_lsr_info(struct tty_struct *tty,
Al Viro97c49652006-10-09 20:29:03 +01002163 unsigned int __user *value)
Paul B Schroeder3f542972006-08-31 19:41:47 -05002164{
2165 int count;
2166 unsigned int result = 0;
2167
Alan Cox95da3102008-07-22 11:09:07 +01002168 count = mos7840_chars_in_buffer(tty);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002169 if (count == 0) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08002170 dbg("%s -- Empty", __func__);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002171 result = TIOCSER_TEMT;
2172 }
2173
2174 if (copy_to_user(value, &result, sizeof(int)))
2175 return -EFAULT;
2176 return 0;
2177}
2178
2179/*****************************************************************************
Paul B Schroeder3f542972006-08-31 19:41:47 -05002180 * mos7840_get_serial_info
2181 * function to get information about serial port
2182 *****************************************************************************/
2183
2184static int mos7840_get_serial_info(struct moschip_port *mos7840_port,
Al Viro97c49652006-10-09 20:29:03 +01002185 struct serial_struct __user *retinfo)
Paul B Schroeder3f542972006-08-31 19:41:47 -05002186{
2187 struct serial_struct tmp;
2188
2189 if (mos7840_port == NULL)
2190 return -1;
2191
2192 if (!retinfo)
2193 return -EFAULT;
2194
2195 memset(&tmp, 0, sizeof(tmp));
2196
2197 tmp.type = PORT_16550A;
2198 tmp.line = mos7840_port->port->serial->minor;
2199 tmp.port = mos7840_port->port->number;
2200 tmp.irq = 0;
2201 tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
2202 tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
2203 tmp.baud_base = 9600;
2204 tmp.close_delay = 5 * HZ;
2205 tmp.closing_wait = 30 * HZ;
2206
2207 if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
2208 return -EFAULT;
2209 return 0;
2210}
2211
Alan Cox0bca1b92010-09-16 18:21:40 +01002212static int mos7840_get_icount(struct tty_struct *tty,
2213 struct serial_icounter_struct *icount)
2214{
2215 struct usb_serial_port *port = tty->driver_data;
2216 struct moschip_port *mos7840_port;
2217 struct async_icount cnow;
2218
2219 mos7840_port = mos7840_get_port_private(port);
2220 cnow = mos7840_port->icount;
2221
2222 smp_rmb();
2223 icount->cts = cnow.cts;
2224 icount->dsr = cnow.dsr;
2225 icount->rng = cnow.rng;
2226 icount->dcd = cnow.dcd;
2227 icount->rx = cnow.rx;
2228 icount->tx = cnow.tx;
2229 icount->frame = cnow.frame;
2230 icount->overrun = cnow.overrun;
2231 icount->parity = cnow.parity;
2232 icount->brk = cnow.brk;
2233 icount->buf_overrun = cnow.buf_overrun;
2234
2235 dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __func__,
2236 port->number, icount->rx, icount->tx);
2237 return 0;
2238}
2239
Paul B Schroeder3f542972006-08-31 19:41:47 -05002240/*****************************************************************************
2241 * SerialIoctl
2242 * this function handles any ioctl calls to the driver
2243 *****************************************************************************/
2244
Alan Cox00a0d0d2011-02-14 16:27:06 +00002245static int mos7840_ioctl(struct tty_struct *tty,
Paul B Schroeder3f542972006-08-31 19:41:47 -05002246 unsigned int cmd, unsigned long arg)
2247{
Alan Cox95da3102008-07-22 11:09:07 +01002248 struct usb_serial_port *port = tty->driver_data;
Al Viro97c49652006-10-09 20:29:03 +01002249 void __user *argp = (void __user *)arg;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002250 struct moschip_port *mos7840_port;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002251
2252 struct async_icount cnow;
2253 struct async_icount cprev;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002254
Harvey Harrison441b62c2008-03-03 16:08:34 -08002255 if (mos7840_port_paranoia_check(port, __func__)) {
Tony Cook84fe6e72009-04-18 22:55:06 +09302256 dbg("%s", "Invalid port");
Paul B Schroeder3f542972006-08-31 19:41:47 -05002257 return -1;
2258 }
2259
2260 mos7840_port = mos7840_get_port_private(port);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002261
2262 if (mos7840_port == NULL)
2263 return -1;
2264
Harvey Harrison441b62c2008-03-03 16:08:34 -08002265 dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002266
2267 switch (cmd) {
2268 /* return number of bytes available */
2269
Paul B Schroeder3f542972006-08-31 19:41:47 -05002270 case TIOCSERGETLSR:
Harvey Harrison441b62c2008-03-03 16:08:34 -08002271 dbg("%s (%d) TIOCSERGETLSR", __func__, port->number);
Alan Cox95da3102008-07-22 11:09:07 +01002272 return mos7840_get_lsr_info(tty, argp);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002273
Paul B Schroeder3f542972006-08-31 19:41:47 -05002274 case TIOCGSERIAL:
Harvey Harrison441b62c2008-03-03 16:08:34 -08002275 dbg("%s (%d) TIOCGSERIAL", __func__, port->number);
Al Viro97c49652006-10-09 20:29:03 +01002276 return mos7840_get_serial_info(mos7840_port, argp);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002277
2278 case TIOCSSERIAL:
Harvey Harrison441b62c2008-03-03 16:08:34 -08002279 dbg("%s (%d) TIOCSSERIAL", __func__, port->number);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002280 break;
2281
2282 case TIOCMIWAIT:
Harvey Harrison441b62c2008-03-03 16:08:34 -08002283 dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002284 cprev = mos7840_port->icount;
2285 while (1) {
Alan Cox880af9d2008-07-22 11:16:12 +01002286 /* interruptible_sleep_on(&mos7840_port->delta_msr_wait); */
Paul B Schroeder3f542972006-08-31 19:41:47 -05002287 mos7840_port->delta_msr_cond = 0;
2288 wait_event_interruptible(mos7840_port->delta_msr_wait,
2289 (mos7840_port->
2290 delta_msr_cond == 1));
2291
2292 /* see if a signal did it */
2293 if (signal_pending(current))
2294 return -ERESTARTSYS;
2295 cnow = mos7840_port->icount;
Oliver Neukum0de9a702007-03-16 20:28:28 +01002296 smp_rmb();
Paul B Schroeder3f542972006-08-31 19:41:47 -05002297 if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
2298 cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
2299 return -EIO; /* no change => error */
2300 if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
2301 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
2302 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
2303 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
2304 return 0;
2305 }
2306 cprev = cnow;
2307 }
2308 /* NOTREACHED */
2309 break;
2310
Paul B Schroeder3f542972006-08-31 19:41:47 -05002311 default:
2312 break;
2313 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05002314 return -ENOIOCTLCMD;
2315}
2316
2317static int mos7840_calc_num_ports(struct usb_serial *serial)
2318{
Donald Lee093ea2d2012-03-14 15:26:33 +08002319 __u16 Data = 0x00;
2320 int ret = 0;
2321 int mos7840_num_ports;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002322
Donald Lee093ea2d2012-03-14 15:26:33 +08002323 ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
2324 MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &Data,
2325 VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
2326
2327 if ((Data & 0x01) == 0) {
2328 mos7840_num_ports = 2;
2329 serial->num_bulk_in = 2;
2330 serial->num_bulk_out = 2;
2331 serial->num_ports = 2;
2332 } else {
2333 mos7840_num_ports = 4;
Oliver Neukum0de9a702007-03-16 20:28:28 +01002334 serial->num_bulk_in = 4;
2335 serial->num_bulk_out = 4;
Donald Lee093ea2d2012-03-14 15:26:33 +08002336 serial->num_ports = 4;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002337 }
Donald Lee093ea2d2012-03-14 15:26:33 +08002338
Paul B Schroeder3f542972006-08-31 19:41:47 -05002339 return mos7840_num_ports;
2340}
2341
2342/****************************************************************************
2343 * mos7840_startup
2344 ****************************************************************************/
2345
2346static int mos7840_startup(struct usb_serial *serial)
2347{
2348 struct moschip_port *mos7840_port;
2349 struct usb_device *dev;
2350 int i, status;
2351
2352 __u16 Data;
Tony Cook84fe6e72009-04-18 22:55:06 +09302353 dbg("%s", "mos7840_startup :Entering..........");
Paul B Schroeder3f542972006-08-31 19:41:47 -05002354
2355 if (!serial) {
Tony Cook84fe6e72009-04-18 22:55:06 +09302356 dbg("%s", "Invalid Handler");
Paul B Schroeder3f542972006-08-31 19:41:47 -05002357 return -1;
2358 }
2359
2360 dev = serial->dev;
2361
Tony Cook84fe6e72009-04-18 22:55:06 +09302362 dbg("%s", "Entering...");
2363 dbg ("mos7840_startup: serial = %p", serial);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002364
2365 /* we set up the pointers to the endpoints in the mos7840_open *
2366 * function, as the structures aren't created yet. */
2367
2368 /* set up port private structures */
2369 for (i = 0; i < serial->num_ports; ++i) {
Tony Cook84fe6e72009-04-18 22:55:06 +09302370 dbg ("mos7840_startup: configuring port %d............", i);
Burman Yan7ac9da12006-11-22 20:54:38 +02002371 mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002372 if (mos7840_port == NULL) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07002373 dev_err(&dev->dev, "%s - Out of memory\n", __func__);
Oliver Neukum0de9a702007-03-16 20:28:28 +01002374 status = -ENOMEM;
2375 i--; /* don't follow NULL pointer cleaning up */
2376 goto error;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002377 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05002378
Alan Cox880af9d2008-07-22 11:16:12 +01002379 /* Initialize all port interrupt end point to port 0 int
2380 * endpoint. Our device has only one interrupt end point
2381 * common to all port */
Paul B Schroeder3f542972006-08-31 19:41:47 -05002382
2383 mos7840_port->port = serial->port[i];
2384 mos7840_set_port_private(serial->port[i], mos7840_port);
Oliver Neukum0de9a702007-03-16 20:28:28 +01002385 spin_lock_init(&mos7840_port->pool_lock);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002386
Tony Cook37768ad2009-04-18 22:42:18 +09302387 /* minor is not initialised until later by
2388 * usb-serial.c:get_free_serial() and cannot therefore be used
2389 * to index device instances */
2390 mos7840_port->port_num = i + 1;
2391 dbg ("serial->port[i]->number = %d", serial->port[i]->number);
2392 dbg ("serial->port[i]->serial->minor = %d", serial->port[i]->serial->minor);
2393 dbg ("mos7840_port->port_num = %d", mos7840_port->port_num);
2394 dbg ("serial->minor = %d", serial->minor);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002395
2396 if (mos7840_port->port_num == 1) {
2397 mos7840_port->SpRegOffset = 0x0;
2398 mos7840_port->ControlRegOffset = 0x1;
2399 mos7840_port->DcrRegOffset = 0x4;
2400 } else if ((mos7840_port->port_num == 2)
Oliver Neukum0de9a702007-03-16 20:28:28 +01002401 && (serial->num_ports == 4)) {
Paul B Schroeder3f542972006-08-31 19:41:47 -05002402 mos7840_port->SpRegOffset = 0x8;
2403 mos7840_port->ControlRegOffset = 0x9;
2404 mos7840_port->DcrRegOffset = 0x16;
2405 } else if ((mos7840_port->port_num == 2)
Oliver Neukum0de9a702007-03-16 20:28:28 +01002406 && (serial->num_ports == 2)) {
Paul B Schroeder3f542972006-08-31 19:41:47 -05002407 mos7840_port->SpRegOffset = 0xa;
2408 mos7840_port->ControlRegOffset = 0xb;
2409 mos7840_port->DcrRegOffset = 0x19;
2410 } else if ((mos7840_port->port_num == 3)
Oliver Neukum0de9a702007-03-16 20:28:28 +01002411 && (serial->num_ports == 4)) {
Paul B Schroeder3f542972006-08-31 19:41:47 -05002412 mos7840_port->SpRegOffset = 0xa;
2413 mos7840_port->ControlRegOffset = 0xb;
2414 mos7840_port->DcrRegOffset = 0x19;
2415 } else if ((mos7840_port->port_num == 4)
Oliver Neukum0de9a702007-03-16 20:28:28 +01002416 && (serial->num_ports == 4)) {
Paul B Schroeder3f542972006-08-31 19:41:47 -05002417 mos7840_port->SpRegOffset = 0xc;
2418 mos7840_port->ControlRegOffset = 0xd;
2419 mos7840_port->DcrRegOffset = 0x1c;
2420 }
2421 mos7840_dump_serial_port(mos7840_port);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002422 mos7840_set_port_private(serial->port[i], mos7840_port);
2423
Alan Cox880af9d2008-07-22 11:16:12 +01002424 /* enable rx_disable bit in control register */
2425 status = mos7840_get_reg_sync(serial->port[i],
2426 mos7840_port->ControlRegOffset, &Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002427 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +09302428 dbg("Reading ControlReg failed status-0x%x", status);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002429 break;
2430 } else
Tony Cook84fe6e72009-04-18 22:55:06 +09302431 dbg("ControlReg Reading success val is %x, status%d",
Paul B Schroeder3f542972006-08-31 19:41:47 -05002432 Data, status);
Alan Cox880af9d2008-07-22 11:16:12 +01002433 Data |= 0x08; /* setting driver done bit */
2434 Data |= 0x04; /* sp1_bit to have cts change reflect in
2435 modem status reg */
Paul B Schroeder3f542972006-08-31 19:41:47 -05002436
Alan Cox880af9d2008-07-22 11:16:12 +01002437 /* Data |= 0x20; //rx_disable bit */
2438 status = mos7840_set_reg_sync(serial->port[i],
Paul B Schroeder3f542972006-08-31 19:41:47 -05002439 mos7840_port->ControlRegOffset, Data);
2440 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +09302441 dbg("Writing ControlReg failed(rx_disable) status-0x%x", status);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002442 break;
2443 } else
Tony Cook84fe6e72009-04-18 22:55:06 +09302444 dbg("ControlReg Writing success(rx_disable) status%d",
Paul B Schroeder3f542972006-08-31 19:41:47 -05002445 status);
2446
Alan Cox880af9d2008-07-22 11:16:12 +01002447 /* Write default values in DCR (i.e 0x01 in DCR0, 0x05 in DCR2
2448 and 0x24 in DCR3 */
Paul B Schroeder3f542972006-08-31 19:41:47 -05002449 Data = 0x01;
Alan Cox880af9d2008-07-22 11:16:12 +01002450 status = mos7840_set_reg_sync(serial->port[i],
2451 (__u16) (mos7840_port->DcrRegOffset + 0), Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002452 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +09302453 dbg("Writing DCR0 failed status-0x%x", status);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002454 break;
2455 } else
Tony Cook84fe6e72009-04-18 22:55:06 +09302456 dbg("DCR0 Writing success status%d", status);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002457
2458 Data = 0x05;
Alan Cox880af9d2008-07-22 11:16:12 +01002459 status = mos7840_set_reg_sync(serial->port[i],
2460 (__u16) (mos7840_port->DcrRegOffset + 1), Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002461 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +09302462 dbg("Writing DCR1 failed status-0x%x", status);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002463 break;
2464 } else
Tony Cook84fe6e72009-04-18 22:55:06 +09302465 dbg("DCR1 Writing success status%d", status);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002466
2467 Data = 0x24;
Alan Cox880af9d2008-07-22 11:16:12 +01002468 status = mos7840_set_reg_sync(serial->port[i],
2469 (__u16) (mos7840_port->DcrRegOffset + 2), Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002470 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +09302471 dbg("Writing DCR2 failed status-0x%x", status);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002472 break;
2473 } else
Tony Cook84fe6e72009-04-18 22:55:06 +09302474 dbg("DCR2 Writing success status%d", status);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002475
Alan Cox880af9d2008-07-22 11:16:12 +01002476 /* write values in clkstart0x0 and clkmulti 0x20 */
Paul B Schroeder3f542972006-08-31 19:41:47 -05002477 Data = 0x0;
Alan Cox880af9d2008-07-22 11:16:12 +01002478 status = mos7840_set_reg_sync(serial->port[i],
Paul B Schroeder3f542972006-08-31 19:41:47 -05002479 CLK_START_VALUE_REGISTER, Data);
2480 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +09302481 dbg("Writing CLK_START_VALUE_REGISTER failed status-0x%x", status);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002482 break;
2483 } else
Tony Cook84fe6e72009-04-18 22:55:06 +09302484 dbg("CLK_START_VALUE_REGISTER Writing success status%d", status);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002485
2486 Data = 0x20;
Alan Cox880af9d2008-07-22 11:16:12 +01002487 status = mos7840_set_reg_sync(serial->port[i],
2488 CLK_MULTI_REGISTER, Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002489 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +09302490 dbg("Writing CLK_MULTI_REGISTER failed status-0x%x",
Paul B Schroeder3f542972006-08-31 19:41:47 -05002491 status);
Oliver Neukum0de9a702007-03-16 20:28:28 +01002492 goto error;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002493 } else
Tony Cook84fe6e72009-04-18 22:55:06 +09302494 dbg("CLK_MULTI_REGISTER Writing success status%d",
Paul B Schroeder3f542972006-08-31 19:41:47 -05002495 status);
2496
Alan Cox880af9d2008-07-22 11:16:12 +01002497 /* write value 0x0 to scratchpad register */
Paul B Schroeder3f542972006-08-31 19:41:47 -05002498 Data = 0x00;
Alan Cox880af9d2008-07-22 11:16:12 +01002499 status = mos7840_set_uart_reg(serial->port[i],
2500 SCRATCH_PAD_REGISTER, Data);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002501 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +09302502 dbg("Writing SCRATCH_PAD_REGISTER failed status-0x%x",
Paul B Schroeder3f542972006-08-31 19:41:47 -05002503 status);
2504 break;
2505 } else
Tony Cook84fe6e72009-04-18 22:55:06 +09302506 dbg("SCRATCH_PAD_REGISTER Writing success status%d",
Paul B Schroeder3f542972006-08-31 19:41:47 -05002507 status);
2508
Alan Cox880af9d2008-07-22 11:16:12 +01002509 /* Zero Length flag register */
Paul B Schroeder3f542972006-08-31 19:41:47 -05002510 if ((mos7840_port->port_num != 1)
Oliver Neukum0de9a702007-03-16 20:28:28 +01002511 && (serial->num_ports == 2)) {
Paul B Schroeder3f542972006-08-31 19:41:47 -05002512
2513 Data = 0xff;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002514 status = mos7840_set_reg_sync(serial->port[i],
Alan Cox880af9d2008-07-22 11:16:12 +01002515 (__u16) (ZLP_REG1 +
2516 ((__u16)mos7840_port->port_num)), Data);
Tony Cook84fe6e72009-04-18 22:55:06 +09302517 dbg("ZLIP offset %x",
Paul B Schroeder3f542972006-08-31 19:41:47 -05002518 (__u16) (ZLP_REG1 +
Alan Cox880af9d2008-07-22 11:16:12 +01002519 ((__u16) mos7840_port->port_num)));
Paul B Schroeder3f542972006-08-31 19:41:47 -05002520 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +09302521 dbg("Writing ZLP_REG%d failed status-0x%x",
Paul B Schroeder3f542972006-08-31 19:41:47 -05002522 i + 2, status);
2523 break;
2524 } else
Tony Cook84fe6e72009-04-18 22:55:06 +09302525 dbg("ZLP_REG%d Writing success status%d",
Paul B Schroeder3f542972006-08-31 19:41:47 -05002526 i + 2, status);
2527 } else {
2528 Data = 0xff;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002529 status = mos7840_set_reg_sync(serial->port[i],
Alan Cox880af9d2008-07-22 11:16:12 +01002530 (__u16) (ZLP_REG1 +
2531 ((__u16)mos7840_port->port_num) - 0x1), Data);
Tony Cook84fe6e72009-04-18 22:55:06 +09302532 dbg("ZLIP offset %x",
Paul B Schroeder3f542972006-08-31 19:41:47 -05002533 (__u16) (ZLP_REG1 +
2534 ((__u16) mos7840_port->port_num) - 0x1));
2535 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +09302536 dbg("Writing ZLP_REG%d failed status-0x%x",
Paul B Schroeder3f542972006-08-31 19:41:47 -05002537 i + 1, status);
2538 break;
2539 } else
Tony Cook84fe6e72009-04-18 22:55:06 +09302540 dbg("ZLP_REG%d Writing success status%d",
Paul B Schroeder3f542972006-08-31 19:41:47 -05002541 i + 1, status);
2542
2543 }
Oliver Neukum0de9a702007-03-16 20:28:28 +01002544 mos7840_port->control_urb = usb_alloc_urb(0, GFP_KERNEL);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002545 mos7840_port->ctrl_buf = kmalloc(16, GFP_KERNEL);
Alan Cox880af9d2008-07-22 11:16:12 +01002546 mos7840_port->dr = kmalloc(sizeof(struct usb_ctrlrequest),
2547 GFP_KERNEL);
2548 if (!mos7840_port->control_urb || !mos7840_port->ctrl_buf ||
2549 !mos7840_port->dr) {
Oliver Neukum0de9a702007-03-16 20:28:28 +01002550 status = -ENOMEM;
2551 goto error;
2552 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05002553 }
Tony Cook84fe6e72009-04-18 22:55:06 +09302554 dbg ("mos7840_startup: all ports configured...........");
Paul B Schroeder3f542972006-08-31 19:41:47 -05002555
Alan Cox880af9d2008-07-22 11:16:12 +01002556 /* Zero Length flag enable */
Paul B Schroeder3f542972006-08-31 19:41:47 -05002557 Data = 0x0f;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002558 status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data);
2559 if (status < 0) {
Tony Cook84fe6e72009-04-18 22:55:06 +09302560 dbg("Writing ZLP_REG5 failed status-0x%x", status);
Roel Kluin7ced46c2007-10-27 03:36:37 +02002561 goto error;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002562 } else
Tony Cook84fe6e72009-04-18 22:55:06 +09302563 dbg("ZLP_REG5 Writing success status%d", status);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002564
2565 /* setting configuration feature to one */
2566 usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
Al Viro97c49652006-10-09 20:29:03 +01002567 (__u8) 0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5 * HZ);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002568 return 0;
Oliver Neukum0de9a702007-03-16 20:28:28 +01002569error:
2570 for (/* nothing */; i >= 0; i--) {
2571 mos7840_port = mos7840_get_port_private(serial->port[i]);
2572
2573 kfree(mos7840_port->dr);
2574 kfree(mos7840_port->ctrl_buf);
2575 usb_free_urb(mos7840_port->control_urb);
2576 kfree(mos7840_port);
Oliver Neukum0de9a702007-03-16 20:28:28 +01002577 }
2578 return status;
Paul B Schroeder3f542972006-08-31 19:41:47 -05002579}
2580
2581/****************************************************************************
Alan Sternf9c99bb2009-06-02 11:53:55 -04002582 * mos7840_disconnect
Paul B Schroeder3f542972006-08-31 19:41:47 -05002583 * This function is called whenever the device is removed from the usb bus.
2584 ****************************************************************************/
2585
Alan Sternf9c99bb2009-06-02 11:53:55 -04002586static void mos7840_disconnect(struct usb_serial *serial)
Paul B Schroeder3f542972006-08-31 19:41:47 -05002587{
2588 int i;
2589 struct moschip_port *mos7840_port;
Alan Sternf9c99bb2009-06-02 11:53:55 -04002590 dbg("%s", " disconnect :entering..........");
Paul B Schroeder3f542972006-08-31 19:41:47 -05002591
2592 if (!serial) {
Tony Cook84fe6e72009-04-18 22:55:06 +09302593 dbg("%s", "Invalid Handler");
Paul B Schroeder3f542972006-08-31 19:41:47 -05002594 return;
2595 }
2596
Alan Cox880af9d2008-07-22 11:16:12 +01002597 /* check for the ports to be closed,close the ports and disconnect */
Paul B Schroeder3f542972006-08-31 19:41:47 -05002598
2599 /* free private structure allocated for serial port *
2600 * stop reads and writes on all ports */
2601
2602 for (i = 0; i < serial->num_ports; ++i) {
2603 mos7840_port = mos7840_get_port_private(serial->port[i]);
Tony Cook37768ad2009-04-18 22:42:18 +09302604 dbg ("mos7840_port %d = %p", i, mos7840_port);
2605 if (mos7840_port) {
Tony Cook37768ad2009-04-18 22:42:18 +09302606 usb_kill_urb(mos7840_port->control_urb);
Alan Sternf9c99bb2009-06-02 11:53:55 -04002607 }
2608 }
2609
2610 dbg("%s", "Thank u :: ");
2611
2612}
2613
2614/****************************************************************************
2615 * mos7840_release
2616 * This function is called when the usb_serial structure is freed.
2617 ****************************************************************************/
2618
2619static void mos7840_release(struct usb_serial *serial)
2620{
2621 int i;
2622 struct moschip_port *mos7840_port;
2623 dbg("%s", " release :entering..........");
2624
2625 if (!serial) {
2626 dbg("%s", "Invalid Handler");
2627 return;
2628 }
2629
2630 /* check for the ports to be closed,close the ports and disconnect */
2631
2632 /* free private structure allocated for serial port *
2633 * stop reads and writes on all ports */
2634
2635 for (i = 0; i < serial->num_ports; ++i) {
2636 mos7840_port = mos7840_get_port_private(serial->port[i]);
2637 dbg("mos7840_port %d = %p", i, mos7840_port);
2638 if (mos7840_port) {
Johan Hovoldb296aac2012-10-25 13:35:09 +02002639 usb_free_urb(mos7840_port->control_urb);
Tony Cook37768ad2009-04-18 22:42:18 +09302640 kfree(mos7840_port->ctrl_buf);
2641 kfree(mos7840_port->dr);
2642 kfree(mos7840_port);
2643 }
Paul B Schroeder3f542972006-08-31 19:41:47 -05002644 }
2645
Tony Cook84fe6e72009-04-18 22:55:06 +09302646 dbg("%s", "Thank u :: ");
Paul B Schroeder3f542972006-08-31 19:41:47 -05002647
2648}
2649
Johannes Hölzld9b1b782006-12-17 21:50:24 +01002650static struct usb_driver io_driver = {
2651 .name = "mos7840",
2652 .probe = usb_serial_probe,
2653 .disconnect = usb_serial_disconnect,
2654 .id_table = moschip_id_table_combined,
Johannes Hölzld9b1b782006-12-17 21:50:24 +01002655};
2656
Paul B Schroeder3f542972006-08-31 19:41:47 -05002657static struct usb_serial_driver moschip7840_4port_device = {
2658 .driver = {
2659 .owner = THIS_MODULE,
2660 .name = "mos7840",
2661 },
2662 .description = DRIVER_DESC,
2663 .id_table = moschip_port_id_table,
Paul B Schroeder3f542972006-08-31 19:41:47 -05002664 .num_ports = 4,
Paul B Schroeder3f542972006-08-31 19:41:47 -05002665 .open = mos7840_open,
2666 .close = mos7840_close,
2667 .write = mos7840_write,
2668 .write_room = mos7840_write_room,
2669 .chars_in_buffer = mos7840_chars_in_buffer,
2670 .throttle = mos7840_throttle,
2671 .unthrottle = mos7840_unthrottle,
2672 .calc_num_ports = mos7840_calc_num_ports,
2673#ifdef MCSSerialProbe
2674 .probe = mos7840_serial_probe,
2675#endif
2676 .ioctl = mos7840_ioctl,
2677 .set_termios = mos7840_set_termios,
2678 .break_ctl = mos7840_break,
2679 .tiocmget = mos7840_tiocmget,
2680 .tiocmset = mos7840_tiocmset,
Alan Cox0bca1b92010-09-16 18:21:40 +01002681 .get_icount = mos7840_get_icount,
Paul B Schroeder3f542972006-08-31 19:41:47 -05002682 .attach = mos7840_startup,
Alan Sternf9c99bb2009-06-02 11:53:55 -04002683 .disconnect = mos7840_disconnect,
2684 .release = mos7840_release,
Paul B Schroeder3f542972006-08-31 19:41:47 -05002685 .read_bulk_callback = mos7840_bulk_in_callback,
2686 .read_int_callback = mos7840_interrupt_callback,
2687};
2688
Alan Stern4d2a7af2012-02-23 14:57:09 -05002689static struct usb_serial_driver * const serial_drivers[] = {
2690 &moschip7840_4port_device, NULL
2691};
2692
Greg Kroah-Hartmane7414d92012-02-28 13:12:10 -08002693module_usb_serial_driver(io_driver, serial_drivers);
Paul B Schroeder3f542972006-08-31 19:41:47 -05002694
Paul B Schroeder3f542972006-08-31 19:41:47 -05002695MODULE_DESCRIPTION(DRIVER_DESC);
2696MODULE_LICENSE("GPL");
2697
2698module_param(debug, bool, S_IRUGO | S_IWUSR);
2699MODULE_PARM_DESC(debug, "Debug enabled or not");