mos7720.c revision 441b62c1edb986827154768d89bbac0ba779984f
10f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
20f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720.c
30f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *   Controls the Moschip 7720 usb to dual port serial convertor
40f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *
50f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Copyright 2006 Moschip Semiconductor Tech. Ltd.
60f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *
70f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * This program is free software; you can redistribute it and/or modify
80f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * it under the terms of the GNU General Public License as published by
90f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * the Free Software Foundation, version 2 of the License.
100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *
110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Developed by:
1250d2dc7266573dfbdc84fc207494dd21315782efGreg Kroah-Hartman * 	Vijaya Kumar <vijaykumar.gn@gmail.com>
1350d2dc7266573dfbdc84fc207494dd21315782efGreg Kroah-Hartman *	Ajay Kumar <naanuajay@yahoo.com>
1450d2dc7266573dfbdc84fc207494dd21315782efGreg Kroah-Hartman *	Gurudeva <ngurudeva@yahoo.com>
150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *
160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Cleaned up from the original by:
170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	Greg Kroah-Hartman <gregkh@suse.de>
180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *
190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Originally based on drivers/usb/serial/io_edgeport.c which is:
200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	Copyright (C) 2000 Inside Out Networks, All rights reserved.
210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com>
220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/kernel.h>
240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/errno.h>
250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/init.h>
260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/slab.h>
270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/tty.h>
280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/tty_driver.h>
290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/tty_flip.h>
300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/module.h>
310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/spinlock.h>
320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/serial.h>
330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/serial_reg.h>
340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/usb.h>
350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <linux/usb/serial.h>
360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#include <asm/uaccess.h>
370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Version Information
410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define DRIVER_VERSION "1.0.0.4F"
430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define DRIVER_AUTHOR "Aspire Communications pvt Ltd."
440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define DRIVER_DESC "Moschip USB Serial Driver"
450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* default urb timeout */
470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define MOS_WDR_TIMEOUT	(HZ * 5)
480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define MOS_PORT1	0x0200
500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define MOS_PORT2	0x0300
510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define MOS_VENREG	0x0000
520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define MOS_MAX_PORT	0x02
530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define MOS_WRITE	0x0E
540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define MOS_READ	0x0D
550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* Interrupt Rotinue Defines	*/
570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define SERIAL_IIR_RLS	0x06
580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define SERIAL_IIR_RDA	0x04
590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define SERIAL_IIR_CTI	0x0c
600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define SERIAL_IIR_THR	0x02
610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define SERIAL_IIR_MS	0x00
620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define NUM_URBS			16	/* URB Count */
640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define URB_TRANSFER_BUFFER_SIZE	32	/* URB Size */
650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* This structure holds all of the local port information */
670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstruct moschip_port
680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u8	shadowLCR;		/* last LCR value received */
700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u8	shadowMCR;		/* last MCR value received */
710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u8	shadowMSR;		/* last MSR value received */
720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	char			open;
730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct async_icount	icount;
740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial_port	*port;	/* loop back to the owner */
750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct urb		*write_urb_pool[NUM_URBS];
760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman};
770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* This structure holds all of the individual serial device information */
790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstruct moschip_serial
800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int interrupt_started;
820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman};
830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int debug;
850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define USB_VENDOR_ID_MOSCHIP		0x9710
870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define MOSCHIP_DEVICE_ID_7720		0x7720
880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define MOSCHIP_DEVICE_ID_7715		0x7715
890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic struct usb_device_id moschip_port_id_table [] = {
910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{ USB_DEVICE(USB_VENDOR_ID_MOSCHIP,MOSCHIP_DEVICE_ID_7720) },
920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{ } /* terminating entry */
930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman};
940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-HartmanMODULE_DEVICE_TABLE(usb, moschip_port_id_table);
950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720_interrupt_callback
990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	this is the callback function for when we have received data on the
1000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	interrupt endpoint.
1010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
1020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic void mos7720_interrupt_callback(struct urb *urb)
1030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
1040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int result;
1050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int length;
10681105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman	int status = urb->status;
107325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum	__u8 *data;
1080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u8 sp1;
1090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u8 sp2;
1100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	dbg("%s"," : Entering\n");
1120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11381105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman	switch (status) {
1140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case 0:
1150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* success */
1160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		break;
1170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case -ECONNRESET:
1180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case -ENOENT:
1190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case -ESHUTDOWN:
1200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* this urb is terminated, clean up */
121441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - urb shutting down with status: %d", __func__,
12281105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman		    status);
1230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
1240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	default:
125441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - nonzero urb status received: %d", __func__,
12681105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman		    status);
1270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		goto exit;
1280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
1290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	length = urb->actual_length;
1310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = urb->transfer_buffer;
1320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Moschip get 4 bytes
1340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	 * Byte 1 IIR Port 1 (port.number is 0)
1350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	 * Byte 2 IIR Port 2 (port.number is 1)
1360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	 * Byte 3 --------------
1370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	 * Byte 4 FIFO status for both */
138325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum
139325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum	/* the above description is inverted
140325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum	 * 	oneukum 2007-03-14 */
141325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum
142325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum	if (unlikely(length != 4)) {
1430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("Wrong data !!!");
1440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
1450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
1460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
147325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum	sp1 = data[3];
148325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum	sp2 = data[2];
1490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
150325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum	if ((sp1 | sp2) & 0x01) {
1510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* No Interrupt Pending in both the ports */
1520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("No Interrupt !!!");
1530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	} else {
1540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		switch (sp1 & 0x0f) {
1550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		case SERIAL_IIR_RLS:
1560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dbg("Serial Port 1: Receiver status error or address "
1570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			    "bit detected in 9-bit mode\n");
1580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			break;
1590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		case SERIAL_IIR_CTI:
1600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dbg("Serial Port 1: Receiver time out");
1610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			break;
1620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		case SERIAL_IIR_MS:
1630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dbg("Serial Port 1: Modem status change");
1640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			break;
1650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
1660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		switch (sp2 & 0x0f) {
1680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		case SERIAL_IIR_RLS:
1690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dbg("Serial Port 2: Receiver status error or address "
1700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			    "bit detected in 9-bit mode");
1710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			break;
1720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		case SERIAL_IIR_CTI:
1730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dbg("Serial Port 2: Receiver time out");
1740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			break;
1750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		case SERIAL_IIR_MS:
1760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dbg("Serial Port 2: Modem status change");
1770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			break;
1780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
1790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
1800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanexit:
1820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	result = usb_submit_urb(urb, GFP_ATOMIC);
1830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (result)
1840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dev_err(&urb->dev->dev,
1850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			"%s - Error %d submitting control urb\n",
186441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			__func__, result);
1870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return;
1880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
1890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
1910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720_bulk_in_callback
1920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	this is the callback function for when we have received data on the
1930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	bulk in endpoint.
1940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
1950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic void mos7720_bulk_in_callback(struct urb *urb)
1960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
19781105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman	int retval;
1980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned char *data ;
1990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial_port *port;
2000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
2010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct tty_struct *tty;
20281105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman	int status = urb->status;
2030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
20481105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman	if (status) {
20581105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman		dbg("nonzero read bulk status received: %d", status);
2060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
2070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
2080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = urb->context;
2100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!mos7720_port) {
2110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("%s","NULL mos7720_port pointer \n");
2120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return ;
2130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
2140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	port = mos7720_port->port;
2160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
217441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("Entering...%s", __func__);
2180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = urb->transfer_buffer;
2200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tty = port->tty;
2220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (tty && urb->actual_length) {
2230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		tty_buffer_request_room(tty, urb->actual_length);
2240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		tty_insert_flip_string(tty, data, urb->actual_length);
2250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		tty_flip_buffer_push(tty);
2260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
2270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!port->read_urb) {
2290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("URB KILLED !!!");
2300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
2310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
2320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (port->read_urb->status != -EINPROGRESS) {
2340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		port->read_urb->dev = port->serial->dev;
2350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
23681105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman		retval = usb_submit_urb(port->read_urb, GFP_ATOMIC);
23781105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman		if (retval)
23881105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman			dbg("usb_submit_urb(read bulk) failed, retval = %d",
23981105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman			    retval);
2400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
2410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
2420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
2440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720_bulk_out_data_callback
2450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	this is the callback function for when we have finished sending serial
2460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	data on the bulk out endpoint.
2470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
2480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic void mos7720_bulk_out_data_callback(struct urb *urb)
2490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
2500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
2510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct tty_struct *tty;
25281105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman	int status = urb->status;
2530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
25481105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman	if (status) {
25581105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman		dbg("nonzero write bulk status received:%d", status);
2560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
2570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
2580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = urb->context;
2600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!mos7720_port) {
2610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("NULL mos7720_port pointer");
2620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return ;
2630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
2640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	dbg("Entering .........");
2660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tty = mos7720_port->port->tty;
2680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
269b963a8441cb95999c97bea379607071a869c65f0Jiri Slaby	if (tty && mos7720_port->open)
270b963a8441cb95999c97bea379607071a869c65f0Jiri Slaby		tty_wakeup(tty);
2710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
2720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
2740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * send_mos_cmd
2750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	this function will be used for sending command to device
2760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
2770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value,
2780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			__u16 index, void *data)
2790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
2800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int status;
2810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned int pipe;
2820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
2830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u8 requesttype;
2840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u16 size = 0x0000;
2850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (value < MOS_MAX_PORT) {
2870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (product == MOSCHIP_DEVICE_ID_7715) {
2880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			value = value*0x100+0x100;
2890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		} else {
2900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			value = value*0x100+0x200;
2910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
2920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	} else {
2930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		value = 0x0000;
2940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if ((product == MOSCHIP_DEVICE_ID_7715) &&
2950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		    (index != 0x08)) {
2960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dbg("serial->product== MOSCHIP_DEVICE_ID_7715");
2970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			//index = 0x01 ;
2980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
2990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
3000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (request == MOS_WRITE) {
3020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		request = (__u8)MOS_WRITE;
3030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		requesttype = (__u8)0x40;
3040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		value  = value + (__u16)*((unsigned char *)data);
3050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		data = NULL;
3060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		pipe = usb_sndctrlpipe(serial->dev, 0);
3070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	} else {
3080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		request = (__u8)MOS_READ;
3090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		requesttype = (__u8)0xC0;
3100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		size = 0x01;
3110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		pipe = usb_rcvctrlpipe(serial->dev,0);
3120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
3130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	status = usb_control_msg(serial->dev, pipe, request, requesttype,
3150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				 value, index, data, size, MOS_WDR_TIMEOUT);
3160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (status < 0)
3180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("Command Write failed Value %x index %x\n",value,index);
3190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return status;
3210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
3220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int mos7720_open(struct usb_serial_port *port, struct file * filp)
3240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
3250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial *serial;
3260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial_port *port0;
3270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct urb *urb;
3280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_serial *mos7720_serial;
3290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
3300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int response;
3310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int port_number;
3320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	char data;
333fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum	int allocated_urbs = 0;
3340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int j;
3350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	serial = port->serial;
3370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = usb_get_serial_port_data(port);
3390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
3400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -ENODEV;
3410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	port0 = serial->port[0];
3430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_serial = usb_get_serial_data(serial);
3450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_serial == NULL || port0 == NULL)
3470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -ENODEV;
3480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	usb_clear_halt(serial->dev, port->write_urb->pipe);
3500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	usb_clear_halt(serial->dev, port->read_urb->pipe);
3510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Initialising the write urb pool */
3530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	for (j = 0; j < NUM_URBS; ++j) {
354c2cf3f6ec58cf1d9e2a92cd74506dcf2265b31a1Oliver Neukum		urb = usb_alloc_urb(0,GFP_KERNEL);
3550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mos7720_port->write_urb_pool[j] = urb;
3560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (urb == NULL) {
3580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			err("No more urbs???");
3590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			continue;
3600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
3610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
3630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman					       GFP_KERNEL);
3640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (!urb->transfer_buffer) {
365441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			err("%s-out of memory for urb buffers.", __func__);
366fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum			usb_free_urb(mos7720_port->write_urb_pool[j]);
367fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum			mos7720_port->write_urb_pool[j] = NULL;
3680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			continue;
3690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
370fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum		allocated_urbs++;
3710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
3720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
373fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum	if (!allocated_urbs)
374fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum		return -ENOMEM;
375fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum
3760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	 /* Initialize MCS7720 -- Write Init values to corresponding Registers
3770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	  *
3780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	  * Register Index
3790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	  * 1 : IER
3800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	  * 2 : FCR
3810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	  * 3 : LCR
3820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	  * 4 : MCR
3830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	  *
3840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	  * 0x08 : SP1/2 Control Reg
3850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	  */
3860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	port_number = port->number - port->serial->minor;
3870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(port->serial, MOS_READ, port_number, UART_LSR, &data);
3880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	dbg("SS::%p LSR:%x\n",mos7720_port, data);
3890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	dbg("Check:Sending Command ..........");
3910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x02;
3930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x01, &data);
3940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x02;
3950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x02, &data);
3960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00;
3980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
3990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00;
4000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
4010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0xCF;
4030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
4040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x03;
4050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        mos7720_port->shadowLCR  = data;
4060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
4070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x0b;
4080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        mos7720_port->shadowMCR  = data;
4090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
4100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x0b;
4110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
4120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00;
4140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
4150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00;
4160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
4170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*	data = 0x00;
4190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, port_number + 1, &data);
4200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x03;
4210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data);
4220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00;
4230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(port->serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data);
4240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman*/
4250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00;
4260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
4270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = data | (port->number - port->serial->minor + 1);
4290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
4300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x83;
4320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        mos7720_port->shadowLCR  = data;
4330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
4340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x0c;
4350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data);
4360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00;
4370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
4380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x03;
4390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        mos7720_port->shadowLCR  = data;
4400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
4410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x0c;
4420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
4430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x0c;
4440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
4450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman//Matrix
4470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* force low_latency on so that our tty_push actually forces *
4490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	 * the data through,otherwise it is scheduled, and with      *
4500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	 * high data rates (like with OHCI) data can get lost.       */
4510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (port->tty)
4530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		port->tty->low_latency = 1;
4540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* see if we've set up our endpoint info yet   *
4560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	 * (can't set it up in mos7720_startup as the  *
4570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	 * structures were not set up at that time.)   */
4580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!mos7720_serial->interrupt_started) {
4590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("Interrupt buffer NULL !!!");
4600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* not set up yet, so do it now */
4620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mos7720_serial->interrupt_started = 1;
4630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("To Submit URB !!!");
4650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* set up our interrupt urb */
4670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		usb_fill_int_urb(port0->interrupt_in_urb, serial->dev,
4680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				 usb_rcvintpipe(serial->dev,
4690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				 		port->interrupt_in_endpointAddress),
4700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				 port0->interrupt_in_buffer,
4710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				 port0->interrupt_in_urb->transfer_buffer_length,
4720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				 mos7720_interrupt_callback, mos7720_port,
4730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				 port0->interrupt_in_urb->interval);
4740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* start interrupt read for this mos7720 this interrupt *
4760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	         * will continue as long as the mos7720 is connected    */
4770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("Submit URB over !!!");
4780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		response = usb_submit_urb(port0->interrupt_in_urb, GFP_KERNEL);
4790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (response)
4800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dev_err(&port->dev,
481898eb71cb17644964c5895fb190e79e3d0c49679Joe Perches				"%s - Error %d submitting control urb\n",
482441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison				__func__, response);
4830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
4840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* set up our bulk in urb */
4860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	usb_fill_bulk_urb(port->read_urb, serial->dev,
4870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			  usb_rcvbulkpipe(serial->dev,
4880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			  		  port->bulk_in_endpointAddress),
4890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			  port->bulk_in_buffer,
4900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			  port->read_urb->transfer_buffer_length,
4910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			  mos7720_bulk_in_callback, mos7720_port);
4920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	response = usb_submit_urb(port->read_urb, GFP_KERNEL);
4930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (response)
4940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dev_err(&port->dev,
495441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			"%s - Error %d submitting read urb\n", __func__, response);
4960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* initialize our icount structure */
4980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount));
4990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* initialize our port settings */
5010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */
5020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* send a open port command */
5040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port->open = 1;
5050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return 0;
5070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
5080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
5100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720_chars_in_buffer
5110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	this function is called by the tty driver when it wants to know how many
5120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	bytes of data we currently have outstanding in the port (data that has
5130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	been written, but hasn't made it out the port yet)
5140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	If successful, we return the number of bytes left to be written in the
5150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	system,
5160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	Otherwise we return a negative error number.
5170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
5180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int mos7720_chars_in_buffer(struct usb_serial_port *port)
5190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
5200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int i;
5210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int chars = 0;
5220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
5230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
524441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s:entering ...........", __func__);
5250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = usb_get_serial_port_data(port);
5270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL) {
528441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s:leaving ...........", __func__);
5290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -ENODEV;
5300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
5310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	for (i = 0; i < NUM_URBS; ++i) {
533fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum		if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status == -EINPROGRESS)
5340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			chars += URB_TRANSFER_BUFFER_SIZE;
5350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
536441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - returns %d", __func__, chars);
5370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return chars;
5380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
5390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic void mos7720_close(struct usb_serial_port *port, struct file *filp)
5410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
5420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial *serial;
5430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
5440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	char data;
5450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int j;
5460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	dbg("mos7720_close:entering...");
5480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	serial = port->serial;
5500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = usb_get_serial_port_data(port);
5520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
5530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
5540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	for (j = 0; j < NUM_URBS; ++j)
5560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		usb_kill_urb(mos7720_port->write_urb_pool[j]);
5570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Freeing Write URBs */
5590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	for (j = 0; j < NUM_URBS; ++j) {
5600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (mos7720_port->write_urb_pool[j]) {
5610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			kfree(mos7720_port->write_urb_pool[j]->transfer_buffer);
5620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			usb_free_urb(mos7720_port->write_urb_pool[j]);
5630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
5640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
5650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* While closing port, shutdown all bulk read, write  *
567a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	 * and interrupt read if they exists, otherwise nop   */
568a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	dbg("Shutdown bulk write");
569a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	usb_kill_urb(port->write_urb);
570a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	dbg("Shutdown bulk read");
571a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	usb_kill_urb(port->read_urb);
572a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum
573a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	mutex_lock(&serial->disc_mutex);
574a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	/* these commands must not be issued if the device has
575a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	 * been disconnected */
576a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	if (!serial->disconnected) {
577a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum		data = 0x00;
578a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum		send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
579a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum			     0x04, &data);
580a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum
581a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum		data = 0x00;
582a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum		send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
583a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum			     0x01, &data);
5840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
585a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	mutex_unlock(&serial->disc_mutex);
5860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port->open = 0;
5870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
588441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("Leaving %s", __func__);
5890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
5900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic void mos7720_break(struct usb_serial_port *port, int break_state)
5920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
5930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        unsigned char data;
5940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial *serial;
5950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
5960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
597441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("Entering %s", __func__);
5980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	serial = port->serial;
6000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = usb_get_serial_port_data(port);
6020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
6030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
6040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (break_state == -1)
6060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		data = mos7720_port->shadowLCR | UART_LCR_SBC;
6070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	else
6080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		data = mos7720_port->shadowLCR & ~UART_LCR_SBC;
6090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port->shadowLCR  = data;
6110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
6120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		     0x03, &data);
6130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return;
6150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
6160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
6180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720_write_room
6190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	this function is called by the tty driver when it wants to know how many
6200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	bytes of data we can accept for a specific port.
6210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	If successful, we return the amount of room that we have for this port
6220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	Otherwise we return a negative error number.
6230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
6240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int mos7720_write_room(struct usb_serial_port *port)
6250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
6260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
6270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int room = 0;
6280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int i;
6290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
630441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s:entering ...........", __func__);
6310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = usb_get_serial_port_data(port);
6330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL) {
634441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s:leaving ...........", __func__);
6350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -ENODEV;
6360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
6370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	for (i = 0; i < NUM_URBS; ++i) {
639fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum		if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status != -EINPROGRESS)
6400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			room += URB_TRANSFER_BUFFER_SIZE;
6410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
6420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
643441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - returns %d", __func__, room);
6440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return room;
6450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
6460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int mos7720_write(struct usb_serial_port *port,
6480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			 const unsigned char *data, int count)
6490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
6500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int status;
6510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int i;
6520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int bytes_sent = 0;
6530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int transfer_size;
6540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
6560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial *serial;
6570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct urb    *urb;
6580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	const unsigned char *current_position = data;
6590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
660441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s:entering ...........", __func__);
6610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	serial = port->serial;
6630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = usb_get_serial_port_data(port);
6650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL) {
6660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("mos7720_port is NULL");
6670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -ENODEV;
6680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
6690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* try to find a free urb in the list */
6710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	urb = NULL;
6720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	for (i = 0; i < NUM_URBS; ++i) {
674fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum		if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) {
6750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			urb = mos7720_port->write_urb_pool[i];
6760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dbg("URB:%d",i);
6770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			break;
6780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
6790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
6800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (urb == NULL) {
682441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - no more free urbs", __func__);
6830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		goto exit;
6840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
6850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (urb->transfer_buffer == NULL) {
6870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
6880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman					       GFP_KERNEL);
6890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (urb->transfer_buffer == NULL) {
690441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			err("%s no more kernel memory...", __func__);
6910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			goto exit;
6920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
6930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
6940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE);
6950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	memcpy(urb->transfer_buffer, current_position, transfer_size);
697441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	usb_serial_debug_data(debug, &port->dev, __func__, transfer_size,
6980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			      urb->transfer_buffer);
6990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* fill urb with data and submit  */
7010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	usb_fill_bulk_urb(urb, serial->dev,
7020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			  usb_sndbulkpipe(serial->dev,
7030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			  		  port->bulk_out_endpointAddress),
7040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			  urb->transfer_buffer, transfer_size,
7050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			  mos7720_bulk_out_data_callback, mos7720_port);
7060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* send it down the pipe */
7080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	status = usb_submit_urb(urb,GFP_ATOMIC);
7090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (status) {
7100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		err("%s - usb_submit_urb(write bulk) failed with status = %d",
711441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		    __func__, status);
7120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		bytes_sent = status;
7130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		goto exit;
7140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
7150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	bytes_sent = transfer_size;
7160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanexit:
7180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return bytes_sent;
7190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
7200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic void mos7720_throttle(struct usb_serial_port *port)
7220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
7230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
7240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct tty_struct *tty;
7250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int status;
7260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
727441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s- port %d\n", __func__, port->number);
7280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = usb_get_serial_port_data(port);
7300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
7320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
7330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!mos7720_port->open) {
7350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("port not opened");
7360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
7370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
7380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
739441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s: Entering ..........", __func__);
7400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tty = port->tty;
7420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!tty) {
743441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - no tty available", __func__);
7440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
7450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
7460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* if we are implementing XON/XOFF, send the stop character */
7480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (I_IXOFF(tty)) {
7490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		unsigned char stop_char = STOP_CHAR(tty);
7500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		status = mos7720_write(port, &stop_char, 1);
7510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (status <= 0)
7520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			return;
7530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
7540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* if we are implementing RTS/CTS, toggle that line */
7560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (tty->termios->c_cflag & CRTSCTS) {
7570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mos7720_port->shadowMCR &= ~UART_MCR_RTS;
7580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		status = send_mos_cmd(port->serial, MOS_WRITE,
7590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				      port->number - port->serial->minor,
7600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				      UART_MCR, &mos7720_port->shadowMCR);
7610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (status != 0)
7620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			return;
7630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
7640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
7650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic void mos7720_unthrottle(struct usb_serial_port *port)
7670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
7680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct tty_struct *tty;
7690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int status;
7700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
7710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
7730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
7740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!mos7720_port->open) {
776441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - port not opened", __func__);
7770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
7780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
7790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
780441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s: Entering ..........", __func__);
7810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tty = port->tty;
7830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!tty) {
784441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - no tty available", __func__);
7850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
7860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
7870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* if we are implementing XON/XOFF, send the start character */
7890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (I_IXOFF(tty)) {
7900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		unsigned char start_char = START_CHAR(tty);
7910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		status = mos7720_write(port, &start_char, 1);
7920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (status <= 0)
7930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			return;
7940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
7950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* if we are implementing RTS/CTS, toggle that line */
7970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (tty->termios->c_cflag & CRTSCTS) {
7980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mos7720_port->shadowMCR |= UART_MCR_RTS;
7990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		status = send_mos_cmd(port->serial, MOS_WRITE,
8000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				      port->number - port->serial->minor,
8010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				      UART_MCR, &mos7720_port->shadowMCR);
8020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (status != 0)
8030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			return;
8040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
8050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
8060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int set_higher_rates(struct moschip_port *mos7720_port,
8080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			    unsigned int baud)
8090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
8100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned char data;
8110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial_port *port;
8120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial *serial;
8130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int port_number;
8140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
8160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -EINVAL;
8170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	port = mos7720_port->port;
8190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	serial = port->serial;
8200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        /***********************************************
8220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman         *      Init Sequence for higher rates
8230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman         ***********************************************/
8240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	dbg("Sending Setting Commands ..........");
8250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	port_number = port->number - port->serial->minor;
8260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x000;
8280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
8290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x000;
8300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
8310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x0CF;
8320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port->number, 0x02, &data);
8330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00b;
8340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        mos7720_port->shadowMCR  = data;
8350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
8360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00b;
8370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
8380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x000;
8400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
8410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x000;
8420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
8430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        /***********************************************
8460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman         *              Set for higher rates           *
8470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman         ***********************************************/
8480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = baud * 0x10;
8500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1,&data);
8510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x003;
8530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
8540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x003;
8550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
8560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x02b;
8580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        mos7720_port->shadowMCR  = data;
8590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
8600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x02b;
8610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
8620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        /***********************************************
8640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman         *              Set DLL/DLM
8650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman         ***********************************************/
8660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = mos7720_port->shadowLCR | UART_LCR_DLAB;
8680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        mos7720_port->shadowLCR  = data;
8690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
8700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data =  0x001; /* DLL */
8720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data);
8730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data =  0x000; /* DLM */
8740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
8750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
8770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        mos7720_port->shadowLCR  = data;
8780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
8790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return 0;
8810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
8820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* baud rate information */
8840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstruct divisor_table_entry
8850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
8860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u32  baudrate;
8870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u16  divisor;
8880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman};
8890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* Define table of divisors for moschip 7720 hardware	   *
8910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * These assume a 3.6864MHz crystal, the standard /16, and *
8920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * MCR.7 = 0.						   */
8930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic struct divisor_table_entry divisor_table[] = {
8940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   50,		2304},
8950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   110,	1047},	/* 2094.545455 => 230450   => .0217 % over */
8960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   134,	857},	/* 1713.011152 => 230398.5 => .00065% under */
8970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   150,	768},
8980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   300,	384},
8990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   600,	192},
9000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   1200,	96},
9010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   1800,	64},
9020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   2400,	48},
9030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   4800,	24},
9040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   7200,	16},
9050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   9600,	12},
9060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   19200,	6},
9070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   38400,	3},
9080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   57600,	2},
9090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   115200,	1},
9100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman};
9110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*****************************************************************************
9130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * calc_baud_rate_divisor
9140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	this function calculates the proper baud rate divisor for the specified
9150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	baud rate.
9160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *****************************************************************************/
9170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int calc_baud_rate_divisor(int baudrate, int *divisor)
9180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
9190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int i;
9200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u16 custom;
9210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u16 round1;
9220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u16 round;
9230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
925441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - %d", __func__, baudrate);
9260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	for (i = 0; i < ARRAY_SIZE(divisor_table); i++) {
9280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (divisor_table[i].baudrate == baudrate) {
9290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			*divisor = divisor_table[i].divisor;
9300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			return 0;
9310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
9320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
9330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        /* After trying for all the standard baud rates    *
9350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman         * Try calculating the divisor for this baud rate  */
9360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (baudrate > 75 &&  baudrate < 230400) {
9370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* get the divisor */
9380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		custom = (__u16)(230400L  / baudrate);
9390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* Check for round off */
9410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		round1 = (__u16)(2304000L / baudrate);
9420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		round = (__u16)(round1 - (custom * 10));
9430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (round > 4)
9440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			custom++;
9450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		*divisor = custom;
9460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("Baud %d = %d",baudrate, custom);
9480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return 0;
9490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
9500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	dbg("Baud calculation Failed...");
9520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return -EINVAL;
9530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
9540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
9560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * send_cmd_write_baud_rate
9570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	this function sends the proper command to change the baud rate of the
9580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	specified port.
9590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
9600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int send_cmd_write_baud_rate(struct moschip_port *mos7720_port,
9610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				    int baudrate)
9620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
9630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial_port *port;
9640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial *serial;
9650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int divisor;
9660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int status;
9670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned char data;
9680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned char number;
9690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
9710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -1;
9720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	port = mos7720_port->port;
9740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	serial = port->serial;
9750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
976441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s: Entering ..........", __func__);
9770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	number = port->number - port->serial->minor;
979441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port = %d, baud = %d", __func__, port->number, baudrate);
9800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        /* Calculate the Divisor */
9820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	status = calc_baud_rate_divisor(baudrate, &divisor);
9830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (status) {
984441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		err("%s - bad baud rate", __func__);
9850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return status;
9860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
9870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        /* Enable access to divisor latch */
9890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        data = mos7720_port->shadowLCR | UART_LCR_DLAB;
9900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        mos7720_port->shadowLCR  = data;
9910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        send_mos_cmd(serial, MOS_WRITE, number, UART_LCR, &data);
9920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Write the divisor */
9940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = ((unsigned char)(divisor & 0xff));
9950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        send_mos_cmd(serial, MOS_WRITE, number, 0x00, &data);
9960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = ((unsigned char)((divisor & 0xff00) >> 8));
9980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        send_mos_cmd(serial, MOS_WRITE, number, 0x01, &data);
9990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        /* Disable access to divisor latch */
10010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        data = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
10020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        mos7720_port->shadowLCR = data;
10030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        send_mos_cmd(serial, MOS_WRITE, number, 0x03, &data);
10040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return status;
10060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
10070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
10090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * change_port_settings
10100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	This routine is called to set the UART on the device to match
10110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *      the specified new settings.
10120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
10130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic void change_port_settings(struct moschip_port *mos7720_port,
1014606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox				 struct ktermios *old_termios)
10150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
10160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial_port *port;
10170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial *serial;
10180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct tty_struct *tty;
10190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int baud;
10200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned cflag;
10210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned iflag;
10220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u8 mask = 0xff;
10230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u8 lData;
10240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u8 lParity;
10250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u8 lStop;
10260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int status;
10270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int port_number;
10280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	char data;
10290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
10310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return ;
10320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	port = mos7720_port->port;
10340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	serial = port->serial;
10350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	port_number = port->number - port->serial->minor;
10360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1037441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
10380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!mos7720_port->open) {
1040441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - port not opened", __func__);
10410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
10420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
10430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tty = mos7720_port->port->tty;
10450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1046441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s: Entering ..........", __func__);
10470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	lData = UART_LCR_WLEN8;
10490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	lStop = 0x00;	/* 1 stop bit */
10500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	lParity = 0x00;	/* No parity */
10510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	cflag = tty->termios->c_cflag;
10530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	iflag = tty->termios->c_iflag;
10540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Change the number of bits */
10560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	switch (cflag & CSIZE) {
10570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case CS5:
10580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		lData = UART_LCR_WLEN5;
10590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mask = 0x1f;
10600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		break;
10610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case CS6:
10630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		lData = UART_LCR_WLEN6;
10640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mask = 0x3f;
10650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		break;
10660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case CS7:
10680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		lData = UART_LCR_WLEN7;
10690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mask = 0x7f;
10700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		break;
10710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	default:
10720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case CS8:
10730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		lData = UART_LCR_WLEN8;
10740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		break;
10750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
10760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Change the Parity bit */
10780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (cflag & PARENB) {
10790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (cflag & PARODD) {
10800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			lParity = UART_LCR_PARITY;
1081441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			dbg("%s - parity = odd", __func__);
10820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		} else {
10830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			lParity = (UART_LCR_EPAR | UART_LCR_PARITY);
1084441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			dbg("%s - parity = even", __func__);
10850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
10860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	} else {
1088441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - parity = none", __func__);
10890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
10900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (cflag & CMSPAR)
10920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		lParity = lParity | 0x20;
10930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Change the Stop bit */
10950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (cflag & CSTOPB) {
10960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		lStop = UART_LCR_STOP;
1097441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - stop bits = 2", __func__);
10980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	} else {
10990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		lStop = 0x00;
1100441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - stop bits = 1", __func__);
11010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
11020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define LCR_BITS_MASK		0x03	/* Mask for bits/char field */
11040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define LCR_STOP_MASK		0x04	/* Mask for stop bits field */
11050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define LCR_PAR_MASK		0x38	/* Mask for parity field */
11060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Update the LCR with the correct value */
11080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
11090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port->shadowLCR |= (lData | lParity | lStop);
11100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Disable Interrupts */
11130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00;
11140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        send_mos_cmd(serial,MOS_WRITE,port->number - port->serial->minor, UART_IER, &data);
11150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00;
11170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data);
11180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0xcf;
11200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data);
11210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Send the updated LCR value to the mos7720 */
11230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = mos7720_port->shadowLCR;
11240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        send_mos_cmd(serial, MOS_WRITE, port_number, UART_LCR, &data);
11250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        data = 0x00b;
11270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        mos7720_port->shadowMCR = data;
11280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
11290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        data = 0x00b;
11300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
11310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* set up the MCR register and send it to the mos7720 */
11330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port->shadowMCR = UART_MCR_OUT2;
11340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (cflag & CBAUD)
11350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mos7720_port->shadowMCR |= (UART_MCR_DTR | UART_MCR_RTS);
11360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (cflag & CRTSCTS) {
11380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mos7720_port->shadowMCR |= (UART_MCR_XONANY);
11390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman                /* To set hardware flow control to the specified *
11410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman                 * serial port, in SP1/2_CONTROL_REG             */
11420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (port->number) {
11430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			data = 0x001;
11440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT,
11450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				     0x08, &data);
11460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		} else {
11470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			data = 0x002;
11480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT,
11490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				     0x08, &data);
11500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
11510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	} else {
11520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mos7720_port->shadowMCR &= ~(UART_MCR_XONANY);
11530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
11540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = mos7720_port->shadowMCR;
11560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, UART_MCR, &data);
11570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Determine divisor based on baud rate */
11590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	baud = tty_get_baud_rate(tty);
11600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!baud) {
11610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* pick a default, any default... */
11620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("Picked default baud...");
11630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		baud = 9600;
11640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
11650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (baud >= 230400) {
11670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		set_higher_rates(mos7720_port, baud);
11680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* Enable Interrupts */
11690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		data = 0x0c;
11700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data);
11710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
11720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
11730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1174441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - baud rate = %d", __func__, baud);
11750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	status = send_cmd_write_baud_rate(mos7720_port, baud);
117665d063ab21feea8cf65d64fba50a5c4fa7bfd6beAlan Cox	/* FIXME: needs to write actual resulting baud back not just
117765d063ab21feea8cf65d64fba50a5c4fa7bfd6beAlan Cox	   blindly do so */
117865d063ab21feea8cf65d64fba50a5c4fa7bfd6beAlan Cox	if (cflag & CBAUD)
117965d063ab21feea8cf65d64fba50a5c4fa7bfd6beAlan Cox		tty_encode_baud_rate(tty, baud, baud);
11800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Enable Interrupts */
11810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x0c;
11820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data);
11830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (port->read_urb->status != -EINPROGRESS) {
11850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		port->read_urb->dev = serial->dev;
11860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
11880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (status)
11890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dbg("usb_submit_urb(read bulk) failed, status = %d",
11900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			    status);
11910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
11920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return;
11930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
11940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
11960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720_set_termios
11970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	this function is called by the tty driver when it wants to change the
11980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	termios structure.
11990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
12000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic void mos7720_set_termios(struct usb_serial_port *port,
1201606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox				struct ktermios *old_termios)
12020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
12030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int status;
12040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned int cflag;
12050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial *serial;
12060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
12070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct tty_struct *tty;
12080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	serial = port->serial;
12100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = usb_get_serial_port_data(port);
12120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
12140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
12150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tty = port->tty;
12170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!mos7720_port->open) {
1220441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - port not opened", __func__);
12210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
12220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
12230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	dbg("%s\n","setting termios - ASPIRE");
12250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	cflag = tty->termios->c_cflag;
12270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1228441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - cflag %08x iflag %08x", __func__,
12290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	    tty->termios->c_cflag,
12300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	    RELEVANT_IFLAG(tty->termios->c_iflag));
12310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1232441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - old cflag %08x old iflag %08x", __func__,
123365d063ab21feea8cf65d64fba50a5c4fa7bfd6beAlan Cox	    old_termios->c_cflag,
123465d063ab21feea8cf65d64fba50a5c4fa7bfd6beAlan Cox	    RELEVANT_IFLAG(old_termios->c_iflag));
12350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1236441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
12370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* change the port settings to the new ones specified */
12390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	change_port_settings(mos7720_port, old_termios);
12400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if(!port->read_urb) {
12420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("%s","URB KILLED !!!!!\n");
12430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
12440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
12450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if(port->read_urb->status != -EINPROGRESS) {
12470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		port->read_urb->dev = serial->dev;
12480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
12490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (status)
12500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dbg("usb_submit_urb(read bulk) failed, status = %d",
12510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			    status);
12520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
12530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return;
12540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
12550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
12570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * get_lsr_info - get line status register info
12580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *
12590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Purpose: Let user call ioctl() to get info when the UART physically
12600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 	    is emptied.  On bus types like RS485, the transmitter must
12610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 	    release the bus after transmitting. This must be done when
12620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 	    the transmit shift register is empty, not be done when the
12630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 	    transmit holding register is empty.  This functionality
12640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 	    allows an RS485 driver to be written in user space.
12650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
12660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int get_lsr_info(struct moschip_port *mos7720_port,
12670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			unsigned int __user *value)
12680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
12690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int count;
12700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned int result = 0;
12710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	count = mos7720_chars_in_buffer(mos7720_port->port);
12730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (count == 0) {
1274441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s -- Empty", __func__);
12750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		result = TIOCSER_TEMT;
12760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
12770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (copy_to_user(value, &result, sizeof(int)))
12790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -EFAULT;
12800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return 0;
12810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
12820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
12840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * get_number_bytes_avail - get number of bytes available
12850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *
12860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Purpose: Let user call ioctl to get the count of number of bytes available.
12870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
12880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int get_number_bytes_avail(struct moschip_port *mos7720_port,
12890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				  unsigned int __user *value)
12900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
12910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned int result = 0;
12920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct tty_struct *tty = mos7720_port->port->tty;
12930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!tty)
12950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -ENOIOCTLCMD;
12960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	result = tty->read_cnt;
12980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1299441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s(%d) = %d", __func__,  mos7720_port->port->number, result);
13000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (copy_to_user(value, &result, sizeof(int)))
13010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -EFAULT;
13020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return -ENOIOCTLCMD;
13040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
13050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
13070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			  unsigned int __user *value)
13080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
13090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned int mcr ;
13100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned int arg;
13110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned char data;
13120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial_port *port;
13140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
13160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -1;
13170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	port = (struct usb_serial_port*)mos7720_port->port;
13190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mcr = mos7720_port->shadowMCR;
13200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (copy_from_user(&arg, value, sizeof(int)))
13220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -EFAULT;
13230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	switch (cmd) {
13250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCMBIS:
13260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (arg & TIOCM_RTS)
13270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			mcr |= UART_MCR_RTS;
13280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (arg & TIOCM_DTR)
13290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			mcr |= UART_MCR_RTS;
13300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (arg & TIOCM_LOOP)
13310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			mcr |= UART_MCR_LOOP;
13320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		break;
13330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCMBIC:
13350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (arg & TIOCM_RTS)
13360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			mcr &= ~UART_MCR_RTS;
13370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (arg & TIOCM_DTR)
13380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			mcr &= ~UART_MCR_RTS;
13390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (arg & TIOCM_LOOP)
13400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			mcr &= ~UART_MCR_LOOP;
13410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		break;
13420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCMSET:
13440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* turn off the RTS and DTR and LOOPBACK
13450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		 * and then only turn on what was asked to */
13460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mcr &=  ~(UART_MCR_RTS | UART_MCR_DTR | UART_MCR_LOOP);
13470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mcr |= ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0);
13480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mcr |= ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0);
13490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mcr |= ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0);
13500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		break;
13510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
13520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port->shadowMCR = mcr;
13540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = mos7720_port->shadowMCR;
13560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(port->serial, MOS_WRITE,
13570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		     port->number - port->serial->minor, UART_MCR, &data);
13580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return 0;
13600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
13610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int get_modem_info(struct moschip_port *mos7720_port,
13630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			  unsigned int __user *value)
13640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
13650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned int result = 0;
13660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned int msr = mos7720_port->shadowMSR;
13670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned int mcr = mos7720_port->shadowMCR;
13680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	result = ((mcr & UART_MCR_DTR)	? TIOCM_DTR: 0)	  /* 0x002 */
13700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		  | ((mcr & UART_MCR_RTS)	? TIOCM_RTS: 0)   /* 0x004 */
13710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		  | ((msr & UART_MSR_CTS)	? TIOCM_CTS: 0)   /* 0x020 */
13720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		  | ((msr & UART_MSR_DCD)	? TIOCM_CAR: 0)   /* 0x040 */
13730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		  | ((msr & UART_MSR_RI)	? TIOCM_RI:  0)   /* 0x080 */
13740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		  | ((msr & UART_MSR_DSR)	? TIOCM_DSR: 0);  /* 0x100 */
13750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1377441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s -- %x", __func__, result);
13780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (copy_to_user(value, &result, sizeof(int)))
13800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -EFAULT;
13810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return 0;
13820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
13830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int get_serial_info(struct moschip_port *mos7720_port,
13850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			   struct serial_struct __user *retinfo)
13860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
13870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct serial_struct tmp;
13880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!retinfo)
13900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -EFAULT;
13910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	memset(&tmp, 0, sizeof(tmp));
13930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tmp.type		= PORT_16550A;
13950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tmp.line		= mos7720_port->port->serial->minor;
13960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tmp.port		= mos7720_port->port->number;
13970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tmp.irq			= 0;
13980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tmp.flags		= ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
13990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman        tmp.xmit_fifo_size	= NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
14000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tmp.baud_base		= 9600;
14010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tmp.close_delay		= 5*HZ;
14020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tmp.closing_wait	= 30*HZ;
14030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
14050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -EFAULT;
14060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return 0;
14070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
14080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int mos7720_ioctl(struct usb_serial_port *port, struct file *file,
14100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			 unsigned int cmd, unsigned long arg)
14110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
14120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
14130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct async_icount cnow;
14140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct async_icount cprev;
14150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct serial_icounter_struct icount;
14160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = usb_get_serial_port_data(port);
14180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
14190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -ENODEV;
14200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1421441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
14220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	switch (cmd) {
14240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCINQ:
14250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* return number of bytes available */
1426441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s (%d) TIOCINQ", __func__,  port->number);
14270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return get_number_bytes_avail(mos7720_port,
14280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman					      (unsigned int __user *)arg);
14290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		break;
14300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCSERGETLSR:
1432441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s (%d) TIOCSERGETLSR", __func__,  port->number);
14330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return get_lsr_info(mos7720_port, (unsigned int __user *)arg);
14340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return 0;
14350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCMBIS:
14370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCMBIC:
14380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCMSET:
1439441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __func__,
14400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		    port->number);
14410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return set_modem_info(mos7720_port, cmd,
14420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				      (unsigned int __user *)arg);
14430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCMGET:
1445441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s (%d) TIOCMGET", __func__,  port->number);
14460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return get_modem_info(mos7720_port,
14470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				      (unsigned int __user *)arg);
14480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCGSERIAL:
1450441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s (%d) TIOCGSERIAL", __func__,  port->number);
14510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return get_serial_info(mos7720_port,
14520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				       (struct serial_struct __user *)arg);
14530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCSSERIAL:
1455441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s (%d) TIOCSSERIAL", __func__,  port->number);
14560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		break;
14570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCMIWAIT:
1459441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);
14600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		cprev = mos7720_port->icount;
14610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		while (1) {
14620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			if (signal_pending(current))
14630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				return -ERESTARTSYS;
14640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			cnow = mos7720_port->icount;
14650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
14660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
14670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				return -EIO; /* no change => error */
14680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
14690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
14700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
14710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
14720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				return 0;
14730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			}
14740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			cprev = cnow;
14750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
14760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* NOTREACHED */
14770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		break;
14780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCGICOUNT:
14800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		cnow = mos7720_port->icount;
14810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.cts = cnow.cts;
14820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.dsr = cnow.dsr;
14830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.rng = cnow.rng;
14840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.dcd = cnow.dcd;
14850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.rx = cnow.rx;
14860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.tx = cnow.tx;
14870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.frame = cnow.frame;
14880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.overrun = cnow.overrun;
14890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.parity = cnow.parity;
14900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.brk = cnow.brk;
14910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.buf_overrun = cnow.buf_overrun;
14920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1493441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __func__,
14940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		    port->number, icount.rx, icount.tx );
14950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (copy_to_user((void __user *)arg, &icount, sizeof(icount)))
14960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			return -EFAULT;
14970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return 0;
14980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
14990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return -ENOIOCTLCMD;
15010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
15020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int mos7720_startup(struct usb_serial *serial)
15040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
15050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_serial *mos7720_serial;
15060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
15070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_device *dev;
15080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int i;
15090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	char data;
15100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1511441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s: Entering ..........", __func__);
15120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!serial) {
15140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("Invalid Handler");
15150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -ENODEV;
15160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
15170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	dev = serial->dev;
15190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* create our private serial structure */
15210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_serial = kzalloc(sizeof(struct moschip_serial), GFP_KERNEL);
15220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_serial == NULL) {
1523441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		err("%s - Out of memory", __func__);
15240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -ENOMEM;
15250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
15260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	usb_set_serial_data(serial, mos7720_serial);
15280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* we set up the pointers to the endpoints in the mos7720_open *
15300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	 * function, as the structures aren't created yet.             */
15310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* set up port private structures */
15330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	for (i = 0; i < serial->num_ports; ++i) {
15340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
15350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (mos7720_port == NULL) {
1536441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			err("%s - Out of memory", __func__);
15370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			usb_set_serial_data(serial, NULL);
15380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			kfree(mos7720_serial);
15390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			return -ENOMEM;
15400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
15410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* Initialize all port interrupt end point to port 0 int
15430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		 * endpoint.  Our device has only one interrupt endpoint
15440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		 * comman to all ports */
15450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		serial->port[i]->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress;
15460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mos7720_port->port = serial->port[i];
15480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		usb_set_serial_port_data(serial->port[i], mos7720_port);
15490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("port number is %d", serial->port[i]->number);
15510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("serial number is %d", serial->minor);
15520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
15530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* setting configuration feature to one */
15560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
15570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			(__u8)0x03, 0x00,0x01,0x00, NULL, 0x00, 5*HZ);
15580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial,MOS_READ,0x00, UART_LSR, &data);  // LSR For Port 1
15600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	dbg("LSR:%x",data);
15610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial,MOS_READ,0x01, UART_LSR, &data);  // LSR For Port 2
15630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	dbg("LSR:%x",data);
15640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return 0;
15660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
15670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic void mos7720_shutdown(struct usb_serial *serial)
15690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
15700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int i;
15710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* free private structure allocated for serial port */
15730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	for (i=0; i < serial->num_ports; ++i) {
15740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		kfree(usb_get_serial_port_data(serial->port[i]));
15750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		usb_set_serial_port_data(serial->port[i], NULL);
15760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
15770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* free private structure allocated for serial device */
15790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	kfree(usb_get_serial_data(serial));
15800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	usb_set_serial_data(serial, NULL);
15810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
15820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1583d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzlstatic struct usb_driver usb_driver = {
1584d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl	.name =		"moschip7720",
1585d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl	.probe =	usb_serial_probe,
1586d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl	.disconnect =	usb_serial_disconnect,
1587d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl	.id_table =	moschip_port_id_table,
1588d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl	.no_dynamic_id =	1,
1589d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl};
1590d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl
15910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic struct usb_serial_driver moschip7720_2port_driver = {
15920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.driver = {
15930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		.owner =	THIS_MODULE,
15940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		.name =		"moschip7720",
15950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	},
15960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.description		= "Moschip 2 port adapter",
1597d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl	.usb_driver		= &usb_driver,
15980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.id_table		= moschip_port_id_table,
15990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.num_ports		= 2,
16000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.open			= mos7720_open,
16010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.close			= mos7720_close,
16020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.throttle		= mos7720_throttle,
16030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.unthrottle		= mos7720_unthrottle,
16040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.attach			= mos7720_startup,
16050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.shutdown		= mos7720_shutdown,
16060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.ioctl			= mos7720_ioctl,
16070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.set_termios		= mos7720_set_termios,
16080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.write			= mos7720_write,
16090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.write_room		= mos7720_write_room,
16100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.chars_in_buffer	= mos7720_chars_in_buffer,
16110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.break_ctl		= mos7720_break,
16120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.read_bulk_callback	= mos7720_bulk_in_callback,
1613e8e30c765c5cfa5219918d3e5017fc563cf7ea03Oliver Neukum	.read_int_callback	= mos7720_interrupt_callback,
16140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman};
16150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int __init moschip7720_init(void)
16170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
16180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int retval;
16190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1620441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s: Entering ..........", __func__);
16210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Register with the usb serial */
16230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	retval = usb_serial_register(&moschip7720_2port_driver);
16240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (retval)
16250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		goto failed_port_device_register;
16260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	info(DRIVER_DESC " " DRIVER_VERSION);
16280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Register with the usb */
16300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	retval = usb_register(&usb_driver);
16310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (retval)
16320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		goto failed_usb_register;
16330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return 0;
16350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanfailed_usb_register:
16370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	usb_serial_deregister(&moschip7720_2port_driver);
16380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanfailed_port_device_register:
16400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return retval;
16410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
16420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic void __exit moschip7720_exit(void)
16440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
16450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	usb_deregister(&usb_driver);
16460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	usb_serial_deregister(&moschip7720_2port_driver);
16470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
16480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanmodule_init(moschip7720_init);
16500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanmodule_exit(moschip7720_exit);
16510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* Module information */
16530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-HartmanMODULE_AUTHOR( DRIVER_AUTHOR );
16540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-HartmanMODULE_DESCRIPTION( DRIVER_DESC );
16550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-HartmanMODULE_LICENSE("GPL");
16560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanmodule_param(debug, bool, S_IRUGO | S_IWUSR);
16580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-HartmanMODULE_PARM_DESC(debug, "Debug enabled or not");
1659