1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Tty port functions
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <linux/types.h>
7*4882a593Smuzhiyun #include <linux/errno.h>
8*4882a593Smuzhiyun #include <linux/tty.h>
9*4882a593Smuzhiyun #include <linux/tty_driver.h>
10*4882a593Smuzhiyun #include <linux/tty_flip.h>
11*4882a593Smuzhiyun #include <linux/serial.h>
12*4882a593Smuzhiyun #include <linux/timer.h>
13*4882a593Smuzhiyun #include <linux/string.h>
14*4882a593Smuzhiyun #include <linux/slab.h>
15*4882a593Smuzhiyun #include <linux/sched/signal.h>
16*4882a593Smuzhiyun #include <linux/wait.h>
17*4882a593Smuzhiyun #include <linux/bitops.h>
18*4882a593Smuzhiyun #include <linux/delay.h>
19*4882a593Smuzhiyun #include <linux/module.h>
20*4882a593Smuzhiyun #include <linux/serdev.h>
21*4882a593Smuzhiyun
tty_port_default_receive_buf(struct tty_port * port,const unsigned char * p,const unsigned char * f,size_t count)22*4882a593Smuzhiyun static int tty_port_default_receive_buf(struct tty_port *port,
23*4882a593Smuzhiyun const unsigned char *p,
24*4882a593Smuzhiyun const unsigned char *f, size_t count)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun int ret;
27*4882a593Smuzhiyun struct tty_struct *tty;
28*4882a593Smuzhiyun struct tty_ldisc *disc;
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun tty = READ_ONCE(port->itty);
31*4882a593Smuzhiyun if (!tty)
32*4882a593Smuzhiyun return 0;
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun disc = tty_ldisc_ref(tty);
35*4882a593Smuzhiyun if (!disc)
36*4882a593Smuzhiyun return 0;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun ret = tty_ldisc_receive_buf(disc, p, (char *)f, count);
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun tty_ldisc_deref(disc);
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun return ret;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun
tty_port_default_wakeup(struct tty_port * port)45*4882a593Smuzhiyun static void tty_port_default_wakeup(struct tty_port *port)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun struct tty_struct *tty = tty_port_tty_get(port);
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun if (tty) {
50*4882a593Smuzhiyun tty_wakeup(tty);
51*4882a593Smuzhiyun tty_kref_put(tty);
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun const struct tty_port_client_operations tty_port_default_client_ops = {
56*4882a593Smuzhiyun .receive_buf = tty_port_default_receive_buf,
57*4882a593Smuzhiyun .write_wakeup = tty_port_default_wakeup,
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(tty_port_default_client_ops);
60*4882a593Smuzhiyun
tty_port_init(struct tty_port * port)61*4882a593Smuzhiyun void tty_port_init(struct tty_port *port)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun memset(port, 0, sizeof(*port));
64*4882a593Smuzhiyun tty_buffer_init(port);
65*4882a593Smuzhiyun init_waitqueue_head(&port->open_wait);
66*4882a593Smuzhiyun init_waitqueue_head(&port->delta_msr_wait);
67*4882a593Smuzhiyun mutex_init(&port->mutex);
68*4882a593Smuzhiyun mutex_init(&port->buf_mutex);
69*4882a593Smuzhiyun spin_lock_init(&port->lock);
70*4882a593Smuzhiyun port->close_delay = (50 * HZ) / 100;
71*4882a593Smuzhiyun port->closing_wait = (3000 * HZ) / 100;
72*4882a593Smuzhiyun port->client_ops = &tty_port_default_client_ops;
73*4882a593Smuzhiyun kref_init(&port->kref);
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun EXPORT_SYMBOL(tty_port_init);
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun /**
78*4882a593Smuzhiyun * tty_port_link_device - link tty and tty_port
79*4882a593Smuzhiyun * @port: tty_port of the device
80*4882a593Smuzhiyun * @driver: tty_driver for this device
81*4882a593Smuzhiyun * @index: index of the tty
82*4882a593Smuzhiyun *
83*4882a593Smuzhiyun * Provide the tty layer with a link from a tty (specified by @index) to a
84*4882a593Smuzhiyun * tty_port (@port). Use this only if neither tty_port_register_device nor
85*4882a593Smuzhiyun * tty_port_install is used in the driver. If used, this has to be called before
86*4882a593Smuzhiyun * tty_register_driver.
87*4882a593Smuzhiyun */
tty_port_link_device(struct tty_port * port,struct tty_driver * driver,unsigned index)88*4882a593Smuzhiyun void tty_port_link_device(struct tty_port *port,
89*4882a593Smuzhiyun struct tty_driver *driver, unsigned index)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun if (WARN_ON(index >= driver->num))
92*4882a593Smuzhiyun return;
93*4882a593Smuzhiyun driver->ports[index] = port;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(tty_port_link_device);
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun /**
98*4882a593Smuzhiyun * tty_port_register_device - register tty device
99*4882a593Smuzhiyun * @port: tty_port of the device
100*4882a593Smuzhiyun * @driver: tty_driver for this device
101*4882a593Smuzhiyun * @index: index of the tty
102*4882a593Smuzhiyun * @device: parent if exists, otherwise NULL
103*4882a593Smuzhiyun *
104*4882a593Smuzhiyun * It is the same as tty_register_device except the provided @port is linked to
105*4882a593Smuzhiyun * a concrete tty specified by @index. Use this or tty_port_install (or both).
106*4882a593Smuzhiyun * Call tty_port_link_device as a last resort.
107*4882a593Smuzhiyun */
tty_port_register_device(struct tty_port * port,struct tty_driver * driver,unsigned index,struct device * device)108*4882a593Smuzhiyun struct device *tty_port_register_device(struct tty_port *port,
109*4882a593Smuzhiyun struct tty_driver *driver, unsigned index,
110*4882a593Smuzhiyun struct device *device)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun return tty_port_register_device_attr(port, driver, index, device, NULL, NULL);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(tty_port_register_device);
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun /**
117*4882a593Smuzhiyun * tty_port_register_device_attr - register tty device
118*4882a593Smuzhiyun * @port: tty_port of the device
119*4882a593Smuzhiyun * @driver: tty_driver for this device
120*4882a593Smuzhiyun * @index: index of the tty
121*4882a593Smuzhiyun * @device: parent if exists, otherwise NULL
122*4882a593Smuzhiyun * @drvdata: Driver data to be set to device.
123*4882a593Smuzhiyun * @attr_grp: Attribute group to be set on device.
124*4882a593Smuzhiyun *
125*4882a593Smuzhiyun * It is the same as tty_register_device_attr except the provided @port is
126*4882a593Smuzhiyun * linked to a concrete tty specified by @index. Use this or tty_port_install
127*4882a593Smuzhiyun * (or both). Call tty_port_link_device as a last resort.
128*4882a593Smuzhiyun */
tty_port_register_device_attr(struct tty_port * port,struct tty_driver * driver,unsigned index,struct device * device,void * drvdata,const struct attribute_group ** attr_grp)129*4882a593Smuzhiyun struct device *tty_port_register_device_attr(struct tty_port *port,
130*4882a593Smuzhiyun struct tty_driver *driver, unsigned index,
131*4882a593Smuzhiyun struct device *device, void *drvdata,
132*4882a593Smuzhiyun const struct attribute_group **attr_grp)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun tty_port_link_device(port, driver, index);
135*4882a593Smuzhiyun return tty_register_device_attr(driver, index, device, drvdata,
136*4882a593Smuzhiyun attr_grp);
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(tty_port_register_device_attr);
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun /**
141*4882a593Smuzhiyun * tty_port_register_device_attr_serdev - register tty or serdev device
142*4882a593Smuzhiyun * @port: tty_port of the device
143*4882a593Smuzhiyun * @driver: tty_driver for this device
144*4882a593Smuzhiyun * @index: index of the tty
145*4882a593Smuzhiyun * @device: parent if exists, otherwise NULL
146*4882a593Smuzhiyun * @drvdata: driver data for the device
147*4882a593Smuzhiyun * @attr_grp: attribute group for the device
148*4882a593Smuzhiyun *
149*4882a593Smuzhiyun * Register a serdev or tty device depending on if the parent device has any
150*4882a593Smuzhiyun * defined serdev clients or not.
151*4882a593Smuzhiyun */
tty_port_register_device_attr_serdev(struct tty_port * port,struct tty_driver * driver,unsigned index,struct device * device,void * drvdata,const struct attribute_group ** attr_grp)152*4882a593Smuzhiyun struct device *tty_port_register_device_attr_serdev(struct tty_port *port,
153*4882a593Smuzhiyun struct tty_driver *driver, unsigned index,
154*4882a593Smuzhiyun struct device *device, void *drvdata,
155*4882a593Smuzhiyun const struct attribute_group **attr_grp)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun struct device *dev;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun tty_port_link_device(port, driver, index);
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun dev = serdev_tty_port_register(port, device, driver, index);
162*4882a593Smuzhiyun if (PTR_ERR(dev) != -ENODEV) {
163*4882a593Smuzhiyun /* Skip creating cdev if we registered a serdev device */
164*4882a593Smuzhiyun return dev;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun return tty_register_device_attr(driver, index, device, drvdata,
168*4882a593Smuzhiyun attr_grp);
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(tty_port_register_device_attr_serdev);
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun /**
173*4882a593Smuzhiyun * tty_port_register_device_serdev - register tty or serdev device
174*4882a593Smuzhiyun * @port: tty_port of the device
175*4882a593Smuzhiyun * @driver: tty_driver for this device
176*4882a593Smuzhiyun * @index: index of the tty
177*4882a593Smuzhiyun * @device: parent if exists, otherwise NULL
178*4882a593Smuzhiyun *
179*4882a593Smuzhiyun * Register a serdev or tty device depending on if the parent device has any
180*4882a593Smuzhiyun * defined serdev clients or not.
181*4882a593Smuzhiyun */
tty_port_register_device_serdev(struct tty_port * port,struct tty_driver * driver,unsigned index,struct device * device)182*4882a593Smuzhiyun struct device *tty_port_register_device_serdev(struct tty_port *port,
183*4882a593Smuzhiyun struct tty_driver *driver, unsigned index,
184*4882a593Smuzhiyun struct device *device)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun return tty_port_register_device_attr_serdev(port, driver, index,
187*4882a593Smuzhiyun device, NULL, NULL);
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(tty_port_register_device_serdev);
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun /**
192*4882a593Smuzhiyun * tty_port_unregister_device - deregister a tty or serdev device
193*4882a593Smuzhiyun * @port: tty_port of the device
194*4882a593Smuzhiyun * @driver: tty_driver for this device
195*4882a593Smuzhiyun * @index: index of the tty
196*4882a593Smuzhiyun *
197*4882a593Smuzhiyun * If a tty or serdev device is registered with a call to
198*4882a593Smuzhiyun * tty_port_register_device_serdev() then this function must be called when
199*4882a593Smuzhiyun * the device is gone.
200*4882a593Smuzhiyun */
tty_port_unregister_device(struct tty_port * port,struct tty_driver * driver,unsigned index)201*4882a593Smuzhiyun void tty_port_unregister_device(struct tty_port *port,
202*4882a593Smuzhiyun struct tty_driver *driver, unsigned index)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun int ret;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun ret = serdev_tty_port_unregister(port);
207*4882a593Smuzhiyun if (ret == 0)
208*4882a593Smuzhiyun return;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun tty_unregister_device(driver, index);
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(tty_port_unregister_device);
213*4882a593Smuzhiyun
tty_port_alloc_xmit_buf(struct tty_port * port)214*4882a593Smuzhiyun int tty_port_alloc_xmit_buf(struct tty_port *port)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun /* We may sleep in get_zeroed_page() */
217*4882a593Smuzhiyun mutex_lock(&port->buf_mutex);
218*4882a593Smuzhiyun if (port->xmit_buf == NULL)
219*4882a593Smuzhiyun port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
220*4882a593Smuzhiyun mutex_unlock(&port->buf_mutex);
221*4882a593Smuzhiyun if (port->xmit_buf == NULL)
222*4882a593Smuzhiyun return -ENOMEM;
223*4882a593Smuzhiyun return 0;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
226*4882a593Smuzhiyun
tty_port_free_xmit_buf(struct tty_port * port)227*4882a593Smuzhiyun void tty_port_free_xmit_buf(struct tty_port *port)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun mutex_lock(&port->buf_mutex);
230*4882a593Smuzhiyun if (port->xmit_buf != NULL) {
231*4882a593Smuzhiyun free_page((unsigned long)port->xmit_buf);
232*4882a593Smuzhiyun port->xmit_buf = NULL;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun mutex_unlock(&port->buf_mutex);
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun EXPORT_SYMBOL(tty_port_free_xmit_buf);
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun /**
239*4882a593Smuzhiyun * tty_port_destroy -- destroy inited port
240*4882a593Smuzhiyun * @port: tty port to be destroyed
241*4882a593Smuzhiyun *
242*4882a593Smuzhiyun * When a port was initialized using tty_port_init, one has to destroy the
243*4882a593Smuzhiyun * port by this function. Either indirectly by using tty_port refcounting
244*4882a593Smuzhiyun * (tty_port_put) or directly if refcounting is not used.
245*4882a593Smuzhiyun */
tty_port_destroy(struct tty_port * port)246*4882a593Smuzhiyun void tty_port_destroy(struct tty_port *port)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun tty_buffer_cancel_work(port);
249*4882a593Smuzhiyun tty_buffer_free_all(port);
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun EXPORT_SYMBOL(tty_port_destroy);
252*4882a593Smuzhiyun
tty_port_destructor(struct kref * kref)253*4882a593Smuzhiyun static void tty_port_destructor(struct kref *kref)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun struct tty_port *port = container_of(kref, struct tty_port, kref);
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun /* check if last port ref was dropped before tty release */
258*4882a593Smuzhiyun if (WARN_ON(port->itty))
259*4882a593Smuzhiyun return;
260*4882a593Smuzhiyun if (port->xmit_buf)
261*4882a593Smuzhiyun free_page((unsigned long)port->xmit_buf);
262*4882a593Smuzhiyun tty_port_destroy(port);
263*4882a593Smuzhiyun if (port->ops && port->ops->destruct)
264*4882a593Smuzhiyun port->ops->destruct(port);
265*4882a593Smuzhiyun else
266*4882a593Smuzhiyun kfree(port);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
tty_port_put(struct tty_port * port)269*4882a593Smuzhiyun void tty_port_put(struct tty_port *port)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun if (port)
272*4882a593Smuzhiyun kref_put(&port->kref, tty_port_destructor);
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun EXPORT_SYMBOL(tty_port_put);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun /**
277*4882a593Smuzhiyun * tty_port_tty_get - get a tty reference
278*4882a593Smuzhiyun * @port: tty port
279*4882a593Smuzhiyun *
280*4882a593Smuzhiyun * Return a refcount protected tty instance or NULL if the port is not
281*4882a593Smuzhiyun * associated with a tty (eg due to close or hangup)
282*4882a593Smuzhiyun */
tty_port_tty_get(struct tty_port * port)283*4882a593Smuzhiyun struct tty_struct *tty_port_tty_get(struct tty_port *port)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun unsigned long flags;
286*4882a593Smuzhiyun struct tty_struct *tty;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
289*4882a593Smuzhiyun tty = tty_kref_get(port->tty);
290*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
291*4882a593Smuzhiyun return tty;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun EXPORT_SYMBOL(tty_port_tty_get);
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun /**
296*4882a593Smuzhiyun * tty_port_tty_set - set the tty of a port
297*4882a593Smuzhiyun * @port: tty port
298*4882a593Smuzhiyun * @tty: the tty
299*4882a593Smuzhiyun *
300*4882a593Smuzhiyun * Associate the port and tty pair. Manages any internal refcounts.
301*4882a593Smuzhiyun * Pass NULL to deassociate a port
302*4882a593Smuzhiyun */
tty_port_tty_set(struct tty_port * port,struct tty_struct * tty)303*4882a593Smuzhiyun void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun unsigned long flags;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
308*4882a593Smuzhiyun tty_kref_put(port->tty);
309*4882a593Smuzhiyun port->tty = tty_kref_get(tty);
310*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun EXPORT_SYMBOL(tty_port_tty_set);
313*4882a593Smuzhiyun
tty_port_shutdown(struct tty_port * port,struct tty_struct * tty)314*4882a593Smuzhiyun static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
315*4882a593Smuzhiyun {
316*4882a593Smuzhiyun mutex_lock(&port->mutex);
317*4882a593Smuzhiyun if (port->console)
318*4882a593Smuzhiyun goto out;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun if (tty_port_initialized(port)) {
321*4882a593Smuzhiyun tty_port_set_initialized(port, 0);
322*4882a593Smuzhiyun /*
323*4882a593Smuzhiyun * Drop DTR/RTS if HUPCL is set. This causes any attached
324*4882a593Smuzhiyun * modem to hang up the line.
325*4882a593Smuzhiyun */
326*4882a593Smuzhiyun if (tty && C_HUPCL(tty))
327*4882a593Smuzhiyun tty_port_lower_dtr_rts(port);
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun if (port->ops->shutdown)
330*4882a593Smuzhiyun port->ops->shutdown(port);
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun out:
333*4882a593Smuzhiyun mutex_unlock(&port->mutex);
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun /**
337*4882a593Smuzhiyun * tty_port_hangup - hangup helper
338*4882a593Smuzhiyun * @port: tty port
339*4882a593Smuzhiyun *
340*4882a593Smuzhiyun * Perform port level tty hangup flag and count changes. Drop the tty
341*4882a593Smuzhiyun * reference.
342*4882a593Smuzhiyun *
343*4882a593Smuzhiyun * Caller holds tty lock.
344*4882a593Smuzhiyun */
tty_port_hangup(struct tty_port * port)345*4882a593Smuzhiyun void tty_port_hangup(struct tty_port *port)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun struct tty_struct *tty;
348*4882a593Smuzhiyun unsigned long flags;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
351*4882a593Smuzhiyun port->count = 0;
352*4882a593Smuzhiyun tty = port->tty;
353*4882a593Smuzhiyun if (tty)
354*4882a593Smuzhiyun set_bit(TTY_IO_ERROR, &tty->flags);
355*4882a593Smuzhiyun port->tty = NULL;
356*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
357*4882a593Smuzhiyun tty_port_set_active(port, 0);
358*4882a593Smuzhiyun tty_port_shutdown(port, tty);
359*4882a593Smuzhiyun tty_kref_put(tty);
360*4882a593Smuzhiyun wake_up_interruptible(&port->open_wait);
361*4882a593Smuzhiyun wake_up_interruptible(&port->delta_msr_wait);
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun EXPORT_SYMBOL(tty_port_hangup);
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun /**
366*4882a593Smuzhiyun * tty_port_tty_hangup - helper to hang up a tty
367*4882a593Smuzhiyun *
368*4882a593Smuzhiyun * @port: tty port
369*4882a593Smuzhiyun * @check_clocal: hang only ttys with CLOCAL unset?
370*4882a593Smuzhiyun */
tty_port_tty_hangup(struct tty_port * port,bool check_clocal)371*4882a593Smuzhiyun void tty_port_tty_hangup(struct tty_port *port, bool check_clocal)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun struct tty_struct *tty = tty_port_tty_get(port);
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun if (tty && (!check_clocal || !C_CLOCAL(tty)))
376*4882a593Smuzhiyun tty_hangup(tty);
377*4882a593Smuzhiyun tty_kref_put(tty);
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(tty_port_tty_hangup);
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun /**
382*4882a593Smuzhiyun * tty_port_tty_wakeup - helper to wake up a tty
383*4882a593Smuzhiyun *
384*4882a593Smuzhiyun * @port: tty port
385*4882a593Smuzhiyun */
tty_port_tty_wakeup(struct tty_port * port)386*4882a593Smuzhiyun void tty_port_tty_wakeup(struct tty_port *port)
387*4882a593Smuzhiyun {
388*4882a593Smuzhiyun port->client_ops->write_wakeup(port);
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(tty_port_tty_wakeup);
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun /**
393*4882a593Smuzhiyun * tty_port_carrier_raised - carrier raised check
394*4882a593Smuzhiyun * @port: tty port
395*4882a593Smuzhiyun *
396*4882a593Smuzhiyun * Wrapper for the carrier detect logic. For the moment this is used
397*4882a593Smuzhiyun * to hide some internal details. This will eventually become entirely
398*4882a593Smuzhiyun * internal to the tty port.
399*4882a593Smuzhiyun */
tty_port_carrier_raised(struct tty_port * port)400*4882a593Smuzhiyun int tty_port_carrier_raised(struct tty_port *port)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun if (port->ops->carrier_raised == NULL)
403*4882a593Smuzhiyun return 1;
404*4882a593Smuzhiyun return port->ops->carrier_raised(port);
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun EXPORT_SYMBOL(tty_port_carrier_raised);
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun /**
409*4882a593Smuzhiyun * tty_port_raise_dtr_rts - Raise DTR/RTS
410*4882a593Smuzhiyun * @port: tty port
411*4882a593Smuzhiyun *
412*4882a593Smuzhiyun * Wrapper for the DTR/RTS raise logic. For the moment this is used
413*4882a593Smuzhiyun * to hide some internal details. This will eventually become entirely
414*4882a593Smuzhiyun * internal to the tty port.
415*4882a593Smuzhiyun */
tty_port_raise_dtr_rts(struct tty_port * port)416*4882a593Smuzhiyun void tty_port_raise_dtr_rts(struct tty_port *port)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun if (port->ops->dtr_rts)
419*4882a593Smuzhiyun port->ops->dtr_rts(port, 1);
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun EXPORT_SYMBOL(tty_port_raise_dtr_rts);
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun /**
424*4882a593Smuzhiyun * tty_port_lower_dtr_rts - Lower DTR/RTS
425*4882a593Smuzhiyun * @port: tty port
426*4882a593Smuzhiyun *
427*4882a593Smuzhiyun * Wrapper for the DTR/RTS raise logic. For the moment this is used
428*4882a593Smuzhiyun * to hide some internal details. This will eventually become entirely
429*4882a593Smuzhiyun * internal to the tty port.
430*4882a593Smuzhiyun */
tty_port_lower_dtr_rts(struct tty_port * port)431*4882a593Smuzhiyun void tty_port_lower_dtr_rts(struct tty_port *port)
432*4882a593Smuzhiyun {
433*4882a593Smuzhiyun if (port->ops->dtr_rts)
434*4882a593Smuzhiyun port->ops->dtr_rts(port, 0);
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun EXPORT_SYMBOL(tty_port_lower_dtr_rts);
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun /**
439*4882a593Smuzhiyun * tty_port_block_til_ready - Waiting logic for tty open
440*4882a593Smuzhiyun * @port: the tty port being opened
441*4882a593Smuzhiyun * @tty: the tty device being bound
442*4882a593Smuzhiyun * @filp: the file pointer of the opener or NULL
443*4882a593Smuzhiyun *
444*4882a593Smuzhiyun * Implement the core POSIX/SuS tty behaviour when opening a tty device.
445*4882a593Smuzhiyun * Handles:
446*4882a593Smuzhiyun * - hangup (both before and during)
447*4882a593Smuzhiyun * - non blocking open
448*4882a593Smuzhiyun * - rts/dtr/dcd
449*4882a593Smuzhiyun * - signals
450*4882a593Smuzhiyun * - port flags and counts
451*4882a593Smuzhiyun *
452*4882a593Smuzhiyun * The passed tty_port must implement the carrier_raised method if it can
453*4882a593Smuzhiyun * do carrier detect and the dtr_rts method if it supports software
454*4882a593Smuzhiyun * management of these lines. Note that the dtr/rts raise is done each
455*4882a593Smuzhiyun * iteration as a hangup may have previously dropped them while we wait.
456*4882a593Smuzhiyun *
457*4882a593Smuzhiyun * Caller holds tty lock.
458*4882a593Smuzhiyun *
459*4882a593Smuzhiyun * NB: May drop and reacquire tty lock when blocking, so tty and tty_port
460*4882a593Smuzhiyun * may have changed state (eg., may have been hung up).
461*4882a593Smuzhiyun */
tty_port_block_til_ready(struct tty_port * port,struct tty_struct * tty,struct file * filp)462*4882a593Smuzhiyun int tty_port_block_til_ready(struct tty_port *port,
463*4882a593Smuzhiyun struct tty_struct *tty, struct file *filp)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun int do_clocal = 0, retval;
466*4882a593Smuzhiyun unsigned long flags;
467*4882a593Smuzhiyun DEFINE_WAIT(wait);
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun /* if non-blocking mode is set we can pass directly to open unless
470*4882a593Smuzhiyun the port has just hung up or is in another error state */
471*4882a593Smuzhiyun if (tty_io_error(tty)) {
472*4882a593Smuzhiyun tty_port_set_active(port, 1);
473*4882a593Smuzhiyun return 0;
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun if (filp == NULL || (filp->f_flags & O_NONBLOCK)) {
476*4882a593Smuzhiyun /* Indicate we are open */
477*4882a593Smuzhiyun if (C_BAUD(tty))
478*4882a593Smuzhiyun tty_port_raise_dtr_rts(port);
479*4882a593Smuzhiyun tty_port_set_active(port, 1);
480*4882a593Smuzhiyun return 0;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun if (C_CLOCAL(tty))
484*4882a593Smuzhiyun do_clocal = 1;
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun /* Block waiting until we can proceed. We may need to wait for the
487*4882a593Smuzhiyun carrier, but we must also wait for any close that is in progress
488*4882a593Smuzhiyun before the next open may complete */
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun retval = 0;
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun /* The port lock protects the port counts */
493*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
494*4882a593Smuzhiyun port->count--;
495*4882a593Smuzhiyun port->blocked_open++;
496*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun while (1) {
499*4882a593Smuzhiyun /* Indicate we are open */
500*4882a593Smuzhiyun if (C_BAUD(tty) && tty_port_initialized(port))
501*4882a593Smuzhiyun tty_port_raise_dtr_rts(port);
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
504*4882a593Smuzhiyun /* Check for a hangup or uninitialised port.
505*4882a593Smuzhiyun Return accordingly */
506*4882a593Smuzhiyun if (tty_hung_up_p(filp) || !tty_port_initialized(port)) {
507*4882a593Smuzhiyun if (port->flags & ASYNC_HUP_NOTIFY)
508*4882a593Smuzhiyun retval = -EAGAIN;
509*4882a593Smuzhiyun else
510*4882a593Smuzhiyun retval = -ERESTARTSYS;
511*4882a593Smuzhiyun break;
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun /*
514*4882a593Smuzhiyun * Probe the carrier. For devices with no carrier detect
515*4882a593Smuzhiyun * tty_port_carrier_raised will always return true.
516*4882a593Smuzhiyun * Never ask drivers if CLOCAL is set, this causes troubles
517*4882a593Smuzhiyun * on some hardware.
518*4882a593Smuzhiyun */
519*4882a593Smuzhiyun if (do_clocal || tty_port_carrier_raised(port))
520*4882a593Smuzhiyun break;
521*4882a593Smuzhiyun if (signal_pending(current)) {
522*4882a593Smuzhiyun retval = -ERESTARTSYS;
523*4882a593Smuzhiyun break;
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun tty_unlock(tty);
526*4882a593Smuzhiyun schedule();
527*4882a593Smuzhiyun tty_lock(tty);
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun finish_wait(&port->open_wait, &wait);
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun /* Update counts. A parallel hangup will have set count to zero and
532*4882a593Smuzhiyun we must not mess that up further */
533*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
534*4882a593Smuzhiyun if (!tty_hung_up_p(filp))
535*4882a593Smuzhiyun port->count++;
536*4882a593Smuzhiyun port->blocked_open--;
537*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
538*4882a593Smuzhiyun if (retval == 0)
539*4882a593Smuzhiyun tty_port_set_active(port, 1);
540*4882a593Smuzhiyun return retval;
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun EXPORT_SYMBOL(tty_port_block_til_ready);
543*4882a593Smuzhiyun
tty_port_drain_delay(struct tty_port * port,struct tty_struct * tty)544*4882a593Smuzhiyun static void tty_port_drain_delay(struct tty_port *port, struct tty_struct *tty)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun unsigned int bps = tty_get_baud_rate(tty);
547*4882a593Smuzhiyun long timeout;
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun if (bps > 1200) {
550*4882a593Smuzhiyun timeout = (HZ * 10 * port->drain_delay) / bps;
551*4882a593Smuzhiyun timeout = max_t(long, timeout, HZ / 10);
552*4882a593Smuzhiyun } else {
553*4882a593Smuzhiyun timeout = 2 * HZ;
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun schedule_timeout_interruptible(timeout);
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun /* Caller holds tty lock. */
tty_port_close_start(struct tty_port * port,struct tty_struct * tty,struct file * filp)559*4882a593Smuzhiyun int tty_port_close_start(struct tty_port *port,
560*4882a593Smuzhiyun struct tty_struct *tty, struct file *filp)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun unsigned long flags;
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun if (tty_hung_up_p(filp))
565*4882a593Smuzhiyun return 0;
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
568*4882a593Smuzhiyun if (tty->count == 1 && port->count != 1) {
569*4882a593Smuzhiyun tty_warn(tty, "%s: tty->count = 1 port count = %d\n", __func__,
570*4882a593Smuzhiyun port->count);
571*4882a593Smuzhiyun port->count = 1;
572*4882a593Smuzhiyun }
573*4882a593Smuzhiyun if (--port->count < 0) {
574*4882a593Smuzhiyun tty_warn(tty, "%s: bad port count (%d)\n", __func__,
575*4882a593Smuzhiyun port->count);
576*4882a593Smuzhiyun port->count = 0;
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun if (port->count) {
580*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
581*4882a593Smuzhiyun return 0;
582*4882a593Smuzhiyun }
583*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun tty->closing = 1;
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun if (tty_port_initialized(port)) {
588*4882a593Smuzhiyun /* Don't block on a stalled port, just pull the chain */
589*4882a593Smuzhiyun if (tty->flow_stopped)
590*4882a593Smuzhiyun tty_driver_flush_buffer(tty);
591*4882a593Smuzhiyun if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
592*4882a593Smuzhiyun tty_wait_until_sent(tty, port->closing_wait);
593*4882a593Smuzhiyun if (port->drain_delay)
594*4882a593Smuzhiyun tty_port_drain_delay(port, tty);
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun /* Flush the ldisc buffering */
597*4882a593Smuzhiyun tty_ldisc_flush(tty);
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun /* Report to caller this is the last port reference */
600*4882a593Smuzhiyun return 1;
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun EXPORT_SYMBOL(tty_port_close_start);
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun /* Caller holds tty lock */
tty_port_close_end(struct tty_port * port,struct tty_struct * tty)605*4882a593Smuzhiyun void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
606*4882a593Smuzhiyun {
607*4882a593Smuzhiyun unsigned long flags;
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun tty_ldisc_flush(tty);
610*4882a593Smuzhiyun tty->closing = 0;
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun if (port->blocked_open) {
615*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
616*4882a593Smuzhiyun if (port->close_delay)
617*4882a593Smuzhiyun msleep_interruptible(jiffies_to_msecs(port->close_delay));
618*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
619*4882a593Smuzhiyun wake_up_interruptible(&port->open_wait);
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
622*4882a593Smuzhiyun tty_port_set_active(port, 0);
623*4882a593Smuzhiyun }
624*4882a593Smuzhiyun EXPORT_SYMBOL(tty_port_close_end);
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun /**
627*4882a593Smuzhiyun * tty_port_close
628*4882a593Smuzhiyun *
629*4882a593Smuzhiyun * Caller holds tty lock
630*4882a593Smuzhiyun */
tty_port_close(struct tty_port * port,struct tty_struct * tty,struct file * filp)631*4882a593Smuzhiyun void tty_port_close(struct tty_port *port, struct tty_struct *tty,
632*4882a593Smuzhiyun struct file *filp)
633*4882a593Smuzhiyun {
634*4882a593Smuzhiyun if (tty_port_close_start(port, tty, filp) == 0)
635*4882a593Smuzhiyun return;
636*4882a593Smuzhiyun tty_port_shutdown(port, tty);
637*4882a593Smuzhiyun if (!port->console)
638*4882a593Smuzhiyun set_bit(TTY_IO_ERROR, &tty->flags);
639*4882a593Smuzhiyun tty_port_close_end(port, tty);
640*4882a593Smuzhiyun tty_port_tty_set(port, NULL);
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun EXPORT_SYMBOL(tty_port_close);
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun /**
645*4882a593Smuzhiyun * tty_port_install - generic tty->ops->install handler
646*4882a593Smuzhiyun * @port: tty_port of the device
647*4882a593Smuzhiyun * @driver: tty_driver for this device
648*4882a593Smuzhiyun * @tty: tty to be installed
649*4882a593Smuzhiyun *
650*4882a593Smuzhiyun * It is the same as tty_standard_install except the provided @port is linked
651*4882a593Smuzhiyun * to a concrete tty specified by @tty. Use this or tty_port_register_device
652*4882a593Smuzhiyun * (or both). Call tty_port_link_device as a last resort.
653*4882a593Smuzhiyun */
tty_port_install(struct tty_port * port,struct tty_driver * driver,struct tty_struct * tty)654*4882a593Smuzhiyun int tty_port_install(struct tty_port *port, struct tty_driver *driver,
655*4882a593Smuzhiyun struct tty_struct *tty)
656*4882a593Smuzhiyun {
657*4882a593Smuzhiyun tty->port = port;
658*4882a593Smuzhiyun return tty_standard_install(driver, tty);
659*4882a593Smuzhiyun }
660*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(tty_port_install);
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun /**
663*4882a593Smuzhiyun * tty_port_open
664*4882a593Smuzhiyun *
665*4882a593Smuzhiyun * Caller holds tty lock.
666*4882a593Smuzhiyun *
667*4882a593Smuzhiyun * NB: may drop and reacquire tty lock (in tty_port_block_til_ready()) so
668*4882a593Smuzhiyun * tty and tty_port may have changed state (eg., may be hung up now)
669*4882a593Smuzhiyun */
tty_port_open(struct tty_port * port,struct tty_struct * tty,struct file * filp)670*4882a593Smuzhiyun int tty_port_open(struct tty_port *port, struct tty_struct *tty,
671*4882a593Smuzhiyun struct file *filp)
672*4882a593Smuzhiyun {
673*4882a593Smuzhiyun spin_lock_irq(&port->lock);
674*4882a593Smuzhiyun ++port->count;
675*4882a593Smuzhiyun spin_unlock_irq(&port->lock);
676*4882a593Smuzhiyun tty_port_tty_set(port, tty);
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun /*
679*4882a593Smuzhiyun * Do the device-specific open only if the hardware isn't
680*4882a593Smuzhiyun * already initialized. Serialize open and shutdown using the
681*4882a593Smuzhiyun * port mutex.
682*4882a593Smuzhiyun */
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun mutex_lock(&port->mutex);
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun if (!tty_port_initialized(port)) {
687*4882a593Smuzhiyun clear_bit(TTY_IO_ERROR, &tty->flags);
688*4882a593Smuzhiyun if (port->ops->activate) {
689*4882a593Smuzhiyun int retval = port->ops->activate(port, tty);
690*4882a593Smuzhiyun if (retval) {
691*4882a593Smuzhiyun mutex_unlock(&port->mutex);
692*4882a593Smuzhiyun return retval;
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun }
695*4882a593Smuzhiyun tty_port_set_initialized(port, 1);
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun mutex_unlock(&port->mutex);
698*4882a593Smuzhiyun return tty_port_block_til_ready(port, tty, filp);
699*4882a593Smuzhiyun }
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun EXPORT_SYMBOL(tty_port_open);
702