xref: /OK3568_Linux_fs/kernel/drivers/usb/serial/mos7720.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * mos7720.c
4*4882a593Smuzhiyun  *   Controls the Moschip 7720 usb to dual port serial converter
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright 2006 Moschip Semiconductor Tech. Ltd.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Developed by:
9*4882a593Smuzhiyun  * 	Vijaya Kumar <vijaykumar.gn@gmail.com>
10*4882a593Smuzhiyun  *	Ajay Kumar <naanuajay@yahoo.com>
11*4882a593Smuzhiyun  *	Gurudeva <ngurudeva@yahoo.com>
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  * Cleaned up from the original by:
14*4882a593Smuzhiyun  *	Greg Kroah-Hartman <gregkh@suse.de>
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  * Originally based on drivers/usb/serial/io_edgeport.c which is:
17*4882a593Smuzhiyun  *	Copyright (C) 2000 Inside Out Networks, All rights reserved.
18*4882a593Smuzhiyun  *	Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com>
19*4882a593Smuzhiyun  */
20*4882a593Smuzhiyun #include <linux/kernel.h>
21*4882a593Smuzhiyun #include <linux/errno.h>
22*4882a593Smuzhiyun #include <linux/slab.h>
23*4882a593Smuzhiyun #include <linux/tty.h>
24*4882a593Smuzhiyun #include <linux/tty_driver.h>
25*4882a593Smuzhiyun #include <linux/tty_flip.h>
26*4882a593Smuzhiyun #include <linux/module.h>
27*4882a593Smuzhiyun #include <linux/spinlock.h>
28*4882a593Smuzhiyun #include <linux/serial.h>
29*4882a593Smuzhiyun #include <linux/serial_reg.h>
30*4882a593Smuzhiyun #include <linux/usb.h>
31*4882a593Smuzhiyun #include <linux/usb/serial.h>
32*4882a593Smuzhiyun #include <linux/uaccess.h>
33*4882a593Smuzhiyun #include <linux/parport.h>
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #define DRIVER_AUTHOR "Aspire Communications pvt Ltd."
36*4882a593Smuzhiyun #define DRIVER_DESC "Moschip USB Serial Driver"
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun /* default urb timeout */
39*4882a593Smuzhiyun #define MOS_WDR_TIMEOUT	5000
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun #define MOS_MAX_PORT	0x02
42*4882a593Smuzhiyun #define MOS_WRITE	0x0E
43*4882a593Smuzhiyun #define MOS_READ	0x0D
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun /* Interrupt Routines Defines	*/
46*4882a593Smuzhiyun #define SERIAL_IIR_RLS	0x06
47*4882a593Smuzhiyun #define SERIAL_IIR_RDA	0x04
48*4882a593Smuzhiyun #define SERIAL_IIR_CTI	0x0c
49*4882a593Smuzhiyun #define SERIAL_IIR_THR	0x02
50*4882a593Smuzhiyun #define SERIAL_IIR_MS	0x00
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun #define NUM_URBS			16	/* URB Count */
53*4882a593Smuzhiyun #define URB_TRANSFER_BUFFER_SIZE	32	/* URB Size */
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun /* This structure holds all of the local serial port information */
56*4882a593Smuzhiyun struct moschip_port {
57*4882a593Smuzhiyun 	__u8	shadowLCR;		/* last LCR value received */
58*4882a593Smuzhiyun 	__u8	shadowMCR;		/* last MCR value received */
59*4882a593Smuzhiyun 	__u8	shadowMSR;		/* last MSR value received */
60*4882a593Smuzhiyun 	char			open;
61*4882a593Smuzhiyun 	struct usb_serial_port	*port;	/* loop back to the owner */
62*4882a593Smuzhiyun 	struct urb		*write_urb_pool[NUM_URBS];
63*4882a593Smuzhiyun };
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun #define USB_VENDOR_ID_MOSCHIP		0x9710
66*4882a593Smuzhiyun #define MOSCHIP_DEVICE_ID_7720		0x7720
67*4882a593Smuzhiyun #define MOSCHIP_DEVICE_ID_7715		0x7715
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun static const struct usb_device_id id_table[] = {
70*4882a593Smuzhiyun 	{ USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7720) },
71*4882a593Smuzhiyun 	{ USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7715) },
72*4882a593Smuzhiyun 	{ } /* terminating entry */
73*4882a593Smuzhiyun };
74*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, id_table);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun /* initial values for parport regs */
79*4882a593Smuzhiyun #define DCR_INIT_VAL       0x0c	/* SLCTIN, nINIT */
80*4882a593Smuzhiyun #define ECR_INIT_VAL       0x00	/* SPP mode */
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun struct urbtracker {
83*4882a593Smuzhiyun 	struct mos7715_parport  *mos_parport;
84*4882a593Smuzhiyun 	struct list_head        urblist_entry;
85*4882a593Smuzhiyun 	struct kref             ref_count;
86*4882a593Smuzhiyun 	struct urb              *urb;
87*4882a593Smuzhiyun 	struct usb_ctrlrequest	*setup;
88*4882a593Smuzhiyun };
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun enum mos7715_pp_modes {
91*4882a593Smuzhiyun 	SPP = 0<<5,
92*4882a593Smuzhiyun 	PS2 = 1<<5,      /* moschip calls this 'NIBBLE' mode */
93*4882a593Smuzhiyun 	PPF = 2<<5,	 /* moschip calls this 'CB-FIFO mode */
94*4882a593Smuzhiyun };
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun struct mos7715_parport {
97*4882a593Smuzhiyun 	struct parport          *pp;	       /* back to containing struct */
98*4882a593Smuzhiyun 	struct kref             ref_count;     /* to instance of this struct */
99*4882a593Smuzhiyun 	struct list_head        deferred_urbs; /* list deferred async urbs */
100*4882a593Smuzhiyun 	struct list_head        active_urbs;   /* list async urbs in flight */
101*4882a593Smuzhiyun 	spinlock_t              listlock;      /* protects list access */
102*4882a593Smuzhiyun 	bool                    msg_pending;   /* usb sync call pending */
103*4882a593Smuzhiyun 	struct completion       syncmsg_compl; /* usb sync call completed */
104*4882a593Smuzhiyun 	struct tasklet_struct   urb_tasklet;   /* for sending deferred urbs */
105*4882a593Smuzhiyun 	struct usb_serial       *serial;       /* back to containing struct */
106*4882a593Smuzhiyun 	__u8	                shadowECR;     /* parallel port regs... */
107*4882a593Smuzhiyun 	__u8	                shadowDCR;
108*4882a593Smuzhiyun 	atomic_t                shadowDSR;     /* updated in int-in callback */
109*4882a593Smuzhiyun };
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun /* lock guards against dereferencing NULL ptr in parport ops callbacks */
112*4882a593Smuzhiyun static DEFINE_SPINLOCK(release_lock);
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun #endif	/* CONFIG_USB_SERIAL_MOS7715_PARPORT */
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun static const unsigned int dummy; /* for clarity in register access fns */
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun enum mos_regs {
119*4882a593Smuzhiyun 	MOS7720_THR,		  /* serial port regs */
120*4882a593Smuzhiyun 	MOS7720_RHR,
121*4882a593Smuzhiyun 	MOS7720_IER,
122*4882a593Smuzhiyun 	MOS7720_FCR,
123*4882a593Smuzhiyun 	MOS7720_ISR,
124*4882a593Smuzhiyun 	MOS7720_LCR,
125*4882a593Smuzhiyun 	MOS7720_MCR,
126*4882a593Smuzhiyun 	MOS7720_LSR,
127*4882a593Smuzhiyun 	MOS7720_MSR,
128*4882a593Smuzhiyun 	MOS7720_SPR,
129*4882a593Smuzhiyun 	MOS7720_DLL,
130*4882a593Smuzhiyun 	MOS7720_DLM,
131*4882a593Smuzhiyun 	MOS7720_DPR,		  /* parallel port regs */
132*4882a593Smuzhiyun 	MOS7720_DSR,
133*4882a593Smuzhiyun 	MOS7720_DCR,
134*4882a593Smuzhiyun 	MOS7720_ECR,
135*4882a593Smuzhiyun 	MOS7720_SP1_REG,	  /* device control regs */
136*4882a593Smuzhiyun 	MOS7720_SP2_REG,	  /* serial port 2 (7720 only) */
137*4882a593Smuzhiyun 	MOS7720_PP_REG,
138*4882a593Smuzhiyun 	MOS7720_SP_CONTROL_REG,
139*4882a593Smuzhiyun };
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun /*
142*4882a593Smuzhiyun  * Return the correct value for the Windex field of the setup packet
143*4882a593Smuzhiyun  * for a control endpoint message.  See the 7715 datasheet.
144*4882a593Smuzhiyun  */
get_reg_index(enum mos_regs reg)145*4882a593Smuzhiyun static inline __u16 get_reg_index(enum mos_regs reg)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun 	static const __u16 mos7715_index_lookup_table[] = {
148*4882a593Smuzhiyun 		0x00,		/* MOS7720_THR */
149*4882a593Smuzhiyun 		0x00,		/* MOS7720_RHR */
150*4882a593Smuzhiyun 		0x01,		/* MOS7720_IER */
151*4882a593Smuzhiyun 		0x02,		/* MOS7720_FCR */
152*4882a593Smuzhiyun 		0x02,		/* MOS7720_ISR */
153*4882a593Smuzhiyun 		0x03,		/* MOS7720_LCR */
154*4882a593Smuzhiyun 		0x04,		/* MOS7720_MCR */
155*4882a593Smuzhiyun 		0x05,		/* MOS7720_LSR */
156*4882a593Smuzhiyun 		0x06,		/* MOS7720_MSR */
157*4882a593Smuzhiyun 		0x07,		/* MOS7720_SPR */
158*4882a593Smuzhiyun 		0x00,		/* MOS7720_DLL */
159*4882a593Smuzhiyun 		0x01,		/* MOS7720_DLM */
160*4882a593Smuzhiyun 		0x00,		/* MOS7720_DPR */
161*4882a593Smuzhiyun 		0x01,		/* MOS7720_DSR */
162*4882a593Smuzhiyun 		0x02,		/* MOS7720_DCR */
163*4882a593Smuzhiyun 		0x0a,		/* MOS7720_ECR */
164*4882a593Smuzhiyun 		0x01,		/* MOS7720_SP1_REG */
165*4882a593Smuzhiyun 		0x02,		/* MOS7720_SP2_REG (7720 only) */
166*4882a593Smuzhiyun 		0x04,		/* MOS7720_PP_REG (7715 only) */
167*4882a593Smuzhiyun 		0x08,		/* MOS7720_SP_CONTROL_REG */
168*4882a593Smuzhiyun 	};
169*4882a593Smuzhiyun 	return mos7715_index_lookup_table[reg];
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun /*
173*4882a593Smuzhiyun  * Return the correct value for the upper byte of the Wvalue field of
174*4882a593Smuzhiyun  * the setup packet for a control endpoint message.
175*4882a593Smuzhiyun  */
get_reg_value(enum mos_regs reg,unsigned int serial_portnum)176*4882a593Smuzhiyun static inline __u16 get_reg_value(enum mos_regs reg,
177*4882a593Smuzhiyun 				  unsigned int serial_portnum)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun 	if (reg >= MOS7720_SP1_REG)	/* control reg */
180*4882a593Smuzhiyun 		return 0x0000;
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	else if (reg >= MOS7720_DPR)	/* parallel port reg (7715 only) */
183*4882a593Smuzhiyun 		return 0x0100;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	else			      /* serial port reg */
186*4882a593Smuzhiyun 		return (serial_portnum + 2) << 8;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun /*
190*4882a593Smuzhiyun  * Write data byte to the specified device register.  The data is embedded in
191*4882a593Smuzhiyun  * the value field of the setup packet. serial_portnum is ignored for registers
192*4882a593Smuzhiyun  * not specific to a particular serial port.
193*4882a593Smuzhiyun  */
write_mos_reg(struct usb_serial * serial,unsigned int serial_portnum,enum mos_regs reg,__u8 data)194*4882a593Smuzhiyun static int write_mos_reg(struct usb_serial *serial, unsigned int serial_portnum,
195*4882a593Smuzhiyun 			 enum mos_regs reg, __u8 data)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun 	struct usb_device *usbdev = serial->dev;
198*4882a593Smuzhiyun 	unsigned int pipe = usb_sndctrlpipe(usbdev, 0);
199*4882a593Smuzhiyun 	__u8 request = (__u8)0x0e;
200*4882a593Smuzhiyun 	__u8 requesttype = (__u8)0x40;
201*4882a593Smuzhiyun 	__u16 index = get_reg_index(reg);
202*4882a593Smuzhiyun 	__u16 value = get_reg_value(reg, serial_portnum) + data;
203*4882a593Smuzhiyun 	int status = usb_control_msg(usbdev, pipe, request, requesttype, value,
204*4882a593Smuzhiyun 				     index, NULL, 0, MOS_WDR_TIMEOUT);
205*4882a593Smuzhiyun 	if (status < 0)
206*4882a593Smuzhiyun 		dev_err(&usbdev->dev,
207*4882a593Smuzhiyun 			"mos7720: usb_control_msg() failed: %d\n", status);
208*4882a593Smuzhiyun 	return status;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun /*
212*4882a593Smuzhiyun  * Read data byte from the specified device register.  The data returned by the
213*4882a593Smuzhiyun  * device is embedded in the value field of the setup packet.  serial_portnum is
214*4882a593Smuzhiyun  * ignored for registers that are not specific to a particular serial port.
215*4882a593Smuzhiyun  */
read_mos_reg(struct usb_serial * serial,unsigned int serial_portnum,enum mos_regs reg,__u8 * data)216*4882a593Smuzhiyun static int read_mos_reg(struct usb_serial *serial, unsigned int serial_portnum,
217*4882a593Smuzhiyun 			enum mos_regs reg, __u8 *data)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun 	struct usb_device *usbdev = serial->dev;
220*4882a593Smuzhiyun 	unsigned int pipe = usb_rcvctrlpipe(usbdev, 0);
221*4882a593Smuzhiyun 	__u8 request = (__u8)0x0d;
222*4882a593Smuzhiyun 	__u8 requesttype = (__u8)0xc0;
223*4882a593Smuzhiyun 	__u16 index = get_reg_index(reg);
224*4882a593Smuzhiyun 	__u16 value = get_reg_value(reg, serial_portnum);
225*4882a593Smuzhiyun 	u8 *buf;
226*4882a593Smuzhiyun 	int status;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	buf = kmalloc(1, GFP_KERNEL);
229*4882a593Smuzhiyun 	if (!buf) {
230*4882a593Smuzhiyun 		*data = 0;
231*4882a593Smuzhiyun 		return -ENOMEM;
232*4882a593Smuzhiyun 	}
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	status = usb_control_msg(usbdev, pipe, request, requesttype, value,
235*4882a593Smuzhiyun 				     index, buf, 1, MOS_WDR_TIMEOUT);
236*4882a593Smuzhiyun 	if (status == 1) {
237*4882a593Smuzhiyun 		*data = *buf;
238*4882a593Smuzhiyun 	} else {
239*4882a593Smuzhiyun 		dev_err(&usbdev->dev,
240*4882a593Smuzhiyun 			"mos7720: usb_control_msg() failed: %d\n", status);
241*4882a593Smuzhiyun 		if (status >= 0)
242*4882a593Smuzhiyun 			status = -EIO;
243*4882a593Smuzhiyun 		*data = 0;
244*4882a593Smuzhiyun 	}
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	kfree(buf);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	return status;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
252*4882a593Smuzhiyun 
mos7715_change_mode(struct mos7715_parport * mos_parport,enum mos7715_pp_modes mode)253*4882a593Smuzhiyun static inline int mos7715_change_mode(struct mos7715_parport *mos_parport,
254*4882a593Smuzhiyun 				      enum mos7715_pp_modes mode)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun 	mos_parport->shadowECR = mode;
257*4882a593Smuzhiyun 	write_mos_reg(mos_parport->serial, dummy, MOS7720_ECR,
258*4882a593Smuzhiyun 		      mos_parport->shadowECR);
259*4882a593Smuzhiyun 	return 0;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun 
destroy_mos_parport(struct kref * kref)262*4882a593Smuzhiyun static void destroy_mos_parport(struct kref *kref)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun 	struct mos7715_parport *mos_parport =
265*4882a593Smuzhiyun 		container_of(kref, struct mos7715_parport, ref_count);
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	kfree(mos_parport);
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun 
destroy_urbtracker(struct kref * kref)270*4882a593Smuzhiyun static void destroy_urbtracker(struct kref *kref)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun 	struct urbtracker *urbtrack =
273*4882a593Smuzhiyun 		container_of(kref, struct urbtracker, ref_count);
274*4882a593Smuzhiyun 	struct mos7715_parport *mos_parport = urbtrack->mos_parport;
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	usb_free_urb(urbtrack->urb);
277*4882a593Smuzhiyun 	kfree(urbtrack->setup);
278*4882a593Smuzhiyun 	kfree(urbtrack);
279*4882a593Smuzhiyun 	kref_put(&mos_parport->ref_count, destroy_mos_parport);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun /*
283*4882a593Smuzhiyun  * This runs as a tasklet when sending an urb in a non-blocking parallel
284*4882a593Smuzhiyun  * port callback had to be deferred because the disconnect mutex could not be
285*4882a593Smuzhiyun  * obtained at the time.
286*4882a593Smuzhiyun  */
send_deferred_urbs(struct tasklet_struct * t)287*4882a593Smuzhiyun static void send_deferred_urbs(struct tasklet_struct *t)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun 	int ret_val;
290*4882a593Smuzhiyun 	unsigned long flags;
291*4882a593Smuzhiyun 	struct mos7715_parport *mos_parport = from_tasklet(mos_parport, t,
292*4882a593Smuzhiyun 							   urb_tasklet);
293*4882a593Smuzhiyun 	struct urbtracker *urbtrack, *tmp;
294*4882a593Smuzhiyun 	struct list_head *cursor, *next;
295*4882a593Smuzhiyun 	struct device *dev;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	/* if release function ran, game over */
298*4882a593Smuzhiyun 	if (unlikely(mos_parport->serial == NULL))
299*4882a593Smuzhiyun 		return;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	dev = &mos_parport->serial->dev->dev;
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	/* try again to get the mutex */
304*4882a593Smuzhiyun 	if (!mutex_trylock(&mos_parport->serial->disc_mutex)) {
305*4882a593Smuzhiyun 		dev_dbg(dev, "%s: rescheduling tasklet\n", __func__);
306*4882a593Smuzhiyun 		tasklet_schedule(&mos_parport->urb_tasklet);
307*4882a593Smuzhiyun 		return;
308*4882a593Smuzhiyun 	}
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	/* if device disconnected, game over */
311*4882a593Smuzhiyun 	if (unlikely(mos_parport->serial->disconnected)) {
312*4882a593Smuzhiyun 		mutex_unlock(&mos_parport->serial->disc_mutex);
313*4882a593Smuzhiyun 		return;
314*4882a593Smuzhiyun 	}
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	spin_lock_irqsave(&mos_parport->listlock, flags);
317*4882a593Smuzhiyun 	if (list_empty(&mos_parport->deferred_urbs)) {
318*4882a593Smuzhiyun 		spin_unlock_irqrestore(&mos_parport->listlock, flags);
319*4882a593Smuzhiyun 		mutex_unlock(&mos_parport->serial->disc_mutex);
320*4882a593Smuzhiyun 		dev_dbg(dev, "%s: deferred_urbs list empty\n", __func__);
321*4882a593Smuzhiyun 		return;
322*4882a593Smuzhiyun 	}
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	/* move contents of deferred_urbs list to active_urbs list and submit */
325*4882a593Smuzhiyun 	list_for_each_safe(cursor, next, &mos_parport->deferred_urbs)
326*4882a593Smuzhiyun 		list_move_tail(cursor, &mos_parport->active_urbs);
327*4882a593Smuzhiyun 	list_for_each_entry_safe(urbtrack, tmp, &mos_parport->active_urbs,
328*4882a593Smuzhiyun 			    urblist_entry) {
329*4882a593Smuzhiyun 		ret_val = usb_submit_urb(urbtrack->urb, GFP_ATOMIC);
330*4882a593Smuzhiyun 		dev_dbg(dev, "%s: urb submitted\n", __func__);
331*4882a593Smuzhiyun 		if (ret_val) {
332*4882a593Smuzhiyun 			dev_err(dev, "usb_submit_urb() failed: %d\n", ret_val);
333*4882a593Smuzhiyun 			list_del(&urbtrack->urblist_entry);
334*4882a593Smuzhiyun 			kref_put(&urbtrack->ref_count, destroy_urbtracker);
335*4882a593Smuzhiyun 		}
336*4882a593Smuzhiyun 	}
337*4882a593Smuzhiyun 	spin_unlock_irqrestore(&mos_parport->listlock, flags);
338*4882a593Smuzhiyun 	mutex_unlock(&mos_parport->serial->disc_mutex);
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun /* callback for parallel port control urbs submitted asynchronously */
async_complete(struct urb * urb)342*4882a593Smuzhiyun static void async_complete(struct urb *urb)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun 	struct urbtracker *urbtrack = urb->context;
345*4882a593Smuzhiyun 	int status = urb->status;
346*4882a593Smuzhiyun 	unsigned long flags;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	if (unlikely(status))
349*4882a593Smuzhiyun 		dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __func__, status);
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	/* remove the urbtracker from the active_urbs list */
352*4882a593Smuzhiyun 	spin_lock_irqsave(&urbtrack->mos_parport->listlock, flags);
353*4882a593Smuzhiyun 	list_del(&urbtrack->urblist_entry);
354*4882a593Smuzhiyun 	spin_unlock_irqrestore(&urbtrack->mos_parport->listlock, flags);
355*4882a593Smuzhiyun 	kref_put(&urbtrack->ref_count, destroy_urbtracker);
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun 
write_parport_reg_nonblock(struct mos7715_parport * mos_parport,enum mos_regs reg,__u8 data)358*4882a593Smuzhiyun static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,
359*4882a593Smuzhiyun 				      enum mos_regs reg, __u8 data)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun 	struct urbtracker *urbtrack;
362*4882a593Smuzhiyun 	int ret_val;
363*4882a593Smuzhiyun 	unsigned long flags;
364*4882a593Smuzhiyun 	struct usb_serial *serial = mos_parport->serial;
365*4882a593Smuzhiyun 	struct usb_device *usbdev = serial->dev;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	/* create and initialize the control urb and containing urbtracker */
368*4882a593Smuzhiyun 	urbtrack = kmalloc(sizeof(struct urbtracker), GFP_ATOMIC);
369*4882a593Smuzhiyun 	if (!urbtrack)
370*4882a593Smuzhiyun 		return -ENOMEM;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	urbtrack->urb = usb_alloc_urb(0, GFP_ATOMIC);
373*4882a593Smuzhiyun 	if (!urbtrack->urb) {
374*4882a593Smuzhiyun 		kfree(urbtrack);
375*4882a593Smuzhiyun 		return -ENOMEM;
376*4882a593Smuzhiyun 	}
377*4882a593Smuzhiyun 	urbtrack->setup = kmalloc(sizeof(*urbtrack->setup), GFP_ATOMIC);
378*4882a593Smuzhiyun 	if (!urbtrack->setup) {
379*4882a593Smuzhiyun 		usb_free_urb(urbtrack->urb);
380*4882a593Smuzhiyun 		kfree(urbtrack);
381*4882a593Smuzhiyun 		return -ENOMEM;
382*4882a593Smuzhiyun 	}
383*4882a593Smuzhiyun 	urbtrack->setup->bRequestType = (__u8)0x40;
384*4882a593Smuzhiyun 	urbtrack->setup->bRequest = (__u8)0x0e;
385*4882a593Smuzhiyun 	urbtrack->setup->wValue = cpu_to_le16(get_reg_value(reg, dummy));
386*4882a593Smuzhiyun 	urbtrack->setup->wIndex = cpu_to_le16(get_reg_index(reg));
387*4882a593Smuzhiyun 	urbtrack->setup->wLength = 0;
388*4882a593Smuzhiyun 	usb_fill_control_urb(urbtrack->urb, usbdev,
389*4882a593Smuzhiyun 			     usb_sndctrlpipe(usbdev, 0),
390*4882a593Smuzhiyun 			     (unsigned char *)urbtrack->setup,
391*4882a593Smuzhiyun 			     NULL, 0, async_complete, urbtrack);
392*4882a593Smuzhiyun 	kref_get(&mos_parport->ref_count);
393*4882a593Smuzhiyun 	urbtrack->mos_parport = mos_parport;
394*4882a593Smuzhiyun 	kref_init(&urbtrack->ref_count);
395*4882a593Smuzhiyun 	INIT_LIST_HEAD(&urbtrack->urblist_entry);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	/*
398*4882a593Smuzhiyun 	 * get the disconnect mutex, or add tracker to the deferred_urbs list
399*4882a593Smuzhiyun 	 * and schedule a tasklet to try again later
400*4882a593Smuzhiyun 	 */
401*4882a593Smuzhiyun 	if (!mutex_trylock(&serial->disc_mutex)) {
402*4882a593Smuzhiyun 		spin_lock_irqsave(&mos_parport->listlock, flags);
403*4882a593Smuzhiyun 		list_add_tail(&urbtrack->urblist_entry,
404*4882a593Smuzhiyun 			      &mos_parport->deferred_urbs);
405*4882a593Smuzhiyun 		spin_unlock_irqrestore(&mos_parport->listlock, flags);
406*4882a593Smuzhiyun 		tasklet_schedule(&mos_parport->urb_tasklet);
407*4882a593Smuzhiyun 		dev_dbg(&usbdev->dev, "tasklet scheduled\n");
408*4882a593Smuzhiyun 		return 0;
409*4882a593Smuzhiyun 	}
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	/* bail if device disconnected */
412*4882a593Smuzhiyun 	if (serial->disconnected) {
413*4882a593Smuzhiyun 		kref_put(&urbtrack->ref_count, destroy_urbtracker);
414*4882a593Smuzhiyun 		mutex_unlock(&serial->disc_mutex);
415*4882a593Smuzhiyun 		return -ENODEV;
416*4882a593Smuzhiyun 	}
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	/* add the tracker to the active_urbs list and submit */
419*4882a593Smuzhiyun 	spin_lock_irqsave(&mos_parport->listlock, flags);
420*4882a593Smuzhiyun 	list_add_tail(&urbtrack->urblist_entry, &mos_parport->active_urbs);
421*4882a593Smuzhiyun 	spin_unlock_irqrestore(&mos_parport->listlock, flags);
422*4882a593Smuzhiyun 	ret_val = usb_submit_urb(urbtrack->urb, GFP_ATOMIC);
423*4882a593Smuzhiyun 	mutex_unlock(&serial->disc_mutex);
424*4882a593Smuzhiyun 	if (ret_val) {
425*4882a593Smuzhiyun 		dev_err(&usbdev->dev,
426*4882a593Smuzhiyun 			"%s: submit_urb() failed: %d\n", __func__, ret_val);
427*4882a593Smuzhiyun 		spin_lock_irqsave(&mos_parport->listlock, flags);
428*4882a593Smuzhiyun 		list_del(&urbtrack->urblist_entry);
429*4882a593Smuzhiyun 		spin_unlock_irqrestore(&mos_parport->listlock, flags);
430*4882a593Smuzhiyun 		kref_put(&urbtrack->ref_count, destroy_urbtracker);
431*4882a593Smuzhiyun 		return ret_val;
432*4882a593Smuzhiyun 	}
433*4882a593Smuzhiyun 	return 0;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun /*
437*4882a593Smuzhiyun  * This is the the common top part of all parallel port callback operations that
438*4882a593Smuzhiyun  * send synchronous messages to the device.  This implements convoluted locking
439*4882a593Smuzhiyun  * that avoids two scenarios: (1) a port operation is called after usbserial
440*4882a593Smuzhiyun  * has called our release function, at which point struct mos7715_parport has
441*4882a593Smuzhiyun  * been destroyed, and (2) the device has been disconnected, but usbserial has
442*4882a593Smuzhiyun  * not called the release function yet because someone has a serial port open.
443*4882a593Smuzhiyun  * The shared release_lock prevents the first, and the mutex and disconnected
444*4882a593Smuzhiyun  * flag maintained by usbserial covers the second.  We also use the msg_pending
445*4882a593Smuzhiyun  * flag to ensure that all synchronous usb message calls have completed before
446*4882a593Smuzhiyun  * our release function can return.
447*4882a593Smuzhiyun  */
parport_prologue(struct parport * pp)448*4882a593Smuzhiyun static int parport_prologue(struct parport *pp)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun 	struct mos7715_parport *mos_parport;
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	spin_lock(&release_lock);
453*4882a593Smuzhiyun 	mos_parport = pp->private_data;
454*4882a593Smuzhiyun 	if (unlikely(mos_parport == NULL)) {
455*4882a593Smuzhiyun 		/* release fn called, port struct destroyed */
456*4882a593Smuzhiyun 		spin_unlock(&release_lock);
457*4882a593Smuzhiyun 		return -1;
458*4882a593Smuzhiyun 	}
459*4882a593Smuzhiyun 	mos_parport->msg_pending = true;   /* synch usb call pending */
460*4882a593Smuzhiyun 	reinit_completion(&mos_parport->syncmsg_compl);
461*4882a593Smuzhiyun 	spin_unlock(&release_lock);
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	mutex_lock(&mos_parport->serial->disc_mutex);
464*4882a593Smuzhiyun 	if (mos_parport->serial->disconnected) {
465*4882a593Smuzhiyun 		/* device disconnected */
466*4882a593Smuzhiyun 		mutex_unlock(&mos_parport->serial->disc_mutex);
467*4882a593Smuzhiyun 		mos_parport->msg_pending = false;
468*4882a593Smuzhiyun 		complete(&mos_parport->syncmsg_compl);
469*4882a593Smuzhiyun 		return -1;
470*4882a593Smuzhiyun 	}
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	return 0;
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun /*
476*4882a593Smuzhiyun  * This is the common bottom part of all parallel port functions that send
477*4882a593Smuzhiyun  * synchronous messages to the device.
478*4882a593Smuzhiyun  */
parport_epilogue(struct parport * pp)479*4882a593Smuzhiyun static inline void parport_epilogue(struct parport *pp)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun 	struct mos7715_parport *mos_parport = pp->private_data;
482*4882a593Smuzhiyun 	mutex_unlock(&mos_parport->serial->disc_mutex);
483*4882a593Smuzhiyun 	mos_parport->msg_pending = false;
484*4882a593Smuzhiyun 	complete(&mos_parport->syncmsg_compl);
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun 
parport_mos7715_write_data(struct parport * pp,unsigned char d)487*4882a593Smuzhiyun static void parport_mos7715_write_data(struct parport *pp, unsigned char d)
488*4882a593Smuzhiyun {
489*4882a593Smuzhiyun 	struct mos7715_parport *mos_parport = pp->private_data;
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	if (parport_prologue(pp) < 0)
492*4882a593Smuzhiyun 		return;
493*4882a593Smuzhiyun 	mos7715_change_mode(mos_parport, SPP);
494*4882a593Smuzhiyun 	write_mos_reg(mos_parport->serial, dummy, MOS7720_DPR, (__u8)d);
495*4882a593Smuzhiyun 	parport_epilogue(pp);
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun 
parport_mos7715_read_data(struct parport * pp)498*4882a593Smuzhiyun static unsigned char parport_mos7715_read_data(struct parport *pp)
499*4882a593Smuzhiyun {
500*4882a593Smuzhiyun 	struct mos7715_parport *mos_parport = pp->private_data;
501*4882a593Smuzhiyun 	unsigned char d;
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	if (parport_prologue(pp) < 0)
504*4882a593Smuzhiyun 		return 0;
505*4882a593Smuzhiyun 	read_mos_reg(mos_parport->serial, dummy, MOS7720_DPR, &d);
506*4882a593Smuzhiyun 	parport_epilogue(pp);
507*4882a593Smuzhiyun 	return d;
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun 
parport_mos7715_write_control(struct parport * pp,unsigned char d)510*4882a593Smuzhiyun static void parport_mos7715_write_control(struct parport *pp, unsigned char d)
511*4882a593Smuzhiyun {
512*4882a593Smuzhiyun 	struct mos7715_parport *mos_parport = pp->private_data;
513*4882a593Smuzhiyun 	__u8 data;
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	if (parport_prologue(pp) < 0)
516*4882a593Smuzhiyun 		return;
517*4882a593Smuzhiyun 	data = ((__u8)d & 0x0f) | (mos_parport->shadowDCR & 0xf0);
518*4882a593Smuzhiyun 	write_mos_reg(mos_parport->serial, dummy, MOS7720_DCR, data);
519*4882a593Smuzhiyun 	mos_parport->shadowDCR = data;
520*4882a593Smuzhiyun 	parport_epilogue(pp);
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun 
parport_mos7715_read_control(struct parport * pp)523*4882a593Smuzhiyun static unsigned char parport_mos7715_read_control(struct parport *pp)
524*4882a593Smuzhiyun {
525*4882a593Smuzhiyun 	struct mos7715_parport *mos_parport;
526*4882a593Smuzhiyun 	__u8 dcr;
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	spin_lock(&release_lock);
529*4882a593Smuzhiyun 	mos_parport = pp->private_data;
530*4882a593Smuzhiyun 	if (unlikely(mos_parport == NULL)) {
531*4882a593Smuzhiyun 		spin_unlock(&release_lock);
532*4882a593Smuzhiyun 		return 0;
533*4882a593Smuzhiyun 	}
534*4882a593Smuzhiyun 	dcr = mos_parport->shadowDCR & 0x0f;
535*4882a593Smuzhiyun 	spin_unlock(&release_lock);
536*4882a593Smuzhiyun 	return dcr;
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun 
parport_mos7715_frob_control(struct parport * pp,unsigned char mask,unsigned char val)539*4882a593Smuzhiyun static unsigned char parport_mos7715_frob_control(struct parport *pp,
540*4882a593Smuzhiyun 						  unsigned char mask,
541*4882a593Smuzhiyun 						  unsigned char val)
542*4882a593Smuzhiyun {
543*4882a593Smuzhiyun 	struct mos7715_parport *mos_parport = pp->private_data;
544*4882a593Smuzhiyun 	__u8 dcr;
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 	mask &= 0x0f;
547*4882a593Smuzhiyun 	val &= 0x0f;
548*4882a593Smuzhiyun 	if (parport_prologue(pp) < 0)
549*4882a593Smuzhiyun 		return 0;
550*4882a593Smuzhiyun 	mos_parport->shadowDCR = (mos_parport->shadowDCR & (~mask)) ^ val;
551*4882a593Smuzhiyun 	write_mos_reg(mos_parport->serial, dummy, MOS7720_DCR,
552*4882a593Smuzhiyun 		      mos_parport->shadowDCR);
553*4882a593Smuzhiyun 	dcr = mos_parport->shadowDCR & 0x0f;
554*4882a593Smuzhiyun 	parport_epilogue(pp);
555*4882a593Smuzhiyun 	return dcr;
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun 
parport_mos7715_read_status(struct parport * pp)558*4882a593Smuzhiyun static unsigned char parport_mos7715_read_status(struct parport *pp)
559*4882a593Smuzhiyun {
560*4882a593Smuzhiyun 	unsigned char status;
561*4882a593Smuzhiyun 	struct mos7715_parport *mos_parport;
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	spin_lock(&release_lock);
564*4882a593Smuzhiyun 	mos_parport = pp->private_data;
565*4882a593Smuzhiyun 	if (unlikely(mos_parport == NULL)) {	/* release called */
566*4882a593Smuzhiyun 		spin_unlock(&release_lock);
567*4882a593Smuzhiyun 		return 0;
568*4882a593Smuzhiyun 	}
569*4882a593Smuzhiyun 	status = atomic_read(&mos_parport->shadowDSR) & 0xf8;
570*4882a593Smuzhiyun 	spin_unlock(&release_lock);
571*4882a593Smuzhiyun 	return status;
572*4882a593Smuzhiyun }
573*4882a593Smuzhiyun 
parport_mos7715_enable_irq(struct parport * pp)574*4882a593Smuzhiyun static void parport_mos7715_enable_irq(struct parport *pp)
575*4882a593Smuzhiyun {
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun 
parport_mos7715_disable_irq(struct parport * pp)578*4882a593Smuzhiyun static void parport_mos7715_disable_irq(struct parport *pp)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun 
parport_mos7715_data_forward(struct parport * pp)582*4882a593Smuzhiyun static void parport_mos7715_data_forward(struct parport *pp)
583*4882a593Smuzhiyun {
584*4882a593Smuzhiyun 	struct mos7715_parport *mos_parport = pp->private_data;
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	if (parport_prologue(pp) < 0)
587*4882a593Smuzhiyun 		return;
588*4882a593Smuzhiyun 	mos7715_change_mode(mos_parport, PS2);
589*4882a593Smuzhiyun 	mos_parport->shadowDCR &=  ~0x20;
590*4882a593Smuzhiyun 	write_mos_reg(mos_parport->serial, dummy, MOS7720_DCR,
591*4882a593Smuzhiyun 		      mos_parport->shadowDCR);
592*4882a593Smuzhiyun 	parport_epilogue(pp);
593*4882a593Smuzhiyun }
594*4882a593Smuzhiyun 
parport_mos7715_data_reverse(struct parport * pp)595*4882a593Smuzhiyun static void parport_mos7715_data_reverse(struct parport *pp)
596*4882a593Smuzhiyun {
597*4882a593Smuzhiyun 	struct mos7715_parport *mos_parport = pp->private_data;
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	if (parport_prologue(pp) < 0)
600*4882a593Smuzhiyun 		return;
601*4882a593Smuzhiyun 	mos7715_change_mode(mos_parport, PS2);
602*4882a593Smuzhiyun 	mos_parport->shadowDCR |= 0x20;
603*4882a593Smuzhiyun 	write_mos_reg(mos_parport->serial, dummy, MOS7720_DCR,
604*4882a593Smuzhiyun 		      mos_parport->shadowDCR);
605*4882a593Smuzhiyun 	parport_epilogue(pp);
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun 
parport_mos7715_init_state(struct pardevice * dev,struct parport_state * s)608*4882a593Smuzhiyun static void parport_mos7715_init_state(struct pardevice *dev,
609*4882a593Smuzhiyun 				       struct parport_state *s)
610*4882a593Smuzhiyun {
611*4882a593Smuzhiyun 	s->u.pc.ctr = DCR_INIT_VAL;
612*4882a593Smuzhiyun 	s->u.pc.ecr = ECR_INIT_VAL;
613*4882a593Smuzhiyun }
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun /* N.B. Parport core code requires that this function not block */
parport_mos7715_save_state(struct parport * pp,struct parport_state * s)616*4882a593Smuzhiyun static void parport_mos7715_save_state(struct parport *pp,
617*4882a593Smuzhiyun 				       struct parport_state *s)
618*4882a593Smuzhiyun {
619*4882a593Smuzhiyun 	struct mos7715_parport *mos_parport;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	spin_lock(&release_lock);
622*4882a593Smuzhiyun 	mos_parport = pp->private_data;
623*4882a593Smuzhiyun 	if (unlikely(mos_parport == NULL)) {	/* release called */
624*4882a593Smuzhiyun 		spin_unlock(&release_lock);
625*4882a593Smuzhiyun 		return;
626*4882a593Smuzhiyun 	}
627*4882a593Smuzhiyun 	s->u.pc.ctr = mos_parport->shadowDCR;
628*4882a593Smuzhiyun 	s->u.pc.ecr = mos_parport->shadowECR;
629*4882a593Smuzhiyun 	spin_unlock(&release_lock);
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun /* N.B. Parport core code requires that this function not block */
parport_mos7715_restore_state(struct parport * pp,struct parport_state * s)633*4882a593Smuzhiyun static void parport_mos7715_restore_state(struct parport *pp,
634*4882a593Smuzhiyun 					  struct parport_state *s)
635*4882a593Smuzhiyun {
636*4882a593Smuzhiyun 	struct mos7715_parport *mos_parport;
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	spin_lock(&release_lock);
639*4882a593Smuzhiyun 	mos_parport = pp->private_data;
640*4882a593Smuzhiyun 	if (unlikely(mos_parport == NULL)) {	/* release called */
641*4882a593Smuzhiyun 		spin_unlock(&release_lock);
642*4882a593Smuzhiyun 		return;
643*4882a593Smuzhiyun 	}
644*4882a593Smuzhiyun 	mos_parport->shadowDCR = s->u.pc.ctr;
645*4882a593Smuzhiyun 	mos_parport->shadowECR = s->u.pc.ecr;
646*4882a593Smuzhiyun 	write_parport_reg_nonblock(mos_parport, MOS7720_DCR,
647*4882a593Smuzhiyun 				   mos_parport->shadowDCR);
648*4882a593Smuzhiyun 	write_parport_reg_nonblock(mos_parport, MOS7720_ECR,
649*4882a593Smuzhiyun 				   mos_parport->shadowECR);
650*4882a593Smuzhiyun 	spin_unlock(&release_lock);
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun 
parport_mos7715_write_compat(struct parport * pp,const void * buffer,size_t len,int flags)653*4882a593Smuzhiyun static size_t parport_mos7715_write_compat(struct parport *pp,
654*4882a593Smuzhiyun 					   const void *buffer,
655*4882a593Smuzhiyun 					   size_t len, int flags)
656*4882a593Smuzhiyun {
657*4882a593Smuzhiyun 	int retval;
658*4882a593Smuzhiyun 	struct mos7715_parport *mos_parport = pp->private_data;
659*4882a593Smuzhiyun 	int actual_len;
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 	if (parport_prologue(pp) < 0)
662*4882a593Smuzhiyun 		return 0;
663*4882a593Smuzhiyun 	mos7715_change_mode(mos_parport, PPF);
664*4882a593Smuzhiyun 	retval = usb_bulk_msg(mos_parport->serial->dev,
665*4882a593Smuzhiyun 			      usb_sndbulkpipe(mos_parport->serial->dev, 2),
666*4882a593Smuzhiyun 			      (void *)buffer, len, &actual_len,
667*4882a593Smuzhiyun 			      MOS_WDR_TIMEOUT);
668*4882a593Smuzhiyun 	parport_epilogue(pp);
669*4882a593Smuzhiyun 	if (retval) {
670*4882a593Smuzhiyun 		dev_err(&mos_parport->serial->dev->dev,
671*4882a593Smuzhiyun 			"mos7720: usb_bulk_msg() failed: %d\n", retval);
672*4882a593Smuzhiyun 		return 0;
673*4882a593Smuzhiyun 	}
674*4882a593Smuzhiyun 	return actual_len;
675*4882a593Smuzhiyun }
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun static struct parport_operations parport_mos7715_ops = {
678*4882a593Smuzhiyun 	.owner =		THIS_MODULE,
679*4882a593Smuzhiyun 	.write_data =		parport_mos7715_write_data,
680*4882a593Smuzhiyun 	.read_data =		parport_mos7715_read_data,
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun 	.write_control =	parport_mos7715_write_control,
683*4882a593Smuzhiyun 	.read_control =		parport_mos7715_read_control,
684*4882a593Smuzhiyun 	.frob_control =		parport_mos7715_frob_control,
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	.read_status =		parport_mos7715_read_status,
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	.enable_irq =		parport_mos7715_enable_irq,
689*4882a593Smuzhiyun 	.disable_irq =		parport_mos7715_disable_irq,
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	.data_forward =		parport_mos7715_data_forward,
692*4882a593Smuzhiyun 	.data_reverse =		parport_mos7715_data_reverse,
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun 	.init_state =		parport_mos7715_init_state,
695*4882a593Smuzhiyun 	.save_state =		parport_mos7715_save_state,
696*4882a593Smuzhiyun 	.restore_state =	parport_mos7715_restore_state,
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun 	.compat_write_data =	parport_mos7715_write_compat,
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 	.nibble_read_data =	parport_ieee1284_read_nibble,
701*4882a593Smuzhiyun 	.byte_read_data =	parport_ieee1284_read_byte,
702*4882a593Smuzhiyun };
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun /*
705*4882a593Smuzhiyun  * Allocate and initialize parallel port control struct, initialize
706*4882a593Smuzhiyun  * the parallel port hardware device, and register with the parport subsystem.
707*4882a593Smuzhiyun  */
mos7715_parport_init(struct usb_serial * serial)708*4882a593Smuzhiyun static int mos7715_parport_init(struct usb_serial *serial)
709*4882a593Smuzhiyun {
710*4882a593Smuzhiyun 	struct mos7715_parport *mos_parport;
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	/* allocate and initialize parallel port control struct */
713*4882a593Smuzhiyun 	mos_parport = kzalloc(sizeof(struct mos7715_parport), GFP_KERNEL);
714*4882a593Smuzhiyun 	if (!mos_parport)
715*4882a593Smuzhiyun 		return -ENOMEM;
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 	mos_parport->msg_pending = false;
718*4882a593Smuzhiyun 	kref_init(&mos_parport->ref_count);
719*4882a593Smuzhiyun 	spin_lock_init(&mos_parport->listlock);
720*4882a593Smuzhiyun 	INIT_LIST_HEAD(&mos_parport->active_urbs);
721*4882a593Smuzhiyun 	INIT_LIST_HEAD(&mos_parport->deferred_urbs);
722*4882a593Smuzhiyun 	usb_set_serial_data(serial, mos_parport); /* hijack private pointer */
723*4882a593Smuzhiyun 	mos_parport->serial = serial;
724*4882a593Smuzhiyun 	tasklet_setup(&mos_parport->urb_tasklet, send_deferred_urbs);
725*4882a593Smuzhiyun 	init_completion(&mos_parport->syncmsg_compl);
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	/* cycle parallel port reset bit */
728*4882a593Smuzhiyun 	write_mos_reg(mos_parport->serial, dummy, MOS7720_PP_REG, (__u8)0x80);
729*4882a593Smuzhiyun 	write_mos_reg(mos_parport->serial, dummy, MOS7720_PP_REG, (__u8)0x00);
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	/* initialize device registers */
732*4882a593Smuzhiyun 	mos_parport->shadowDCR = DCR_INIT_VAL;
733*4882a593Smuzhiyun 	write_mos_reg(mos_parport->serial, dummy, MOS7720_DCR,
734*4882a593Smuzhiyun 		      mos_parport->shadowDCR);
735*4882a593Smuzhiyun 	mos_parport->shadowECR = ECR_INIT_VAL;
736*4882a593Smuzhiyun 	write_mos_reg(mos_parport->serial, dummy, MOS7720_ECR,
737*4882a593Smuzhiyun 		      mos_parport->shadowECR);
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 	/* register with parport core */
740*4882a593Smuzhiyun 	mos_parport->pp = parport_register_port(0, PARPORT_IRQ_NONE,
741*4882a593Smuzhiyun 						PARPORT_DMA_NONE,
742*4882a593Smuzhiyun 						&parport_mos7715_ops);
743*4882a593Smuzhiyun 	if (mos_parport->pp == NULL) {
744*4882a593Smuzhiyun 		dev_err(&serial->interface->dev,
745*4882a593Smuzhiyun 			"Could not register parport\n");
746*4882a593Smuzhiyun 		kref_put(&mos_parport->ref_count, destroy_mos_parport);
747*4882a593Smuzhiyun 		return -EIO;
748*4882a593Smuzhiyun 	}
749*4882a593Smuzhiyun 	mos_parport->pp->private_data = mos_parport;
750*4882a593Smuzhiyun 	mos_parport->pp->modes = PARPORT_MODE_COMPAT | PARPORT_MODE_PCSPP;
751*4882a593Smuzhiyun 	mos_parport->pp->dev = &serial->interface->dev;
752*4882a593Smuzhiyun 	parport_announce_port(mos_parport->pp);
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 	return 0;
755*4882a593Smuzhiyun }
756*4882a593Smuzhiyun #endif	/* CONFIG_USB_SERIAL_MOS7715_PARPORT */
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun /*
759*4882a593Smuzhiyun  * mos7720_interrupt_callback
760*4882a593Smuzhiyun  *	this is the callback function for when we have received data on the
761*4882a593Smuzhiyun  *	interrupt endpoint.
762*4882a593Smuzhiyun  */
mos7720_interrupt_callback(struct urb * urb)763*4882a593Smuzhiyun static void mos7720_interrupt_callback(struct urb *urb)
764*4882a593Smuzhiyun {
765*4882a593Smuzhiyun 	int result;
766*4882a593Smuzhiyun 	int length;
767*4882a593Smuzhiyun 	int status = urb->status;
768*4882a593Smuzhiyun 	struct device *dev = &urb->dev->dev;
769*4882a593Smuzhiyun 	__u8 *data;
770*4882a593Smuzhiyun 	__u8 sp1;
771*4882a593Smuzhiyun 	__u8 sp2;
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	switch (status) {
774*4882a593Smuzhiyun 	case 0:
775*4882a593Smuzhiyun 		/* success */
776*4882a593Smuzhiyun 		break;
777*4882a593Smuzhiyun 	case -ECONNRESET:
778*4882a593Smuzhiyun 	case -ENOENT:
779*4882a593Smuzhiyun 	case -ESHUTDOWN:
780*4882a593Smuzhiyun 		/* this urb is terminated, clean up */
781*4882a593Smuzhiyun 		dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status);
782*4882a593Smuzhiyun 		return;
783*4882a593Smuzhiyun 	default:
784*4882a593Smuzhiyun 		dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status);
785*4882a593Smuzhiyun 		goto exit;
786*4882a593Smuzhiyun 	}
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun 	length = urb->actual_length;
789*4882a593Smuzhiyun 	data = urb->transfer_buffer;
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 	/* Moschip get 4 bytes
792*4882a593Smuzhiyun 	 * Byte 1 IIR Port 1 (port.number is 0)
793*4882a593Smuzhiyun 	 * Byte 2 IIR Port 2 (port.number is 1)
794*4882a593Smuzhiyun 	 * Byte 3 --------------
795*4882a593Smuzhiyun 	 * Byte 4 FIFO status for both */
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 	/* the above description is inverted
798*4882a593Smuzhiyun 	 * 	oneukum 2007-03-14 */
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 	if (unlikely(length != 4)) {
801*4882a593Smuzhiyun 		dev_dbg(dev, "Wrong data !!!\n");
802*4882a593Smuzhiyun 		return;
803*4882a593Smuzhiyun 	}
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun 	sp1 = data[3];
806*4882a593Smuzhiyun 	sp2 = data[2];
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun 	if ((sp1 | sp2) & 0x01) {
809*4882a593Smuzhiyun 		/* No Interrupt Pending in both the ports */
810*4882a593Smuzhiyun 		dev_dbg(dev, "No Interrupt !!!\n");
811*4882a593Smuzhiyun 	} else {
812*4882a593Smuzhiyun 		switch (sp1 & 0x0f) {
813*4882a593Smuzhiyun 		case SERIAL_IIR_RLS:
814*4882a593Smuzhiyun 			dev_dbg(dev, "Serial Port 1: Receiver status error or address bit detected in 9-bit mode\n");
815*4882a593Smuzhiyun 			break;
816*4882a593Smuzhiyun 		case SERIAL_IIR_CTI:
817*4882a593Smuzhiyun 			dev_dbg(dev, "Serial Port 1: Receiver time out\n");
818*4882a593Smuzhiyun 			break;
819*4882a593Smuzhiyun 		case SERIAL_IIR_MS:
820*4882a593Smuzhiyun 			/* dev_dbg(dev, "Serial Port 1: Modem status change\n"); */
821*4882a593Smuzhiyun 			break;
822*4882a593Smuzhiyun 		}
823*4882a593Smuzhiyun 
824*4882a593Smuzhiyun 		switch (sp2 & 0x0f) {
825*4882a593Smuzhiyun 		case SERIAL_IIR_RLS:
826*4882a593Smuzhiyun 			dev_dbg(dev, "Serial Port 2: Receiver status error or address bit detected in 9-bit mode\n");
827*4882a593Smuzhiyun 			break;
828*4882a593Smuzhiyun 		case SERIAL_IIR_CTI:
829*4882a593Smuzhiyun 			dev_dbg(dev, "Serial Port 2: Receiver time out\n");
830*4882a593Smuzhiyun 			break;
831*4882a593Smuzhiyun 		case SERIAL_IIR_MS:
832*4882a593Smuzhiyun 			/* dev_dbg(dev, "Serial Port 2: Modem status change\n"); */
833*4882a593Smuzhiyun 			break;
834*4882a593Smuzhiyun 		}
835*4882a593Smuzhiyun 	}
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun exit:
838*4882a593Smuzhiyun 	result = usb_submit_urb(urb, GFP_ATOMIC);
839*4882a593Smuzhiyun 	if (result)
840*4882a593Smuzhiyun 		dev_err(dev, "%s - Error %d submitting control urb\n", __func__, result);
841*4882a593Smuzhiyun }
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun /*
844*4882a593Smuzhiyun  * mos7715_interrupt_callback
845*4882a593Smuzhiyun  *	this is the 7715's callback function for when we have received data on
846*4882a593Smuzhiyun  *	the interrupt endpoint.
847*4882a593Smuzhiyun  */
mos7715_interrupt_callback(struct urb * urb)848*4882a593Smuzhiyun static void mos7715_interrupt_callback(struct urb *urb)
849*4882a593Smuzhiyun {
850*4882a593Smuzhiyun 	int result;
851*4882a593Smuzhiyun 	int length;
852*4882a593Smuzhiyun 	int status = urb->status;
853*4882a593Smuzhiyun 	struct device *dev = &urb->dev->dev;
854*4882a593Smuzhiyun 	__u8 *data;
855*4882a593Smuzhiyun 	__u8 iir;
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 	switch (status) {
858*4882a593Smuzhiyun 	case 0:
859*4882a593Smuzhiyun 		/* success */
860*4882a593Smuzhiyun 		break;
861*4882a593Smuzhiyun 	case -ECONNRESET:
862*4882a593Smuzhiyun 	case -ENOENT:
863*4882a593Smuzhiyun 	case -ESHUTDOWN:
864*4882a593Smuzhiyun 	case -ENODEV:
865*4882a593Smuzhiyun 		/* this urb is terminated, clean up */
866*4882a593Smuzhiyun 		dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status);
867*4882a593Smuzhiyun 		return;
868*4882a593Smuzhiyun 	default:
869*4882a593Smuzhiyun 		dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status);
870*4882a593Smuzhiyun 		goto exit;
871*4882a593Smuzhiyun 	}
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun 	length = urb->actual_length;
874*4882a593Smuzhiyun 	data = urb->transfer_buffer;
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun 	/* Structure of data from 7715 device:
877*4882a593Smuzhiyun 	 * Byte 1: IIR serial Port
878*4882a593Smuzhiyun 	 * Byte 2: unused
879*4882a593Smuzhiyun 	 * Byte 2: DSR parallel port
880*4882a593Smuzhiyun 	 * Byte 4: FIFO status for both */
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun 	if (unlikely(length != 4)) {
883*4882a593Smuzhiyun 		dev_dbg(dev, "Wrong data !!!\n");
884*4882a593Smuzhiyun 		return;
885*4882a593Smuzhiyun 	}
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun 	iir = data[0];
888*4882a593Smuzhiyun 	if (!(iir & 0x01)) {	/* serial port interrupt pending */
889*4882a593Smuzhiyun 		switch (iir & 0x0f) {
890*4882a593Smuzhiyun 		case SERIAL_IIR_RLS:
891*4882a593Smuzhiyun 			dev_dbg(dev, "Serial Port: Receiver status error or address bit detected in 9-bit mode\n");
892*4882a593Smuzhiyun 			break;
893*4882a593Smuzhiyun 		case SERIAL_IIR_CTI:
894*4882a593Smuzhiyun 			dev_dbg(dev, "Serial Port: Receiver time out\n");
895*4882a593Smuzhiyun 			break;
896*4882a593Smuzhiyun 		case SERIAL_IIR_MS:
897*4882a593Smuzhiyun 			/* dev_dbg(dev, "Serial Port: Modem status change\n"); */
898*4882a593Smuzhiyun 			break;
899*4882a593Smuzhiyun 		}
900*4882a593Smuzhiyun 	}
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
903*4882a593Smuzhiyun 	{       /* update local copy of DSR reg */
904*4882a593Smuzhiyun 		struct usb_serial_port *port = urb->context;
905*4882a593Smuzhiyun 		struct mos7715_parport *mos_parport = port->serial->private;
906*4882a593Smuzhiyun 		if (unlikely(mos_parport == NULL))
907*4882a593Smuzhiyun 			return;
908*4882a593Smuzhiyun 		atomic_set(&mos_parport->shadowDSR, data[2]);
909*4882a593Smuzhiyun 	}
910*4882a593Smuzhiyun #endif
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun exit:
913*4882a593Smuzhiyun 	result = usb_submit_urb(urb, GFP_ATOMIC);
914*4882a593Smuzhiyun 	if (result)
915*4882a593Smuzhiyun 		dev_err(dev, "%s - Error %d submitting control urb\n", __func__, result);
916*4882a593Smuzhiyun }
917*4882a593Smuzhiyun 
918*4882a593Smuzhiyun /*
919*4882a593Smuzhiyun  * mos7720_bulk_in_callback
920*4882a593Smuzhiyun  *	this is the callback function for when we have received data on the
921*4882a593Smuzhiyun  *	bulk in endpoint.
922*4882a593Smuzhiyun  */
mos7720_bulk_in_callback(struct urb * urb)923*4882a593Smuzhiyun static void mos7720_bulk_in_callback(struct urb *urb)
924*4882a593Smuzhiyun {
925*4882a593Smuzhiyun 	int retval;
926*4882a593Smuzhiyun 	unsigned char *data ;
927*4882a593Smuzhiyun 	struct usb_serial_port *port;
928*4882a593Smuzhiyun 	int status = urb->status;
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun 	if (status) {
931*4882a593Smuzhiyun 		dev_dbg(&urb->dev->dev, "nonzero read bulk status received: %d\n", status);
932*4882a593Smuzhiyun 		return;
933*4882a593Smuzhiyun 	}
934*4882a593Smuzhiyun 
935*4882a593Smuzhiyun 	port = urb->context;
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 	dev_dbg(&port->dev, "Entering...%s\n", __func__);
938*4882a593Smuzhiyun 
939*4882a593Smuzhiyun 	data = urb->transfer_buffer;
940*4882a593Smuzhiyun 
941*4882a593Smuzhiyun 	if (urb->actual_length) {
942*4882a593Smuzhiyun 		tty_insert_flip_string(&port->port, data, urb->actual_length);
943*4882a593Smuzhiyun 		tty_flip_buffer_push(&port->port);
944*4882a593Smuzhiyun 	}
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun 	if (port->read_urb->status != -EINPROGRESS) {
947*4882a593Smuzhiyun 		retval = usb_submit_urb(port->read_urb, GFP_ATOMIC);
948*4882a593Smuzhiyun 		if (retval)
949*4882a593Smuzhiyun 			dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, retval = %d\n", retval);
950*4882a593Smuzhiyun 	}
951*4882a593Smuzhiyun }
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun /*
954*4882a593Smuzhiyun  * mos7720_bulk_out_data_callback
955*4882a593Smuzhiyun  *	this is the callback function for when we have finished sending serial
956*4882a593Smuzhiyun  *	data on the bulk out endpoint.
957*4882a593Smuzhiyun  */
mos7720_bulk_out_data_callback(struct urb * urb)958*4882a593Smuzhiyun static void mos7720_bulk_out_data_callback(struct urb *urb)
959*4882a593Smuzhiyun {
960*4882a593Smuzhiyun 	struct moschip_port *mos7720_port;
961*4882a593Smuzhiyun 	int status = urb->status;
962*4882a593Smuzhiyun 
963*4882a593Smuzhiyun 	if (status) {
964*4882a593Smuzhiyun 		dev_dbg(&urb->dev->dev, "nonzero write bulk status received:%d\n", status);
965*4882a593Smuzhiyun 		return;
966*4882a593Smuzhiyun 	}
967*4882a593Smuzhiyun 
968*4882a593Smuzhiyun 	mos7720_port = urb->context;
969*4882a593Smuzhiyun 	if (!mos7720_port) {
970*4882a593Smuzhiyun 		dev_dbg(&urb->dev->dev, "NULL mos7720_port pointer\n");
971*4882a593Smuzhiyun 		return ;
972*4882a593Smuzhiyun 	}
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun 	if (mos7720_port->open)
975*4882a593Smuzhiyun 		tty_port_tty_wakeup(&mos7720_port->port->port);
976*4882a593Smuzhiyun }
977*4882a593Smuzhiyun 
mos77xx_calc_num_ports(struct usb_serial * serial,struct usb_serial_endpoints * epds)978*4882a593Smuzhiyun static int mos77xx_calc_num_ports(struct usb_serial *serial,
979*4882a593Smuzhiyun 					struct usb_serial_endpoints *epds)
980*4882a593Smuzhiyun {
981*4882a593Smuzhiyun 	u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
982*4882a593Smuzhiyun 
983*4882a593Smuzhiyun 	if (product == MOSCHIP_DEVICE_ID_7715) {
984*4882a593Smuzhiyun 		/*
985*4882a593Smuzhiyun 		 * The 7715 uses the first bulk in/out endpoint pair for the
986*4882a593Smuzhiyun 		 * parallel port, and the second for the serial port. We swap
987*4882a593Smuzhiyun 		 * the endpoint descriptors here so that the the first and
988*4882a593Smuzhiyun 		 * only registered port structure uses the serial-port
989*4882a593Smuzhiyun 		 * endpoints.
990*4882a593Smuzhiyun 		 */
991*4882a593Smuzhiyun 		swap(epds->bulk_in[0], epds->bulk_in[1]);
992*4882a593Smuzhiyun 		swap(epds->bulk_out[0], epds->bulk_out[1]);
993*4882a593Smuzhiyun 
994*4882a593Smuzhiyun 		return 1;
995*4882a593Smuzhiyun 	}
996*4882a593Smuzhiyun 
997*4882a593Smuzhiyun 	return 2;
998*4882a593Smuzhiyun }
999*4882a593Smuzhiyun 
mos7720_open(struct tty_struct * tty,struct usb_serial_port * port)1000*4882a593Smuzhiyun static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)
1001*4882a593Smuzhiyun {
1002*4882a593Smuzhiyun 	struct usb_serial *serial;
1003*4882a593Smuzhiyun 	struct urb *urb;
1004*4882a593Smuzhiyun 	struct moschip_port *mos7720_port;
1005*4882a593Smuzhiyun 	int response;
1006*4882a593Smuzhiyun 	int port_number;
1007*4882a593Smuzhiyun 	__u8 data;
1008*4882a593Smuzhiyun 	int allocated_urbs = 0;
1009*4882a593Smuzhiyun 	int j;
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun 	serial = port->serial;
1012*4882a593Smuzhiyun 
1013*4882a593Smuzhiyun 	mos7720_port = usb_get_serial_port_data(port);
1014*4882a593Smuzhiyun 	if (mos7720_port == NULL)
1015*4882a593Smuzhiyun 		return -ENODEV;
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun 	usb_clear_halt(serial->dev, port->write_urb->pipe);
1018*4882a593Smuzhiyun 	usb_clear_halt(serial->dev, port->read_urb->pipe);
1019*4882a593Smuzhiyun 
1020*4882a593Smuzhiyun 	/* Initialising the write urb pool */
1021*4882a593Smuzhiyun 	for (j = 0; j < NUM_URBS; ++j) {
1022*4882a593Smuzhiyun 		urb = usb_alloc_urb(0, GFP_KERNEL);
1023*4882a593Smuzhiyun 		mos7720_port->write_urb_pool[j] = urb;
1024*4882a593Smuzhiyun 		if (!urb)
1025*4882a593Smuzhiyun 			continue;
1026*4882a593Smuzhiyun 
1027*4882a593Smuzhiyun 		urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
1028*4882a593Smuzhiyun 					       GFP_KERNEL);
1029*4882a593Smuzhiyun 		if (!urb->transfer_buffer) {
1030*4882a593Smuzhiyun 			usb_free_urb(mos7720_port->write_urb_pool[j]);
1031*4882a593Smuzhiyun 			mos7720_port->write_urb_pool[j] = NULL;
1032*4882a593Smuzhiyun 			continue;
1033*4882a593Smuzhiyun 		}
1034*4882a593Smuzhiyun 		allocated_urbs++;
1035*4882a593Smuzhiyun 	}
1036*4882a593Smuzhiyun 
1037*4882a593Smuzhiyun 	if (!allocated_urbs)
1038*4882a593Smuzhiyun 		return -ENOMEM;
1039*4882a593Smuzhiyun 
1040*4882a593Smuzhiyun 	 /* Initialize MCS7720 -- Write Init values to corresponding Registers
1041*4882a593Smuzhiyun 	  *
1042*4882a593Smuzhiyun 	  * Register Index
1043*4882a593Smuzhiyun 	  * 0 : MOS7720_THR/MOS7720_RHR
1044*4882a593Smuzhiyun 	  * 1 : MOS7720_IER
1045*4882a593Smuzhiyun 	  * 2 : MOS7720_FCR
1046*4882a593Smuzhiyun 	  * 3 : MOS7720_LCR
1047*4882a593Smuzhiyun 	  * 4 : MOS7720_MCR
1048*4882a593Smuzhiyun 	  * 5 : MOS7720_LSR
1049*4882a593Smuzhiyun 	  * 6 : MOS7720_MSR
1050*4882a593Smuzhiyun 	  * 7 : MOS7720_SPR
1051*4882a593Smuzhiyun 	  *
1052*4882a593Smuzhiyun 	  * 0x08 : SP1/2 Control Reg
1053*4882a593Smuzhiyun 	  */
1054*4882a593Smuzhiyun 	port_number = port->port_number;
1055*4882a593Smuzhiyun 	read_mos_reg(serial, port_number, MOS7720_LSR, &data);
1056*4882a593Smuzhiyun 
1057*4882a593Smuzhiyun 	dev_dbg(&port->dev, "SS::%p LSR:%x\n", mos7720_port, data);
1058*4882a593Smuzhiyun 
1059*4882a593Smuzhiyun 	write_mos_reg(serial, dummy, MOS7720_SP1_REG, 0x02);
1060*4882a593Smuzhiyun 	write_mos_reg(serial, dummy, MOS7720_SP2_REG, 0x02);
1061*4882a593Smuzhiyun 
1062*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_IER, 0x00);
1063*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_FCR, 0x00);
1064*4882a593Smuzhiyun 
1065*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_FCR, 0xcf);
1066*4882a593Smuzhiyun 	mos7720_port->shadowLCR = 0x03;
1067*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_LCR,
1068*4882a593Smuzhiyun 		      mos7720_port->shadowLCR);
1069*4882a593Smuzhiyun 	mos7720_port->shadowMCR = 0x0b;
1070*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_MCR,
1071*4882a593Smuzhiyun 		      mos7720_port->shadowMCR);
1072*4882a593Smuzhiyun 
1073*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_SP_CONTROL_REG, 0x00);
1074*4882a593Smuzhiyun 	read_mos_reg(serial, dummy, MOS7720_SP_CONTROL_REG, &data);
1075*4882a593Smuzhiyun 	data = data | (port->port_number + 1);
1076*4882a593Smuzhiyun 	write_mos_reg(serial, dummy, MOS7720_SP_CONTROL_REG, data);
1077*4882a593Smuzhiyun 	mos7720_port->shadowLCR = 0x83;
1078*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_LCR,
1079*4882a593Smuzhiyun 		      mos7720_port->shadowLCR);
1080*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_THR, 0x0c);
1081*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_IER, 0x00);
1082*4882a593Smuzhiyun 	mos7720_port->shadowLCR = 0x03;
1083*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_LCR,
1084*4882a593Smuzhiyun 		      mos7720_port->shadowLCR);
1085*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_IER, 0x0c);
1086*4882a593Smuzhiyun 
1087*4882a593Smuzhiyun 	response = usb_submit_urb(port->read_urb, GFP_KERNEL);
1088*4882a593Smuzhiyun 	if (response)
1089*4882a593Smuzhiyun 		dev_err(&port->dev, "%s - Error %d submitting read urb\n",
1090*4882a593Smuzhiyun 							__func__, response);
1091*4882a593Smuzhiyun 
1092*4882a593Smuzhiyun 	/* initialize our port settings */
1093*4882a593Smuzhiyun 	mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */
1094*4882a593Smuzhiyun 
1095*4882a593Smuzhiyun 	/* send a open port command */
1096*4882a593Smuzhiyun 	mos7720_port->open = 1;
1097*4882a593Smuzhiyun 
1098*4882a593Smuzhiyun 	return 0;
1099*4882a593Smuzhiyun }
1100*4882a593Smuzhiyun 
1101*4882a593Smuzhiyun /*
1102*4882a593Smuzhiyun  * mos7720_chars_in_buffer
1103*4882a593Smuzhiyun  *	this function is called by the tty driver when it wants to know how many
1104*4882a593Smuzhiyun  *	bytes of data we currently have outstanding in the port (data that has
1105*4882a593Smuzhiyun  *	been written, but hasn't made it out the port yet)
1106*4882a593Smuzhiyun  *	If successful, we return the number of bytes left to be written in the
1107*4882a593Smuzhiyun  *	system,
1108*4882a593Smuzhiyun  *	Otherwise we return a negative error number.
1109*4882a593Smuzhiyun  */
mos7720_chars_in_buffer(struct tty_struct * tty)1110*4882a593Smuzhiyun static int mos7720_chars_in_buffer(struct tty_struct *tty)
1111*4882a593Smuzhiyun {
1112*4882a593Smuzhiyun 	struct usb_serial_port *port = tty->driver_data;
1113*4882a593Smuzhiyun 	int i;
1114*4882a593Smuzhiyun 	int chars = 0;
1115*4882a593Smuzhiyun 	struct moschip_port *mos7720_port;
1116*4882a593Smuzhiyun 
1117*4882a593Smuzhiyun 	mos7720_port = usb_get_serial_port_data(port);
1118*4882a593Smuzhiyun 	if (mos7720_port == NULL)
1119*4882a593Smuzhiyun 		return 0;
1120*4882a593Smuzhiyun 
1121*4882a593Smuzhiyun 	for (i = 0; i < NUM_URBS; ++i) {
1122*4882a593Smuzhiyun 		if (mos7720_port->write_urb_pool[i] &&
1123*4882a593Smuzhiyun 		    mos7720_port->write_urb_pool[i]->status == -EINPROGRESS)
1124*4882a593Smuzhiyun 			chars += URB_TRANSFER_BUFFER_SIZE;
1125*4882a593Smuzhiyun 	}
1126*4882a593Smuzhiyun 	dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
1127*4882a593Smuzhiyun 	return chars;
1128*4882a593Smuzhiyun }
1129*4882a593Smuzhiyun 
mos7720_close(struct usb_serial_port * port)1130*4882a593Smuzhiyun static void mos7720_close(struct usb_serial_port *port)
1131*4882a593Smuzhiyun {
1132*4882a593Smuzhiyun 	struct usb_serial *serial;
1133*4882a593Smuzhiyun 	struct moschip_port *mos7720_port;
1134*4882a593Smuzhiyun 	int j;
1135*4882a593Smuzhiyun 
1136*4882a593Smuzhiyun 	serial = port->serial;
1137*4882a593Smuzhiyun 
1138*4882a593Smuzhiyun 	mos7720_port = usb_get_serial_port_data(port);
1139*4882a593Smuzhiyun 	if (mos7720_port == NULL)
1140*4882a593Smuzhiyun 		return;
1141*4882a593Smuzhiyun 
1142*4882a593Smuzhiyun 	for (j = 0; j < NUM_URBS; ++j)
1143*4882a593Smuzhiyun 		usb_kill_urb(mos7720_port->write_urb_pool[j]);
1144*4882a593Smuzhiyun 
1145*4882a593Smuzhiyun 	/* Freeing Write URBs */
1146*4882a593Smuzhiyun 	for (j = 0; j < NUM_URBS; ++j) {
1147*4882a593Smuzhiyun 		if (mos7720_port->write_urb_pool[j]) {
1148*4882a593Smuzhiyun 			kfree(mos7720_port->write_urb_pool[j]->transfer_buffer);
1149*4882a593Smuzhiyun 			usb_free_urb(mos7720_port->write_urb_pool[j]);
1150*4882a593Smuzhiyun 		}
1151*4882a593Smuzhiyun 	}
1152*4882a593Smuzhiyun 
1153*4882a593Smuzhiyun 	/* While closing port, shutdown all bulk read, write  *
1154*4882a593Smuzhiyun 	 * and interrupt read if they exists, otherwise nop   */
1155*4882a593Smuzhiyun 	usb_kill_urb(port->write_urb);
1156*4882a593Smuzhiyun 	usb_kill_urb(port->read_urb);
1157*4882a593Smuzhiyun 
1158*4882a593Smuzhiyun 	write_mos_reg(serial, port->port_number, MOS7720_MCR, 0x00);
1159*4882a593Smuzhiyun 	write_mos_reg(serial, port->port_number, MOS7720_IER, 0x00);
1160*4882a593Smuzhiyun 
1161*4882a593Smuzhiyun 	mos7720_port->open = 0;
1162*4882a593Smuzhiyun }
1163*4882a593Smuzhiyun 
mos7720_break(struct tty_struct * tty,int break_state)1164*4882a593Smuzhiyun static void mos7720_break(struct tty_struct *tty, int break_state)
1165*4882a593Smuzhiyun {
1166*4882a593Smuzhiyun 	struct usb_serial_port *port = tty->driver_data;
1167*4882a593Smuzhiyun 	unsigned char data;
1168*4882a593Smuzhiyun 	struct usb_serial *serial;
1169*4882a593Smuzhiyun 	struct moschip_port *mos7720_port;
1170*4882a593Smuzhiyun 
1171*4882a593Smuzhiyun 	serial = port->serial;
1172*4882a593Smuzhiyun 
1173*4882a593Smuzhiyun 	mos7720_port = usb_get_serial_port_data(port);
1174*4882a593Smuzhiyun 	if (mos7720_port == NULL)
1175*4882a593Smuzhiyun 		return;
1176*4882a593Smuzhiyun 
1177*4882a593Smuzhiyun 	if (break_state == -1)
1178*4882a593Smuzhiyun 		data = mos7720_port->shadowLCR | UART_LCR_SBC;
1179*4882a593Smuzhiyun 	else
1180*4882a593Smuzhiyun 		data = mos7720_port->shadowLCR & ~UART_LCR_SBC;
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun 	mos7720_port->shadowLCR  = data;
1183*4882a593Smuzhiyun 	write_mos_reg(serial, port->port_number, MOS7720_LCR,
1184*4882a593Smuzhiyun 		      mos7720_port->shadowLCR);
1185*4882a593Smuzhiyun }
1186*4882a593Smuzhiyun 
1187*4882a593Smuzhiyun /*
1188*4882a593Smuzhiyun  * mos7720_write_room
1189*4882a593Smuzhiyun  *	this function is called by the tty driver when it wants to know how many
1190*4882a593Smuzhiyun  *	bytes of data we can accept for a specific port.
1191*4882a593Smuzhiyun  *	If successful, we return the amount of room that we have for this port
1192*4882a593Smuzhiyun  *	Otherwise we return a negative error number.
1193*4882a593Smuzhiyun  */
mos7720_write_room(struct tty_struct * tty)1194*4882a593Smuzhiyun static int mos7720_write_room(struct tty_struct *tty)
1195*4882a593Smuzhiyun {
1196*4882a593Smuzhiyun 	struct usb_serial_port *port = tty->driver_data;
1197*4882a593Smuzhiyun 	struct moschip_port *mos7720_port;
1198*4882a593Smuzhiyun 	int room = 0;
1199*4882a593Smuzhiyun 	int i;
1200*4882a593Smuzhiyun 
1201*4882a593Smuzhiyun 	mos7720_port = usb_get_serial_port_data(port);
1202*4882a593Smuzhiyun 	if (mos7720_port == NULL)
1203*4882a593Smuzhiyun 		return -ENODEV;
1204*4882a593Smuzhiyun 
1205*4882a593Smuzhiyun 	/* FIXME: Locking */
1206*4882a593Smuzhiyun 	for (i = 0; i < NUM_URBS; ++i) {
1207*4882a593Smuzhiyun 		if (mos7720_port->write_urb_pool[i] &&
1208*4882a593Smuzhiyun 		    mos7720_port->write_urb_pool[i]->status != -EINPROGRESS)
1209*4882a593Smuzhiyun 			room += URB_TRANSFER_BUFFER_SIZE;
1210*4882a593Smuzhiyun 	}
1211*4882a593Smuzhiyun 
1212*4882a593Smuzhiyun 	dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
1213*4882a593Smuzhiyun 	return room;
1214*4882a593Smuzhiyun }
1215*4882a593Smuzhiyun 
mos7720_write(struct tty_struct * tty,struct usb_serial_port * port,const unsigned char * data,int count)1216*4882a593Smuzhiyun static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port,
1217*4882a593Smuzhiyun 				 const unsigned char *data, int count)
1218*4882a593Smuzhiyun {
1219*4882a593Smuzhiyun 	int status;
1220*4882a593Smuzhiyun 	int i;
1221*4882a593Smuzhiyun 	int bytes_sent = 0;
1222*4882a593Smuzhiyun 	int transfer_size;
1223*4882a593Smuzhiyun 
1224*4882a593Smuzhiyun 	struct moschip_port *mos7720_port;
1225*4882a593Smuzhiyun 	struct usb_serial *serial;
1226*4882a593Smuzhiyun 	struct urb    *urb;
1227*4882a593Smuzhiyun 	const unsigned char *current_position = data;
1228*4882a593Smuzhiyun 
1229*4882a593Smuzhiyun 	serial = port->serial;
1230*4882a593Smuzhiyun 
1231*4882a593Smuzhiyun 	mos7720_port = usb_get_serial_port_data(port);
1232*4882a593Smuzhiyun 	if (mos7720_port == NULL)
1233*4882a593Smuzhiyun 		return -ENODEV;
1234*4882a593Smuzhiyun 
1235*4882a593Smuzhiyun 	/* try to find a free urb in the list */
1236*4882a593Smuzhiyun 	urb = NULL;
1237*4882a593Smuzhiyun 
1238*4882a593Smuzhiyun 	for (i = 0; i < NUM_URBS; ++i) {
1239*4882a593Smuzhiyun 		if (mos7720_port->write_urb_pool[i] &&
1240*4882a593Smuzhiyun 		    mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) {
1241*4882a593Smuzhiyun 			urb = mos7720_port->write_urb_pool[i];
1242*4882a593Smuzhiyun 			dev_dbg(&port->dev, "URB:%d\n", i);
1243*4882a593Smuzhiyun 			break;
1244*4882a593Smuzhiyun 		}
1245*4882a593Smuzhiyun 	}
1246*4882a593Smuzhiyun 
1247*4882a593Smuzhiyun 	if (urb == NULL) {
1248*4882a593Smuzhiyun 		dev_dbg(&port->dev, "%s - no more free urbs\n", __func__);
1249*4882a593Smuzhiyun 		goto exit;
1250*4882a593Smuzhiyun 	}
1251*4882a593Smuzhiyun 
1252*4882a593Smuzhiyun 	if (urb->transfer_buffer == NULL) {
1253*4882a593Smuzhiyun 		urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
1254*4882a593Smuzhiyun 					       GFP_ATOMIC);
1255*4882a593Smuzhiyun 		if (!urb->transfer_buffer) {
1256*4882a593Smuzhiyun 			bytes_sent = -ENOMEM;
1257*4882a593Smuzhiyun 			goto exit;
1258*4882a593Smuzhiyun 		}
1259*4882a593Smuzhiyun 	}
1260*4882a593Smuzhiyun 	transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
1261*4882a593Smuzhiyun 
1262*4882a593Smuzhiyun 	memcpy(urb->transfer_buffer, current_position, transfer_size);
1263*4882a593Smuzhiyun 	usb_serial_debug_data(&port->dev, __func__, transfer_size,
1264*4882a593Smuzhiyun 			      urb->transfer_buffer);
1265*4882a593Smuzhiyun 
1266*4882a593Smuzhiyun 	/* fill urb with data and submit  */
1267*4882a593Smuzhiyun 	usb_fill_bulk_urb(urb, serial->dev,
1268*4882a593Smuzhiyun 			  usb_sndbulkpipe(serial->dev,
1269*4882a593Smuzhiyun 					port->bulk_out_endpointAddress),
1270*4882a593Smuzhiyun 			  urb->transfer_buffer, transfer_size,
1271*4882a593Smuzhiyun 			  mos7720_bulk_out_data_callback, mos7720_port);
1272*4882a593Smuzhiyun 
1273*4882a593Smuzhiyun 	/* send it down the pipe */
1274*4882a593Smuzhiyun 	status = usb_submit_urb(urb, GFP_ATOMIC);
1275*4882a593Smuzhiyun 	if (status) {
1276*4882a593Smuzhiyun 		dev_err_console(port, "%s - usb_submit_urb(write bulk) failed "
1277*4882a593Smuzhiyun 			"with status = %d\n", __func__, status);
1278*4882a593Smuzhiyun 		bytes_sent = status;
1279*4882a593Smuzhiyun 		goto exit;
1280*4882a593Smuzhiyun 	}
1281*4882a593Smuzhiyun 	bytes_sent = transfer_size;
1282*4882a593Smuzhiyun 
1283*4882a593Smuzhiyun exit:
1284*4882a593Smuzhiyun 	return bytes_sent;
1285*4882a593Smuzhiyun }
1286*4882a593Smuzhiyun 
mos7720_throttle(struct tty_struct * tty)1287*4882a593Smuzhiyun static void mos7720_throttle(struct tty_struct *tty)
1288*4882a593Smuzhiyun {
1289*4882a593Smuzhiyun 	struct usb_serial_port *port = tty->driver_data;
1290*4882a593Smuzhiyun 	struct moschip_port *mos7720_port;
1291*4882a593Smuzhiyun 	int status;
1292*4882a593Smuzhiyun 
1293*4882a593Smuzhiyun 	mos7720_port = usb_get_serial_port_data(port);
1294*4882a593Smuzhiyun 
1295*4882a593Smuzhiyun 	if (mos7720_port == NULL)
1296*4882a593Smuzhiyun 		return;
1297*4882a593Smuzhiyun 
1298*4882a593Smuzhiyun 	if (!mos7720_port->open) {
1299*4882a593Smuzhiyun 		dev_dbg(&port->dev, "%s - port not opened\n", __func__);
1300*4882a593Smuzhiyun 		return;
1301*4882a593Smuzhiyun 	}
1302*4882a593Smuzhiyun 
1303*4882a593Smuzhiyun 	/* if we are implementing XON/XOFF, send the stop character */
1304*4882a593Smuzhiyun 	if (I_IXOFF(tty)) {
1305*4882a593Smuzhiyun 		unsigned char stop_char = STOP_CHAR(tty);
1306*4882a593Smuzhiyun 		status = mos7720_write(tty, port, &stop_char, 1);
1307*4882a593Smuzhiyun 		if (status <= 0)
1308*4882a593Smuzhiyun 			return;
1309*4882a593Smuzhiyun 	}
1310*4882a593Smuzhiyun 
1311*4882a593Smuzhiyun 	/* if we are implementing RTS/CTS, toggle that line */
1312*4882a593Smuzhiyun 	if (C_CRTSCTS(tty)) {
1313*4882a593Smuzhiyun 		mos7720_port->shadowMCR &= ~UART_MCR_RTS;
1314*4882a593Smuzhiyun 		write_mos_reg(port->serial, port->port_number, MOS7720_MCR,
1315*4882a593Smuzhiyun 			      mos7720_port->shadowMCR);
1316*4882a593Smuzhiyun 	}
1317*4882a593Smuzhiyun }
1318*4882a593Smuzhiyun 
mos7720_unthrottle(struct tty_struct * tty)1319*4882a593Smuzhiyun static void mos7720_unthrottle(struct tty_struct *tty)
1320*4882a593Smuzhiyun {
1321*4882a593Smuzhiyun 	struct usb_serial_port *port = tty->driver_data;
1322*4882a593Smuzhiyun 	struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
1323*4882a593Smuzhiyun 	int status;
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun 	if (mos7720_port == NULL)
1326*4882a593Smuzhiyun 		return;
1327*4882a593Smuzhiyun 
1328*4882a593Smuzhiyun 	if (!mos7720_port->open) {
1329*4882a593Smuzhiyun 		dev_dbg(&port->dev, "%s - port not opened\n", __func__);
1330*4882a593Smuzhiyun 		return;
1331*4882a593Smuzhiyun 	}
1332*4882a593Smuzhiyun 
1333*4882a593Smuzhiyun 	/* if we are implementing XON/XOFF, send the start character */
1334*4882a593Smuzhiyun 	if (I_IXOFF(tty)) {
1335*4882a593Smuzhiyun 		unsigned char start_char = START_CHAR(tty);
1336*4882a593Smuzhiyun 		status = mos7720_write(tty, port, &start_char, 1);
1337*4882a593Smuzhiyun 		if (status <= 0)
1338*4882a593Smuzhiyun 			return;
1339*4882a593Smuzhiyun 	}
1340*4882a593Smuzhiyun 
1341*4882a593Smuzhiyun 	/* if we are implementing RTS/CTS, toggle that line */
1342*4882a593Smuzhiyun 	if (C_CRTSCTS(tty)) {
1343*4882a593Smuzhiyun 		mos7720_port->shadowMCR |= UART_MCR_RTS;
1344*4882a593Smuzhiyun 		write_mos_reg(port->serial, port->port_number, MOS7720_MCR,
1345*4882a593Smuzhiyun 			      mos7720_port->shadowMCR);
1346*4882a593Smuzhiyun 	}
1347*4882a593Smuzhiyun }
1348*4882a593Smuzhiyun 
1349*4882a593Smuzhiyun /* FIXME: this function does not work */
set_higher_rates(struct moschip_port * mos7720_port,unsigned int baud)1350*4882a593Smuzhiyun static int set_higher_rates(struct moschip_port *mos7720_port,
1351*4882a593Smuzhiyun 			    unsigned int baud)
1352*4882a593Smuzhiyun {
1353*4882a593Smuzhiyun 	struct usb_serial_port *port;
1354*4882a593Smuzhiyun 	struct usb_serial *serial;
1355*4882a593Smuzhiyun 	int port_number;
1356*4882a593Smuzhiyun 	enum mos_regs sp_reg;
1357*4882a593Smuzhiyun 	if (mos7720_port == NULL)
1358*4882a593Smuzhiyun 		return -EINVAL;
1359*4882a593Smuzhiyun 
1360*4882a593Smuzhiyun 	port = mos7720_port->port;
1361*4882a593Smuzhiyun 	serial = port->serial;
1362*4882a593Smuzhiyun 
1363*4882a593Smuzhiyun 	 /***********************************************
1364*4882a593Smuzhiyun 	 *      Init Sequence for higher rates
1365*4882a593Smuzhiyun 	 ***********************************************/
1366*4882a593Smuzhiyun 	dev_dbg(&port->dev, "Sending Setting Commands ..........\n");
1367*4882a593Smuzhiyun 	port_number = port->port_number;
1368*4882a593Smuzhiyun 
1369*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_IER, 0x00);
1370*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_FCR, 0x00);
1371*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_FCR, 0xcf);
1372*4882a593Smuzhiyun 	mos7720_port->shadowMCR = 0x0b;
1373*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_MCR,
1374*4882a593Smuzhiyun 		      mos7720_port->shadowMCR);
1375*4882a593Smuzhiyun 	write_mos_reg(serial, dummy, MOS7720_SP_CONTROL_REG, 0x00);
1376*4882a593Smuzhiyun 
1377*4882a593Smuzhiyun 	/***********************************************
1378*4882a593Smuzhiyun 	 *              Set for higher rates           *
1379*4882a593Smuzhiyun 	 ***********************************************/
1380*4882a593Smuzhiyun 	/* writing baud rate verbatum into uart clock field clearly not right */
1381*4882a593Smuzhiyun 	if (port_number == 0)
1382*4882a593Smuzhiyun 		sp_reg = MOS7720_SP1_REG;
1383*4882a593Smuzhiyun 	else
1384*4882a593Smuzhiyun 		sp_reg = MOS7720_SP2_REG;
1385*4882a593Smuzhiyun 	write_mos_reg(serial, dummy, sp_reg, baud * 0x10);
1386*4882a593Smuzhiyun 	write_mos_reg(serial, dummy, MOS7720_SP_CONTROL_REG, 0x03);
1387*4882a593Smuzhiyun 	mos7720_port->shadowMCR = 0x2b;
1388*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_MCR,
1389*4882a593Smuzhiyun 		      mos7720_port->shadowMCR);
1390*4882a593Smuzhiyun 
1391*4882a593Smuzhiyun 	/***********************************************
1392*4882a593Smuzhiyun 	 *              Set DLL/DLM
1393*4882a593Smuzhiyun 	 ***********************************************/
1394*4882a593Smuzhiyun 	mos7720_port->shadowLCR = mos7720_port->shadowLCR | UART_LCR_DLAB;
1395*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_LCR,
1396*4882a593Smuzhiyun 		      mos7720_port->shadowLCR);
1397*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_DLL, 0x01);
1398*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_DLM, 0x00);
1399*4882a593Smuzhiyun 	mos7720_port->shadowLCR = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
1400*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_LCR,
1401*4882a593Smuzhiyun 		      mos7720_port->shadowLCR);
1402*4882a593Smuzhiyun 
1403*4882a593Smuzhiyun 	return 0;
1404*4882a593Smuzhiyun }
1405*4882a593Smuzhiyun 
1406*4882a593Smuzhiyun /* baud rate information */
1407*4882a593Smuzhiyun struct divisor_table_entry {
1408*4882a593Smuzhiyun 	__u32  baudrate;
1409*4882a593Smuzhiyun 	__u16  divisor;
1410*4882a593Smuzhiyun };
1411*4882a593Smuzhiyun 
1412*4882a593Smuzhiyun /* Define table of divisors for moschip 7720 hardware	   *
1413*4882a593Smuzhiyun  * These assume a 3.6864MHz crystal, the standard /16, and *
1414*4882a593Smuzhiyun  * MCR.7 = 0.						   */
1415*4882a593Smuzhiyun static const struct divisor_table_entry divisor_table[] = {
1416*4882a593Smuzhiyun 	{   50,		2304},
1417*4882a593Smuzhiyun 	{   110,	1047},	/* 2094.545455 => 230450   => .0217 % over */
1418*4882a593Smuzhiyun 	{   134,	857},	/* 1713.011152 => 230398.5 => .00065% under */
1419*4882a593Smuzhiyun 	{   150,	768},
1420*4882a593Smuzhiyun 	{   300,	384},
1421*4882a593Smuzhiyun 	{   600,	192},
1422*4882a593Smuzhiyun 	{   1200,	96},
1423*4882a593Smuzhiyun 	{   1800,	64},
1424*4882a593Smuzhiyun 	{   2400,	48},
1425*4882a593Smuzhiyun 	{   4800,	24},
1426*4882a593Smuzhiyun 	{   7200,	16},
1427*4882a593Smuzhiyun 	{   9600,	12},
1428*4882a593Smuzhiyun 	{   19200,	6},
1429*4882a593Smuzhiyun 	{   38400,	3},
1430*4882a593Smuzhiyun 	{   57600,	2},
1431*4882a593Smuzhiyun 	{   115200,	1},
1432*4882a593Smuzhiyun };
1433*4882a593Smuzhiyun 
1434*4882a593Smuzhiyun /*****************************************************************************
1435*4882a593Smuzhiyun  * calc_baud_rate_divisor
1436*4882a593Smuzhiyun  *	this function calculates the proper baud rate divisor for the specified
1437*4882a593Smuzhiyun  *	baud rate.
1438*4882a593Smuzhiyun  *****************************************************************************/
calc_baud_rate_divisor(struct usb_serial_port * port,int baudrate,int * divisor)1439*4882a593Smuzhiyun static int calc_baud_rate_divisor(struct usb_serial_port *port, int baudrate, int *divisor)
1440*4882a593Smuzhiyun {
1441*4882a593Smuzhiyun 	int i;
1442*4882a593Smuzhiyun 	__u16 custom;
1443*4882a593Smuzhiyun 	__u16 round1;
1444*4882a593Smuzhiyun 	__u16 round;
1445*4882a593Smuzhiyun 
1446*4882a593Smuzhiyun 
1447*4882a593Smuzhiyun 	dev_dbg(&port->dev, "%s - %d\n", __func__, baudrate);
1448*4882a593Smuzhiyun 
1449*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(divisor_table); i++) {
1450*4882a593Smuzhiyun 		if (divisor_table[i].baudrate == baudrate) {
1451*4882a593Smuzhiyun 			*divisor = divisor_table[i].divisor;
1452*4882a593Smuzhiyun 			return 0;
1453*4882a593Smuzhiyun 		}
1454*4882a593Smuzhiyun 	}
1455*4882a593Smuzhiyun 
1456*4882a593Smuzhiyun 	/* After trying for all the standard baud rates    *
1457*4882a593Smuzhiyun 	 * Try calculating the divisor for this baud rate  */
1458*4882a593Smuzhiyun 	if (baudrate > 75 &&  baudrate < 230400) {
1459*4882a593Smuzhiyun 		/* get the divisor */
1460*4882a593Smuzhiyun 		custom = (__u16)(230400L  / baudrate);
1461*4882a593Smuzhiyun 
1462*4882a593Smuzhiyun 		/* Check for round off */
1463*4882a593Smuzhiyun 		round1 = (__u16)(2304000L / baudrate);
1464*4882a593Smuzhiyun 		round = (__u16)(round1 - (custom * 10));
1465*4882a593Smuzhiyun 		if (round > 4)
1466*4882a593Smuzhiyun 			custom++;
1467*4882a593Smuzhiyun 		*divisor = custom;
1468*4882a593Smuzhiyun 
1469*4882a593Smuzhiyun 		dev_dbg(&port->dev, "Baud %d = %d\n", baudrate, custom);
1470*4882a593Smuzhiyun 		return 0;
1471*4882a593Smuzhiyun 	}
1472*4882a593Smuzhiyun 
1473*4882a593Smuzhiyun 	dev_dbg(&port->dev, "Baud calculation Failed...\n");
1474*4882a593Smuzhiyun 	return -EINVAL;
1475*4882a593Smuzhiyun }
1476*4882a593Smuzhiyun 
1477*4882a593Smuzhiyun /*
1478*4882a593Smuzhiyun  * send_cmd_write_baud_rate
1479*4882a593Smuzhiyun  *	this function sends the proper command to change the baud rate of the
1480*4882a593Smuzhiyun  *	specified port.
1481*4882a593Smuzhiyun  */
send_cmd_write_baud_rate(struct moschip_port * mos7720_port,int baudrate)1482*4882a593Smuzhiyun static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port,
1483*4882a593Smuzhiyun 				    int baudrate)
1484*4882a593Smuzhiyun {
1485*4882a593Smuzhiyun 	struct usb_serial_port *port;
1486*4882a593Smuzhiyun 	struct usb_serial *serial;
1487*4882a593Smuzhiyun 	int divisor;
1488*4882a593Smuzhiyun 	int status;
1489*4882a593Smuzhiyun 	unsigned char number;
1490*4882a593Smuzhiyun 
1491*4882a593Smuzhiyun 	if (mos7720_port == NULL)
1492*4882a593Smuzhiyun 		return -1;
1493*4882a593Smuzhiyun 
1494*4882a593Smuzhiyun 	port = mos7720_port->port;
1495*4882a593Smuzhiyun 	serial = port->serial;
1496*4882a593Smuzhiyun 
1497*4882a593Smuzhiyun 	number = port->port_number;
1498*4882a593Smuzhiyun 	dev_dbg(&port->dev, "%s - baud = %d\n", __func__, baudrate);
1499*4882a593Smuzhiyun 
1500*4882a593Smuzhiyun 	/* Calculate the Divisor */
1501*4882a593Smuzhiyun 	status = calc_baud_rate_divisor(port, baudrate, &divisor);
1502*4882a593Smuzhiyun 	if (status) {
1503*4882a593Smuzhiyun 		dev_err(&port->dev, "%s - bad baud rate\n", __func__);
1504*4882a593Smuzhiyun 		return status;
1505*4882a593Smuzhiyun 	}
1506*4882a593Smuzhiyun 
1507*4882a593Smuzhiyun 	/* Enable access to divisor latch */
1508*4882a593Smuzhiyun 	mos7720_port->shadowLCR = mos7720_port->shadowLCR | UART_LCR_DLAB;
1509*4882a593Smuzhiyun 	write_mos_reg(serial, number, MOS7720_LCR, mos7720_port->shadowLCR);
1510*4882a593Smuzhiyun 
1511*4882a593Smuzhiyun 	/* Write the divisor */
1512*4882a593Smuzhiyun 	write_mos_reg(serial, number, MOS7720_DLL, (__u8)(divisor & 0xff));
1513*4882a593Smuzhiyun 	write_mos_reg(serial, number, MOS7720_DLM,
1514*4882a593Smuzhiyun 		      (__u8)((divisor & 0xff00) >> 8));
1515*4882a593Smuzhiyun 
1516*4882a593Smuzhiyun 	/* Disable access to divisor latch */
1517*4882a593Smuzhiyun 	mos7720_port->shadowLCR = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
1518*4882a593Smuzhiyun 	write_mos_reg(serial, number, MOS7720_LCR, mos7720_port->shadowLCR);
1519*4882a593Smuzhiyun 
1520*4882a593Smuzhiyun 	return status;
1521*4882a593Smuzhiyun }
1522*4882a593Smuzhiyun 
1523*4882a593Smuzhiyun /*
1524*4882a593Smuzhiyun  * change_port_settings
1525*4882a593Smuzhiyun  *	This routine is called to set the UART on the device to match
1526*4882a593Smuzhiyun  *      the specified new settings.
1527*4882a593Smuzhiyun  */
change_port_settings(struct tty_struct * tty,struct moschip_port * mos7720_port,struct ktermios * old_termios)1528*4882a593Smuzhiyun static void change_port_settings(struct tty_struct *tty,
1529*4882a593Smuzhiyun 				 struct moschip_port *mos7720_port,
1530*4882a593Smuzhiyun 				 struct ktermios *old_termios)
1531*4882a593Smuzhiyun {
1532*4882a593Smuzhiyun 	struct usb_serial_port *port;
1533*4882a593Smuzhiyun 	struct usb_serial *serial;
1534*4882a593Smuzhiyun 	int baud;
1535*4882a593Smuzhiyun 	unsigned cflag;
1536*4882a593Smuzhiyun 	__u8 lData;
1537*4882a593Smuzhiyun 	__u8 lParity;
1538*4882a593Smuzhiyun 	__u8 lStop;
1539*4882a593Smuzhiyun 	int status;
1540*4882a593Smuzhiyun 	int port_number;
1541*4882a593Smuzhiyun 
1542*4882a593Smuzhiyun 	if (mos7720_port == NULL)
1543*4882a593Smuzhiyun 		return ;
1544*4882a593Smuzhiyun 
1545*4882a593Smuzhiyun 	port = mos7720_port->port;
1546*4882a593Smuzhiyun 	serial = port->serial;
1547*4882a593Smuzhiyun 	port_number = port->port_number;
1548*4882a593Smuzhiyun 
1549*4882a593Smuzhiyun 	if (!mos7720_port->open) {
1550*4882a593Smuzhiyun 		dev_dbg(&port->dev, "%s - port not opened\n", __func__);
1551*4882a593Smuzhiyun 		return;
1552*4882a593Smuzhiyun 	}
1553*4882a593Smuzhiyun 
1554*4882a593Smuzhiyun 	lData = UART_LCR_WLEN8;
1555*4882a593Smuzhiyun 	lStop = 0x00;	/* 1 stop bit */
1556*4882a593Smuzhiyun 	lParity = 0x00;	/* No parity */
1557*4882a593Smuzhiyun 
1558*4882a593Smuzhiyun 	cflag = tty->termios.c_cflag;
1559*4882a593Smuzhiyun 
1560*4882a593Smuzhiyun 	/* Change the number of bits */
1561*4882a593Smuzhiyun 	switch (cflag & CSIZE) {
1562*4882a593Smuzhiyun 	case CS5:
1563*4882a593Smuzhiyun 		lData = UART_LCR_WLEN5;
1564*4882a593Smuzhiyun 		break;
1565*4882a593Smuzhiyun 
1566*4882a593Smuzhiyun 	case CS6:
1567*4882a593Smuzhiyun 		lData = UART_LCR_WLEN6;
1568*4882a593Smuzhiyun 		break;
1569*4882a593Smuzhiyun 
1570*4882a593Smuzhiyun 	case CS7:
1571*4882a593Smuzhiyun 		lData = UART_LCR_WLEN7;
1572*4882a593Smuzhiyun 		break;
1573*4882a593Smuzhiyun 	default:
1574*4882a593Smuzhiyun 	case CS8:
1575*4882a593Smuzhiyun 		lData = UART_LCR_WLEN8;
1576*4882a593Smuzhiyun 		break;
1577*4882a593Smuzhiyun 	}
1578*4882a593Smuzhiyun 
1579*4882a593Smuzhiyun 	/* Change the Parity bit */
1580*4882a593Smuzhiyun 	if (cflag & PARENB) {
1581*4882a593Smuzhiyun 		if (cflag & PARODD) {
1582*4882a593Smuzhiyun 			lParity = UART_LCR_PARITY;
1583*4882a593Smuzhiyun 			dev_dbg(&port->dev, "%s - parity = odd\n", __func__);
1584*4882a593Smuzhiyun 		} else {
1585*4882a593Smuzhiyun 			lParity = (UART_LCR_EPAR | UART_LCR_PARITY);
1586*4882a593Smuzhiyun 			dev_dbg(&port->dev, "%s - parity = even\n", __func__);
1587*4882a593Smuzhiyun 		}
1588*4882a593Smuzhiyun 
1589*4882a593Smuzhiyun 	} else {
1590*4882a593Smuzhiyun 		dev_dbg(&port->dev, "%s - parity = none\n", __func__);
1591*4882a593Smuzhiyun 	}
1592*4882a593Smuzhiyun 
1593*4882a593Smuzhiyun 	if (cflag & CMSPAR)
1594*4882a593Smuzhiyun 		lParity = lParity | 0x20;
1595*4882a593Smuzhiyun 
1596*4882a593Smuzhiyun 	/* Change the Stop bit */
1597*4882a593Smuzhiyun 	if (cflag & CSTOPB) {
1598*4882a593Smuzhiyun 		lStop = UART_LCR_STOP;
1599*4882a593Smuzhiyun 		dev_dbg(&port->dev, "%s - stop bits = 2\n", __func__);
1600*4882a593Smuzhiyun 	} else {
1601*4882a593Smuzhiyun 		lStop = 0x00;
1602*4882a593Smuzhiyun 		dev_dbg(&port->dev, "%s - stop bits = 1\n", __func__);
1603*4882a593Smuzhiyun 	}
1604*4882a593Smuzhiyun 
1605*4882a593Smuzhiyun #define LCR_BITS_MASK		0x03	/* Mask for bits/char field */
1606*4882a593Smuzhiyun #define LCR_STOP_MASK		0x04	/* Mask for stop bits field */
1607*4882a593Smuzhiyun #define LCR_PAR_MASK		0x38	/* Mask for parity field */
1608*4882a593Smuzhiyun 
1609*4882a593Smuzhiyun 	/* Update the LCR with the correct value */
1610*4882a593Smuzhiyun 	mos7720_port->shadowLCR &=
1611*4882a593Smuzhiyun 		~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
1612*4882a593Smuzhiyun 	mos7720_port->shadowLCR |= (lData | lParity | lStop);
1613*4882a593Smuzhiyun 
1614*4882a593Smuzhiyun 
1615*4882a593Smuzhiyun 	/* Disable Interrupts */
1616*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_IER, 0x00);
1617*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_FCR, 0x00);
1618*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_FCR, 0xcf);
1619*4882a593Smuzhiyun 
1620*4882a593Smuzhiyun 	/* Send the updated LCR value to the mos7720 */
1621*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_LCR,
1622*4882a593Smuzhiyun 		      mos7720_port->shadowLCR);
1623*4882a593Smuzhiyun 	mos7720_port->shadowMCR = 0x0b;
1624*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_MCR,
1625*4882a593Smuzhiyun 		      mos7720_port->shadowMCR);
1626*4882a593Smuzhiyun 
1627*4882a593Smuzhiyun 	/* set up the MCR register and send it to the mos7720 */
1628*4882a593Smuzhiyun 	mos7720_port->shadowMCR = UART_MCR_OUT2;
1629*4882a593Smuzhiyun 	if (cflag & CBAUD)
1630*4882a593Smuzhiyun 		mos7720_port->shadowMCR |= (UART_MCR_DTR | UART_MCR_RTS);
1631*4882a593Smuzhiyun 
1632*4882a593Smuzhiyun 	if (cflag & CRTSCTS) {
1633*4882a593Smuzhiyun 		mos7720_port->shadowMCR |= (UART_MCR_XONANY);
1634*4882a593Smuzhiyun 		/* To set hardware flow control to the specified *
1635*4882a593Smuzhiyun 		 * serial port, in SP1/2_CONTROL_REG             */
1636*4882a593Smuzhiyun 		if (port_number)
1637*4882a593Smuzhiyun 			write_mos_reg(serial, dummy, MOS7720_SP_CONTROL_REG,
1638*4882a593Smuzhiyun 				      0x01);
1639*4882a593Smuzhiyun 		else
1640*4882a593Smuzhiyun 			write_mos_reg(serial, dummy, MOS7720_SP_CONTROL_REG,
1641*4882a593Smuzhiyun 				      0x02);
1642*4882a593Smuzhiyun 
1643*4882a593Smuzhiyun 	} else
1644*4882a593Smuzhiyun 		mos7720_port->shadowMCR &= ~(UART_MCR_XONANY);
1645*4882a593Smuzhiyun 
1646*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_MCR,
1647*4882a593Smuzhiyun 		      mos7720_port->shadowMCR);
1648*4882a593Smuzhiyun 
1649*4882a593Smuzhiyun 	/* Determine divisor based on baud rate */
1650*4882a593Smuzhiyun 	baud = tty_get_baud_rate(tty);
1651*4882a593Smuzhiyun 	if (!baud) {
1652*4882a593Smuzhiyun 		/* pick a default, any default... */
1653*4882a593Smuzhiyun 		dev_dbg(&port->dev, "Picked default baud...\n");
1654*4882a593Smuzhiyun 		baud = 9600;
1655*4882a593Smuzhiyun 	}
1656*4882a593Smuzhiyun 
1657*4882a593Smuzhiyun 	if (baud >= 230400) {
1658*4882a593Smuzhiyun 		set_higher_rates(mos7720_port, baud);
1659*4882a593Smuzhiyun 		/* Enable Interrupts */
1660*4882a593Smuzhiyun 		write_mos_reg(serial, port_number, MOS7720_IER, 0x0c);
1661*4882a593Smuzhiyun 		return;
1662*4882a593Smuzhiyun 	}
1663*4882a593Smuzhiyun 
1664*4882a593Smuzhiyun 	dev_dbg(&port->dev, "%s - baud rate = %d\n", __func__, baud);
1665*4882a593Smuzhiyun 	status = send_cmd_write_baud_rate(mos7720_port, baud);
1666*4882a593Smuzhiyun 	/* FIXME: needs to write actual resulting baud back not just
1667*4882a593Smuzhiyun 	   blindly do so */
1668*4882a593Smuzhiyun 	if (cflag & CBAUD)
1669*4882a593Smuzhiyun 		tty_encode_baud_rate(tty, baud, baud);
1670*4882a593Smuzhiyun 	/* Enable Interrupts */
1671*4882a593Smuzhiyun 	write_mos_reg(serial, port_number, MOS7720_IER, 0x0c);
1672*4882a593Smuzhiyun 
1673*4882a593Smuzhiyun 	if (port->read_urb->status != -EINPROGRESS) {
1674*4882a593Smuzhiyun 		status = usb_submit_urb(port->read_urb, GFP_KERNEL);
1675*4882a593Smuzhiyun 		if (status)
1676*4882a593Smuzhiyun 			dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n", status);
1677*4882a593Smuzhiyun 	}
1678*4882a593Smuzhiyun }
1679*4882a593Smuzhiyun 
1680*4882a593Smuzhiyun /*
1681*4882a593Smuzhiyun  * mos7720_set_termios
1682*4882a593Smuzhiyun  *	this function is called by the tty driver when it wants to change the
1683*4882a593Smuzhiyun  *	termios structure.
1684*4882a593Smuzhiyun  */
mos7720_set_termios(struct tty_struct * tty,struct usb_serial_port * port,struct ktermios * old_termios)1685*4882a593Smuzhiyun static void mos7720_set_termios(struct tty_struct *tty,
1686*4882a593Smuzhiyun 		struct usb_serial_port *port, struct ktermios *old_termios)
1687*4882a593Smuzhiyun {
1688*4882a593Smuzhiyun 	int status;
1689*4882a593Smuzhiyun 	struct moschip_port *mos7720_port;
1690*4882a593Smuzhiyun 
1691*4882a593Smuzhiyun 	mos7720_port = usb_get_serial_port_data(port);
1692*4882a593Smuzhiyun 
1693*4882a593Smuzhiyun 	if (mos7720_port == NULL)
1694*4882a593Smuzhiyun 		return;
1695*4882a593Smuzhiyun 
1696*4882a593Smuzhiyun 	if (!mos7720_port->open) {
1697*4882a593Smuzhiyun 		dev_dbg(&port->dev, "%s - port not opened\n", __func__);
1698*4882a593Smuzhiyun 		return;
1699*4882a593Smuzhiyun 	}
1700*4882a593Smuzhiyun 
1701*4882a593Smuzhiyun 	/* change the port settings to the new ones specified */
1702*4882a593Smuzhiyun 	change_port_settings(tty, mos7720_port, old_termios);
1703*4882a593Smuzhiyun 
1704*4882a593Smuzhiyun 	if (port->read_urb->status != -EINPROGRESS) {
1705*4882a593Smuzhiyun 		status = usb_submit_urb(port->read_urb, GFP_KERNEL);
1706*4882a593Smuzhiyun 		if (status)
1707*4882a593Smuzhiyun 			dev_dbg(&port->dev, "usb_submit_urb(read bulk) failed, status = %d\n", status);
1708*4882a593Smuzhiyun 	}
1709*4882a593Smuzhiyun }
1710*4882a593Smuzhiyun 
1711*4882a593Smuzhiyun /*
1712*4882a593Smuzhiyun  * get_lsr_info - get line status register info
1713*4882a593Smuzhiyun  *
1714*4882a593Smuzhiyun  * Purpose: Let user call ioctl() to get info when the UART physically
1715*4882a593Smuzhiyun  * 	    is emptied.  On bus types like RS485, the transmitter must
1716*4882a593Smuzhiyun  * 	    release the bus after transmitting. This must be done when
1717*4882a593Smuzhiyun  * 	    the transmit shift register is empty, not be done when the
1718*4882a593Smuzhiyun  * 	    transmit holding register is empty.  This functionality
1719*4882a593Smuzhiyun  * 	    allows an RS485 driver to be written in user space.
1720*4882a593Smuzhiyun  */
get_lsr_info(struct tty_struct * tty,struct moschip_port * mos7720_port,unsigned int __user * value)1721*4882a593Smuzhiyun static int get_lsr_info(struct tty_struct *tty,
1722*4882a593Smuzhiyun 		struct moschip_port *mos7720_port, unsigned int __user *value)
1723*4882a593Smuzhiyun {
1724*4882a593Smuzhiyun 	struct usb_serial_port *port = tty->driver_data;
1725*4882a593Smuzhiyun 	unsigned int result = 0;
1726*4882a593Smuzhiyun 	unsigned char data = 0;
1727*4882a593Smuzhiyun 	int port_number = port->port_number;
1728*4882a593Smuzhiyun 	int count;
1729*4882a593Smuzhiyun 
1730*4882a593Smuzhiyun 	count = mos7720_chars_in_buffer(tty);
1731*4882a593Smuzhiyun 	if (count == 0) {
1732*4882a593Smuzhiyun 		read_mos_reg(port->serial, port_number, MOS7720_LSR, &data);
1733*4882a593Smuzhiyun 		if ((data & (UART_LSR_TEMT | UART_LSR_THRE))
1734*4882a593Smuzhiyun 					== (UART_LSR_TEMT | UART_LSR_THRE)) {
1735*4882a593Smuzhiyun 			dev_dbg(&port->dev, "%s -- Empty\n", __func__);
1736*4882a593Smuzhiyun 			result = TIOCSER_TEMT;
1737*4882a593Smuzhiyun 		}
1738*4882a593Smuzhiyun 	}
1739*4882a593Smuzhiyun 	if (copy_to_user(value, &result, sizeof(int)))
1740*4882a593Smuzhiyun 		return -EFAULT;
1741*4882a593Smuzhiyun 	return 0;
1742*4882a593Smuzhiyun }
1743*4882a593Smuzhiyun 
mos7720_tiocmget(struct tty_struct * tty)1744*4882a593Smuzhiyun static int mos7720_tiocmget(struct tty_struct *tty)
1745*4882a593Smuzhiyun {
1746*4882a593Smuzhiyun 	struct usb_serial_port *port = tty->driver_data;
1747*4882a593Smuzhiyun 	struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
1748*4882a593Smuzhiyun 	unsigned int result = 0;
1749*4882a593Smuzhiyun 	unsigned int mcr ;
1750*4882a593Smuzhiyun 	unsigned int msr ;
1751*4882a593Smuzhiyun 
1752*4882a593Smuzhiyun 	mcr = mos7720_port->shadowMCR;
1753*4882a593Smuzhiyun 	msr = mos7720_port->shadowMSR;
1754*4882a593Smuzhiyun 
1755*4882a593Smuzhiyun 	result = ((mcr & UART_MCR_DTR)  ? TIOCM_DTR : 0)   /* 0x002 */
1756*4882a593Smuzhiyun 	  | ((mcr & UART_MCR_RTS)   ? TIOCM_RTS : 0)   /* 0x004 */
1757*4882a593Smuzhiyun 	  | ((msr & UART_MSR_CTS)   ? TIOCM_CTS : 0)   /* 0x020 */
1758*4882a593Smuzhiyun 	  | ((msr & UART_MSR_DCD)   ? TIOCM_CAR : 0)   /* 0x040 */
1759*4882a593Smuzhiyun 	  | ((msr & UART_MSR_RI)    ? TIOCM_RI :  0)   /* 0x080 */
1760*4882a593Smuzhiyun 	  | ((msr & UART_MSR_DSR)   ? TIOCM_DSR : 0);  /* 0x100 */
1761*4882a593Smuzhiyun 
1762*4882a593Smuzhiyun 	return result;
1763*4882a593Smuzhiyun }
1764*4882a593Smuzhiyun 
mos7720_tiocmset(struct tty_struct * tty,unsigned int set,unsigned int clear)1765*4882a593Smuzhiyun static int mos7720_tiocmset(struct tty_struct *tty,
1766*4882a593Smuzhiyun 			    unsigned int set, unsigned int clear)
1767*4882a593Smuzhiyun {
1768*4882a593Smuzhiyun 	struct usb_serial_port *port = tty->driver_data;
1769*4882a593Smuzhiyun 	struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
1770*4882a593Smuzhiyun 	unsigned int mcr ;
1771*4882a593Smuzhiyun 
1772*4882a593Smuzhiyun 	mcr = mos7720_port->shadowMCR;
1773*4882a593Smuzhiyun 
1774*4882a593Smuzhiyun 	if (set & TIOCM_RTS)
1775*4882a593Smuzhiyun 		mcr |= UART_MCR_RTS;
1776*4882a593Smuzhiyun 	if (set & TIOCM_DTR)
1777*4882a593Smuzhiyun 		mcr |= UART_MCR_DTR;
1778*4882a593Smuzhiyun 	if (set & TIOCM_LOOP)
1779*4882a593Smuzhiyun 		mcr |= UART_MCR_LOOP;
1780*4882a593Smuzhiyun 
1781*4882a593Smuzhiyun 	if (clear & TIOCM_RTS)
1782*4882a593Smuzhiyun 		mcr &= ~UART_MCR_RTS;
1783*4882a593Smuzhiyun 	if (clear & TIOCM_DTR)
1784*4882a593Smuzhiyun 		mcr &= ~UART_MCR_DTR;
1785*4882a593Smuzhiyun 	if (clear & TIOCM_LOOP)
1786*4882a593Smuzhiyun 		mcr &= ~UART_MCR_LOOP;
1787*4882a593Smuzhiyun 
1788*4882a593Smuzhiyun 	mos7720_port->shadowMCR = mcr;
1789*4882a593Smuzhiyun 	write_mos_reg(port->serial, port->port_number, MOS7720_MCR,
1790*4882a593Smuzhiyun 		      mos7720_port->shadowMCR);
1791*4882a593Smuzhiyun 
1792*4882a593Smuzhiyun 	return 0;
1793*4882a593Smuzhiyun }
1794*4882a593Smuzhiyun 
get_serial_info(struct tty_struct * tty,struct serial_struct * ss)1795*4882a593Smuzhiyun static int get_serial_info(struct tty_struct *tty,
1796*4882a593Smuzhiyun 			   struct serial_struct *ss)
1797*4882a593Smuzhiyun {
1798*4882a593Smuzhiyun 	struct usb_serial_port *port = tty->driver_data;
1799*4882a593Smuzhiyun 	struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
1800*4882a593Smuzhiyun 
1801*4882a593Smuzhiyun 	ss->type		= PORT_16550A;
1802*4882a593Smuzhiyun 	ss->line		= mos7720_port->port->minor;
1803*4882a593Smuzhiyun 	ss->port		= mos7720_port->port->port_number;
1804*4882a593Smuzhiyun 	ss->irq			= 0;
1805*4882a593Smuzhiyun 	ss->xmit_fifo_size	= NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
1806*4882a593Smuzhiyun 	ss->baud_base		= 9600;
1807*4882a593Smuzhiyun 	ss->close_delay		= 5*HZ;
1808*4882a593Smuzhiyun 	ss->closing_wait	= 30*HZ;
1809*4882a593Smuzhiyun 	return 0;
1810*4882a593Smuzhiyun }
1811*4882a593Smuzhiyun 
mos7720_ioctl(struct tty_struct * tty,unsigned int cmd,unsigned long arg)1812*4882a593Smuzhiyun static int mos7720_ioctl(struct tty_struct *tty,
1813*4882a593Smuzhiyun 			 unsigned int cmd, unsigned long arg)
1814*4882a593Smuzhiyun {
1815*4882a593Smuzhiyun 	struct usb_serial_port *port = tty->driver_data;
1816*4882a593Smuzhiyun 	struct moschip_port *mos7720_port;
1817*4882a593Smuzhiyun 
1818*4882a593Smuzhiyun 	mos7720_port = usb_get_serial_port_data(port);
1819*4882a593Smuzhiyun 	if (mos7720_port == NULL)
1820*4882a593Smuzhiyun 		return -ENODEV;
1821*4882a593Smuzhiyun 
1822*4882a593Smuzhiyun 	switch (cmd) {
1823*4882a593Smuzhiyun 	case TIOCSERGETLSR:
1824*4882a593Smuzhiyun 		dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__);
1825*4882a593Smuzhiyun 		return get_lsr_info(tty, mos7720_port,
1826*4882a593Smuzhiyun 					(unsigned int __user *)arg);
1827*4882a593Smuzhiyun 	}
1828*4882a593Smuzhiyun 
1829*4882a593Smuzhiyun 	return -ENOIOCTLCMD;
1830*4882a593Smuzhiyun }
1831*4882a593Smuzhiyun 
mos7720_startup(struct usb_serial * serial)1832*4882a593Smuzhiyun static int mos7720_startup(struct usb_serial *serial)
1833*4882a593Smuzhiyun {
1834*4882a593Smuzhiyun 	struct usb_device *dev;
1835*4882a593Smuzhiyun 	char data;
1836*4882a593Smuzhiyun 	u16 product;
1837*4882a593Smuzhiyun 	int ret_val;
1838*4882a593Smuzhiyun 
1839*4882a593Smuzhiyun 	product = le16_to_cpu(serial->dev->descriptor.idProduct);
1840*4882a593Smuzhiyun 	dev = serial->dev;
1841*4882a593Smuzhiyun 
1842*4882a593Smuzhiyun 	if (product == MOSCHIP_DEVICE_ID_7715) {
1843*4882a593Smuzhiyun 		struct urb *urb = serial->port[0]->interrupt_in_urb;
1844*4882a593Smuzhiyun 
1845*4882a593Smuzhiyun 		urb->complete = mos7715_interrupt_callback;
1846*4882a593Smuzhiyun 
1847*4882a593Smuzhiyun #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
1848*4882a593Smuzhiyun 		ret_val = mos7715_parport_init(serial);
1849*4882a593Smuzhiyun 		if (ret_val < 0)
1850*4882a593Smuzhiyun 			return ret_val;
1851*4882a593Smuzhiyun #endif
1852*4882a593Smuzhiyun 	}
1853*4882a593Smuzhiyun 	/* start the interrupt urb */
1854*4882a593Smuzhiyun 	ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL);
1855*4882a593Smuzhiyun 	if (ret_val) {
1856*4882a593Smuzhiyun 		dev_err(&dev->dev, "failed to submit interrupt urb: %d\n",
1857*4882a593Smuzhiyun 			ret_val);
1858*4882a593Smuzhiyun 	}
1859*4882a593Smuzhiyun 
1860*4882a593Smuzhiyun 	/* LSR For Port 1 */
1861*4882a593Smuzhiyun 	read_mos_reg(serial, 0, MOS7720_LSR, &data);
1862*4882a593Smuzhiyun 	dev_dbg(&dev->dev, "LSR:%x\n", data);
1863*4882a593Smuzhiyun 
1864*4882a593Smuzhiyun 	return 0;
1865*4882a593Smuzhiyun }
1866*4882a593Smuzhiyun 
mos7720_release(struct usb_serial * serial)1867*4882a593Smuzhiyun static void mos7720_release(struct usb_serial *serial)
1868*4882a593Smuzhiyun {
1869*4882a593Smuzhiyun 	usb_kill_urb(serial->port[0]->interrupt_in_urb);
1870*4882a593Smuzhiyun 
1871*4882a593Smuzhiyun #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
1872*4882a593Smuzhiyun 	/* close the parallel port */
1873*4882a593Smuzhiyun 
1874*4882a593Smuzhiyun 	if (le16_to_cpu(serial->dev->descriptor.idProduct)
1875*4882a593Smuzhiyun 	    == MOSCHIP_DEVICE_ID_7715) {
1876*4882a593Smuzhiyun 		struct urbtracker *urbtrack;
1877*4882a593Smuzhiyun 		unsigned long flags;
1878*4882a593Smuzhiyun 		struct mos7715_parport *mos_parport =
1879*4882a593Smuzhiyun 			usb_get_serial_data(serial);
1880*4882a593Smuzhiyun 
1881*4882a593Smuzhiyun 		/* prevent NULL ptr dereference in port callbacks */
1882*4882a593Smuzhiyun 		spin_lock(&release_lock);
1883*4882a593Smuzhiyun 		mos_parport->pp->private_data = NULL;
1884*4882a593Smuzhiyun 		spin_unlock(&release_lock);
1885*4882a593Smuzhiyun 
1886*4882a593Smuzhiyun 		/* wait for synchronous usb calls to return */
1887*4882a593Smuzhiyun 		if (mos_parport->msg_pending)
1888*4882a593Smuzhiyun 			wait_for_completion_timeout(&mos_parport->syncmsg_compl,
1889*4882a593Smuzhiyun 					    msecs_to_jiffies(MOS_WDR_TIMEOUT));
1890*4882a593Smuzhiyun 
1891*4882a593Smuzhiyun 		parport_remove_port(mos_parport->pp);
1892*4882a593Smuzhiyun 		usb_set_serial_data(serial, NULL);
1893*4882a593Smuzhiyun 		mos_parport->serial = NULL;
1894*4882a593Smuzhiyun 
1895*4882a593Smuzhiyun 		/* if tasklet currently scheduled, wait for it to complete */
1896*4882a593Smuzhiyun 		tasklet_kill(&mos_parport->urb_tasklet);
1897*4882a593Smuzhiyun 
1898*4882a593Smuzhiyun 		/* unlink any urbs sent by the tasklet  */
1899*4882a593Smuzhiyun 		spin_lock_irqsave(&mos_parport->listlock, flags);
1900*4882a593Smuzhiyun 		list_for_each_entry(urbtrack,
1901*4882a593Smuzhiyun 				    &mos_parport->active_urbs,
1902*4882a593Smuzhiyun 				    urblist_entry)
1903*4882a593Smuzhiyun 			usb_unlink_urb(urbtrack->urb);
1904*4882a593Smuzhiyun 		spin_unlock_irqrestore(&mos_parport->listlock, flags);
1905*4882a593Smuzhiyun 		parport_del_port(mos_parport->pp);
1906*4882a593Smuzhiyun 
1907*4882a593Smuzhiyun 		kref_put(&mos_parport->ref_count, destroy_mos_parport);
1908*4882a593Smuzhiyun 	}
1909*4882a593Smuzhiyun #endif
1910*4882a593Smuzhiyun }
1911*4882a593Smuzhiyun 
mos7720_port_probe(struct usb_serial_port * port)1912*4882a593Smuzhiyun static int mos7720_port_probe(struct usb_serial_port *port)
1913*4882a593Smuzhiyun {
1914*4882a593Smuzhiyun 	struct moschip_port *mos7720_port;
1915*4882a593Smuzhiyun 
1916*4882a593Smuzhiyun 	mos7720_port = kzalloc(sizeof(*mos7720_port), GFP_KERNEL);
1917*4882a593Smuzhiyun 	if (!mos7720_port)
1918*4882a593Smuzhiyun 		return -ENOMEM;
1919*4882a593Smuzhiyun 
1920*4882a593Smuzhiyun 	mos7720_port->port = port;
1921*4882a593Smuzhiyun 
1922*4882a593Smuzhiyun 	usb_set_serial_port_data(port, mos7720_port);
1923*4882a593Smuzhiyun 
1924*4882a593Smuzhiyun 	return 0;
1925*4882a593Smuzhiyun }
1926*4882a593Smuzhiyun 
mos7720_port_remove(struct usb_serial_port * port)1927*4882a593Smuzhiyun static int mos7720_port_remove(struct usb_serial_port *port)
1928*4882a593Smuzhiyun {
1929*4882a593Smuzhiyun 	struct moschip_port *mos7720_port;
1930*4882a593Smuzhiyun 
1931*4882a593Smuzhiyun 	mos7720_port = usb_get_serial_port_data(port);
1932*4882a593Smuzhiyun 	kfree(mos7720_port);
1933*4882a593Smuzhiyun 
1934*4882a593Smuzhiyun 	return 0;
1935*4882a593Smuzhiyun }
1936*4882a593Smuzhiyun 
1937*4882a593Smuzhiyun static struct usb_serial_driver moschip7720_2port_driver = {
1938*4882a593Smuzhiyun 	.driver = {
1939*4882a593Smuzhiyun 		.owner =	THIS_MODULE,
1940*4882a593Smuzhiyun 		.name =		"moschip7720",
1941*4882a593Smuzhiyun 	},
1942*4882a593Smuzhiyun 	.description		= "Moschip 2 port adapter",
1943*4882a593Smuzhiyun 	.id_table		= id_table,
1944*4882a593Smuzhiyun 	.num_bulk_in		= 2,
1945*4882a593Smuzhiyun 	.num_bulk_out		= 2,
1946*4882a593Smuzhiyun 	.num_interrupt_in	= 1,
1947*4882a593Smuzhiyun 	.calc_num_ports		= mos77xx_calc_num_ports,
1948*4882a593Smuzhiyun 	.open			= mos7720_open,
1949*4882a593Smuzhiyun 	.close			= mos7720_close,
1950*4882a593Smuzhiyun 	.throttle		= mos7720_throttle,
1951*4882a593Smuzhiyun 	.unthrottle		= mos7720_unthrottle,
1952*4882a593Smuzhiyun 	.attach			= mos7720_startup,
1953*4882a593Smuzhiyun 	.release		= mos7720_release,
1954*4882a593Smuzhiyun 	.port_probe		= mos7720_port_probe,
1955*4882a593Smuzhiyun 	.port_remove		= mos7720_port_remove,
1956*4882a593Smuzhiyun 	.ioctl			= mos7720_ioctl,
1957*4882a593Smuzhiyun 	.tiocmget		= mos7720_tiocmget,
1958*4882a593Smuzhiyun 	.tiocmset		= mos7720_tiocmset,
1959*4882a593Smuzhiyun 	.get_serial		= get_serial_info,
1960*4882a593Smuzhiyun 	.set_termios		= mos7720_set_termios,
1961*4882a593Smuzhiyun 	.write			= mos7720_write,
1962*4882a593Smuzhiyun 	.write_room		= mos7720_write_room,
1963*4882a593Smuzhiyun 	.chars_in_buffer	= mos7720_chars_in_buffer,
1964*4882a593Smuzhiyun 	.break_ctl		= mos7720_break,
1965*4882a593Smuzhiyun 	.read_bulk_callback	= mos7720_bulk_in_callback,
1966*4882a593Smuzhiyun 	.read_int_callback	= mos7720_interrupt_callback,
1967*4882a593Smuzhiyun };
1968*4882a593Smuzhiyun 
1969*4882a593Smuzhiyun static struct usb_serial_driver * const serial_drivers[] = {
1970*4882a593Smuzhiyun 	&moschip7720_2port_driver, NULL
1971*4882a593Smuzhiyun };
1972*4882a593Smuzhiyun 
1973*4882a593Smuzhiyun module_usb_serial_driver(serial_drivers, id_table);
1974*4882a593Smuzhiyun 
1975*4882a593Smuzhiyun MODULE_AUTHOR(DRIVER_AUTHOR);
1976*4882a593Smuzhiyun MODULE_DESCRIPTION(DRIVER_DESC);
1977*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
1978