pcm_bluetooth.c revision 9217b7d4f85216946943ab588e06b6bcd2f1b5bc
1e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann/*
2e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *
3e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  BlueZ - Bluetooth protocol stack for Linux
4e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *
5e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  Copyright (C) 2004-2007  Marcel Holtmann <marcel@holtmann.org>
6e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *
7e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *
8e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  This library is free software; you can redistribute it and/or
9e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  modify it under the terms of the GNU Lesser General Public
10e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  License as published by the Free Software Foundation; either
11e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  version 2.1 of the License, or (at your option) any later version.
12e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *
13e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  This library is distributed in the hope that it will be useful,
14e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  Lesser General Public License for more details.
17e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *
18e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  You should have received a copy of the GNU Lesser General Public
19e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  License along with this library; if not, write to the Free Software
20e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *
22e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann */
23e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann
24e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann#ifdef HAVE_CONFIG_H
25e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann#include <config.h>
26e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann#endif
275ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann
28b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann#include <sys/socket.h>
29b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann#include <sys/un.h>
30b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
315ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann#include <alsa/asoundlib.h>
325ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann#include <alsa/pcm_external.h>
335ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann
348742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#include <bluetooth/bluetooth.h>
358742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#include <bluetooth/sco.h>
368742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
37b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann#include "ipc.h"
38b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
39b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann#define DBG(fmt, arg...)  printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
40b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
418742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#ifndef SCO_TXBUFS
428742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#define SCO_TXBUFS 0x03
438742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#endif
448742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
458742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#ifndef SCO_RXBUFS
468742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#define SCO_RXBUFS 0x04
478742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#endif
488742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
49b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstruct bluetooth_data {
50b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	snd_pcm_ioplug_t io;
51b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	snd_pcm_sframes_t hw_ptr;
528742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct ipc_data_cfg cfg;	/* Bluetooth device config */
538742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	int sock;			/* Daemon unix socket */
548742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	uint8_t *buffer;		/* Transfer buffer */
558742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	uint8_t count;			/* Transfer buffer counter */
56b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann};
57b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
58b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstatic int bluetooth_start(snd_pcm_ioplug_t *io)
59b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann{
609217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg	DBG("bluetooth_start %p", io);
61b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
62b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return 0;
63b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann}
64b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
65b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstatic int bluetooth_stop(snd_pcm_ioplug_t *io)
66b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann{
679217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg	DBG("bluetooth_stop %p", io);
68b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
69b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return 0;
70b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann}
71b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
72b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstatic snd_pcm_sframes_t bluetooth_pointer(snd_pcm_ioplug_t *io)
73b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann{
74b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	struct bluetooth_data *data = io->private_data;
75b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
769217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg	DBG("bluetooth_pointer %p", io);
77b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
788742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("hw_ptr=%lu", data->hw_ptr);
79b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
80b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return data->hw_ptr;
81b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann}
82b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
83b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstatic int bluetooth_close(snd_pcm_ioplug_t *io)
84b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann{
85b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	struct bluetooth_data *data = io->private_data;
86b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
879217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg	DBG("bluetooth_close %p", io);
88b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
89b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	free(data);
90b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
91b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return 0;
92b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann}
93b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
948742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentzstatic int bluetooth_prepare(snd_pcm_ioplug_t *io)
958742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz{
968742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct bluetooth_data *data = io->private_data;
978742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
9800c71248e732de0230c12df4240087a6b2747179Johan Hedberg	DBG("Preparing with io->period_size = %lu, io->buffer_size = %lu",
9900c71248e732de0230c12df4240087a6b2747179Johan Hedberg			io->period_size, io->buffer_size);
1008742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1019217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg	if (io->stream == SND_PCM_STREAM_PLAYBACK)
10200c71248e732de0230c12df4240087a6b2747179Johan Hedberg		/* If not null for playback, xmms doesn't display time
10300c71248e732de0230c12df4240087a6b2747179Johan Hedberg		 * correctly */
1048742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		data->hw_ptr = 0;
1059217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg	else
10600c71248e732de0230c12df4240087a6b2747179Johan Hedberg		/* ALSA library is really picky on the fact hw_ptr is not null.
10700c71248e732de0230c12df4240087a6b2747179Johan Hedberg		 * If it is, capture won't start */
1088742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		data->hw_ptr = io->period_size;
1099217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg
1108742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	return 0;
1118742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz}
1128742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1138742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentzstatic int bluetooth_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params)
1148742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz{
1158742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct bluetooth_data *data = io->private_data;
1168742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct ipc_data_cfg cfg = data->cfg;
1178742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	uint32_t period_count = io->buffer_size / io->period_size;
11800c71248e732de0230c12df4240087a6b2747179Johan Hedberg	int opt_name;
1199217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg
1209217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg	DBG("fd = %d, period_count = %d", cfg.fd, period_count);
12100c71248e732de0230c12df4240087a6b2747179Johan Hedberg
12200c71248e732de0230c12df4240087a6b2747179Johan Hedberg	opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
12300c71248e732de0230c12df4240087a6b2747179Johan Hedberg			SCO_TXBUFS : SCO_RXBUFS;
1248742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
12500c71248e732de0230c12df4240087a6b2747179Johan Hedberg	if (setsockopt(cfg.fd, SOL_SCO, opt_name, &period_count,
1269217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg			sizeof(period_count)) == 0)
1278742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		return 0;
1289217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg
12900c71248e732de0230c12df4240087a6b2747179Johan Hedberg	opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
1309217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg		SO_SNDBUF : SO_RCVBUF;
13100c71248e732de0230c12df4240087a6b2747179Johan Hedberg
13200c71248e732de0230c12df4240087a6b2747179Johan Hedberg	if (setsockopt(cfg.fd, SOL_SCO, opt_name, &period_count,
13300c71248e732de0230c12df4240087a6b2747179Johan Hedberg			sizeof(period_count)) == 0)
1349217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg		return 0;
13500c71248e732de0230c12df4240087a6b2747179Johan Hedberg
136019dd58ff876fcdaae5a7cd257822955d28b5b96Brad Midgley	/* backward compatible to the old patch */
137019dd58ff876fcdaae5a7cd257822955d28b5b96Brad Midgley
138019dd58ff876fcdaae5a7cd257822955d28b5b96Brad Midgley	opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
139019dd58ff876fcdaae5a7cd257822955d28b5b96Brad Midgley			SCO_TXBUFS : SCO_RXBUFS;
140019dd58ff876fcdaae5a7cd257822955d28b5b96Brad Midgley
141019dd58ff876fcdaae5a7cd257822955d28b5b96Brad Midgley	if (setsockopt(cfg.fd, SOL_SCO, opt_name, &period_count,
142019dd58ff876fcdaae5a7cd257822955d28b5b96Brad Midgley			sizeof(period_count)) == 0)
143019dd58ff876fcdaae5a7cd257822955d28b5b96Brad Midgley		return 0;
144019dd58ff876fcdaae5a7cd257822955d28b5b96Brad Midgley
145019dd58ff876fcdaae5a7cd257822955d28b5b96Brad Midgley	SNDERR("Unable to set number of SCO buffers: please upgrade your "
14600c71248e732de0230c12df4240087a6b2747179Johan Hedberg			"kernel!");
14700c71248e732de0230c12df4240087a6b2747179Johan Hedberg
14800c71248e732de0230c12df4240087a6b2747179Johan Hedberg	return -EINVAL;
1498742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz}
1508742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1518742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentzstatic snd_pcm_sframes_t bluetooth_read(snd_pcm_ioplug_t *io,
1528742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz					const snd_pcm_channel_area_t *areas,
1538742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz					snd_pcm_uframes_t offset,
1548742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz					snd_pcm_uframes_t size)
1558742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz{
1568742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct bluetooth_data *data = io->private_data;
1578742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct ipc_data_cfg cfg = data->cfg;
15800c71248e732de0230c12df4240087a6b2747179Johan Hedberg	snd_pcm_uframes_t frames_to_write, ret;
15900c71248e732de0230c12df4240087a6b2747179Johan Hedberg	unsigned char *buff;
16000c71248e732de0230c12df4240087a6b2747179Johan Hedberg	int nrecv;
1618742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1628742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("areas->step=%u, areas->first=%u, offset=%lu, size=%lu, io->nonblock=%u",
1638742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		areas->step, areas->first, offset, size, io->nonblock);
1648742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
16500c71248e732de0230c12df4240087a6b2747179Johan Hedberg	if (data->count > 0)
16600c71248e732de0230c12df4240087a6b2747179Johan Hedberg		goto proceed;
16700c71248e732de0230c12df4240087a6b2747179Johan Hedberg
16800c71248e732de0230c12df4240087a6b2747179Johan Hedberg	nrecv = recv(cfg.fd, data->buffer, cfg.pkt_len,
16900c71248e732de0230c12df4240087a6b2747179Johan Hedberg			MSG_WAITALL | (io->nonblock ? MSG_DONTWAIT : 0));
17000c71248e732de0230c12df4240087a6b2747179Johan Hedberg
17100c71248e732de0230c12df4240087a6b2747179Johan Hedberg	if (nrecv < 0) {
17200c71248e732de0230c12df4240087a6b2747179Johan Hedberg		ret = (errno == EPIPE) ? -EIO : -errno;
17300c71248e732de0230c12df4240087a6b2747179Johan Hedberg		goto done;
1748742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
17500c71248e732de0230c12df4240087a6b2747179Johan Hedberg
17600c71248e732de0230c12df4240087a6b2747179Johan Hedberg	if (nrecv != cfg.pkt_len) {
17700c71248e732de0230c12df4240087a6b2747179Johan Hedberg		ret = -EIO;
17800c71248e732de0230c12df4240087a6b2747179Johan Hedberg		SNDERR(strerror(-ret));
17900c71248e732de0230c12df4240087a6b2747179Johan Hedberg		goto done;
1808742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
1818742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
18200c71248e732de0230c12df4240087a6b2747179Johan Hedberg	/* Increment hardware transmition pointer */
18300c71248e732de0230c12df4240087a6b2747179Johan Hedberg	data->hw_ptr = (data->hw_ptr + cfg.pkt_len / cfg.sample_size) % io->buffer_size;
18400c71248e732de0230c12df4240087a6b2747179Johan Hedberg
18500c71248e732de0230c12df4240087a6b2747179Johan Hedbergproceed:
18600c71248e732de0230c12df4240087a6b2747179Johan Hedberg	buff = (unsigned char *) areas->addr + (areas->first + areas->step * offset) / 8;
18700c71248e732de0230c12df4240087a6b2747179Johan Hedberg
18800c71248e732de0230c12df4240087a6b2747179Johan Hedberg	if ((data->count + cfg.sample_size * size) <= cfg.pkt_len)
18900c71248e732de0230c12df4240087a6b2747179Johan Hedberg		frames_to_write = size;
19000c71248e732de0230c12df4240087a6b2747179Johan Hedberg	else
19100c71248e732de0230c12df4240087a6b2747179Johan Hedberg		frames_to_write = (cfg.pkt_len - data->count) / cfg.sample_size;
19200c71248e732de0230c12df4240087a6b2747179Johan Hedberg
19300c71248e732de0230c12df4240087a6b2747179Johan Hedberg	memcpy(buff, data->buffer + data->count, areas->step / 8 * frames_to_write);
19400c71248e732de0230c12df4240087a6b2747179Johan Hedberg	data->count += (areas->step / 8 * frames_to_write);
19500c71248e732de0230c12df4240087a6b2747179Johan Hedberg	data->count %= cfg.pkt_len;
19600c71248e732de0230c12df4240087a6b2747179Johan Hedberg
19700c71248e732de0230c12df4240087a6b2747179Johan Hedberg	/* Return written frames count */
19800c71248e732de0230c12df4240087a6b2747179Johan Hedberg	ret = frames_to_write;
19900c71248e732de0230c12df4240087a6b2747179Johan Hedberg
20000c71248e732de0230c12df4240087a6b2747179Johan Hedbergdone:
20100c71248e732de0230c12df4240087a6b2747179Johan Hedberg	DBG("returning %lu", ret);
2028742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	return ret;
2038742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz}
2048742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
2058742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentzstatic snd_pcm_sframes_t bluetooth_write(snd_pcm_ioplug_t *io,
2068742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz					const snd_pcm_channel_area_t *areas,
2078742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz					snd_pcm_uframes_t offset,
2088742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz					snd_pcm_uframes_t size)
2098742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz{
2108742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct bluetooth_data *data = io->private_data;
2118742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct ipc_data_cfg cfg = data->cfg;
2128742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	snd_pcm_sframes_t ret = 0;
2138742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	snd_pcm_uframes_t frames_to_read;
2148742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	unsigned char *buff;
21500c71248e732de0230c12df4240087a6b2747179Johan Hedberg	int rsend;
2168742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
21700c71248e732de0230c12df4240087a6b2747179Johan Hedberg	DBG("areas->step=%u, areas->first=%u, offset=%lu, size=%lu,"
21800c71248e732de0230c12df4240087a6b2747179Johan Hedberg			"io->nonblock=%u", areas->step, areas->first,
21900c71248e732de0230c12df4240087a6b2747179Johan Hedberg			offset, size, io->nonblock);
2208742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
2218742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	if ((data->count + cfg.sample_size * size) <= cfg.pkt_len)
2228742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		frames_to_read = size;
2238742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	else
2248742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		frames_to_read = (cfg.pkt_len - data->count) / cfg.sample_size;
2258742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
2268742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	/* Ready for more data */
2278742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	buff = (unsigned char *) areas->addr + (areas->first + areas->step * offset) / 8;
2288742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	memcpy(data->buffer + data->count, buff, areas->step / 8 * frames_to_read);
2298742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
23000c71248e732de0230c12df4240087a6b2747179Johan Hedberg	if ((data->count + areas->step / 8 * frames_to_read) != cfg.pkt_len) {
2318742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		/* Remember we have some frame in the pipe now */
2328742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		data->count += areas->step / 8 * frames_to_read;
2338742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		ret = frames_to_read;
23400c71248e732de0230c12df4240087a6b2747179Johan Hedberg		goto done;
2358742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
2368742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
23700c71248e732de0230c12df4240087a6b2747179Johan Hedberg	rsend = send(cfg.fd, data->buffer, cfg.pkt_len, io->nonblock ? MSG_DONTWAIT : 0);
23800c71248e732de0230c12df4240087a6b2747179Johan Hedberg	if (rsend > 0) {
23900c71248e732de0230c12df4240087a6b2747179Johan Hedberg		/* Reset count pointer */
24000c71248e732de0230c12df4240087a6b2747179Johan Hedberg		data->count = 0;
24100c71248e732de0230c12df4240087a6b2747179Johan Hedberg
24200c71248e732de0230c12df4240087a6b2747179Johan Hedberg		/* Increment hardware transmition pointer */
24300c71248e732de0230c12df4240087a6b2747179Johan Hedberg		data->hw_ptr = (data->hw_ptr + cfg.pkt_len / cfg.sample_size) % io->buffer_size;
24400c71248e732de0230c12df4240087a6b2747179Johan Hedberg
24500c71248e732de0230c12df4240087a6b2747179Johan Hedberg		ret = frames_to_read;
24600c71248e732de0230c12df4240087a6b2747179Johan Hedberg	} else if (rsend < 0)
24700c71248e732de0230c12df4240087a6b2747179Johan Hedberg		ret = (errno == EPIPE) ? -EIO : -errno;
24800c71248e732de0230c12df4240087a6b2747179Johan Hedberg	else
24900c71248e732de0230c12df4240087a6b2747179Johan Hedberg		ret = -EIO;
25000c71248e732de0230c12df4240087a6b2747179Johan Hedberg
25100c71248e732de0230c12df4240087a6b2747179Johan Hedbergdone:
2528742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("returning %d", (int)ret);
2538742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	return ret;
2548742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz}
2558742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
256b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstatic snd_pcm_ioplug_callback_t bluetooth_playback_callback = {
257b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.start		= bluetooth_start,
258b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.stop		= bluetooth_stop,
259b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.pointer	= bluetooth_pointer,
260b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.close		= bluetooth_close,
261b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.hw_params	= bluetooth_hw_params,
262b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.prepare	= bluetooth_prepare,
263b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.transfer	= bluetooth_write,
264b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann};
265b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
266b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstatic snd_pcm_ioplug_callback_t bluetooth_capture_callback = {
267b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.start		= bluetooth_start,
268b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.stop		= bluetooth_stop,
269b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.pointer	= bluetooth_pointer,
270b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.close		= bluetooth_close,
271b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.hw_params	= bluetooth_hw_params,
272b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.prepare	= bluetooth_prepare,
273b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.transfer	= bluetooth_read,
274b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann};
275b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
276b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann#define ARRAY_NELEMS(a) (sizeof((a)) / sizeof((a)[0]))
277b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
278b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstatic int bluetooth_hw_constraint(snd_pcm_ioplug_t *io)
279b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann{
280b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	snd_pcm_access_t access_list[] = {
281b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		SND_PCM_ACCESS_RW_INTERLEAVED,
282b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		/* Mmap access is really useless fo this driver, but we
283b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		 * support it because some pieces of software out there
284b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		 * insist on using it */
285b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		SND_PCM_ACCESS_MMAP_INTERLEAVED
286b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	};
287b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	unsigned int format_list[] = {
288b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		SND_PCM_FORMAT_S16_LE
289b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	};
290b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	int err;
291b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
292b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS,
293b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann					ARRAY_NELEMS(access_list), access_list);
294b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
295b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return err;
296b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
297b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT,
298b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann					ARRAY_NELEMS(format_list), format_list);
299b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
300b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return err;
301b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
302b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS, 1, 1);
303b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
304b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return err;
305b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
306b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE, 8000, 8000);
307b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
308b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return err;
309b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
310b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, 48, 48);
311b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
312b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return err;
313b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
314b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS, 2, 200);
315b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
316b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return err;
317b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
318b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return 0;
319b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann}
320b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
3218742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentzstatic int bluetooth_cfg(struct bluetooth_data *data)
3225ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann{
323d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg	int ret, len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_cfg);
324f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	struct ipc_packet *pkt;
3258742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
3268742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("Sending PKT_TYPE_CFG_REQ...");
32700c71248e732de0230c12df4240087a6b2747179Johan Hedberg
328f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	pkt = malloc(len);
32900c71248e732de0230c12df4240087a6b2747179Johan Hedberg	if (!pkt)
33000c71248e732de0230c12df4240087a6b2747179Johan Hedberg		return -ENOMEM;
33100c71248e732de0230c12df4240087a6b2747179Johan Hedberg
332f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	memset(pkt, 0, len);
333f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	pkt->type = PKT_TYPE_CFG_REQ;
334f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	pkt->role = PKT_ROLE_NONE;
335f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	pkt->error = PKT_ERROR_NONE;
33600c71248e732de0230c12df4240087a6b2747179Johan Hedberg
337d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg	ret = send(data->sock, pkt, len, 0);
338d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg	if (ret < 0) {
339d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg		ret = -errno;
340d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg		goto done;
341d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg	} else if (ret == 0) {
342d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg		ret = -EIO;
343d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg		goto done;
344d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg	}
34500c71248e732de0230c12df4240087a6b2747179Johan Hedberg
346d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg	DBG("OK - %d bytes sent", ret);
3478742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
3488742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("Waiting for response...");
3498742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
350f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	memset(pkt, 0, len);
351d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg	ret = recv(data->sock, pkt, len, 0);
352d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg	if (ret < 0) {
353d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg		ret = -errno;
354d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg		goto done;
355d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg	} else if (ret == 0) {
356d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg		ret = -EIO;
357d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg		goto done;
358d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg	}
35900c71248e732de0230c12df4240087a6b2747179Johan Hedberg
360d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg	DBG("OK - %d bytes received", ret);
361b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
362f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	if (pkt->type != PKT_TYPE_CFG_RSP) {
36300c71248e732de0230c12df4240087a6b2747179Johan Hedberg		SNDERR("Unexpected packet type received: type = %d",
36400c71248e732de0230c12df4240087a6b2747179Johan Hedberg				pkt->type);
365d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg		ret = -EINVAL;
366d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg		goto done;
3678742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
368b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
369f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	if (pkt->error != PKT_ERROR_NONE) {
37000c71248e732de0230c12df4240087a6b2747179Johan Hedberg		SNDERR("Error while configuring device: error = %d",
37100c71248e732de0230c12df4240087a6b2747179Johan Hedberg				pkt->error);
372d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg		ret = pkt->error;
373d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg		goto done;
3748742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
375b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
376f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	if (pkt->length != sizeof(struct ipc_data_cfg)) {
377019dd58ff876fcdaae5a7cd257822955d28b5b96Brad Midgley		SNDERR("Error while configuring device: packet size doesn't "
37800c71248e732de0230c12df4240087a6b2747179Johan Hedberg				"match");
379d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg		ret = -EINVAL;
380d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg		goto done;
3818742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
382b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
383f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	memcpy(&data->cfg, pkt->data, sizeof(struct ipc_data_cfg));
384b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
3858742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("Device configuration:");
386f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz
38700c71248e732de0230c12df4240087a6b2747179Johan Hedberg	DBG("fd=%d, fd_opt=%u, channels=%u, pkt_len=%u, sample_size=%u,"
38800c71248e732de0230c12df4240087a6b2747179Johan Hedberg			"rate=%u", data->cfg.fd, data->cfg.fd_opt,
38900c71248e732de0230c12df4240087a6b2747179Johan Hedberg			data->cfg.channels, data->cfg.pkt_len,
39000c71248e732de0230c12df4240087a6b2747179Johan Hedberg			data->cfg.sample_size, data->cfg.rate);
3918742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
392f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	if (data->cfg.fd == -1) {
393019dd58ff876fcdaae5a7cd257822955d28b5b96Brad Midgley		SNDERR("Error while configuring device: could not acquire "
39400c71248e732de0230c12df4240087a6b2747179Johan Hedberg				"audio socket");
395d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg		ret = -EINVAL;
396d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg		goto done;
397f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	}
398f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz
399d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg	ret = 0;
40000c71248e732de0230c12df4240087a6b2747179Johan Hedberg
401d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedbergdone:
402d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg	free(pkt);
403d95acb81523269d5e00485bc1350f8b3e6ee0050Johan Hedberg	return ret;
4048742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz}
4058742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
4068742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentzstatic int bluetooth_init(struct bluetooth_data *data)
4078742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz{
4088742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	int sk, err, id;
4098742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct sockaddr_un addr;
4108742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
411f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	if (!data)
412f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz		return -EINVAL;
413f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz
41400c71248e732de0230c12df4240087a6b2747179Johan Hedberg	memset(data, 0, sizeof(struct bluetooth_data));
41500c71248e732de0230c12df4240087a6b2747179Johan Hedberg
41600c71248e732de0230c12df4240087a6b2747179Johan Hedberg	data->sock = -1;
41700c71248e732de0230c12df4240087a6b2747179Johan Hedberg
418b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	id = abs(getpid() * rand());
419b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
420b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	sk = socket(PF_LOCAL, SOCK_DGRAM, 0);
421b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (sk < 0) {
42200c71248e732de0230c12df4240087a6b2747179Johan Hedberg		err = -errno;
423b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		SNDERR("Can't open socket");
424b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return -errno;
425b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	}
426b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
427b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	memset(&addr, 0, sizeof(addr));
428b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	addr.sun_family = AF_UNIX;
429e343f2b21a2209d5713e20ad38bbcc862897380bJohan Hedberg	snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s/%d",
430e343f2b21a2209d5713e20ad38bbcc862897380bJohan Hedberg			IPC_SOCKET_NAME, id);
431b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
4328742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("Binding address: %s", addr.sun_path + 1);
433b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
43400c71248e732de0230c12df4240087a6b2747179Johan Hedberg		err = -errno;
435b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		SNDERR("Can't bind socket");
436b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		close(sk);
43700c71248e732de0230c12df4240087a6b2747179Johan Hedberg		return err;
438b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	}
439b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
440b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	memset(&addr, 0, sizeof(addr));
441b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	addr.sun_family = AF_UNIX;
442e343f2b21a2209d5713e20ad38bbcc862897380bJohan Hedberg	snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s", IPC_SOCKET_NAME);
443b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
4448742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("Connecting to address: %s", addr.sun_path + 1);
445b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
44600c71248e732de0230c12df4240087a6b2747179Johan Hedberg		err = -errno;
447b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		SNDERR("Can't connect socket");
448b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		close(sk);
44900c71248e732de0230c12df4240087a6b2747179Johan Hedberg		return err;
450b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	}
451b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
452b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	data->sock = sk;
453b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
45400c71248e732de0230c12df4240087a6b2747179Johan Hedberg	err = bluetooth_cfg(data);
45500c71248e732de0230c12df4240087a6b2747179Johan Hedberg	if (err < 0)
4568742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		return err;
4578742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
4588742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	data->buffer = malloc(data->cfg.pkt_len);
45900c71248e732de0230c12df4240087a6b2747179Johan Hedberg	if (!data->buffer)
46000c71248e732de0230c12df4240087a6b2747179Johan Hedberg		return -ENOMEM;
4618742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
4628742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	memset(data->buffer, 0, data->cfg.pkt_len);
463b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
4648742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	return 0;
4658742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz}
4668742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
4678742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von DentzSND_PCM_PLUGIN_DEFINE_FUNC(bluetooth)
4688742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz{
469f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	struct bluetooth_data *data;
4708742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	int err;
4718742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
47200c71248e732de0230c12df4240087a6b2747179Johan Hedberg	DBG("Bluetooth PCM plugin (%s)",
4738742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		stream == SND_PCM_STREAM_PLAYBACK ? "Playback" : "Capture");
4748742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
475f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	data = malloc(sizeof(struct bluetooth_data));
47600c71248e732de0230c12df4240087a6b2747179Johan Hedberg	if (!data) {
47700c71248e732de0230c12df4240087a6b2747179Johan Hedberg		err = -ENOMEM;
47800c71248e732de0230c12df4240087a6b2747179Johan Hedberg		goto error;
47900c71248e732de0230c12df4240087a6b2747179Johan Hedberg	}
48000c71248e732de0230c12df4240087a6b2747179Johan Hedberg
481f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	err = bluetooth_init(data);
4828742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	if (err < 0)
4838742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		goto error;
4848742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
485f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	data->io.version = SND_PCM_IOPLUG_VERSION;
486f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	data->io.name = "Bluetooth Audio Device";
48700c71248e732de0230c12df4240087a6b2747179Johan Hedberg	data->io.mmap_rw = 0; /* No direct mmap communication */
4888742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
489f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	data->io.callback = stream == SND_PCM_STREAM_PLAYBACK ?
490b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		&bluetooth_playback_callback : &bluetooth_capture_callback;
491f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	data->io.poll_fd = data->cfg.fd;
492f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	data->io.poll_events = stream == SND_PCM_STREAM_PLAYBACK ?
49300c71248e732de0230c12df4240087a6b2747179Johan Hedberg					POLLOUT : POLLIN;
494f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	data->io.private_data = data;
495b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
496f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	err = snd_pcm_ioplug_create(&data->io, name, stream, mode);
497b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
498b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		goto error;
499b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
500f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	err = bluetooth_hw_constraint(&data->io);
501b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0) {
502f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz		snd_pcm_ioplug_delete(&data->io);
5038742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		goto error;
504b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	}
505b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
506f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	*pcmp = data->io.pcm;
507b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
508b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return 0;
509b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
510b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannerror:
51100c71248e732de0230c12df4240087a6b2747179Johan Hedberg	if (data) {
51200c71248e732de0230c12df4240087a6b2747179Johan Hedberg		if (data->sock >= 0)
51300c71248e732de0230c12df4240087a6b2747179Johan Hedberg			close(data->sock);
51400c71248e732de0230c12df4240087a6b2747179Johan Hedberg		free(data);
51500c71248e732de0230c12df4240087a6b2747179Johan Hedberg	}
5165ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann
517b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return err;
5185ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann}
5195ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann
5205ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel HoltmannSND_PCM_PLUGIN_SYMBOL(bluetooth);
521