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