linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [Bluez-devel] [PATCH] Fixes in rfcomm tty
@ 2007-12-14  1:19 Denis KENZIOR
  2007-12-14 15:21 ` [Bluez-devel] [PATCH] Fixes in headset_send Alok
  0 siblings, 1 reply; 2+ messages in thread
From: Denis KENZIOR @ 2007-12-14  1:19 UTC (permalink / raw)
  To: bluez-devel

[-- Attachment #1: Type: text/plain, Size: 685 bytes --]

Marcel,

This patch fixes two issues in the RFCOMM tty support:

1)  If the TTY socket receives data before TTY is created, or the TTY is not 
opened (e.g. on devfs) then the data is discarded.  This makes it impossible 
to support some protocols which send data right away, e.g. DUN and HFP

2)  The serial core sends us lots of 1 byte requests when dealing with 
canonical ttys (e.g. ones that echo).  This attempts to fix this issue by 
tweaking how the wfree is handled and also tries to be intelligent in the 
handling these 1 byte requests.  Currently once the TTY runs out of 
TX_Credits, it will just append the pending 1 byte requests onto the tail of 
the TX_Queue. 

-Denis

[-- Attachment #2: rfcomm-tty-keep-socket-data.patch --]
[-- Type: text/x-diff, Size: 7425 bytes --]

diff -r -U5 a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
--- a/net/bluetooth/rfcomm/core.c	2007-08-23 09:23:54.000000000 +1000
+++ b/net/bluetooth/rfcomm/core.c	2007-12-14 11:08:54.000000000 +1000
@@ -457,11 +457,10 @@
 	BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len);
 
 	if (len > d->mtu)
 		return -EINVAL;
 
-	rfcomm_make_uih(skb, d->addr);
 	skb_queue_tail(&d->tx_queue, skb);
 
 	if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags))
 		rfcomm_schedule(RFCOMM_SCHED_TX);
 	return len;
@@ -1021,10 +1020,11 @@
 		put_unaligned(htobs(__len16(len)), (__le16 *) &hdr->len);
 	} else {
 		hdr = (void *) skb_push(skb, 3);
 		hdr->len = __len8(len);
 	}
+	
 	hdr->addr = addr;
 	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
 
 	crc = skb_put(skb, 1);
 	*crc = __fcs((void *) hdr);
@@ -1673,19 +1673,23 @@
 	}
 
 	if (test_bit(RFCOMM_TX_THROTTLED, &d->flags))
 		return skb_queue_len(&d->tx_queue);
 
+	/* Need to lock this in case the tty driver might be messing with the tx queue */
+	rfcomm_dlc_lock(d);
 	while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) {
+		rfcomm_make_uih(skb, d->addr);
 		err = rfcomm_send_frame(d->session, skb->data, skb->len);
 		if (err < 0) {
 			skb_queue_head(&d->tx_queue, skb);
 			break;
 		}
 		kfree_skb(skb);
 		d->tx_credits--;
 	}
+	rfcomm_dlc_unlock(d);
 
 	if (d->cfc && !d->tx_credits) {
 		/* We're out of TX credits.
 		 * Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */
 		set_bit(RFCOMM_TX_THROTTLED, &d->flags);
diff -r -U5 a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
--- a/net/bluetooth/rfcomm/tty.c	2007-08-23 09:23:54.000000000 +1000
+++ b/net/bluetooth/rfcomm/tty.c	2007-12-14 11:13:23.000000000 +1000
@@ -75,20 +75,25 @@
 	struct tasklet_struct   wakeup_task;
 
 	struct device		*tty_dev;
 
 	atomic_t 		wmem_alloc;
+
+	struct tasklet_struct	copy_task;
+	struct sk_buff_head	rx_queue;
+	atomic_t		rxq_mem_alloc;
 };
 
 static LIST_HEAD(rfcomm_dev_list);
 static DEFINE_RWLOCK(rfcomm_dev_lock);
 
 static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
 static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
 static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
 
 static void rfcomm_tty_wakeup(unsigned long arg);
+static void rfcomm_tty_copy_buffered(unsigned long arg);
 
 /* ---- Device functions ---- */
 static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
 {
 	struct rfcomm_dlc *dlc = dev->dlc;
@@ -192,10 +197,12 @@
 static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
 {
 	struct rfcomm_dev *dev;
 	struct list_head *head = &rfcomm_dev_list, *p;
 	int err = 0;
+	struct sock *sk;
+	struct sk_buff *skb;
 
 	BT_DBG("id %d channel %d", req->dev_id, req->channel);
 
 	dev = kzalloc(sizeof(struct rfcomm_dev), GFP_KERNEL);
 	if (!dev)
@@ -248,12 +255,24 @@
 	dev->flags = req->flags &
 		((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
 
 	init_waitqueue_head(&dev->wait);
 	tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
+	skb_queue_head_init(&dev->rx_queue);
+	tasklet_init(&dev->copy_task, rfcomm_tty_copy_buffered, (unsigned long) dev);
 
 	rfcomm_dlc_lock(dlc);
+	if (req->flags & (1 << RFCOMM_REUSE_DLC)) {
+		sk = dlc->owner;
+		atomic_set(&dev->rxq_mem_alloc, 0);
+		while (sk && (skb = skb_dequeue(&sk->sk_receive_queue))) {
+			atomic_sub(skb->len, &sk->sk_rmem_alloc);
+			atomic_add(skb->len, &dev->rxq_mem_alloc);
+			skb_queue_tail(&dev->rx_queue, skb);
+		}
+	}
+
 	dlc->data_ready   = rfcomm_dev_data_ready;
 	dlc->state_change = rfcomm_dev_state_change;
 	dlc->modem_status = rfcomm_dev_modem_status;
 
 	dlc->owner = dev;
@@ -292,18 +311,17 @@
 }
 
 /* ---- Send buffer ---- */
 static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc)
 {
-	/* We can't let it be zero, because we don't get a callback
-	   when tx_credits becomes nonzero, hence we'd never wake up */
-	return dlc->mtu * (dlc->tx_credits?:1);
+	return RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
 }
 
 static void rfcomm_wfree(struct sk_buff *skb)
 {
 	struct rfcomm_dev *dev = (void *) skb->sk;
+	
 	atomic_sub(skb->truesize, &dev->wmem_alloc);
 	if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
 		tasklet_schedule(&dev->wakeup_task);
 	rfcomm_dev_put(dev);
 }
@@ -506,15 +524,24 @@
 static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
 {
 	struct rfcomm_dev *dev = dlc->owner;
 	struct tty_struct *tty;
 
-	if (!dev || !(tty = dev->tty)) {
+	if (!dev) {
 		kfree_skb(skb);
 		return;
 	}
 
+	if (!(tty = dev->tty) || !skb_queue_empty(&dev->rx_queue)) {
+		atomic_add(skb->len, &dev->rxq_mem_alloc);
+		skb_queue_tail(&dev->rx_queue, skb);
+
+		if (atomic_read(&dev->rxq_mem_alloc) >= RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10)
+			rfcomm_dlc_throttle(dlc);
+		return;
+	}
+
 	BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len);
 
 	tty_insert_flip_string(tty, skb->data, skb->len);
 	tty_flip_buffer_push(tty);
 
@@ -588,10 +615,35 @@
 #ifdef SERIAL_HAVE_POLL_WAIT
 	wake_up_interruptible(&tty->poll_wait);
 #endif
 }
 
+static void rfcomm_tty_copy_buffered(unsigned long arg)
+{
+	struct rfcomm_dev *dev = (void *) arg;
+	struct tty_struct *tty = dev->tty;
+	struct sk_buff *skb;
+
+	if (!tty)
+		return;
+
+	rfcomm_dlc_lock(dev->dlc);
+
+	while ((skb = skb_dequeue(&dev->rx_queue))) {
+		int inserted;
+		inserted = tty_insert_flip_string(tty, skb->data, skb->len);
+
+		kfree_skb(skb);
+	}
+
+	tty_flip_buffer_push(tty);
+
+	rfcomm_dlc_unthrottle(dev->dlc);
+	rfcomm_dlc_unlock(dev->dlc);
+	tasklet_disable(&dev->copy_task);
+}
+
 static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	struct rfcomm_dev *dev;
 	struct rfcomm_dlc *dlc;
@@ -649,10 +701,12 @@
 		schedule();
 	}
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&dev->wait, &wait);
 
+	tasklet_schedule(&dev->copy_task);
+
 	if (err == 0)
 		device_move(dev->tty_dev, rfcomm_get_device(dev));
 
 	return err;
 }
@@ -671,10 +725,11 @@
 		/* Close DLC and dettach TTY */
 		rfcomm_dlc_close(dev->dlc, 0);
 
 		clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
 		tasklet_kill(&dev->wakeup_task);
+		tasklet_kill(&dev->copy_task);
 
 		rfcomm_dlc_lock(dev->dlc);
 		tty->driver_data = NULL;
 		dev->tty = NULL;
 		rfcomm_dlc_unlock(dev->dlc);
@@ -690,14 +745,30 @@
 	struct sk_buff *skb;
 	int err = 0, sent = 0, size;
 
 	BT_DBG("tty %p count %d", tty, count);
 
+	/* We get lots of 1 byte requests in canonical mode */
+	/* So we just put them on the tail of our tx queue */
+	/* if possible */
+	
+	rfcomm_dlc_lock(dlc);
+	skb = skb_peek_tail(&dlc->tx_queue);
+	if (skb) {
+		size = min_t(uint, count, dlc->mtu - skb->len);
+		memcpy(skb_put(skb, size), buf + sent, size);
+		
+		sent += size;
+		count -= size;
+	}
+	rfcomm_dlc_unlock(dlc);
+	skb = 0;
+
 	while (count) {
 		size = min_t(uint, count, dlc->mtu);
 
-		skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, GFP_ATOMIC);
+		skb = rfcomm_wmalloc(dev, dlc->mtu + RFCOMM_SKB_RESERVE, GFP_ATOMIC);
 
 		if (!skb)
 			break;
 
 		skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
@@ -964,12 +1035,10 @@
 	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)
 		tty->ldisc.write_wakeup(tty);
 }
 
 static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch)

[-- Attachment #3: Type: text/plain, Size: 308 bytes --]

-------------------------------------------------------------------------
SF.Net email is sponsored by:
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services
for just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace

[-- Attachment #4: Type: text/plain, Size: 164 bytes --]

_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel

^ permalink raw reply	[flat|nested] 2+ messages in thread

* [Bluez-devel]  [PATCH] Fixes in headset_send
  2007-12-14  1:19 [Bluez-devel] [PATCH] Fixes in rfcomm tty Denis KENZIOR
@ 2007-12-14 15:21 ` Alok
  0 siblings, 0 replies; 2+ messages in thread
From: Alok @ 2007-12-14 15:21 UTC (permalink / raw)
  To: BlueZ development

[-- Attachment #1: Type: text/plain, Size: 155 bytes --]

Hello, 

The following patch fixes headset_send(). It uses write() instead of
g_io_channel_write().

Let me know if anything needs to be changed. 

-Alok.

[-- Attachment #2: headset_send.patch --]
[-- Type: text/x-patch, Size: 924 bytes --]

diff --git a/audio/headset.c b/audio/headset.c
index 446c1eb..2b9bfc8 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -136,7 +136,8 @@ static int headset_send(struct headset *hs, char *format, ...)
 {
 	char rsp[BUF_SIZE];
 	va_list ap;
-	gsize total_written, written, count;
+	ssize_t total_written, written, count;
+	int fd;
 
 	va_start(ap, format);
 	count = vsnprintf(rsp, sizeof(rsp), format, ap);
@@ -151,14 +152,12 @@ static int headset_send(struct headset *hs, char *format, ...)
 	}
 
 	written = total_written = 0;
+	fd = g_io_channel_unix_get_fd(hs->rfcomm);
 
 	while (total_written < count) {
-		GIOError io_err;
-
-		io_err = g_io_channel_write(hs->rfcomm, rsp + total_written,
-						count - total_written,
-						&written);
-		if (io_err != G_IO_ERROR_NONE)
+		written = write(fd, rsp + total_written,
+				count - total_written);
+		if (written < 0)
 			return -errno;
 
 		total_written += written;

[-- Attachment #3: Type: text/plain, Size: 308 bytes --]

-------------------------------------------------------------------------
SF.Net email is sponsored by:
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services
for just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace

[-- Attachment #4: Type: text/plain, Size: 164 bytes --]

_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel

^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2007-12-14 15:21 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-12-14  1:19 [Bluez-devel] [PATCH] Fixes in rfcomm tty Denis KENZIOR
2007-12-14 15:21 ` [Bluez-devel] [PATCH] Fixes in headset_send Alok

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).