18e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This program is free software; you can redistribute it and/or modify
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   it under the terms of the GNU General Public License version 2 as
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   published by the Free Software Foundation;
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
148e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
158e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
168e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
198e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
208e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   SOFTWARE IS DISCLAIMED.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * RFCOMM TTY.
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/bluetooth/bluetooth.h>
350a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann#include <net/bluetooth/hci_core.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/bluetooth/rfcomm.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RFCOMM_TTY_MAGIC 0x6d02		/* magic number for rfcomm struct */
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RFCOMM_TTY_PORTS RFCOMM_MAX_DEV	/* whole lotta rfcomm devices */
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RFCOMM_TTY_MAJOR 216		/* device node major id of the usb/bluetooth.c driver */
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RFCOMM_TTY_MINOR 0
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct tty_driver *rfcomm_tty_driver;
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct rfcomm_dev {
46f60db8c4246ac7c33448fad173bed85354b7d75eJiri Slaby	struct tty_port		port;
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head	list;
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char			name[12];
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			id;
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			err;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bdaddr_t		src;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bdaddr_t		dst;
56285b4e90318dcf421a00b2ac3fe8ab713f3281e3Andrei Emeltchenko	u8			channel;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
58285b4e90318dcf421a00b2ac3fe8ab713f3281e3Andrei Emeltchenko	uint			modem_status;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dlc	*dlc;
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_queue_head_t       wait;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
63c1a3313698895d8ad4760f98642007bf236af2e8Marcel Holtmann	struct device		*tty_dev;
64c1a3313698895d8ad4760f98642007bf236af2e8Marcel Holtmann
65285b4e90318dcf421a00b2ac3fe8ab713f3281e3Andrei Emeltchenko	atomic_t		wmem_alloc;
66a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann
67a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann	struct sk_buff_head	pending;
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic LIST_HEAD(rfcomm_dev_list);
71393432cd8dc02b88a00decd495913643aa5ff705Gustavo Padovanstatic DEFINE_SPINLOCK(rfcomm_dev_lock);
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ---- Device functions ---- */
7867054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby
7967054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby/*
8067054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby * The reason this isn't actually a race, as you no doubt have a little voice
8167054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby * screaming at you in your head, is that the refcount should never actually
8267054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby * reach zero unless the device has already been taken off the list, in
8367054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby * rfcomm_dev_del(). And if that's not true, we'll hit the BUG() in
8467054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby * rfcomm_dev_destruct() anyway.
8567054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby */
8667054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slabystatic void rfcomm_dev_destruct(struct tty_port *port)
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8867054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby	struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port);
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dlc *dlc = dev->dlc;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("dev %p dlc %p", dev, dlc);
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
93f951375d470c1a20d92c34377991197e6bf17990Dave Young	/* Refcount should only hit zero when called from rfcomm_dev_del()
94f951375d470c1a20d92c34377991197e6bf17990Dave Young	   which will have taken us off the list. Everything else are
95f951375d470c1a20d92c34377991197e6bf17990Dave Young	   refcounting bugs. */
96f951375d470c1a20d92c34377991197e6bf17990Dave Young	BUG_ON(!list_empty(&dev->list));
978de0a15483b357d0f0b821330ec84d1660cadc4eVille Tervo
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_dlc_lock(dlc);
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Detach DLC if it's owned by this dev */
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dlc->owner == dev)
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dlc->owner = NULL;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_dlc_unlock(dlc);
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_dlc_put(dlc);
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty_unregister_device(rfcomm_tty_driver, dev->id);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(dev);
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1108e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki	/* It's safe to call module_put() here because socket still
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   holds reference to this module. */
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	module_put(THIS_MODULE);
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11567054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slabystatic const struct tty_port_operations rfcomm_port_ops = {
11667054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby	.destruct = rfcomm_dev_destruct,
11767054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby};
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct rfcomm_dev *__rfcomm_dev_get(int id)
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev *dev;
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1238035ded466049ca2fe8c04564a0fa00f222abe3fLuiz Augusto von Dentz	list_for_each_entry(dev, &rfcomm_dev_list, list)
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dev->id == id)
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return dev;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1306039aa73a1323edc2d6d93a22505d4dc28f38e3fGustavo Padovanstatic struct rfcomm_dev *rfcomm_dev_get(int id)
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev *dev;
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
134393432cd8dc02b88a00decd495913643aa5ff705Gustavo Padovan	spin_lock(&rfcomm_dev_lock);
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = __rfcomm_dev_get(id);
1378de0a15483b357d0f0b821330ec84d1660cadc4eVille Tervo
1388de0a15483b357d0f0b821330ec84d1660cadc4eVille Tervo	if (dev) {
1398de0a15483b357d0f0b821330ec84d1660cadc4eVille Tervo		if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
1408de0a15483b357d0f0b821330ec84d1660cadc4eVille Tervo			dev = NULL;
1418de0a15483b357d0f0b821330ec84d1660cadc4eVille Tervo		else
14267054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby			tty_port_get(&dev->port);
1438de0a15483b357d0f0b821330ec84d1660cadc4eVille Tervo	}
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
145393432cd8dc02b88a00decd495913643aa5ff705Gustavo Padovan	spin_unlock(&rfcomm_dev_lock);
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dev;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1500a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmannstatic struct device *rfcomm_get_device(struct rfcomm_dev *dev)
1510a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann{
1520a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann	struct hci_dev *hdev;
1530a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann	struct hci_conn *conn;
1540a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann
1550a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann	hdev = hci_get_route(&dev->dst, &dev->src);
1560a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann	if (!hdev)
1570a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann		return NULL;
1580a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann
1590a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst);
1600a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann
1610a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann	hci_dev_put(hdev);
1620a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann
163b2cfcd75df77b80d9cc3fa84190a350dfa79eb93Marcel Holtmann	return conn ? &conn->dev : NULL;
1640a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann}
1650a85b964e141a4b8db6eaf500ceace12f8f52f93Marcel Holtmann
166dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmannstatic ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf)
167dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmann{
168dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmann	struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
169fcb73338ed531dcc00cb17ca76fe3e05f774e4e9Andrei Emeltchenko	return sprintf(buf, "%pMR\n", &dev->dst);
170dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmann}
171dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmann
172dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmannstatic ssize_t show_channel(struct device *tty_dev, struct device_attribute *attr, char *buf)
173dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmann{
174dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmann	struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
175dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmann	return sprintf(buf, "%d\n", dev->channel);
176dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmann}
177dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmann
178dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmannstatic DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
179dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmannstatic DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
180dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmann
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1838035ded466049ca2fe8c04564a0fa00f222abe3fLuiz Augusto von Dentz	struct rfcomm_dev *dev, *entry;
184e57d758ae8e8f00e80f233c823aeeef34bd92796Luiz Augusto von Dentz	struct list_head *head = &rfcomm_dev_list;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("id %d channel %d", req->dev_id, req->channel);
1888e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
18925ea6db04a96d7871e7ece27d566f3228d59d932Marcel Holtmann	dev = kzalloc(sizeof(struct rfcomm_dev), GFP_KERNEL);
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
193393432cd8dc02b88a00decd495913643aa5ff705Gustavo Padovan	spin_lock(&rfcomm_dev_lock);
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (req->dev_id < 0) {
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->id = 0;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1988035ded466049ca2fe8c04564a0fa00f222abe3fLuiz Augusto von Dentz		list_for_each_entry(entry, &rfcomm_dev_list, list) {
1998035ded466049ca2fe8c04564a0fa00f222abe3fLuiz Augusto von Dentz			if (entry->id != dev->id)
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->id++;
203e57d758ae8e8f00e80f233c823aeeef34bd92796Luiz Augusto von Dentz			head = &entry->list;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->id = req->dev_id;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2088035ded466049ca2fe8c04564a0fa00f222abe3fLuiz Augusto von Dentz		list_for_each_entry(entry, &rfcomm_dev_list, list) {
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (entry->id == dev->id) {
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				err = -EADDRINUSE;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto out;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (entry->id > dev->id - 1)
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
217e57d758ae8e8f00e80f233c823aeeef34bd92796Luiz Augusto von Dentz			head = &entry->list;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((dev->id < 0) || (dev->id > RFCOMM_MAX_DEV - 1)) {
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENFILE;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sprintf(dev->name, "rfcomm%d", dev->id);
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_add(&dev->list, head);
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bacpy(&dev->src, &req->src);
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bacpy(&dev->dst, &req->dst);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->channel = req->channel;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2348e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki	dev->flags = req->flags &
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
237f60db8c4246ac7c33448fad173bed85354b7d75eJiri Slaby	tty_port_init(&dev->port);
23867054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby	dev->port.ops = &rfcomm_port_ops;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_waitqueue_head(&dev->wait);
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann	skb_queue_head_init(&dev->pending);
242a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_dlc_lock(dlc);
244a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann
245a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann	if (req->flags & (1 << RFCOMM_REUSE_DLC)) {
246a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann		struct sock *sk = dlc->owner;
247a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann		struct sk_buff *skb;
248a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann
249a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann		BUG_ON(!sk);
250a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann
251a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann		rfcomm_dlc_throttle(dlc);
252a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann
253a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann		while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
254a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann			skb_orphan(skb);
255a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann			skb_queue_tail(&dev->pending, skb);
256a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann			atomic_sub(skb->len, &sk->sk_rmem_alloc);
257a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann		}
258a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann	}
259a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dlc->data_ready   = rfcomm_dev_data_ready;
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dlc->state_change = rfcomm_dev_state_change;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dlc->modem_status = rfcomm_dev_modem_status;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dlc->owner = dev;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->dlc   = dlc;
2668b6b3da765af9600b5edd8e3e84a20523e975884Marcel Holtmann
2678b6b3da765af9600b5edd8e3e84a20523e975884Marcel Holtmann	rfcomm_dev_modem_status(dlc, dlc->remote_v24_sig);
2688b6b3da765af9600b5edd8e3e84a20523e975884Marcel Holtmann
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_dlc_unlock(dlc);
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2718e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki	/* It's safe to call __module_get() here because socket already
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   holds reference to this module. */
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__module_get(THIS_MODULE);
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
276393432cd8dc02b88a00decd495913643aa5ff705Gustavo Padovan	spin_unlock(&rfcomm_dev_lock);
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
278037322abe6141e32e1b1dea86a9405d52c99be5dIlpo Järvinen	if (err < 0)
279037322abe6141e32e1b1dea86a9405d52c99be5dIlpo Järvinen		goto free;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281734cc1783816ae358cef45673a29bf7af974e147Jiri Slaby	dev->tty_dev = tty_port_register_device(&dev->port, rfcomm_tty_driver,
282734cc1783816ae358cef45673a29bf7af974e147Jiri Slaby			dev->id, NULL);
2838de0a15483b357d0f0b821330ec84d1660cadc4eVille Tervo	if (IS_ERR(dev->tty_dev)) {
28409c7d8293a2d1317d16ef4ddb9f6dd2553d0694eMarcel Holtmann		err = PTR_ERR(dev->tty_dev);
2858de0a15483b357d0f0b821330ec84d1660cadc4eVille Tervo		list_del(&dev->list);
286037322abe6141e32e1b1dea86a9405d52c99be5dIlpo Järvinen		goto free;
2878de0a15483b357d0f0b821330ec84d1660cadc4eVille Tervo	}
2888de0a15483b357d0f0b821330ec84d1660cadc4eVille Tervo
289dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmann	dev_set_drvdata(dev->tty_dev, dev);
290dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmann
291dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmann	if (device_create_file(dev->tty_dev, &dev_attr_address) < 0)
292dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmann		BT_ERR("Failed to create address attribute");
293dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmann
294dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmann	if (device_create_file(dev->tty_dev, &dev_attr_channel) < 0)
295dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmann		BT_ERR("Failed to create channel attribute");
296dae6a0f6636d05bcb28ece1f3630b23ed2d66e18Marcel Holtmann
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dev->id;
298037322abe6141e32e1b1dea86a9405d52c99be5dIlpo Järvinen
299037322abe6141e32e1b1dea86a9405d52c99be5dIlpo Järvinenfree:
300037322abe6141e32e1b1dea86a9405d52c99be5dIlpo Järvinen	kfree(dev);
301037322abe6141e32e1b1dea86a9405d52c99be5dIlpo Järvinen	return err;
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_dev_del(struct rfcomm_dev *dev)
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
306f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby	unsigned long flags;
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("dev %p", dev);
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3099a5df92374d65e2886b92e98dd7d873c533a83ffMarcel Holtmann	BUG_ON(test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags));
3109a5df92374d65e2886b92e98dd7d873c533a83ffMarcel Holtmann
311f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby	spin_lock_irqsave(&dev->port.lock, flags);
312f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby	if (dev->port.count > 0) {
313f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby		spin_unlock_irqrestore(&dev->port.lock, flags);
3149a5df92374d65e2886b92e98dd7d873c533a83ffMarcel Holtmann		return;
315f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby	}
316f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby	spin_unlock_irqrestore(&dev->port.lock, flags);
317f951375d470c1a20d92c34377991197e6bf17990Dave Young
318393432cd8dc02b88a00decd495913643aa5ff705Gustavo Padovan	spin_lock(&rfcomm_dev_lock);
319f951375d470c1a20d92c34377991197e6bf17990Dave Young	list_del_init(&dev->list);
320393432cd8dc02b88a00decd495913643aa5ff705Gustavo Padovan	spin_unlock(&rfcomm_dev_lock);
321f951375d470c1a20d92c34377991197e6bf17990Dave Young
32267054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby	tty_port_put(&dev->port);
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ---- Send buffer ---- */
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc)
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We can't let it be zero, because we don't get a callback
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   when tx_credits becomes nonzero, hence we'd never wake up */
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dlc->mtu * (dlc->tx_credits?:1);
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_wfree(struct sk_buff *skb)
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev *dev = (void *) skb->sk;
336b2c4be398bf771a09f84eae6cf12cbd685384b8dJiri Slaby	struct tty_struct *tty = dev->port.tty;
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_sub(skb->truesize, &dev->wmem_alloc);
338b2c4be398bf771a09f84eae6cf12cbd685384b8dJiri Slaby	if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags) && tty)
339b2c4be398bf771a09f84eae6cf12cbd685384b8dJiri Slaby		tty_wakeup(tty);
34067054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby	tty_port_put(&dev->port);
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3436039aa73a1323edc2d6d93a22505d4dc28f38e3fGustavo Padovanstatic void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
34567054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby	tty_port_get(&dev->port);
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atomic_add(skb->truesize, &dev->wmem_alloc);
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb->sk = (void *) dev;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb->destructor = rfcomm_wfree;
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
351dd0fc66fb33cd610bc1a5db8a5e232d34879b4d7Al Virostatic struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, gfp_t priority)
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) {
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sk_buff *skb = alloc_skb(size, priority);
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (skb) {
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rfcomm_set_owner_w(skb, dev);
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return skb;
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ---- Device IOCTLs ---- */
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NOCAP_FLAGS ((1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP))
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rfcomm_create_dev(struct sock *sk, void __user *arg)
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev_req req;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dlc *dlc;
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int id;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(&req, arg, sizeof(req)))
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3768de0a15483b357d0f0b821330ec84d1660cadc4eVille Tervo	BT_DBG("sk %p dev_id %d flags 0x%x", sk, req.dev_id, req.flags);
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (req.flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN))
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EPERM;
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Socket must be connected */
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (sk->sk_state != BT_CONNECTED)
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EBADFD;
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dlc = rfcomm_pi(sk)->dlc;
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rfcomm_dlc_hold(dlc);
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dlc = rfcomm_dlc_alloc(GFP_KERNEL);
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!dlc)
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOMEM;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	id = rfcomm_dev_add(&req, dlc);
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (id < 0) {
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rfcomm_dlc_put(dlc);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return id;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* DLC is now used by device.
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Socket must be disconnected */
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sk->sk_state = BT_CLOSED;
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return id;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rfcomm_release_dev(void __user *arg)
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev_req req;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev *dev;
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(&req, arg, sizeof(req)))
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4178de0a15483b357d0f0b821330ec84d1660cadc4eVille Tervo	BT_DBG("dev_id %d flags 0x%x", req.dev_id, req.flags);
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
419285b4e90318dcf421a00b2ac3fe8ab713f3281e3Andrei Emeltchenko	dev = rfcomm_dev_get(req.dev_id);
420285b4e90318dcf421a00b2ac3fe8ab713f3281e3Andrei Emeltchenko	if (!dev)
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) {
42467054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby		tty_port_put(&dev->port);
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EPERM;
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (req.flags & (1 << RFCOMM_HANGUP_NOW))
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rfcomm_dlc_close(dev->dlc, 0);
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43184950cf0ba02fd6a5defe2511bc41f9aa2237632Mikko Rapeli	/* Shut down TTY synchronously before freeing rfcomm_dev */
432f60db8c4246ac7c33448fad173bed85354b7d75eJiri Slaby	if (dev->port.tty)
433f60db8c4246ac7c33448fad173bed85354b7d75eJiri Slaby		tty_vhangup(dev->port.tty);
43484950cf0ba02fd6a5defe2511bc41f9aa2237632Mikko Rapeli
43593d807401ced2320d0d1e56bf9de099bba5c0424Dave Young	if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
43693d807401ced2320d0d1e56bf9de099bba5c0424Dave Young		rfcomm_dev_del(dev);
43767054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby	tty_port_put(&dev->port);
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rfcomm_get_dev_list(void __user *arg)
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4438035ded466049ca2fe8c04564a0fa00f222abe3fLuiz Augusto von Dentz	struct rfcomm_dev *dev;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev_list_req *dl;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev_info *di;
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int n = 0, size, err;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 dev_num;
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("");
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get_user(dev_num, (u16 __user *) arg))
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev_num || dev_num > (PAGE_SIZE * 4) / sizeof(*di))
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size = sizeof(*dl) + dev_num * sizeof(*di);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
459f9432c5ec8b1e9a09b9b0e5569e3c73db8de432aMathias Krause	dl = kzalloc(size, GFP_KERNEL);
460285b4e90318dcf421a00b2ac3fe8ab713f3281e3Andrei Emeltchenko	if (!dl)
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	di = dl->dev_info;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
465393432cd8dc02b88a00decd495913643aa5ff705Gustavo Padovan	spin_lock(&rfcomm_dev_lock);
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4678035ded466049ca2fe8c04564a0fa00f222abe3fLuiz Augusto von Dentz	list_for_each_entry(dev, &rfcomm_dev_list, list) {
4688de0a15483b357d0f0b821330ec84d1660cadc4eVille Tervo		if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
4698de0a15483b357d0f0b821330ec84d1660cadc4eVille Tervo			continue;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(di + n)->id      = dev->id;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(di + n)->flags   = dev->flags;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(di + n)->state   = dev->dlc->state;
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(di + n)->channel = dev->channel;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bacpy(&(di + n)->src, &dev->src);
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bacpy(&(di + n)->dst, &dev->dst);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (++n >= dev_num)
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
480393432cd8dc02b88a00decd495913643aa5ff705Gustavo Padovan	spin_unlock(&rfcomm_dev_lock);
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dl->dev_num = n;
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size = sizeof(*dl) + n * sizeof(*di);
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = copy_to_user(arg, dl, size);
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(dl);
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err ? -EFAULT : 0;
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rfcomm_get_dev_info(void __user *arg)
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev *dev;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev_info di;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("");
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(&di, arg, sizeof(di)))
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
502285b4e90318dcf421a00b2ac3fe8ab713f3281e3Andrei Emeltchenko	dev = rfcomm_dev_get(di.id);
503285b4e90318dcf421a00b2ac3fe8ab713f3281e3Andrei Emeltchenko	if (!dev)
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	di.flags   = dev->flags;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	di.channel = dev->channel;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	di.state   = dev->dlc->state;
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bacpy(&di.src, &dev->src);
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bacpy(&di.dst, &dev->dst);
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_to_user(arg, &di, sizeof(di)))
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -EFAULT;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51567054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby	tty_port_put(&dev->port);
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("cmd %d arg %p", cmd, arg);
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RFCOMMCREATEDEV:
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rfcomm_create_dev(sk, arg);
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RFCOMMRELEASEDEV:
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rfcomm_release_dev(arg);
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RFCOMMGETDEVLIST:
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rfcomm_get_dev_list(arg);
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case RFCOMMGETDEVINFO:
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rfcomm_get_dev_info(arg);
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ---- DLC callbacks ---- */
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev *dev = dlc->owner;
5448e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
545a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann	if (!dev) {
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree_skb(skb);
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5502e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby	if (!skb_queue_empty(&dev->pending)) {
551a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann		skb_queue_tail(&dev->pending, skb);
552a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann		return;
553a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann	}
554a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann
5552e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby	BT_DBG("dlc %p len %d", dlc, skb->len);
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
55705c7cd39907184328f48d3e7899f9cdd653ad336Jiri Slaby	tty_insert_flip_string(&dev->port, skb->data, skb->len);
5582e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby	tty_flip_buffer_push(&dev->port);
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree_skb(skb);
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev *dev = dlc->owner;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
5688e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("dlc %p dev %p err %d", dlc, dev, err);
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->err = err;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wake_up_interruptible(&dev->wait);
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dlc->state == BT_CLOSED) {
575f60db8c4246ac7c33448fad173bed85354b7d75eJiri Slaby		if (!dev->port.tty) {
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
577537d59af73d894750cff14f90fe2b6d77fbab15bDave Young				/* Drop DLC lock here to avoid deadlock
578537d59af73d894750cff14f90fe2b6d77fbab15bDave Young				 * 1. rfcomm_dev_get will take rfcomm_dev_lock
579537d59af73d894750cff14f90fe2b6d77fbab15bDave Young				 *    but in rfcomm_dev_add there's lock order:
580537d59af73d894750cff14f90fe2b6d77fbab15bDave Young				 *    rfcomm_dev_lock -> dlc lock
58167054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby				 * 2. tty_port_put will deadlock if it's
582537d59af73d894750cff14f90fe2b6d77fbab15bDave Young				 *    the last reference
583537d59af73d894750cff14f90fe2b6d77fbab15bDave Young				 */
584537d59af73d894750cff14f90fe2b6d77fbab15bDave Young				rfcomm_dlc_unlock(dlc);
585537d59af73d894750cff14f90fe2b6d77fbab15bDave Young				if (rfcomm_dev_get(dev->id) == NULL) {
586537d59af73d894750cff14f90fe2b6d77fbab15bDave Young					rfcomm_dlc_lock(dlc);
58777f2a45fa1ba33147fd6cc8ae546188504a822cdMarcel Holtmann					return;
588537d59af73d894750cff14f90fe2b6d77fbab15bDave Young				}
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
59077f2a45fa1ba33147fd6cc8ae546188504a822cdMarcel Holtmann				rfcomm_dev_del(dev);
59167054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby				tty_port_put(&dev->port);
592537d59af73d894750cff14f90fe2b6d77fbab15bDave Young				rfcomm_dlc_lock(dlc);
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5948e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki		} else
595f60db8c4246ac7c33448fad173bed85354b7d75eJiri Slaby			tty_hangup(dev->port.tty);
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev *dev = dlc->owner;
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
6047b9eb9e2099f6f4acd6a36bcd7820d27c3cf5ee3Timo Ter�s
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig);
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6077b9eb9e2099f6f4acd6a36bcd7820d27c3cf5ee3Timo Ter�s	if ((dev->modem_status & TIOCM_CD) && !(v24_sig & RFCOMM_V24_DV)) {
608f60db8c4246ac7c33448fad173bed85354b7d75eJiri Slaby		if (dev->port.tty && !C_CLOCAL(dev->port.tty))
609f60db8c4246ac7c33448fad173bed85354b7d75eJiri Slaby			tty_hangup(dev->port.tty);
6107b9eb9e2099f6f4acd6a36bcd7820d27c3cf5ee3Timo Ter�s	}
6117b9eb9e2099f6f4acd6a36bcd7820d27c3cf5ee3Timo Ter�s
6128e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki	dev->modem_status =
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0) |
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((v24_sig & RFCOMM_V24_RTR) ? (TIOCM_RTS | TIOCM_CTS) : 0) |
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((v24_sig & RFCOMM_V24_IC)  ? TIOCM_RI : 0) |
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((v24_sig & RFCOMM_V24_DV)  ? TIOCM_CD : 0);
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ---- TTY functions ---- */
620a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmannstatic void rfcomm_tty_copy_pending(struct rfcomm_dev *dev)
621a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann{
622a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann	struct sk_buff *skb;
623a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann	int inserted = 0;
624a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann
6252e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby	BT_DBG("dev %p", dev);
626a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann
627a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann	rfcomm_dlc_lock(dev->dlc);
628a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann
629a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann	while ((skb = skb_dequeue(&dev->pending))) {
63005c7cd39907184328f48d3e7899f9cdd653ad336Jiri Slaby		inserted += tty_insert_flip_string(&dev->port, skb->data,
63105c7cd39907184328f48d3e7899f9cdd653ad336Jiri Slaby				skb->len);
632a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann		kfree_skb(skb);
633a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann	}
634a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann
635a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann	rfcomm_dlc_unlock(dev->dlc);
636a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann
637a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann	if (inserted > 0)
6382e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby		tty_flip_buffer_push(&dev->port);
639a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann}
640a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DECLARE_WAITQUEUE(wait, current);
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev *dev;
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dlc *dlc;
646f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby	unsigned long flags;
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err, id;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6498e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki	id = tty->index;
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("tty %p id %d", tty, id);
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We don't leak this refcount. For reasons which are not entirely
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   clear, the TTY layer will call our ->close() method even if the
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   open fails. We decrease the refcount there, and decreasing it
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   here too would cause breakage. */
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = rfcomm_dev_get(id);
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6616ed93dc6427d14cdfe0b272cc0a9ee4685ce9ad7Andrei Emeltchenko	BT_DBG("dev %p dst %pMR channel %d opened %d", dev, &dev->dst,
6626ed93dc6427d14cdfe0b272cc0a9ee4685ce9ad7Andrei Emeltchenko	       dev->channel, dev->port.count);
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
664f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby	spin_lock_irqsave(&dev->port.lock, flags);
665f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby	if (++dev->port.count > 1) {
666f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby		spin_unlock_irqrestore(&dev->port.lock, flags);
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
668f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby	}
669f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby	spin_unlock_irqrestore(&dev->port.lock, flags);
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dlc = dev->dlc;
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Attach TTY and open DLC */
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_dlc_lock(dlc);
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty->driver_data = dev;
677f60db8c4246ac7c33448fad173bed85354b7d75eJiri Slaby	dev->port.tty = tty;
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_dlc_unlock(dlc);
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel);
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err < 0)
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Wait for DLC to connect */
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	add_wait_queue(&dev->wait, &wait);
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (1) {
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_current_state(TASK_INTERRUPTIBLE);
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dlc->state == BT_CLOSED) {
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -dev->err;
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dlc->state == BT_CONNECTED)
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (signal_pending(current)) {
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EINTR;
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
70389c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox		tty_unlock(tty);
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		schedule();
70589c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox		tty_lock(tty);
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_current_state(TASK_RUNNING);
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	remove_wait_queue(&dev->wait, &wait);
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
710c1a3313698895d8ad4760f98642007bf236af2e8Marcel Holtmann	if (err == 0)
711ffa6a7054d172a2f57248dff2de600ca795c5656Cornelia Huck		device_move(dev->tty_dev, rfcomm_get_device(dev),
712ffa6a7054d172a2f57248dff2de600ca795c5656Cornelia Huck			    DPM_ORDER_DEV_AFTER_PARENT);
713c1a3313698895d8ad4760f98642007bf236af2e8Marcel Holtmann
714a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann	rfcomm_tty_copy_pending(dev);
715a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann
716a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann	rfcomm_dlc_unthrottle(dev->dlc);
717a0c22f226502be6eab37a1d9bf6fb0fadf551376Marcel Holtmann
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
724f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby	unsigned long flags;
725f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7299a5df92374d65e2886b92e98dd7d873c533a83ffMarcel Holtmann	BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc,
730f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby						dev->port.count);
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
732f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby	spin_lock_irqsave(&dev->port.lock, flags);
733f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby	if (!--dev->port.count) {
734f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby		spin_unlock_irqrestore(&dev->port.lock, flags);
735acea6852f32b8805e166d885ed7e9f0c7cd10d41Dave Young		if (dev->tty_dev->parent)
736ffa6a7054d172a2f57248dff2de600ca795c5656Cornelia Huck			device_move(dev->tty_dev, NULL, DPM_ORDER_DEV_LAST);
737c1a3313698895d8ad4760f98642007bf236af2e8Marcel Holtmann
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Close DLC and dettach TTY */
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rfcomm_dlc_close(dev->dlc, 0);
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rfcomm_dlc_lock(dev->dlc);
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty->driver_data = NULL;
745f60db8c4246ac7c33448fad173bed85354b7d75eJiri Slaby		dev->port.tty = NULL;
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rfcomm_dlc_unlock(dev->dlc);
7479a5df92374d65e2886b92e98dd7d873c533a83ffMarcel Holtmann
7489a5df92374d65e2886b92e98dd7d873c533a83ffMarcel Holtmann		if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) {
749393432cd8dc02b88a00decd495913643aa5ff705Gustavo Padovan			spin_lock(&rfcomm_dev_lock);
7509a5df92374d65e2886b92e98dd7d873c533a83ffMarcel Holtmann			list_del_init(&dev->list);
751393432cd8dc02b88a00decd495913643aa5ff705Gustavo Padovan			spin_unlock(&rfcomm_dev_lock);
7529a5df92374d65e2886b92e98dd7d873c533a83ffMarcel Holtmann
75367054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby			tty_port_put(&dev->port);
7549a5df92374d65e2886b92e98dd7d873c533a83ffMarcel Holtmann		}
755f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby	} else
756f997a01e3272f08cbbf77392b846878332dafc22Jiri Slaby		spin_unlock_irqrestore(&dev->port.lock, flags);
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
75867054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby	tty_port_put(&dev->port);
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dlc *dlc = dev->dlc;
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0, sent = 0, size;
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("tty %p count %d", tty, count);
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (count) {
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size = min_t(uint, count, dlc->mtu);
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, GFP_ATOMIC);
7748e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!skb)
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(skb_put(skb, size), buf + sent, size);
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
782285b4e90318dcf421a00b2ac3fe8ab713f3281e3Andrei Emeltchenko		err = rfcomm_dlc_send(dlc, skb);
783285b4e90318dcf421a00b2ac3fe8ab713f3281e3Andrei Emeltchenko		if (err < 0) {
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree_skb(skb);
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sent  += size;
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		count -= size;
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sent ? sent : err;
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rfcomm_tty_write_room(struct tty_struct *tty)
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int room;
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("tty %p", tty);
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
802b6e557fbf1dbba8cfa667a25503e5dbd0e9330b7Marcel Holtmann	if (!dev || !dev->dlc)
803b6e557fbf1dbba8cfa667a25503e5dbd0e9330b7Marcel Holtmann		return 0;
804b6e557fbf1dbba8cfa667a25503e5dbd0e9330b7Marcel Holtmann
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc);
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (room < 0)
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		room = 0;
808b6e557fbf1dbba8cfa667a25503e5dbd0e9330b7Marcel Holtmann
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return room;
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8126caa76b7786891b42b66a0e61e2c2fff2c884620Alan Coxstatic int rfcomm_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("tty %p cmd 0x%02x", tty, cmd);
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TCGETS:
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BT_DBG("TCGETS is not supported");
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOIOCTLCMD;
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TCSETS:
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BT_DBG("TCSETS is not supported");
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOIOCTLCMD;
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TIOCMIWAIT:
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BT_DBG("TIOCMIWAIT");
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TIOCGSERIAL:
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BT_ERR("TIOCGSERIAL is not supported");
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOIOCTLCMD;
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TIOCSSERIAL:
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BT_ERR("TIOCSSERIAL is not supported");
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOIOCTLCMD;
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TIOCSERGSTRUCT:
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BT_ERR("TIOCSERGSTRUCT is not supported");
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOIOCTLCMD;
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TIOCSERGETLSR:
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BT_ERR("TIOCSERGETLSR is not supported");
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOIOCTLCMD;
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case TIOCSERCONFIG:
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BT_ERR("TIOCSERCONFIG is not supported");
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOIOCTLCMD;
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOIOCTLCMD;	/* ioctls which we must ignore */
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOIOCTLCMD;
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
857606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Coxstatic void rfcomm_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
859adc8d746caa67fff4b53ba3e5163a6cbacc3b523Alan Cox	struct ktermios *new = &tty->termios;
8603a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	int old_baud_rate = tty_termios_baud_rate(old);
8613a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	int new_baud_rate = tty_termios_baud_rate(new);
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8633a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	u8 baud, data_bits, stop_bits, parity, x_on, x_off;
8643a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	u16 changes = 0;
8653a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter
8663a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
8673a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter
8683a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	BT_DBG("tty %p termios %p", tty, old);
8693a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter
870ff2d367ac33b9278c9516ac1888207dac11d10b0Marcel Holtmann	if (!dev || !dev->dlc || !dev->dlc->session)
871cb19d9ea2ce2bcbe291d3d48e3501dc4f33ba627Marcel Holtmann		return;
872cb19d9ea2ce2bcbe291d3d48e3501dc4f33ba627Marcel Holtmann
8733a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	/* Handle turning off CRTSCTS */
8748e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki	if ((old->c_cflag & CRTSCTS) && !(new->c_cflag & CRTSCTS))
8753a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		BT_DBG("Turning off CRTSCTS unsupported");
8763a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter
8773a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	/* Parity on/off and when on, odd/even */
8783a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	if (((old->c_cflag & PARENB) != (new->c_cflag & PARENB)) ||
879285b4e90318dcf421a00b2ac3fe8ab713f3281e3Andrei Emeltchenko			((old->c_cflag & PARODD) != (new->c_cflag & PARODD))) {
8803a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		changes |= RFCOMM_RPN_PM_PARITY;
8813a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		BT_DBG("Parity change detected.");
8823a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	}
8833a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter
8843a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	/* Mark and space parity are not supported! */
8853a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	if (new->c_cflag & PARENB) {
8863a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		if (new->c_cflag & PARODD) {
8873a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter			BT_DBG("Parity is ODD");
8883a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter			parity = RFCOMM_RPN_PARITY_ODD;
8893a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		} else {
8903a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter			BT_DBG("Parity is EVEN");
8913a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter			parity = RFCOMM_RPN_PARITY_EVEN;
8923a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		}
8933a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	} else {
8943a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		BT_DBG("Parity is OFF");
8953a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		parity = RFCOMM_RPN_PARITY_NONE;
8963a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	}
8973a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter
8983a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	/* Setting the x_on / x_off characters */
8993a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	if (old->c_cc[VSTOP] != new->c_cc[VSTOP]) {
9003a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		BT_DBG("XOFF custom");
9013a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		x_on = new->c_cc[VSTOP];
9023a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		changes |= RFCOMM_RPN_PM_XON;
9033a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	} else {
9043a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		BT_DBG("XOFF default");
9053a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		x_on = RFCOMM_RPN_XON_CHAR;
9063a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	}
9073a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter
9083a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	if (old->c_cc[VSTART] != new->c_cc[VSTART]) {
9093a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		BT_DBG("XON custom");
9103a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		x_off = new->c_cc[VSTART];
9113a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		changes |= RFCOMM_RPN_PM_XOFF;
9123a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	} else {
9133a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		BT_DBG("XON default");
9143a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		x_off = RFCOMM_RPN_XOFF_CHAR;
9153a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	}
9163a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter
9173a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	/* Handle setting of stop bits */
9183a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	if ((old->c_cflag & CSTOPB) != (new->c_cflag & CSTOPB))
9193a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		changes |= RFCOMM_RPN_PM_STOP;
9203a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter
9213a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	/* POSIX does not support 1.5 stop bits and RFCOMM does not
9223a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	 * support 2 stop bits. So a request for 2 stop bits gets
9233a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	 * translated to 1.5 stop bits */
924285b4e90318dcf421a00b2ac3fe8ab713f3281e3Andrei Emeltchenko	if (new->c_cflag & CSTOPB)
9253a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		stop_bits = RFCOMM_RPN_STOP_15;
926285b4e90318dcf421a00b2ac3fe8ab713f3281e3Andrei Emeltchenko	else
9273a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		stop_bits = RFCOMM_RPN_STOP_1;
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9293a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	/* Handle number of data bits [5-8] */
9308e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki	if ((old->c_cflag & CSIZE) != (new->c_cflag & CSIZE))
9313a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		changes |= RFCOMM_RPN_PM_DATA;
9323a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter
9333a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	switch (new->c_cflag & CSIZE) {
9343a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	case CS5:
9353a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		data_bits = RFCOMM_RPN_DATA_5;
9363a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		break;
9373a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	case CS6:
9383a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		data_bits = RFCOMM_RPN_DATA_6;
9393a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		break;
9403a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	case CS7:
9413a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		data_bits = RFCOMM_RPN_DATA_7;
9423a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		break;
9433a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	case CS8:
9443a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		data_bits = RFCOMM_RPN_DATA_8;
9453a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		break;
9463a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	default:
9473a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		data_bits = RFCOMM_RPN_DATA_8;
9483a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		break;
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9503a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter
9513a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	/* Handle baudrate settings */
9523a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	if (old_baud_rate != new_baud_rate)
9533a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		changes |= RFCOMM_RPN_PM_BITRATE;
9543a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter
9553a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	switch (new_baud_rate) {
9563a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	case 2400:
9573a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		baud = RFCOMM_RPN_BR_2400;
9583a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		break;
9593a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	case 4800:
9603a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		baud = RFCOMM_RPN_BR_4800;
9613a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		break;
9623a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	case 7200:
9633a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		baud = RFCOMM_RPN_BR_7200;
9643a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		break;
9653a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	case 9600:
9663a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		baud = RFCOMM_RPN_BR_9600;
9673a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		break;
9688e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki	case 19200:
9693a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		baud = RFCOMM_RPN_BR_19200;
9703a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		break;
9713a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	case 38400:
9723a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		baud = RFCOMM_RPN_BR_38400;
9733a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		break;
9743a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	case 57600:
9753a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		baud = RFCOMM_RPN_BR_57600;
9763a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		break;
9773a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	case 115200:
9783a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		baud = RFCOMM_RPN_BR_115200;
9793a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		break;
9803a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	case 230400:
9813a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		baud = RFCOMM_RPN_BR_230400;
9823a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		break;
9833a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	default:
9843a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		/* 9600 is standard accordinag to the RFCOMM specification */
9853a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		baud = RFCOMM_RPN_BR_9600;
9863a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		break;
9878e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki
9883a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	}
9893a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter
9903a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	if (changes)
9913a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		rfcomm_send_rpn(dev->dlc->session, 1, dev->dlc->dlci, baud,
9923a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter				data_bits, stop_bits, parity,
9933a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter				RFCOMM_RPN_FLOW_NONE, x_on, x_off, changes);
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_tty_throttle(struct tty_struct *tty)
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("tty %p dev %p", tty, dev);
10013a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_dlc_throttle(dev->dlc);
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_tty_unthrottle(struct tty_struct *tty)
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("tty %p dev %p", tty, dev);
10103a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_dlc_unthrottle(dev->dlc);
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rfcomm_tty_chars_in_buffer(struct tty_struct *tty)
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("tty %p dev %p", tty, dev);
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1020b6e557fbf1dbba8cfa667a25503e5dbd0e9330b7Marcel Holtmann	if (!dev || !dev->dlc)
1021b6e557fbf1dbba8cfa667a25503e5dbd0e9330b7Marcel Holtmann		return 0;
1022b6e557fbf1dbba8cfa667a25503e5dbd0e9330b7Marcel Holtmann
1023b6e557fbf1dbba8cfa667a25503e5dbd0e9330b7Marcel Holtmann	if (!skb_queue_empty(&dev->dlc->tx_queue))
1024b6e557fbf1dbba8cfa667a25503e5dbd0e9330b7Marcel Holtmann		return dev->dlc->mtu;
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_tty_flush_buffer(struct tty_struct *tty)
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("tty %p dev %p", tty, dev);
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1035b6e557fbf1dbba8cfa667a25503e5dbd0e9330b7Marcel Holtmann	if (!dev || !dev->dlc)
1036b6e557fbf1dbba8cfa667a25503e5dbd0e9330b7Marcel Holtmann		return;
1037b6e557fbf1dbba8cfa667a25503e5dbd0e9330b7Marcel Holtmann
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_purge(&dev->dlc->tx_queue);
1039a352def21a642133758b868c71bee12ab34ad5c5Alan Cox	tty_wakeup(tty);
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch)
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("tty %p ch %c", tty, ch);
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("tty %p timeout %d", tty, timeout);
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rfcomm_tty_hangup(struct tty_struct *tty)
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("tty %p dev %p", tty, dev);
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1058b6e557fbf1dbba8cfa667a25503e5dbd0e9330b7Marcel Holtmann	if (!dev)
1059b6e557fbf1dbba8cfa667a25503e5dbd0e9330b7Marcel Holtmann		return;
1060b6e557fbf1dbba8cfa667a25503e5dbd0e9330b7Marcel Holtmann
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_tty_flush_buffer(tty);
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
106377f2a45fa1ba33147fd6cc8ae546188504a822cdMarcel Holtmann	if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
106477f2a45fa1ba33147fd6cc8ae546188504a822cdMarcel Holtmann		if (rfcomm_dev_get(dev->id) == NULL)
106577f2a45fa1ba33147fd6cc8ae546188504a822cdMarcel Holtmann			return;
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rfcomm_dev_del(dev);
106767054019289ff11a7ffbc1a5d3c95aeb36e2f03eJiri Slaby		tty_port_put(&dev->port);
106877f2a45fa1ba33147fd6cc8ae546188504a822cdMarcel Holtmann	}
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
107160b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int rfcomm_tty_tiocmget(struct tty_struct *tty)
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10738e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("tty %p dev %p", tty, dev);
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10778e87d14255acffeee36873de226dc25c11b5f46dYOSHIFUJI Hideaki	return dev->modem_status;
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
108020b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int rfcomm_tty_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10823a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
10833a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	struct rfcomm_dlc *dlc = dev->dlc;
10843a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	u8 v24_sig;
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("tty %p dev %p set 0x%02x clear 0x%02x", tty, dev, set, clear);
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10883a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	rfcomm_dlc_get_modem_status(dlc, &v24_sig);
10893a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter
10903a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	if (set & TIOCM_DSR || set & TIOCM_DTR)
10913a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		v24_sig |= RFCOMM_V24_RTC;
10923a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	if (set & TIOCM_RTS || set & TIOCM_CTS)
10933a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		v24_sig |= RFCOMM_V24_RTR;
10943a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	if (set & TIOCM_RI)
10953a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		v24_sig |= RFCOMM_V24_IC;
10963a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	if (set & TIOCM_CD)
10973a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		v24_sig |= RFCOMM_V24_DV;
10983a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter
10993a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	if (clear & TIOCM_DSR || clear & TIOCM_DTR)
11003a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		v24_sig &= ~RFCOMM_V24_RTC;
11013a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	if (clear & TIOCM_RTS || clear & TIOCM_CTS)
11023a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		v24_sig &= ~RFCOMM_V24_RTR;
11033a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	if (clear & TIOCM_RI)
11043a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		v24_sig &= ~RFCOMM_V24_IC;
11053a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	if (clear & TIOCM_CD)
11063a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter		v24_sig &= ~RFCOMM_V24_DV;
11073a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter
11083a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	rfcomm_dlc_set_modem_status(dlc, v24_sig);
11093a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter
11103a5e903c09aed19ca4a1bb26d87b8d6461a93818J. Suter	return 0;
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ---- TTY structure ---- */
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1115b68e31d0ebbcc909d1941f9f230c9d062a3a13d3Jeff Dikestatic const struct tty_operations rfcomm_ops = {
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.open			= rfcomm_tty_open,
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.close			= rfcomm_tty_close,
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write			= rfcomm_tty_write,
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write_room		= rfcomm_tty_write_room,
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.chars_in_buffer	= rfcomm_tty_chars_in_buffer,
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.flush_buffer		= rfcomm_tty_flush_buffer,
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.ioctl			= rfcomm_tty_ioctl,
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.throttle		= rfcomm_tty_throttle,
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.unthrottle		= rfcomm_tty_unthrottle,
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_termios		= rfcomm_tty_set_termios,
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.send_xchar		= rfcomm_tty_send_xchar,
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hangup			= rfcomm_tty_hangup,
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.wait_until_sent	= rfcomm_tty_wait_until_sent,
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.tiocmget		= rfcomm_tty_tiocmget,
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.tiocmset		= rfcomm_tty_tiocmset,
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11332f8362afcd2da8b313ec3cc04a50af19d3592972Gustavo Padovanint __init rfcomm_init_ttys(void)
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11355ada9913630d48438f2e07551af43cbf297372d4David Herrmann	int error;
11365ada9913630d48438f2e07551af43cbf297372d4David Herrmann
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_tty_driver = alloc_tty_driver(RFCOMM_TTY_PORTS);
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!rfcomm_tty_driver)
11395ada9913630d48438f2e07551af43cbf297372d4David Herrmann		return -ENOMEM;
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_tty_driver->driver_name	= "rfcomm";
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_tty_driver->name		= "rfcomm";
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_tty_driver->major	= RFCOMM_TTY_MAJOR;
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_tty_driver->minor_start	= RFCOMM_TTY_MINOR;
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_tty_driver->type		= TTY_DRIVER_TYPE_SERIAL;
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_tty_driver->subtype	= SERIAL_TYPE_NORMAL;
1147331b831983f9d706f4a40d08a996d5c2c7a6ea7bGreg Kroah-Hartman	rfcomm_tty_driver->flags	= TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_tty_driver->init_termios	= tty_std_termios;
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rfcomm_tty_driver->init_termios.c_cflag	= B9600 | CS8 | CREAD | HUPCL | CLOCAL;
1150ca37bdd53b5af06d00e792f2415b93206aa2a541Marcel Holtmann	rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON;
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11535ada9913630d48438f2e07551af43cbf297372d4David Herrmann	error = tty_register_driver(rfcomm_tty_driver);
11545ada9913630d48438f2e07551af43cbf297372d4David Herrmann	if (error) {
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BT_ERR("Can't register RFCOMM TTY driver");
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		put_tty_driver(rfcomm_tty_driver);
11575ada9913630d48438f2e07551af43cbf297372d4David Herrmann		return error;
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_INFO("RFCOMM TTY layer initialized");
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
116528e9509b1270e5cfa8bb3c5ff51f39214aa09262Gustavo Padovanvoid rfcomm_cleanup_ttys(void)
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty_unregister_driver(rfcomm_tty_driver);
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	put_tty_driver(rfcomm_tty_driver);
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1170