mos7720.c revision 0f608f8926968b4beee2cb00ef05522ad84f36eb
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>
364da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox#include <linux/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 */
674da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Coxstruct moschip_port {
680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u8	shadowLCR;		/* last LCR value received */
690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u8	shadowMCR;		/* last MCR value received */
700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u8	shadowMSR;		/* last MSR value received */
710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	char			open;
720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct async_icount	icount;
730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial_port	*port;	/* loop back to the owner */
740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct urb		*write_urb_pool[NUM_URBS];
750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman};
760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* This structure holds all of the individual serial device information */
784da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Coxstruct moschip_serial {
790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int interrupt_started;
800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman};
810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int debug;
830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define USB_VENDOR_ID_MOSCHIP		0x9710
850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define MOSCHIP_DEVICE_ID_7720		0x7720
860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define MOSCHIP_DEVICE_ID_7715		0x7715
870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
880f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakersstatic struct usb_device_id moschip_port_id_table[] = {
894da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	{ USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7720) },
900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{ } /* terminating entry */
910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman};
920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-HartmanMODULE_DEVICE_TABLE(usb, moschip_port_id_table);
930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720_interrupt_callback
970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	this is the callback function for when we have received data on the
980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	interrupt endpoint.
990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
1000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic void mos7720_interrupt_callback(struct urb *urb)
1010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
1020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int result;
1030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int length;
10481105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman	int status = urb->status;
105325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum	__u8 *data;
1060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u8 sp1;
1070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u8 sp2;
1080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1094da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	dbg("%s", " : Entering\n");
1100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11181105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman	switch (status) {
1120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case 0:
1130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* success */
1140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		break;
1150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case -ECONNRESET:
1160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case -ENOENT:
1170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case -ESHUTDOWN:
1180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* this urb is terminated, clean up */
119441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - urb shutting down with status: %d", __func__,
12081105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman		    status);
1210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
1220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	default:
123441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - nonzero urb status received: %d", __func__,
12481105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman		    status);
1250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		goto exit;
1260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
1270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	length = urb->actual_length;
1290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = urb->transfer_buffer;
1300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Moschip get 4 bytes
1320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	 * Byte 1 IIR Port 1 (port.number is 0)
1330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	 * Byte 2 IIR Port 2 (port.number is 1)
1340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	 * Byte 3 --------------
1350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	 * Byte 4 FIFO status for both */
136325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum
137325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum	/* the above description is inverted
138325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum	 * 	oneukum 2007-03-14 */
139325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum
140325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum	if (unlikely(length != 4)) {
1410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("Wrong data !!!");
1420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
1430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
1440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
145325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum	sp1 = data[3];
146325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum	sp2 = data[2];
1470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
148325b70c233396f0cfe15012682a5080bf8040901Oliver Neukum	if ((sp1 | sp2) & 0x01) {
1490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* No Interrupt Pending in both the ports */
1500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("No Interrupt !!!");
1510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	} else {
1520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		switch (sp1 & 0x0f) {
1530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		case SERIAL_IIR_RLS:
1540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dbg("Serial Port 1: Receiver status error or address "
1550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			    "bit detected in 9-bit mode\n");
1560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			break;
1570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		case SERIAL_IIR_CTI:
1580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dbg("Serial Port 1: Receiver time out");
1590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			break;
1600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		case SERIAL_IIR_MS:
1610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dbg("Serial Port 1: Modem status change");
1620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			break;
1630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
1640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		switch (sp2 & 0x0f) {
1660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		case SERIAL_IIR_RLS:
1670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dbg("Serial Port 2: Receiver status error or address "
1680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			    "bit detected in 9-bit mode");
1690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			break;
1700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		case SERIAL_IIR_CTI:
1710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dbg("Serial Port 2: Receiver time out");
1720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			break;
1730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		case SERIAL_IIR_MS:
1740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dbg("Serial Port 2: Modem status change");
1750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			break;
1760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
1770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
1780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanexit:
1800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	result = usb_submit_urb(urb, GFP_ATOMIC);
1810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (result)
1820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dev_err(&urb->dev->dev,
1830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			"%s - Error %d submitting control urb\n",
184441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			__func__, result);
1850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return;
1860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
1870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
1890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720_bulk_in_callback
1900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	this is the callback function for when we have received data on the
1910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	bulk in endpoint.
1920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
1930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic void mos7720_bulk_in_callback(struct urb *urb)
1940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
19581105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman	int retval;
1960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned char *data ;
1970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial_port *port;
1980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
1990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct tty_struct *tty;
20081105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman	int status = urb->status;
2010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
20281105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman	if (status) {
20381105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman		dbg("nonzero read bulk status received: %d", status);
2040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
2050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
2060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = urb->context;
2080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!mos7720_port) {
2094da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		dbg("%s", "NULL mos7720_port pointer \n");
2100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return ;
2110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
2120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	port = mos7720_port->port;
2140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
215441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("Entering...%s", __func__);
2160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = urb->transfer_buffer;
2180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2194a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox	tty = tty_port_tty_get(&port->port);
2200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (tty && urb->actual_length) {
2210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		tty_buffer_request_room(tty, urb->actual_length);
2220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		tty_insert_flip_string(tty, data, urb->actual_length);
2230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		tty_flip_buffer_push(tty);
2240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
2254a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox	tty_kref_put(tty);
2260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!port->read_urb) {
2280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("URB KILLED !!!");
2290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
2300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
2310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (port->read_urb->status != -EINPROGRESS) {
2330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		port->read_urb->dev = port->serial->dev;
2340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
23581105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman		retval = usb_submit_urb(port->read_urb, GFP_ATOMIC);
23681105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman		if (retval)
23781105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman			dbg("usb_submit_urb(read bulk) failed, retval = %d",
23881105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman			    retval);
2390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
2400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
2410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
2430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720_bulk_out_data_callback
2440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	this is the callback function for when we have finished sending serial
2450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	data on the bulk out endpoint.
2460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
2470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic void mos7720_bulk_out_data_callback(struct urb *urb)
2480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
2490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
2500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct tty_struct *tty;
25181105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman	int status = urb->status;
2520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
25381105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman	if (status) {
25481105984848481d8876e454e3c503dbd0e8e4dceGreg Kroah-Hartman		dbg("nonzero write bulk status received:%d", status);
2550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
2560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
2570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = urb->context;
2590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!mos7720_port) {
2600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("NULL mos7720_port pointer");
2610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return ;
2620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
2630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	dbg("Entering .........");
2650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
2664a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox	tty = tty_port_tty_get(&mos7720_port->port->port);
2670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
268b963a8441cb95999c97bea379607071a869c65f0Jiri Slaby	if (tty && mos7720_port->open)
269b963a8441cb95999c97bea379607071a869c65f0Jiri Slaby		tty_wakeup(tty);
2704a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox	tty_kref_put(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) {
2874da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		if (product == MOSCHIP_DEVICE_ID_7715)
2880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			value = value*0x100+0x100;
2894da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		else
2900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			value = value*0x100+0x200;
2910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	} else {
2920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		value = 0x0000;
2930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if ((product == MOSCHIP_DEVICE_ID_7715) &&
2940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		    (index != 0x08)) {
2950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dbg("serial->product== MOSCHIP_DEVICE_ID_7715");
2964da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox			/* index = 0x01 ; */
2970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
2980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
2990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (request == MOS_WRITE) {
3010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		request = (__u8)MOS_WRITE;
3020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		requesttype = (__u8)0x40;
3030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		value  = value + (__u16)*((unsigned char *)data);
3040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		data = NULL;
3050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		pipe = usb_sndctrlpipe(serial->dev, 0);
3060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	} else {
3070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		request = (__u8)MOS_READ;
3080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		requesttype = (__u8)0xC0;
3090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		size = 0x01;
3104da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		pipe = usb_rcvctrlpipe(serial->dev, 0);
3110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
3120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	status = usb_control_msg(serial->dev, pipe, request, requesttype,
3140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				 value, index, data, size, MOS_WDR_TIMEOUT);
3150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (status < 0)
3174da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		dbg("Command Write failed Value %x index %x\n", value, index);
3180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return status;
3200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
3210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
32295da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int mos7720_open(struct tty_struct *tty,
3234da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox			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) {
3544da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		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) {
358194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman			dev_err(&port->dev, "No more urbs???\n");
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) {
365194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman			dev_err(&port->dev,
366194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman				"%s-out of memory for urb buffers.\n",
367194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman				__func__);
368fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum			usb_free_urb(mos7720_port->write_urb_pool[j]);
369fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum			mos7720_port->write_urb_pool[j] = NULL;
3700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			continue;
3710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
372fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum		allocated_urbs++;
3730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
3740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
375fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum	if (!allocated_urbs)
376fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum		return -ENOMEM;
377fe4b65ec9127a336eeaa503f878062d9e6f44591Oliver Neukum
3780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	 /* Initialize MCS7720 -- Write Init values to corresponding Registers
3790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	  *
3800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	  * Register Index
3810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	  * 1 : IER
3820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	  * 2 : FCR
3830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	  * 3 : LCR
3840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	  * 4 : MCR
3850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	  *
3860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	  * 0x08 : SP1/2 Control Reg
3870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	  */
3880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	port_number = port->number - port->serial->minor;
3890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(port->serial, MOS_READ, port_number, UART_LSR, &data);
3904da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	dbg("SS::%p LSR:%x\n", mos7720_port, data);
3910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	dbg("Check:Sending Command ..........");
3930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x02;
3950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x01, &data);
3960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x02;
3970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x02, &data);
3980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
3990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00;
4000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
4010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00;
4020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
4030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0xCF;
4050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
4060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x03;
4074da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	mos7720_port->shadowLCR  = data;
4080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
4090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x0b;
4104da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	mos7720_port->shadowMCR  = data;
4110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
4120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x0b;
4130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
4140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00;
4160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
4170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00;
4180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
4190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*	data = 0x00;
4210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, port_number + 1, &data);
4220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x03;
4230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data);
4240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00;
4254da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	send_mos_cmd(port->serial, MOS_WRITE, MOS_MAX_PORT,
4264da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox						port_number + 1, &data);
4270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman*/
4280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00;
4290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
4300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = data | (port->number - port->serial->minor + 1);
4320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
4330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x83;
4354da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	mos7720_port->shadowLCR  = data;
4360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
4370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x0c;
4380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data);
4390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00;
4400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
4410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x03;
4424da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	mos7720_port->shadowLCR  = data;
4430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
4440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x0c;
4450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
4460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x0c;
4470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
4480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* see if we've set up our endpoint info yet   *
4500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	 * (can't set it up in mos7720_startup as the  *
4510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	 * structures were not set up at that time.)   */
4520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!mos7720_serial->interrupt_started) {
4530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("Interrupt buffer NULL !!!");
4540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* not set up yet, so do it now */
4560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mos7720_serial->interrupt_started = 1;
4570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("To Submit URB !!!");
4590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* set up our interrupt urb */
4610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		usb_fill_int_urb(port0->interrupt_in_urb, serial->dev,
4624da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox			 usb_rcvintpipe(serial->dev,
4634da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox				port->interrupt_in_endpointAddress),
4644da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox			 port0->interrupt_in_buffer,
4654da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox			 port0->interrupt_in_urb->transfer_buffer_length,
4664da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox			 mos7720_interrupt_callback, mos7720_port,
4674da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox			 port0->interrupt_in_urb->interval);
4680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* start interrupt read for this mos7720 this interrupt *
4704da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		 * will continue as long as the mos7720 is connected    */
4710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("Submit URB over !!!");
4720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		response = usb_submit_urb(port0->interrupt_in_urb, GFP_KERNEL);
4730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (response)
4740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dev_err(&port->dev,
475898eb71cb17644964c5895fb190e79e3d0c49679Joe Perches				"%s - Error %d submitting control urb\n",
476441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison				__func__, response);
4770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
4780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* set up our bulk in urb */
4800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	usb_fill_bulk_urb(port->read_urb, serial->dev,
4810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			  usb_rcvbulkpipe(serial->dev,
4824da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox				port->bulk_in_endpointAddress),
4830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			  port->bulk_in_buffer,
4840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			  port->read_urb->transfer_buffer_length,
4850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			  mos7720_bulk_in_callback, mos7720_port);
4860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	response = usb_submit_urb(port->read_urb, GFP_KERNEL);
4870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (response)
4884da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		dev_err(&port->dev, "%s - Error %d submitting read urb\n",
4894da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox							__func__, response);
4900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* initialize our icount structure */
4920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount));
4930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* initialize our port settings */
4950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */
4960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
4970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* send a open port command */
4980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port->open = 1;
4990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return 0;
5010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
5020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
5040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720_chars_in_buffer
5050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	this function is called by the tty driver when it wants to know how many
5060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	bytes of data we currently have outstanding in the port (data that has
5070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	been written, but hasn't made it out the port yet)
5080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	If successful, we return the number of bytes left to be written in the
5090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	system,
5100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	Otherwise we return a negative error number.
5110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
51295da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int mos7720_chars_in_buffer(struct tty_struct *tty)
5130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
51495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
5150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int i;
5160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int chars = 0;
5170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
5180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
519441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s:entering ...........", __func__);
5200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = usb_get_serial_port_data(port);
5220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL) {
523441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s:leaving ...........", __func__);
52423198fda7182969b619613a555f8645fdc3dc334Alan Cox		return 0;
5250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
5260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	for (i = 0; i < NUM_URBS; ++i) {
5284da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		if (mos7720_port->write_urb_pool[i] &&
5294da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		    mos7720_port->write_urb_pool[i]->status == -EINPROGRESS)
5300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			chars += URB_TRANSFER_BUFFER_SIZE;
5310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
532441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - returns %d", __func__, chars);
5330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return chars;
5340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
5350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
536335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void mos7720_close(struct usb_serial_port *port)
5370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
5380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial *serial;
5390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
5400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	char data;
5410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int j;
5420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	dbg("mos7720_close:entering...");
5440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	serial = port->serial;
5460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = usb_get_serial_port_data(port);
5480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
5490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
5500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	for (j = 0; j < NUM_URBS; ++j)
5520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		usb_kill_urb(mos7720_port->write_urb_pool[j]);
5530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Freeing Write URBs */
5550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	for (j = 0; j < NUM_URBS; ++j) {
5560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (mos7720_port->write_urb_pool[j]) {
5570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			kfree(mos7720_port->write_urb_pool[j]->transfer_buffer);
5580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			usb_free_urb(mos7720_port->write_urb_pool[j]);
5590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
5600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
5610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* While closing port, shutdown all bulk read, write  *
563a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	 * and interrupt read if they exists, otherwise nop   */
564a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	dbg("Shutdown bulk write");
565a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	usb_kill_urb(port->write_urb);
566a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	dbg("Shutdown bulk read");
567a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	usb_kill_urb(port->read_urb);
568a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum
569a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	mutex_lock(&serial->disc_mutex);
570a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	/* these commands must not be issued if the device has
571a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	 * been disconnected */
572a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	if (!serial->disconnected) {
573a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum		data = 0x00;
5744da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		send_mos_cmd(serial, MOS_WRITE,
5754da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox			port->number - port->serial->minor, 0x04, &data);
576a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum
577a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum		data = 0x00;
5784da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		send_mos_cmd(serial, MOS_WRITE,
5794da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox			port->number - port->serial->minor, 0x01, &data);
5800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
581a1cd7e99b343543af2be4c8c5755e26f6bfd725aOliver Neukum	mutex_unlock(&serial->disc_mutex);
5820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port->open = 0;
5830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
584441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("Leaving %s", __func__);
5850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
5860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
58795da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void mos7720_break(struct tty_struct *tty, int break_state)
5880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
58995da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
5904da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	unsigned char data;
5910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial *serial;
5920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
5930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
594441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("Entering %s", __func__);
5950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	serial = port->serial;
5970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
5980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = usb_get_serial_port_data(port);
5990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
6000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
6010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (break_state == -1)
6030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		data = mos7720_port->shadowLCR | UART_LCR_SBC;
6040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	else
6050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		data = mos7720_port->shadowLCR & ~UART_LCR_SBC;
6060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port->shadowLCR  = data;
6080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
6090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		     0x03, &data);
6100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return;
6120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
6130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
6150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720_write_room
6160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	this function is called by the tty driver when it wants to know how many
6170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	bytes of data we can accept for a specific port.
6180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	If successful, we return the amount of room that we have for this port
6190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	Otherwise we return a negative error number.
6200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
62195da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int mos7720_write_room(struct tty_struct *tty)
6220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
62395da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
6240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
6250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int room = 0;
6260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int i;
6270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
628441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s:entering ...........", __func__);
6290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = usb_get_serial_port_data(port);
6310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL) {
632441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s:leaving ...........", __func__);
6330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -ENODEV;
6340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
6350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
636a5b6f60c5a30c494017c7a2d11c4067f90d3d0dfAlan Cox	/* FIXME: Locking */
6370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	for (i = 0; i < NUM_URBS; ++i) {
6384da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		if (mos7720_port->write_urb_pool[i] &&
6394da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		    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
64795da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port,
64895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox				 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) {
6744da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		if (mos7720_port->write_urb_pool[i] &&
6754da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		    mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) {
6760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			urb = mos7720_port->write_urb_pool[i];
6774da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox			dbg("URB:%d", i);
6780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			break;
6790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
6800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
6810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (urb == NULL) {
683441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - no more free urbs", __func__);
6840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		goto exit;
6850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
6860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (urb->transfer_buffer == NULL) {
6880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
6890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman					       GFP_KERNEL);
6900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (urb->transfer_buffer == NULL) {
691194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman			dev_err(&port->dev, "%s no more kernel memory...\n",
692194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman				__func__);
6930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			goto exit;
6940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
6950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
6964da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
6970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
6980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	memcpy(urb->transfer_buffer, current_position, transfer_size);
699441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	usb_serial_debug_data(debug, &port->dev, __func__, transfer_size,
7000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			      urb->transfer_buffer);
7010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* fill urb with data and submit  */
7030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	usb_fill_bulk_urb(urb, serial->dev,
7040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			  usb_sndbulkpipe(serial->dev,
7054da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox					port->bulk_out_endpointAddress),
7060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			  urb->transfer_buffer, transfer_size,
7070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			  mos7720_bulk_out_data_callback, mos7720_port);
7080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* send it down the pipe */
7104da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	status = usb_submit_urb(urb, GFP_ATOMIC);
7110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (status) {
712194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman		dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed "
713194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman			"with status = %d\n", __func__, status);
7140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		bytes_sent = status;
7150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		goto exit;
7160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
7170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	bytes_sent = transfer_size;
7180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanexit:
7200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return bytes_sent;
7210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
7220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
72395da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void mos7720_throttle(struct tty_struct *tty)
7240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
72595da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
7260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
7270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int status;
7280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
729441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s- port %d\n", __func__, port->number);
7300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = usb_get_serial_port_data(port);
7320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
7340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
7350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!mos7720_port->open) {
7370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("port not opened");
7380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
7390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
7400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
741441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s: Entering ..........", __func__);
7420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* if we are implementing XON/XOFF, send the stop character */
7440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (I_IXOFF(tty)) {
7450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		unsigned char stop_char = STOP_CHAR(tty);
74695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox		status = mos7720_write(tty, port, &stop_char, 1);
7470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (status <= 0)
7480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			return;
7490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
7500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* if we are implementing RTS/CTS, toggle that line */
7520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (tty->termios->c_cflag & CRTSCTS) {
7530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mos7720_port->shadowMCR &= ~UART_MCR_RTS;
7540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		status = send_mos_cmd(port->serial, MOS_WRITE,
7550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				      port->number - port->serial->minor,
7560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				      UART_MCR, &mos7720_port->shadowMCR);
7570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (status != 0)
7580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			return;
7590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
7600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
7610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
76295da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void mos7720_unthrottle(struct tty_struct *tty)
7630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
76495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
7650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
76695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	int status;
7670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
7690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
7700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!mos7720_port->open) {
772441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - port not opened", __func__);
7730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
7740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
7750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
776441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s: Entering ..........", __func__);
7770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* if we are implementing XON/XOFF, send the start character */
7790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (I_IXOFF(tty)) {
7800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		unsigned char start_char = START_CHAR(tty);
78195da310e66ee8090119596c70ca8432e57f9a97fAlan Cox		status = mos7720_write(tty, port, &start_char, 1);
7820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (status <= 0)
7830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			return;
7840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
7850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* if we are implementing RTS/CTS, toggle that line */
7870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (tty->termios->c_cflag & CRTSCTS) {
7880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mos7720_port->shadowMCR |= UART_MCR_RTS;
7890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		status = send_mos_cmd(port->serial, MOS_WRITE,
7900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				      port->number - port->serial->minor,
7910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				      UART_MCR, &mos7720_port->shadowMCR);
7920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (status != 0)
7930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			return;
7940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
7950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
7960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
7970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int set_higher_rates(struct moschip_port *mos7720_port,
7980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			    unsigned int baud)
7990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
8000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned char data;
8010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial_port *port;
8020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial *serial;
8030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int port_number;
8040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
8060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -EINVAL;
8070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	port = mos7720_port->port;
8090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	serial = port->serial;
8100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8114da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	 /***********************************************
8124da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	 *      Init Sequence for higher rates
8134da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	 ***********************************************/
8140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	dbg("Sending Setting Commands ..........");
8150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	port_number = port->number - port->serial->minor;
8160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x000;
8180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
8190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x000;
8200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
8210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x0CF;
8220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port->number, 0x02, &data);
8230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00b;
8244da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	mos7720_port->shadowMCR  = data;
8250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
8260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00b;
8270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
8280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x000;
8300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
8310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x000;
8320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
8330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8354da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	/***********************************************
8364da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	 *              Set for higher rates           *
8374da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	 ***********************************************/
8380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = baud * 0x10;
8404da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data);
8410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x003;
8430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
8440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x003;
8450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
8460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x02b;
8484da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	mos7720_port->shadowMCR  = data;
8490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
8500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x02b;
8510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
8520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8534da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	/***********************************************
8544da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	 *              Set DLL/DLM
8554da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	 ***********************************************/
8560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = mos7720_port->shadowLCR | UART_LCR_DLAB;
8584da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	mos7720_port->shadowLCR  = data;
8590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
8600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data =  0x001; /* DLL */
8624da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data);
8630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data =  0x000; /* DLM */
8644da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
8650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
8674da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	mos7720_port->shadowLCR  = data;
8680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
8690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return 0;
8710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
8720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* baud rate information */
8744da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Coxstruct divisor_table_entry {
8750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u32  baudrate;
8760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u16  divisor;
8770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman};
8780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
8790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* Define table of divisors for moschip 7720 hardware	   *
8800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * These assume a 3.6864MHz crystal, the standard /16, and *
8810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * MCR.7 = 0.						   */
8820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic struct divisor_table_entry divisor_table[] = {
8830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   50,		2304},
8840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   110,	1047},	/* 2094.545455 => 230450   => .0217 % over */
8850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   134,	857},	/* 1713.011152 => 230398.5 => .00065% under */
8860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   150,	768},
8870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   300,	384},
8880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   600,	192},
8890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   1200,	96},
8900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   1800,	64},
8910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   2400,	48},
8920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   4800,	24},
8930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   7200,	16},
8940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   9600,	12},
8950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   19200,	6},
8960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   38400,	3},
8970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   57600,	2},
8980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	{   115200,	1},
8990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman};
9000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*****************************************************************************
9020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * calc_baud_rate_divisor
9030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	this function calculates the proper baud rate divisor for the specified
9040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	baud rate.
9050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *****************************************************************************/
9060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int calc_baud_rate_divisor(int baudrate, int *divisor)
9070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
9080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int i;
9090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u16 custom;
9100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u16 round1;
9110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u16 round;
9120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
914441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - %d", __func__, baudrate);
9150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	for (i = 0; i < ARRAY_SIZE(divisor_table); i++) {
9170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (divisor_table[i].baudrate == baudrate) {
9180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			*divisor = divisor_table[i].divisor;
9190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			return 0;
9200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
9210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
9220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9234da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	/* After trying for all the standard baud rates    *
9244da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	 * Try calculating the divisor for this baud rate  */
9250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (baudrate > 75 &&  baudrate < 230400) {
9260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* get the divisor */
9270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		custom = (__u16)(230400L  / baudrate);
9280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* Check for round off */
9300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		round1 = (__u16)(2304000L / baudrate);
9310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		round = (__u16)(round1 - (custom * 10));
9320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (round > 4)
9330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			custom++;
9340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		*divisor = custom;
9350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9364da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		dbg("Baud %d = %d", baudrate, custom);
9370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return 0;
9380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
9390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	dbg("Baud calculation Failed...");
9410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return -EINVAL;
9420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
9430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
9450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * send_cmd_write_baud_rate
9460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	this function sends the proper command to change the baud rate of the
9470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	specified port.
9480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
9490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int send_cmd_write_baud_rate(struct moschip_port *mos7720_port,
9500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				    int baudrate)
9510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
9520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial_port *port;
9530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial *serial;
9540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int divisor;
9550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int status;
9560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned char data;
9570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned char number;
9580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
9600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -1;
9610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	port = mos7720_port->port;
9630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	serial = port->serial;
9640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
965441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s: Entering ..........", __func__);
9660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	number = port->number - port->serial->minor;
968441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port = %d, baud = %d", __func__, port->number, baudrate);
9690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9704da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	/* Calculate the Divisor */
9710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	status = calc_baud_rate_divisor(baudrate, &divisor);
9720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (status) {
973194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman		dev_err(&port->dev, "%s - bad baud rate\n", __func__);
9740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return status;
9750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
9760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9774da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	/* Enable access to divisor latch */
9784da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	data = mos7720_port->shadowLCR | UART_LCR_DLAB;
9794da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	mos7720_port->shadowLCR  = data;
9804da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	send_mos_cmd(serial, MOS_WRITE, number, UART_LCR, &data);
9810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Write the divisor */
9830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = ((unsigned char)(divisor & 0xff));
9844da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	send_mos_cmd(serial, MOS_WRITE, number, 0x00, &data);
9850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = ((unsigned char)((divisor & 0xff00) >> 8));
9874da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	send_mos_cmd(serial, MOS_WRITE, number, 0x01, &data);
9880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9894da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	/* Disable access to divisor latch */
9904da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	data = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
9914da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	mos7720_port->shadowLCR = data;
9924da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	send_mos_cmd(serial, MOS_WRITE, number, 0x03, &data);
9930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return status;
9950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
9960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
9970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
9980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * change_port_settings
9990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	This routine is called to set the UART on the device to match
10000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *      the specified new settings.
10010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
100295da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void change_port_settings(struct tty_struct *tty,
100395da310e66ee8090119596c70ca8432e57f9a97fAlan Cox				 struct moschip_port *mos7720_port,
1004606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox				 struct ktermios *old_termios)
10050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
10060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial_port *port;
10070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial *serial;
10080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int baud;
10090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned cflag;
10100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned iflag;
10110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u8 mask = 0xff;
10120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u8 lData;
10130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u8 lParity;
10140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	__u8 lStop;
10150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int status;
10160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int port_number;
10170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	char data;
10180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
10200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return ;
10210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	port = mos7720_port->port;
10230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	serial = port->serial;
10240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	port_number = port->number - port->serial->minor;
10250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1026441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
10270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!mos7720_port->open) {
1029441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - port not opened", __func__);
10300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
10310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
10320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1033441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s: Entering ..........", __func__);
10340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	lData = UART_LCR_WLEN8;
10360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	lStop = 0x00;	/* 1 stop bit */
10370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	lParity = 0x00;	/* No parity */
10380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	cflag = tty->termios->c_cflag;
10400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	iflag = tty->termios->c_iflag;
10410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Change the number of bits */
10430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	switch (cflag & CSIZE) {
10440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case CS5:
10450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		lData = UART_LCR_WLEN5;
10460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mask = 0x1f;
10470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		break;
10480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case CS6:
10500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		lData = UART_LCR_WLEN6;
10510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mask = 0x3f;
10520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		break;
10530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case CS7:
10550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		lData = UART_LCR_WLEN7;
10560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mask = 0x7f;
10570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		break;
10580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	default:
10590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case CS8:
10600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		lData = UART_LCR_WLEN8;
10610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		break;
10620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
10630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Change the Parity bit */
10650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (cflag & PARENB) {
10660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (cflag & PARODD) {
10670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			lParity = UART_LCR_PARITY;
1068441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			dbg("%s - parity = odd", __func__);
10690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		} else {
10700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			lParity = (UART_LCR_EPAR | UART_LCR_PARITY);
1071441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison			dbg("%s - parity = even", __func__);
10720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
10730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	} else {
1075441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - parity = none", __func__);
10760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
10770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (cflag & CMSPAR)
10790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		lParity = lParity | 0x20;
10800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Change the Stop bit */
10820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (cflag & CSTOPB) {
10830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		lStop = UART_LCR_STOP;
1084441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - stop bits = 2", __func__);
10850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	} else {
10860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		lStop = 0x00;
1087441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - stop bits = 1", __func__);
10880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
10890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define LCR_BITS_MASK		0x03	/* Mask for bits/char field */
10910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define LCR_STOP_MASK		0x04	/* Mask for stop bits field */
10920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman#define LCR_PAR_MASK		0x38	/* Mask for parity field */
10930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Update the LCR with the correct value */
10954da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	mos7720_port->shadowLCR &=
10964da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox			~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
10970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port->shadowLCR |= (lData | lParity | lStop);
10980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
10990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Disable Interrupts */
11010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00;
11024da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
11034da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox							UART_IER, &data);
11040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0x00;
11064da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data);
11070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = 0xcf;
11094da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data);
11100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Send the updated LCR value to the mos7720 */
11120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = mos7720_port->shadowLCR;
11134da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	send_mos_cmd(serial, MOS_WRITE, port_number, UART_LCR, &data);
11140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11154da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	data = 0x00b;
11164da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	mos7720_port->shadowMCR = data;
11174da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
11184da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	data = 0x00b;
11194da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
11200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* set up the MCR register and send it to the mos7720 */
11220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port->shadowMCR = UART_MCR_OUT2;
11230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (cflag & CBAUD)
11240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mos7720_port->shadowMCR |= (UART_MCR_DTR | UART_MCR_RTS);
11250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (cflag & CRTSCTS) {
11270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mos7720_port->shadowMCR |= (UART_MCR_XONANY);
11284da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		/* To set hardware flow control to the specified *
11294da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		 * serial port, in SP1/2_CONTROL_REG             */
11300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (port->number) {
11310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			data = 0x001;
11320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT,
11330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				     0x08, &data);
11340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		} else {
11350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			data = 0x002;
11360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT,
11370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				     0x08, &data);
11380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
11390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	} else {
11400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mos7720_port->shadowMCR &= ~(UART_MCR_XONANY);
11410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
11420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = mos7720_port->shadowMCR;
11440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(serial, MOS_WRITE, port_number, UART_MCR, &data);
11450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Determine divisor based on baud rate */
11470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	baud = tty_get_baud_rate(tty);
11480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!baud) {
11490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* pick a default, any default... */
11500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("Picked default baud...");
11510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		baud = 9600;
11520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
11530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (baud >= 230400) {
11550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		set_higher_rates(mos7720_port, baud);
11560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* Enable Interrupts */
11570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		data = 0x0c;
11580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data);
11590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
11600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
11610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1162441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - baud rate = %d", __func__, baud);
11630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	status = send_cmd_write_baud_rate(mos7720_port, baud);
116465d063ab21feea8cf65d64fba50a5c4fa7bfd6beAlan Cox	/* FIXME: needs to write actual resulting baud back not just
116565d063ab21feea8cf65d64fba50a5c4fa7bfd6beAlan Cox	   blindly do so */
116665d063ab21feea8cf65d64fba50a5c4fa7bfd6beAlan Cox	if (cflag & CBAUD)
116765d063ab21feea8cf65d64fba50a5c4fa7bfd6beAlan Cox		tty_encode_baud_rate(tty, baud, 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
11720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (port->read_urb->status != -EINPROGRESS) {
11730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		port->read_urb->dev = serial->dev;
11740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
11760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (status)
11770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dbg("usb_submit_urb(read bulk) failed, status = %d",
11780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			    status);
11790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
11800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return;
11810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
11820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
11840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * mos7720_set_termios
11850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	this function is called by the tty driver when it wants to change the
11860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *	termios structure.
11870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
118895da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void mos7720_set_termios(struct tty_struct *tty,
118995da310e66ee8090119596c70ca8432e57f9a97fAlan Cox		struct usb_serial_port *port, struct ktermios *old_termios)
11900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
11910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int status;
11920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned int cflag;
11930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial *serial;
11940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
11950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	serial = port->serial;
11970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
11980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = usb_get_serial_port_data(port);
11990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
12010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
12020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!mos7720_port->open) {
1204441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s - port not opened", __func__);
12050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
12060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
12070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12084da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	dbg("%s\n", "setting termios - ASPIRE");
12090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	cflag = tty->termios->c_cflag;
12110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1212441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - cflag %08x iflag %08x", __func__,
12130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	    tty->termios->c_cflag,
12140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	    RELEVANT_IFLAG(tty->termios->c_iflag));
12150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1216441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - old cflag %08x old iflag %08x", __func__,
121765d063ab21feea8cf65d64fba50a5c4fa7bfd6beAlan Cox	    old_termios->c_cflag,
121865d063ab21feea8cf65d64fba50a5c4fa7bfd6beAlan Cox	    RELEVANT_IFLAG(old_termios->c_iflag));
12190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1220441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d", __func__, port->number);
12210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* change the port settings to the new ones specified */
122395da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	change_port_settings(tty, mos7720_port, old_termios);
12240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12254da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	if (!port->read_urb) {
12264da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		dbg("%s", "URB KILLED !!!!!\n");
12270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return;
12280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
12290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12304da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	if (port->read_urb->status != -EINPROGRESS) {
12310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		port->read_urb->dev = serial->dev;
12320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
12330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (status)
12340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			dbg("usb_submit_urb(read bulk) failed, status = %d",
12350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			    status);
12360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
12370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return;
12380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
12390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/*
12410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * get_lsr_info - get line status register info
12420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman *
12430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * Purpose: Let user call ioctl() to get info when the UART physically
12440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 	    is emptied.  On bus types like RS485, the transmitter must
12450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 	    release the bus after transmitting. This must be done when
12460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 	    the transmit shift register is empty, not be done when the
12470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 	    transmit holding register is empty.  This functionality
12480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman * 	    allows an RS485 driver to be written in user space.
12490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman */
12504da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Coxstatic int get_lsr_info(struct tty_struct *tty,
12514da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		struct moschip_port *mos7720_port, unsigned int __user *value)
12520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
12530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int count;
12540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned int result = 0;
12550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
125695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	count = mos7720_chars_in_buffer(tty);
12570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (count == 0) {
1258441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s -- Empty", __func__);
12590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		result = TIOCSER_TEMT;
12600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
12610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (copy_to_user(value, &result, sizeof(int)))
12630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -EFAULT;
12640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return 0;
12650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
12660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
12670f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakersstatic int mos7720_tiocmget(struct tty_struct *tty, struct file *file)
12680f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers{
12690f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	struct usb_serial_port *port = tty->driver_data;
12700f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
12710f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	unsigned int result = 0;
12720f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	unsigned int mcr ;
12730f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	unsigned int msr ;
12740f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers
12750f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	dbg("%s - port %d", __func__, port->number);
12760f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers
12770f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	mcr = mos7720_port->shadowMCR;
12780f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	msr = mos7720_port->shadowMSR;
12790f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers
12800f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	result = ((mcr & UART_MCR_DTR)  ? TIOCM_DTR : 0)   /* 0x002 */
12810f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	  | ((mcr & UART_MCR_RTS)   ? TIOCM_RTS : 0)   /* 0x004 */
12820f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	  | ((msr & UART_MSR_CTS)   ? TIOCM_CTS : 0)   /* 0x020 */
12830f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	  | ((msr & UART_MSR_DCD)   ? TIOCM_CAR : 0)   /* 0x040 */
12840f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	  | ((msr & UART_MSR_RI)    ? TIOCM_RI :  0)   /* 0x080 */
12850f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	  | ((msr & UART_MSR_DSR)   ? TIOCM_DSR : 0);  /* 0x100 */
12860f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers
12870f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	dbg("%s -- %x", __func__, result);
12880f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers
12890f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	return result;
12900f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers}
12910f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers
12920f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakersstatic int mos7720_tiocmset(struct tty_struct *tty, struct file *file,
12930f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers					unsigned int set, unsigned int clear)
12940f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers{
12950f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	struct usb_serial_port *port = tty->driver_data;
12960f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
12970f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	unsigned int mcr ;
12980f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	unsigned char lmcr;
12990f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers
13000f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	dbg("%s - port %d", __func__, port->number);
13010f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	dbg("he was at tiocmget");
13020f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers
13030f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	mcr = mos7720_port->shadowMCR;
13040f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers
13050f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	if (set & TIOCM_RTS)
13060f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers		mcr |= UART_MCR_RTS;
13070f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	if (set & TIOCM_DTR)
13080f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers		mcr |= UART_MCR_DTR;
13090f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	if (set & TIOCM_LOOP)
13100f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers		mcr |= UART_MCR_LOOP;
13110f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers
13120f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	if (clear & TIOCM_RTS)
13130f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers		mcr &= ~UART_MCR_RTS;
13140f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	if (clear & TIOCM_DTR)
13150f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers		mcr &= ~UART_MCR_DTR;
13160f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	if (clear & TIOCM_LOOP)
13170f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers		mcr &= ~UART_MCR_LOOP;
13180f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers
13190f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	mos7720_port->shadowMCR = mcr;
13200f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	lmcr = mos7720_port->shadowMCR;
13210f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers
13220f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	send_mos_cmd(port->serial, MOS_WRITE,
13230f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers		port->number - port->serial->minor, UART_MCR, &lmcr);
13240f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers
13250f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	return 0;
13260f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers}
13270f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers
13280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
13290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			  unsigned int __user *value)
13300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
13310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned int mcr ;
13320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned int arg;
13330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	unsigned char data;
13340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_serial_port *port;
13360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
13380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -1;
13390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13404da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	port = (struct usb_serial_port *)mos7720_port->port;
13410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mcr = mos7720_port->shadowMCR;
13420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (copy_from_user(&arg, value, sizeof(int)))
13440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -EFAULT;
13450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	switch (cmd) {
13470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCMBIS:
13480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (arg & TIOCM_RTS)
13490f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			mcr |= UART_MCR_RTS;
13500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (arg & TIOCM_DTR)
13510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			mcr |= UART_MCR_RTS;
13520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (arg & TIOCM_LOOP)
13530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			mcr |= UART_MCR_LOOP;
13540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		break;
13550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCMBIC:
13570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (arg & TIOCM_RTS)
13580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			mcr &= ~UART_MCR_RTS;
13590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (arg & TIOCM_DTR)
13600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			mcr &= ~UART_MCR_RTS;
13610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (arg & TIOCM_LOOP)
13620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			mcr &= ~UART_MCR_LOOP;
13630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		break;
13640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
13660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port->shadowMCR = mcr;
13680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	data = mos7720_port->shadowMCR;
13700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	send_mos_cmd(port->serial, MOS_WRITE,
13710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		     port->number - port->serial->minor, UART_MCR, &data);
13720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return 0;
13740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
13750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int get_serial_info(struct moschip_port *mos7720_port,
13770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			   struct serial_struct __user *retinfo)
13780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
13790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct serial_struct tmp;
13800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!retinfo)
13820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -EFAULT;
13830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	memset(&tmp, 0, sizeof(tmp));
13850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tmp.type		= PORT_16550A;
13870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tmp.line		= mos7720_port->port->serial->minor;
13880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tmp.port		= mos7720_port->port->number;
13890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tmp.irq			= 0;
13900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tmp.flags		= ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
13914da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	tmp.xmit_fifo_size	= NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
13920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tmp.baud_base		= 9600;
13930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tmp.close_delay		= 5*HZ;
13940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	tmp.closing_wait	= 30*HZ;
13950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
13960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
13970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -EFAULT;
13980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return 0;
13990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
14000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
140195da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int mos7720_ioctl(struct tty_struct *tty, struct file *file,
14020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			 unsigned int cmd, unsigned long arg)
14030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
140495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	struct usb_serial_port *port = tty->driver_data;
14050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
14060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct async_icount cnow;
14070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct async_icount cprev;
14080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct serial_icounter_struct icount;
14090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_port = usb_get_serial_port_data(port);
14110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_port == NULL)
14120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -ENODEV;
14130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1414441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
14150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	switch (cmd) {
14170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCSERGETLSR:
1418441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s (%d) TIOCSERGETLSR", __func__,  port->number);
14194da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		return get_lsr_info(tty, mos7720_port,
14204da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox					(unsigned int __user *)arg);
14210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return 0;
14220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
142395da310e66ee8090119596c70ca8432e57f9a97fAlan Cox	/* FIXME: These should be using the mode methods */
14240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCMBIS:
14250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCMBIC:
14264da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET",
14274da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox					__func__, port->number);
14280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return set_modem_info(mos7720_port, cmd,
14290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				      (unsigned int __user *)arg);
14300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCGSERIAL:
1432441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s (%d) TIOCGSERIAL", __func__,  port->number);
14330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return get_serial_info(mos7720_port,
14340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				       (struct serial_struct __user *)arg);
14350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCMIWAIT:
1437441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);
14380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		cprev = mos7720_port->icount;
14390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		while (1) {
14400f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			if (signal_pending(current))
14410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				return -ERESTARTSYS;
14420f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			cnow = mos7720_port->icount;
14430f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
14440f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
14450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				return -EIO; /* no change => error */
14460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
14470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
14480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
14494da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox			    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
14500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman				return 0;
14510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			}
14520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			cprev = cnow;
14530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
14540f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* NOTREACHED */
14550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		break;
14560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	case TIOCGICOUNT:
14580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		cnow = mos7720_port->icount;
14590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.cts = cnow.cts;
14600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.dsr = cnow.dsr;
14610f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.rng = cnow.rng;
14620f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.dcd = cnow.dcd;
14630f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.rx = cnow.rx;
14640f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.tx = cnow.tx;
14650f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.frame = cnow.frame;
14660f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.overrun = cnow.overrun;
14670f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.parity = cnow.parity;
14680f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.brk = cnow.brk;
14690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		icount.buf_overrun = cnow.buf_overrun;
14700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1471441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison		dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __func__,
14724da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		    port->number, icount.rx, icount.tx);
14730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (copy_to_user((void __user *)arg, &icount, sizeof(icount)))
14740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			return -EFAULT;
14750f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return 0;
14760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
14770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return -ENOIOCTLCMD;
14790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
14800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int mos7720_startup(struct usb_serial *serial)
14820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
14830f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_serial *mos7720_serial;
14840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct moschip_port *mos7720_port;
14850f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	struct usb_device *dev;
14860f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int i;
14870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	char data;
14880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1489441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s: Entering ..........", __func__);
14900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (!serial) {
14920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("Invalid Handler");
14930f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -ENODEV;
14940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
14950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	dev = serial->dev;
14970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
14980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* create our private serial structure */
14990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	mos7720_serial = kzalloc(sizeof(struct moschip_serial), GFP_KERNEL);
15000f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (mos7720_serial == NULL) {
1501194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman		dev_err(&dev->dev, "%s - Out of memory\n", __func__);
15020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		return -ENOMEM;
15030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
15040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	usb_set_serial_data(serial, mos7720_serial);
15060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15070f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* we set up the pointers to the endpoints in the mos7720_open *
15080f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	 * function, as the structures aren't created yet.             */
15090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* set up port private structures */
15110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	for (i = 0; i < serial->num_ports; ++i) {
15120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
15130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		if (mos7720_port == NULL) {
1514194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman			dev_err(&dev->dev, "%s - Out of memory\n", __func__);
15150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			usb_set_serial_data(serial, NULL);
15160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			kfree(mos7720_serial);
15170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman			return -ENOMEM;
15180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		}
15190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		/* Initialize all port interrupt end point to port 0 int
15210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		 * endpoint.  Our device has only one interrupt endpoint
15220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		 * comman to all ports */
15234da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox		serial->port[i]->interrupt_in_endpointAddress =
15244da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox				serial->port[0]->interrupt_in_endpointAddress;
15250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		mos7720_port->port = serial->port[i];
15270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		usb_set_serial_port_data(serial->port[i], mos7720_port);
15280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("port number is %d", serial->port[i]->number);
15300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		dbg("serial number is %d", serial->minor);
15310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	}
15320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15340f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* setting configuration feature to one */
15350f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
15364da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox			(__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5*HZ);
15370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15384da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	/* LSR For Port 1 */
15394da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	send_mos_cmd(serial, MOS_READ, 0x00, UART_LSR, &data);
15404da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	dbg("LSR:%x", data);
15410f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15424da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	/* LSR For Port 2 */
15434da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	send_mos_cmd(serial, MOS_READ, 0x01, UART_LSR, &data);
15444da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan Cox	dbg("LSR:%x", data);
15450f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15460f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return 0;
15470f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
15480f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1549f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Sternstatic void mos7720_release(struct usb_serial *serial)
15500f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
15510f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int i;
15520f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15530f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* free private structure allocated for serial port */
1554f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern	for (i = 0; i < serial->num_ports; ++i)
15550f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		kfree(usb_get_serial_port_data(serial->port[i]));
15560f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15570f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* free private structure allocated for serial device */
15580f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	kfree(usb_get_serial_data(serial));
15590f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
15600f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1561d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzlstatic struct usb_driver usb_driver = {
1562d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl	.name =		"moschip7720",
1563d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl	.probe =	usb_serial_probe,
1564d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl	.disconnect =	usb_serial_disconnect,
1565d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl	.id_table =	moschip_port_id_table,
1566d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl	.no_dynamic_id =	1,
1567d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl};
1568d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl
15690f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic struct usb_serial_driver moschip7720_2port_driver = {
15700f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.driver = {
15710f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		.owner =	THIS_MODULE,
15720f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		.name =		"moschip7720",
15730f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	},
15740f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.description		= "Moschip 2 port adapter",
1575d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl	.usb_driver		= &usb_driver,
15760f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.id_table		= moschip_port_id_table,
15770f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.num_ports		= 2,
15780f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.open			= mos7720_open,
15790f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.close			= mos7720_close,
15800f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.throttle		= mos7720_throttle,
15810f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.unthrottle		= mos7720_unthrottle,
15820f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.attach			= mos7720_startup,
1583f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern	.release		= mos7720_release,
15840f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.ioctl			= mos7720_ioctl,
15850f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	.tiocmget		= mos7720_tiocmget,
15860f608f8926968b4beee2cb00ef05522ad84f36ebKees Schoenmakers	.tiocmset		= mos7720_tiocmset,
15870f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.set_termios		= mos7720_set_termios,
15880f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.write			= mos7720_write,
15890f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.write_room		= mos7720_write_room,
15900f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.chars_in_buffer	= mos7720_chars_in_buffer,
15910f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.break_ctl		= mos7720_break,
15920f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	.read_bulk_callback	= mos7720_bulk_in_callback,
1593e8e30c765c5cfa5219918d3e5017fc563cf7ea03Oliver Neukum	.read_int_callback	= mos7720_interrupt_callback,
15940f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman};
15950f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
15960f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic int __init moschip7720_init(void)
15970f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
15980f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	int retval;
15990f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1600441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dbg("%s: Entering ..........", __func__);
16010f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16020f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Register with the usb serial */
16030f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	retval = usb_serial_register(&moschip7720_2port_driver);
16040f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (retval)
16050f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		goto failed_port_device_register;
16060f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
1607c197a8db59daf06dc5e77acd5a9681329cb22458Greg Kroah-Hartman	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
1608c197a8db59daf06dc5e77acd5a9681329cb22458Greg Kroah-Hartman	       DRIVER_DESC "\n");
16090f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16100f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	/* Register with the usb */
16110f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	retval = usb_register(&usb_driver);
16120f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	if (retval)
16130f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman		goto failed_usb_register;
16140f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16150f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return 0;
16160f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16170f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanfailed_usb_register:
16180f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	usb_serial_deregister(&moschip7720_2port_driver);
16190f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16200f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanfailed_port_device_register:
16210f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	return retval;
16220f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
16230f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16240f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanstatic void __exit moschip7720_exit(void)
16250f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman{
16260f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	usb_deregister(&usb_driver);
16270f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman	usb_serial_deregister(&moschip7720_2port_driver);
16280f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman}
16290f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16300f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanmodule_init(moschip7720_init);
16310f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanmodule_exit(moschip7720_exit);
16320f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16330f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman/* Module information */
16344da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan CoxMODULE_AUTHOR(DRIVER_AUTHOR);
16354da1a17dbc5211ac90264cfc4f0e076c8bdc1732Alan CoxMODULE_DESCRIPTION(DRIVER_DESC);
16360f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-HartmanMODULE_LICENSE("GPL");
16370f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartman
16380f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-Hartmanmodule_param(debug, bool, S_IRUGO | S_IWUSR);
16390f64478cbc7a008fe7b7e9ae79a73d8a6904ead8Greg Kroah-HartmanMODULE_PARM_DESC(debug, "Debug enabled or not");
1640