-/*
+/*
RFCOMM implementation for Linux Bluetooth stack (BlueZ).
Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/
* $Id: tty.c,v 1.24 2002/10/03 01:54:38 holtmann Exp $
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
+#include <linux/capability.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/rfcomm.h>
#ifndef CONFIG_BT_RFCOMM_DEBUG
kfree(dev);
- /* It's safe to call module_put() here because socket still
+ /* It's safe to call module_put() here because socket still
holds reference to this module. */
module_put(THIS_MODULE);
}
return dev;
}
+static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
+{
+ struct hci_dev *hdev;
+ struct hci_conn *conn;
+
+ hdev = hci_get_route(&dev->dst, &dev->src);
+ if (!hdev)
+ return NULL;
+
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst);
+
+ hci_dev_put(hdev);
+
+ return conn ? &conn->dev : NULL;
+}
+
static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
{
struct rfcomm_dev *dev;
int err = 0;
BT_DBG("id %d channel %d", req->dev_id, req->channel);
-
- dev = kmalloc(sizeof(struct rfcomm_dev), GFP_KERNEL);
+
+ dev = kzalloc(sizeof(struct rfcomm_dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
- memset(dev, 0, sizeof(struct rfcomm_dev));
write_lock_bh(&rfcomm_dev_lock);
bacpy(&dev->dst, &req->dst);
dev->channel = req->channel;
- dev->flags = req->flags &
+ dev->flags = req->flags &
((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
init_waitqueue_head(&dev->wait);
dev->dlc = dlc;
rfcomm_dlc_unlock(dlc);
- /* It's safe to call __module_get() here because socket already
+ /* It's safe to call __module_get() here because socket already
holds reference to this module. */
__module_get(THIS_MODULE);
return err;
}
- tty_register_device(rfcomm_tty_driver, dev->id, NULL);
+ tty_register_device(rfcomm_tty_driver, dev->id, rfcomm_get_device(dev));
return dev->id;
}
skb->destructor = rfcomm_wfree;
}
-static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int priority)
+static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, gfp_t priority)
{
if (atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) {
struct sk_buff *skb = alloc_skb(size, priority);
{
struct rfcomm_dev *dev = dlc->owner;
struct tty_struct *tty;
-
+
if (!dev || !(tty = dev->tty)) {
kfree_skb(skb);
return;
BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len);
- if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
- register int i;
- for (i = 0; i < skb->len; i++) {
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- tty_flip_buffer_push(tty);
-
- tty_insert_flip_char(tty, skb->data[i], 0);
- }
- tty_flip_buffer_push(tty);
- } else
- tty->ldisc.receive_buf(tty, skb->data, NULL, skb->len);
+ tty_insert_flip_string(tty, skb->data, skb->len);
+ tty_flip_buffer_push(tty);
kfree_skb(skb);
}
struct rfcomm_dev *dev = dlc->owner;
if (!dev)
return;
-
+
BT_DBG("dlc %p dev %p err %d", dlc, dev, err);
dev->err = err;
rfcomm_dev_put(dev);
rfcomm_dlc_lock(dlc);
}
- } else
+ } else
tty_hangup(dev->tty);
}
}
tty_hangup(dev->tty);
}
- dev->modem_status =
+ dev->modem_status =
((v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0) |
((v24_sig & RFCOMM_V24_RTR) ? (TIOCM_RTS | TIOCM_CTS) : 0) |
((v24_sig & RFCOMM_V24_IC) ? TIOCM_RI : 0) |
BT_DBG("dev %p tty %p", dev, tty);
if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
+ (tty->ldisc.write_wakeup)(tty);
wake_up_interruptible(&tty->write_wait);
#ifdef SERIAL_HAVE_POLL_WAIT
struct rfcomm_dlc *dlc;
int err, id;
- id = tty->index;
+ id = tty->index;
BT_DBG("tty %p id %d", tty, id);
size = min_t(uint, count, dlc->mtu);
skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, GFP_ATOMIC);
-
+
if (!skb)
break;
BT_DBG("tty %p", tty);
+ if (!dev || !dev->dlc)
+ return 0;
+
room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc);
if (room < 0)
room = 0;
+
return room;
}
return -ENOIOCTLCMD;
}
-static void rfcomm_tty_set_termios(struct tty_struct *tty, struct termios *old)
+static void rfcomm_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
{
- struct termios *new = (struct termios *) tty->termios;
+ struct ktermios *new = tty->termios;
int old_baud_rate = tty_termios_baud_rate(old);
int new_baud_rate = tty_termios_baud_rate(new);
BT_DBG("tty %p termios %p", tty, old);
+ if (!dev || !dev->dlc || !dev->dlc->session)
+ return;
+
/* Handle turning off CRTSCTS */
- if ((old->c_cflag & CRTSCTS) && !(new->c_cflag & CRTSCTS))
+ if ((old->c_cflag & CRTSCTS) && !(new->c_cflag & CRTSCTS))
BT_DBG("Turning off CRTSCTS unsupported");
/* Parity on/off and when on, odd/even */
}
/* Handle number of data bits [5-8] */
- if ((old->c_cflag & CSIZE) != (new->c_cflag & CSIZE))
+ if ((old->c_cflag & CSIZE) != (new->c_cflag & CSIZE))
changes |= RFCOMM_RPN_PM_DATA;
switch (new->c_cflag & CSIZE) {
case 9600:
baud = RFCOMM_RPN_BR_9600;
break;
- case 19200:
+ case 19200:
baud = RFCOMM_RPN_BR_19200;
break;
case 38400:
/* 9600 is standard accordinag to the RFCOMM specification */
baud = RFCOMM_RPN_BR_9600;
break;
-
+
}
if (changes)
static int rfcomm_tty_chars_in_buffer(struct tty_struct *tty)
{
struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
- struct rfcomm_dlc *dlc = dev->dlc;
BT_DBG("tty %p dev %p", tty, dev);
- if (!skb_queue_empty(&dlc->tx_queue))
- return dlc->mtu;
+ if (!dev || !dev->dlc)
+ return 0;
+
+ if (!skb_queue_empty(&dev->dlc->tx_queue))
+ return dev->dlc->mtu;
return 0;
}
static void rfcomm_tty_flush_buffer(struct tty_struct *tty)
{
struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
- if (!dev)
- return;
BT_DBG("tty %p dev %p", tty, dev);
+ if (!dev || !dev->dlc)
+ return;
+
skb_queue_purge(&dev->dlc->tx_queue);
if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
static void rfcomm_tty_hangup(struct tty_struct *tty)
{
struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
- if (!dev)
- return;
BT_DBG("tty %p dev %p", tty, dev);
+ if (!dev)
+ return;
+
rfcomm_tty_flush_buffer(tty);
if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
static int rfcomm_tty_tiocmget(struct tty_struct *tty, struct file *filp)
{
- struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
BT_DBG("tty %p dev %p", tty, dev);
- return dev->modem_status;
+ return dev->modem_status;
}
static int rfcomm_tty_tiocmset(struct tty_struct *tty, struct file *filp, unsigned int set, unsigned int clear)
/* ---- TTY structure ---- */
-static struct tty_operations rfcomm_ops = {
+static const struct tty_operations rfcomm_ops = {
.open = rfcomm_tty_open,
.close = rfcomm_tty_close,
.write = rfcomm_tty_write,
rfcomm_tty_driver->owner = THIS_MODULE;
rfcomm_tty_driver->driver_name = "rfcomm";
- rfcomm_tty_driver->devfs_name = "bluetooth/rfcomm/";
rfcomm_tty_driver->name = "rfcomm";
rfcomm_tty_driver->major = RFCOMM_TTY_MAJOR;
rfcomm_tty_driver->minor_start = RFCOMM_TTY_MINOR;
rfcomm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
rfcomm_tty_driver->subtype = SERIAL_TYPE_NORMAL;
- rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+ rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
rfcomm_tty_driver->init_termios = tty_std_termios;
rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);