* Re: [Qemu-devel] [PATCH] acl: Fix use after free in qemu_acl_reset()
From: Stefan Hajnoczi @ 2011-10-31 11:55 UTC (permalink / raw)
To: Markus Armbruster; +Cc: qemu-trivial, qemu-devel
In-Reply-To: <1319814422-17952-1-git-send-email-armbru@redhat.com>
On Fri, Oct 28, 2011 at 05:07:02PM +0200, Markus Armbruster wrote:
> Reproducer:
>
> $ MALLOC_PERTURB_=234 qemu-system-x86_64 -vnc :0,acl,sasl [...]
> QEMU 0.15.50 monitor - type 'help' for more information
> (qemu) acl_add vnc.username fred allow
> acl: added rule at position 1
> (qemu) acl_reset vnc.username
> Segmentation fault (core dumped)
>
> Spotted by Coverity.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
> acl.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
Thanks, applied to the trivial patches -next tree:
http://repo.or.cz/w/qemu/stefanha.git/shortlog/refs/heads/trivial-patches-next
Stefan
^ permalink raw reply
* Re: [Qemu-trivial] [Qemu-devel] [PATCH] acl: Fix use after free in qemu_acl_reset()
From: Stefan Hajnoczi @ 2011-10-31 11:55 UTC (permalink / raw)
To: Markus Armbruster; +Cc: qemu-trivial, qemu-devel
In-Reply-To: <1319814422-17952-1-git-send-email-armbru@redhat.com>
On Fri, Oct 28, 2011 at 05:07:02PM +0200, Markus Armbruster wrote:
> Reproducer:
>
> $ MALLOC_PERTURB_=234 qemu-system-x86_64 -vnc :0,acl,sasl [...]
> QEMU 0.15.50 monitor - type 'help' for more information
> (qemu) acl_add vnc.username fred allow
> acl: added rule at position 1
> (qemu) acl_reset vnc.username
> Segmentation fault (core dumped)
>
> Spotted by Coverity.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
> acl.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
Thanks, applied to the trivial patches -next tree:
http://repo.or.cz/w/qemu/stefanha.git/shortlog/refs/heads/trivial-patches-next
Stefan
^ permalink raw reply
* Re: barebox on gta04
From: Robert Schwebel @ 2011-10-31 11:57 UTC (permalink / raw)
To: Johannes Schauer; +Cc: gta04-owner, barebox
In-Reply-To: <20111025100535.GA11941@hoothoot>
Hi Johannes,
On Tue, Oct 25, 2011 at 12:05:35PM +0200, Johannes Schauer wrote:
> > Strange. Should not be the case, no idea what's happening here.
>
> any ideas on what I can try?
Does barebox now work on your gtk04? If not, I'd be willing to help with
the port, but somebody would have to organze a hardware for us in that
case.
rsc
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply
* [U-Boot] Pull request for u-boot-marvell.git
From: Prafulla Wadaskar @ 2011-10-31 11:58 UTC (permalink / raw)
To: u-boot
Hi Albert
Please pull
The following changes since commit b3fee4e17f9f2c136b8fcfc1b7e575b6b3ccd66a:
Anatolij Gustschin (1):
ARM: dreamplug: fix compilation
are available in the git repository at:
u-boot-marvell.git ..BRANCH.NOT.VERIFIED..
Ajay Bhargav (1):
gplugD: Fix for error:MACH_TYPE_SHEEVAD undeclared
Holger Brunck (2):
arm/km: add variable waitforne to mgcoge3un
arm/km/mgcoge3un: enhance "waitforne" feature
Michael Walle (1):
kirkwood: define CONFIG_SYS_CACHELINE_SIZE
Mike Frysinger (1):
kirkwood: drop empty asm-offsets.s file
arch/arm/include/asm/arch-kirkwood/config.h | 3 ++-
board/keymile/km_arm/km_arm.c | 11 ++++++++++-
include/configs/gplugd.h | 12 +++++++++++-
include/configs/mgcoge3un.h | 2 ++
4 files changed, 25 insertions(+), 3 deletions(-)
delete mode 100644 arch/arm/cpu/arm926ejs/kirkwood/asm-offsets.s
Regards...
Prafulla . . .
^ permalink raw reply
* Re: HT (Hyper Threading) aware process scheduling doesn't work as it should
From: Henrique de Moraes Holschuh @ 2011-10-31 11:58 UTC (permalink / raw)
To: Artem S. Tashkinov; +Cc: linux-kernel
In-Reply-To: <574299906.69412.1320054001912.JavaMail.mail@webmail05>
On Mon, 31 Oct 2011, Artem S. Tashkinov wrote:
> > On Oct 31, 2011, Henrique de Moraes Holschuh wrote:
> >
> > On Sun, 30 Oct 2011, Artem S. Tashkinov wrote:
> > > > Please make sure both are set to 0. If they were not 0 at the time you
> > > > ran your tests, please retest and report back.
> > >
> > > That's 0 & 0 for me.
> >
> > How idle is your system during the test?
>
> load average: 0.00, 0.00, 0.00
I believe cpuidle will interfere with the scheduling in that case. Could
you run your test with higher loads (start with one, and go up to eight
tasks that are CPU-hogs, measuring each step)?
> I have to insist that people conduct this test on their own without trusting my
> words. Probably there's something I overlook or don't fully understand but from
What you should attempt to do is to give us a reproducible test case. A
shell script or C/perl/python/whatever program that when run clearly shows
the problem you're complaining about on your system. Failing that, a very
detailed description (read: step by step) of how you're testing things.
I can't see anything wrong in my X5550 workstation (4 cores, 8 threads,
single processor, i.e. not NUMA) running 3.0.8.
> what I see, there's a serious issue here (at least Microsoft XP and 7 work exactly
So far it looks like that, since your system is almost entirely idle, it
could be trying to minimize task-run latency by scheduling work to the few
cores/threads that are not in deep sleep (they take time to wake up, are
often cache-cold, etc).
Please use tools/power/x86/turbostat to track core usage and idle-states
instead of top/htop. That might give you better information, and I
think you will appreciate getting to know that tool. Note: turbostat
reports *averages* for each thread.
--
"One disk to rule them all, One disk to find them. One disk to bring
them all and in the darkness grind them. In the Land of Redmond
where the shadows lie." -- The Silicon Valley Tarot
Henrique Holschuh
^ permalink raw reply
* Re: [RFC 0/4] Fix hci_dev ref-counts
From: Marcel Holtmann @ 2011-10-31 11:58 UTC (permalink / raw)
To: David Herrmann; +Cc: linux-bluetooth, padovan
In-Reply-To: <1319806804-12230-1-git-send-email-dh.herrmann@googlemail.com>
Hi David,
> We currently have two reference counters for each hci_dev. This patchset tries
> to reduce this to one ref-count and fix several bugs with them. The two
> available ref-counts currently are:
>
> 1) hci_dev->dev internal
> This ref-count is increased by hci_alloc_dev() and decreased inside
> hci_free_dev(). No other code currently uses this refcount. It can be set with
> get_device() and put_device().
> When this ref-count drops zero, then the hci_dev structure is deallocated (see
> bt_link_release inside hci_sysfs.c), hence, this ref-count is the most important
> one. However, we currently do not use it correctly.
>
> 2) hci_dev->refcnt
> This ref-count is used inside hci_dev_hold/put() and practically used as if it
> would protect the hci_dev structure. However, if this ref-count drops zero, then
> the ->destruct callback is called which is used by all drivers *exclusively* to
> deallocate driver structures and *not* to deallocate or destroy the hci_dev.
actually I think we should convert the tasklets into one workqueue first
and then integrate deeper into sysfs before trying to hack around this
problem.
Our core driver registration code is from the 2.4 series and needs major
updating. The sysfs code is glued on top of it and not really well
integrated. So fixing that one properly might make some of these race
conditions go away.
Regards
Marcel
^ permalink raw reply
* config ARCH_AT91SAM9X5
From: Paul Bolle @ 2011-10-31 11:59 UTC (permalink / raw)
To: linux-arm-kernel
0) Since the commits
9baeb7e4 ("at91: Add ARCH_ID and basic cpu macros [...]"),
b9e379bc ("net/can: allow CAN_AT91 on AT91SAM9X5"), and
8c3583b6 ("at91: use structure to store the current soc")
the mainline kernel tree uses the Kconfig symbol ARCH_AT91SAM9X5 and the
preprocessor macro CONFIG_ARCH_AT91SAM9X5.
1) But there's currently no Kconfig entry ARCH_AT91SAM9X5. (Neither is
there a direct definition of the macro CONFIG_ARCH_AT91SAM9X5.)
Shouldn't a Kconfig entry for ARCH_AT91SAM9X5 be added (to
arch/arm/mach-at91/Kconfig)?
Paul Bolle
^ permalink raw reply
* Re: is there a filesystem issue with kernel 3.0.x on pandaboards?
From: Robert P. J. Day @ 2011-10-31 12:01 UTC (permalink / raw)
To: Koen Kooi; +Cc: Yocto discussion list
In-Reply-To: <BA8B50AF-70FB-4FF4-B1DA-BF9315C85EF4@dominion.thruhere.net>
On Mon, 31 Oct 2011, Koen Kooi wrote:
>
> Op 29 okt. 2011, om 15:19 heeft Robert P. J. Day het volgende geschreven:
>
> > possibly off-topic but i'm sitting in a fedora/ARM talk right
> > this minute at FSOSS/linuxfest at york u, and the presenter
> > mentioned that when building fedora for pandaboards, they had to
> > back off from kernel 3.0.4 to 2.6.35 because, in that situation,
> > the filesystem had a bad habit of switching unpredictably into
> > read-only mode.
> >
> > is this a known issue in any yocto context? again, sorry if this
> > is wandering far afield but yocto on a pandaboard was at the top
> > of my TODO list for this coming week.
>
> I'm not seeing that problem on the pandaboard that's running 3.0.x
> and angstrom. The default in angstrom/meta-ti is 2.6.35 due to
> multimedia acceleration madness.
i wish i had more info on this. the topic came up when i was
chatting with the people who run the fedora arm farm at seneca
college, so they're pretty knowledgeable. the symptom was that after
they installed a fedora ARM build with a 3.0.x kernel on their
pandaboards, when they started pounding on them with massive writes to
the root filesystem, on a regular basis, the root filesystem would
suddenly switch to read-only mode. when they backed off to a 2.6.35
kernel, all was good.
if i hear more and it sounds relevant, i'll post here.
rday
--
========================================================================
Robert P. J. Day Ottawa, Ontario, CANADA
http://crashcourse.ca
Twitter: http://twitter.com/rpjday
LinkedIn: http://ca.linkedin.com/in/rpjday
========================================================================
^ permalink raw reply
* [Buildroot] [PATCH] busybox: add 1.19.3 getty and modinfo fixes
From: Gustavo Zacarias @ 2011-10-31 12:02 UTC (permalink / raw)
To: buildroot
Signed-off-by: Gustavo Zacarias <gustavo@zacarias.com.ar>
---
.../busybox-1.19.3/busybox-1.19.3-getty.patch | 12 ++++++++++++
.../busybox-1.19.3/busybox-1.19.3-modinfo.patch | 10 ++++++++++
2 files changed, 22 insertions(+), 0 deletions(-)
create mode 100644 package/busybox/busybox-1.19.3/busybox-1.19.3-getty.patch
create mode 100644 package/busybox/busybox-1.19.3/busybox-1.19.3-modinfo.patch
diff --git a/package/busybox/busybox-1.19.3/busybox-1.19.3-getty.patch b/package/busybox/busybox-1.19.3/busybox-1.19.3-getty.patch
new file mode 100644
index 0000000..84dad6f
--- /dev/null
+++ b/package/busybox/busybox-1.19.3/busybox-1.19.3-getty.patch
@@ -0,0 +1,12 @@
+--- busybox-1.19.3/loginutils/getty.c
++++ busybox-1.19.3-getty/loginutils/getty.c
+@@ -271,7 +271,9 @@ static void termios_init(int speed)
+ #ifdef CMSPAR
+ | CMSPAR /* mark or space parity */
+ #endif
++#ifdef CBAUD
+ | CBAUD /* (output) baud rate */
++#endif
+ #ifdef CBAUDEX
+ | CBAUDEX /* (output) baud rate */
+ #endif
diff --git a/package/busybox/busybox-1.19.3/busybox-1.19.3-modinfo.patch b/package/busybox/busybox-1.19.3/busybox-1.19.3-modinfo.patch
new file mode 100644
index 0000000..9dd5c10
--- /dev/null
+++ b/package/busybox/busybox-1.19.3/busybox-1.19.3-modinfo.patch
@@ -0,0 +1,10 @@
+--- busybox-1.19.3/modutils/modinfo.c
++++ busybox-1.19.3-modinfo/modutils/modinfo.c
+@@ -13,6 +13,7 @@
+ //config:config MODINFO
+ //config: bool "modinfo"
+ //config: default y
++//config: select PLATFORM_LINUX
+ //config: help
+ //config: Show information about a Linux Kernel module
+
--
1.7.3.4
^ permalink raw reply related
* [PATCH 01/51] ARM: reset: introduce arm_arch_reset function pointer
From: Russell King - ARM Linux @ 2011-10-31 12:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111029135653.GA25057@mudshark.cambridge.arm.com>
On Sat, Oct 29, 2011 at 02:56:53PM +0100, Will Deacon wrote:
> Hi Russell,
>
> On Sat, Oct 29, 2011 at 11:21:08AM +0100, Russell King - ARM Linux wrote:
> > This would then allow everyone to hook into the restart via the same
> > method irrespective of what they want, and if they want the old
> > 'arch_reset' way, call setup_restart() themselves.
>
> Yup, it's a fantastic idea because it allows us to put all of the identity
> mapping bits into setup_restart as well. So then platforms make the choice
> about the mapping they want, rather than being told via the reboot mode.
I've now committed my patch, so if you'd like to give it an acked by,
and preferably a tested-by, I'll publish it out in a stable branch.
^ permalink raw reply
* [PATCH] SUNRPC: remove non-exclusive pipe creation from RPC pipefs
From: Stanislav Kinsbursky @ 2011-10-31 13:07 UTC (permalink / raw)
To: bfields, Trond.Myklebust
Cc: linux-nfs, xemul, neilb, netdev, linux-kernel, davem, devel
This patch-set was created in context of clone of git branch:
git://git.linux-nfs.org/projects/trondmy/nfs-2.6.git
and rebased on tag "v3.1".
SUNRPC pipefs non-exclusive pipe creation code looks obsolete. IOW, as I see
it, all pipes are creating with unique full path and only once.
Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
---
include/linux/sunrpc/rpc_pipe_fs.h | 1 -
net/sunrpc/rpc_pipe.c | 44 +++++-------------------------------
2 files changed, 6 insertions(+), 39 deletions(-)
diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h
index 271e1b2..80606ab 100644
--- a/include/linux/sunrpc/rpc_pipe_fs.h
+++ b/include/linux/sunrpc/rpc_pipe_fs.h
@@ -30,7 +30,6 @@ struct rpc_inode {
int pipelen;
int nreaders;
int nwriters;
- int nkern_readwriters;
wait_queue_head_t waitq;
#define RPC_PIPE_WAIT_FOR_OPEN 1
int flags;
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 42e4b6e..a1f23c4 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -558,7 +558,6 @@ static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry,
if (err)
return err;
rpci = RPC_I(dentry->d_inode);
- rpci->nkern_readwriters = 1;
rpci->private = private;
rpci->flags = flags;
rpci->ops = ops;
@@ -591,16 +590,12 @@ static int __rpc_unlink(struct inode *dir, struct dentry *dentry)
static int __rpc_rmpipe(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
- struct rpc_inode *rpci = RPC_I(inode);
- rpci->nkern_readwriters--;
- if (rpci->nkern_readwriters != 0)
- return 0;
rpc_close_pipes(inode);
return __rpc_unlink(dir, dentry);
}
-static struct dentry *__rpc_lookup_create(struct dentry *parent,
+static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent,
struct qstr *name)
{
struct dentry *dentry;
@@ -608,27 +603,13 @@ static struct dentry *__rpc_lookup_create(struct dentry *parent,
dentry = d_lookup(parent, name);
if (!dentry) {
dentry = d_alloc(parent, name);
- if (!dentry) {
- dentry = ERR_PTR(-ENOMEM);
- goto out_err;
- }
+ if (!dentry)
+ return ERR_PTR(-ENOMEM);
}
- if (!dentry->d_inode)
+ if (dentry->d_inode == NULL) {
d_set_d_op(dentry, &rpc_dentry_operations);
-out_err:
- return dentry;
-}
-
-static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent,
- struct qstr *name)
-{
- struct dentry *dentry;
-
- dentry = __rpc_lookup_create(parent, name);
- if (IS_ERR(dentry))
- return dentry;
- if (dentry->d_inode == NULL)
return dentry;
+ }
dput(dentry);
return ERR_PTR(-EEXIST);
}
@@ -816,22 +797,9 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name,
q.hash = full_name_hash(q.name, q.len),
mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
- dentry = __rpc_lookup_create(parent, &q);
+ dentry = __rpc_lookup_create_exclusive(parent, &q);
if (IS_ERR(dentry))
goto out;
- if (dentry->d_inode) {
- struct rpc_inode *rpci = RPC_I(dentry->d_inode);
- if (rpci->private != private ||
- rpci->ops != ops ||
- rpci->flags != flags) {
- dput (dentry);
- err = -EBUSY;
- goto out_err;
- }
- rpci->nkern_readwriters++;
- goto out;
- }
-
err = __rpc_mkpipe(dir, dentry, umode, &rpc_pipe_fops,
private, ops, flags);
if (err)
^ permalink raw reply related
* [lm-sensors] [RFC][PATCH] hwmon: add support for MCP3204/3208
From: Paul Fertser @ 2011-10-31 12:10 UTC (permalink / raw)
To: lm-sensors
Add support for these simple low-power cheap ADC ICs.
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
---
Well, adc*_in and adc_diff*_in are not mentioned in the sysfs-attributes.txt
but at least the max1111 uses the former. Waiting for your feedback.
drivers/hwmon/Kconfig | 12 +++
drivers/hwmon/Makefile | 1 +
drivers/hwmon/mcp3208.c | 254 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 267 insertions(+), 0 deletions(-)
create mode 100644 drivers/hwmon/mcp3208.c
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 0b62c3c..48ac1ab 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -787,6 +787,18 @@ config SENSORS_MAX6650
This driver can also be built as a module. If so, the module
will be called max6650.
+config SENSORS_MCP3208
+ tristate "Microchip MCP3204/3208 Multichannel, Serial 12-bit ADC chip"
+ depends on SPI_MASTER
+ help
+ Say y here to support Microchips's MCP3204/3208 ADC chips.
+
+ Since MCP3204 has only half the channels, use only adc[0-3]_in and
+ adc_diff[0-1]_in with it.
+
+ This driver can also be built as a module. If so, the module
+ will be called mcp3208.
+
config SENSORS_NTC_THERMISTOR
tristate "NTC thermistor support"
depends on EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 3c9ccef..847f6af 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -93,6 +93,7 @@ obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
+obj-$(CONFIG_SENSORS_MCP3208) += mcp3208.o
obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
diff --git a/drivers/hwmon/mcp3208.c b/drivers/hwmon/mcp3208.c
new file mode 100644
index 0000000..30bd631
--- /dev/null
+++ b/drivers/hwmon/mcp3208.c
@@ -0,0 +1,254 @@
+/*
+ * mcp3208.c - MCP3204/3208 +2.7V, Low-Power, Multichannel, Serial 12-bit ADCs
+ *
+ * Heavily based on drivers/hwmon/max1111.c
+ *
+ * Copyright (C) 2004-2005 Richard Purdie
+ *
+ * Copyright (C) 2008 Marvell International Ltd.
+ * Eric Miao <eric.miao@marvell.com>
+ *
+ * Copyright (C) 2011 Paul Fertser <fercerpav@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * publishhed by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+
+#define MCP3208_TX_BUF_SIZE 1
+#define MCP3208_RX_BUF_SIZE 2
+
+#define MCP3208_CTRL_START (1<<4)
+#define MCP3208_CTRL_SINGLE (1<<3)
+
+struct mcp3208_data {
+ struct spi_device *spi;
+ struct device *hwmon_dev;
+ struct spi_message msg;
+ struct spi_transfer xfer[2];
+ uint8_t tx_buf[MCP3208_TX_BUF_SIZE];
+ uint8_t rx_buf[MCP3208_RX_BUF_SIZE];
+ struct mutex drvdata_lock;
+ /* protect msg, xfer and buffers from multiple access */
+};
+
+static int mcp3208_read(struct device *dev, int channel)
+{
+ struct mcp3208_data *data = dev_get_drvdata(dev);
+ uint8_t v1, v2;
+ int err;
+
+ /* writing to drvdata struct is not thread safe, wait on mutex */
+ mutex_lock(&data->drvdata_lock);
+
+ data->tx_buf[0] = MCP3208_CTRL_START | channel;
+
+ err = spi_sync(data->spi, &data->msg);
+ if (err < 0) {
+ dev_err(dev, "spi_sync failed with %d\n", err);
+ mutex_unlock(&data->drvdata_lock);
+ return err;
+ }
+
+ v1 = data->rx_buf[0];
+ v2 = data->rx_buf[1];
+
+ mutex_unlock(&data->drvdata_lock);
+
+ if (v1 & (1<<6))
+ return -EINVAL;
+
+ return (v1 & 0x3f) << 6 | (v2 >> 2);
+}
+
+/*
+ * NOTE: SPI devices do not have a default 'name' attribute, which is
+ * likely to be used by hwmon applications to distinguish between
+ * different devices, explicitly add a name attribute here.
+ */
+static ssize_t show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "mcp3208\n");
+}
+
+static ssize_t show_adc(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int channel = to_sensor_dev_attr(attr)->index;
+ int ret;
+
+ ret = mcp3208_read(dev, channel);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", ret);
+}
+
+#define MCP3208_ADC_ATTR(_id) \
+ SENSOR_DEVICE_ATTR(adc##_id##_in, S_IRUGO, show_adc, \
+ NULL, _id | MCP3208_CTRL_SINGLE)
+
+#define MCP3208_DIFF_ADC_ATTR(_id) \
+ SENSOR_DEVICE_ATTR(adc_diff##_id##_in, S_IRUGO, \
+ show_adc, NULL, _id)
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+static MCP3208_ADC_ATTR(0);
+static MCP3208_ADC_ATTR(1);
+static MCP3208_ADC_ATTR(2);
+static MCP3208_ADC_ATTR(3);
+static MCP3208_ADC_ATTR(4);
+static MCP3208_ADC_ATTR(5);
+static MCP3208_ADC_ATTR(6);
+static MCP3208_ADC_ATTR(7);
+
+static MCP3208_DIFF_ADC_ATTR(0);
+static MCP3208_DIFF_ADC_ATTR(1);
+static MCP3208_DIFF_ADC_ATTR(2);
+static MCP3208_DIFF_ADC_ATTR(3);
+static MCP3208_DIFF_ADC_ATTR(4);
+static MCP3208_DIFF_ADC_ATTR(5);
+static MCP3208_DIFF_ADC_ATTR(6);
+static MCP3208_DIFF_ADC_ATTR(7);
+
+static struct attribute *mcp3208_attributes[] = {
+ &dev_attr_name.attr,
+ &sensor_dev_attr_adc0_in.dev_attr.attr,
+ &sensor_dev_attr_adc1_in.dev_attr.attr,
+ &sensor_dev_attr_adc2_in.dev_attr.attr,
+ &sensor_dev_attr_adc3_in.dev_attr.attr,
+ &sensor_dev_attr_adc4_in.dev_attr.attr,
+ &sensor_dev_attr_adc5_in.dev_attr.attr,
+ &sensor_dev_attr_adc6_in.dev_attr.attr,
+ &sensor_dev_attr_adc7_in.dev_attr.attr,
+ &sensor_dev_attr_adc_diff0_in.dev_attr.attr,
+ &sensor_dev_attr_adc_diff1_in.dev_attr.attr,
+ &sensor_dev_attr_adc_diff2_in.dev_attr.attr,
+ &sensor_dev_attr_adc_diff3_in.dev_attr.attr,
+ &sensor_dev_attr_adc_diff4_in.dev_attr.attr,
+ &sensor_dev_attr_adc_diff5_in.dev_attr.attr,
+ &sensor_dev_attr_adc_diff6_in.dev_attr.attr,
+ &sensor_dev_attr_adc_diff7_in.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group mcp3208_attr_group = {
+ .attrs = mcp3208_attributes,
+};
+
+static int __devinit setup_transfer(struct mcp3208_data *data)
+{
+ struct spi_message *m;
+ struct spi_transfer *x;
+
+ m = &data->msg;
+ x = &data->xfer[0];
+
+ spi_message_init(m);
+
+ x->tx_buf = &data->tx_buf[0];
+ x->len = MCP3208_TX_BUF_SIZE;
+ spi_message_add_tail(x, m);
+
+ x++;
+ x->rx_buf = &data->rx_buf[0];
+ x->len = MCP3208_RX_BUF_SIZE;
+ spi_message_add_tail(x, m);
+
+ return 0;
+}
+
+static int __devinit mcp3208_probe(struct spi_device *spi)
+{
+ struct mcp3208_data *data;
+ int err;
+
+ spi->bits_per_word = 8;
+ spi->mode = SPI_MODE_0;
+ err = spi_setup(spi);
+ if (err < 0)
+ return err;
+
+ data = kzalloc(sizeof(struct mcp3208_data), GFP_KERNEL);
+ if (data = NULL) {
+ dev_err(&spi->dev, "failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ err = setup_transfer(data);
+ if (err)
+ goto err_free_data;
+
+ mutex_init(&data->drvdata_lock);
+
+ data->spi = spi;
+ spi_set_drvdata(spi, data);
+
+ err = sysfs_create_group(&spi->dev.kobj, &mcp3208_attr_group);
+ if (err) {
+ dev_err(&spi->dev, "failed to create attribute group\n");
+ goto err_free_data;
+ }
+
+ data->hwmon_dev = hwmon_device_register(&spi->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ dev_err(&spi->dev, "failed to create hwmon device\n");
+ err = PTR_ERR(data->hwmon_dev);
+ goto err_remove;
+ }
+
+ return 0;
+
+err_remove:
+ sysfs_remove_group(&spi->dev.kobj, &mcp3208_attr_group);
+err_free_data:
+ kfree(data);
+ return err;
+}
+
+static int __devexit mcp3208_remove(struct spi_device *spi)
+{
+ struct mcp3208_data *data = spi_get_drvdata(spi);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&spi->dev.kobj, &mcp3208_attr_group);
+ mutex_destroy(&data->drvdata_lock);
+ kfree(data);
+ return 0;
+}
+
+static struct spi_driver mcp3208_driver = {
+ .driver = {
+ .name = "mcp3208",
+ .owner = THIS_MODULE,
+ },
+ .probe = mcp3208_probe,
+ .remove = __devexit_p(mcp3208_remove),
+};
+
+static int __init mcp3208_init(void)
+{
+ return spi_register_driver(&mcp3208_driver);
+}
+module_init(mcp3208_init);
+
+static void __exit mcp3208_exit(void)
+{
+ spi_unregister_driver(&mcp3208_driver);
+}
+module_exit(mcp3208_exit);
+
+MODULE_AUTHOR("Paul Fertser <fercerpav@gmail.com>");
+MODULE_DESCRIPTION("MCP3208 ADC Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:mcp3208");
--
1.7.2.3
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply related
* [PATCH 0/5] RFC for snd-usb: rework usb endpoint logic
From: Daniel Mack @ 2011-10-31 12:10 UTC (permalink / raw)
To: alsa-devel; +Cc: gdiffey, tiwai, clemens, linuxaudio, Daniel Mack, blablack
It's been a while since the last round of patches for this topic, so
here is a new version.
In contrast to earlier versions, I did another bunch of cleanips and
can now use input and output simultaniously.
The patches that follow are structured in a way that should make
reviews easier, as they first implement a new streaming model while
leaving the old one working, and then switch to it in a separate
patch. This way, the series is also fully bisectable.
The problems that remain is a regression in handling data streams
with feedback endpoints in full duplex mode and a hard lockup when
changing audio parameters while two streams are running. I guess the
latter is caused by missing locking.
I didn't sign-off the patches on purpose, as I would really like to
get them reviewed before they go in. Can people have a look and state
whether the whole idea is at all sane?
Thanks a lot,
Daniel
Daniel Mack (5):
ALSA: snd-usb: implement new endpoint streaming model
ALSA: snd-usb: switch over to new endpoint streaming logic
ALSA: snd-usb: remove old streaming logic
ALSA: snd-usb: set MAX_URBS to 16
ALSA: snd-usb: add support for implicit feedback
sound/usb/card.c | 6 +-
sound/usb/card.h | 56 ++-
sound/usb/endpoint.c | 1347 ++++++++++++++++++++++++--------------------------
sound/usb/endpoint.h | 31 +-
sound/usb/pcm.c | 412 +++++++++++++---
sound/usb/stream.c | 31 +-
sound/usb/usbaudio.h | 1 +
7 files changed, 1081 insertions(+), 803 deletions(-)
--
1.7.5.4
^ permalink raw reply
* [PATCH 1/5] ALSA: snd-usb: implement new endpoint streaming model
From: Daniel Mack @ 2011-10-31 12:10 UTC (permalink / raw)
To: alsa-devel; +Cc: gdiffey, tiwai, clemens, linuxaudio, Daniel Mack, blablack
In-Reply-To: <1320063030-3502-1-git-send-email-zonque@gmail.com>
In order to split changes properly, this patch only adds the new
implementation but leaves the old one around, so the rest of the driver
does not behave differently. The switch to actually use the new thing is
submitted separately.
---
sound/usb/card.h | 49 +++
sound/usb/endpoint.c | 818 +++++++++++++++++++++++++++++++++++++++++++++++++-
sound/usb/endpoint.h | 25 ++
sound/usb/usbaudio.h | 1 +
4 files changed, 882 insertions(+), 11 deletions(-)
diff --git a/sound/usb/card.h b/sound/usb/card.h
index a39edcc..8662702 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -29,13 +29,16 @@ struct audioformat {
};
struct snd_usb_substream;
+struct snd_usb_endpoint;
struct snd_urb_ctx {
struct urb *urb;
unsigned int buffer_size; /* size of data buffer, if data URB */
struct snd_usb_substream *subs;
+ struct snd_usb_endpoint *ep;
int index; /* index for urb array */
int packets; /* number of packets per urb */
+ int packet_size[MAX_PACKS_HS]; /* size of packets for next submission */
};
struct snd_urb_ops {
@@ -45,6 +48,52 @@ struct snd_urb_ops {
int (*retire_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
};
+struct snd_usb_endpoint {
+ struct snd_usb_audio *chip;
+
+ int use_count;
+ int ep_num; /* the referenced endpoint number */
+ int type; /* SND_USB_ENDPOINT_TYPE_* */
+ int activated;
+
+ void (* prepare_data_urb) (struct snd_usb_substream *subs,
+ struct urb *urb);
+ void (* retire_data_urb) (struct snd_usb_substream *subs,
+ struct urb *urb);
+
+ struct snd_usb_substream *data_subs;
+ struct snd_usb_endpoint *sync_master;
+ struct snd_usb_endpoint *sync_slave;
+
+ struct snd_urb_ctx urb[MAX_URBS];
+ unsigned int nurbs; /* # urbs */
+ unsigned long active_mask; /* bitmask of active urbs */
+ unsigned long unlink_mask; /* bitmask of unlinked urbs */
+ char *syncbuf; /* sync buffer for all sync URBs */
+ dma_addr_t sync_dma; /* DMA address of syncbuf */
+
+ unsigned int pipe; /* the data i/o pipe */
+ unsigned int freqn; /* nominal sampling rate in fs/fps in Q16.16 format */
+ unsigned int freqm; /* momentary sampling rate in fs/fps in Q16.16 format */
+ int freqshift; /* how much to shift the feedback value to get Q16.16 */
+ unsigned int freqmax; /* maximum sampling rate, used for buffer management */
+ unsigned int phase; /* phase accumulator */
+ unsigned int maxpacksize; /* max packet size in bytes */
+ unsigned int maxframesize; /* max packet size in frames */
+ unsigned int curpacksize; /* current packet size in bytes (for capture) */
+ unsigned int curframesize; /* current packet size in frames (for capture) */
+ unsigned int syncmaxsize; /* sync endpoint packet size */
+ unsigned int fill_max: 1; /* fill max packet size always */
+ unsigned int datainterval; /* log_2 of data packet interval */
+ unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */
+ unsigned char silence_value;
+ unsigned int stride;
+ int iface, alt_idx;
+
+ spinlock_t lock;
+ struct list_head list;
+};
+
struct snd_usb_substream {
struct snd_usb_stream *stream;
struct usb_device *dev;
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 81c6ede..03a67f2 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -19,9 +19,11 @@
#include <linux/init.h>
#include <linux/usb.h>
#include <linux/usb/audio.h>
+#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#include "usbaudio.h"
#include "helper.h"
@@ -50,7 +52,7 @@ static inline unsigned get_usb_high_speed_rate(unsigned int rate)
/*
* unlink active urbs.
*/
-static int deactivate_urbs(struct snd_usb_substream *subs, int force, int can_sleep)
+static int deactivate_urbs_old(struct snd_usb_substream *subs, int force, int can_sleep)
{
struct snd_usb_audio *chip = subs->stream->chip;
unsigned int i;
@@ -112,7 +114,7 @@ static void release_urb_ctx(struct snd_urb_ctx *u)
/*
* wait until all urbs are processed.
*/
-static int wait_clear_urbs(struct snd_usb_substream *subs)
+static int wait_clear_urbs_old(struct snd_usb_substream *subs)
{
unsigned long end_time = jiffies + msecs_to_jiffies(1000);
unsigned int i;
@@ -147,8 +149,8 @@ void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force)
int i;
/* stop urbs (to be sure) */
- deactivate_urbs(subs, force, 1);
- wait_clear_urbs(subs);
+ deactivate_urbs_old(subs, force, 1);
+ wait_clear_urbs_old(subs);
for (i = 0; i < MAX_URBS; i++)
release_urb_ctx(&subs->dataurb[i]);
@@ -163,7 +165,7 @@ void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force)
/*
* complete callback from data urb
*/
-static void snd_complete_urb(struct urb *urb)
+static void snd_complete_urb_old(struct urb *urb)
{
struct snd_urb_ctx *ctx = urb->context;
struct snd_usb_substream *subs = ctx->subs;
@@ -317,7 +319,7 @@ int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
u->urb->interval = 1 << subs->datainterval;
u->urb->context = u;
- u->urb->complete = snd_complete_urb;
+ u->urb->complete = snd_complete_urb_old;
}
if (subs->syncpipe) {
@@ -855,7 +857,7 @@ static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *ru
__error:
// snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
- deactivate_urbs(subs, 0, 0);
+ deactivate_urbs_old(subs, 0, 0);
return -EPIPE;
}
@@ -916,7 +918,7 @@ int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int
subs->ops.prepare = prepare_playback_urb;
return 0;
case SNDRV_PCM_TRIGGER_STOP:
- return deactivate_urbs(subs, 0, 0);
+ return deactivate_urbs_old(subs, 0, 0);
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
subs->ops.prepare = prepare_nodata_playback_urb;
return 0;
@@ -934,7 +936,7 @@ int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int c
subs->ops.retire = retire_capture_urb;
return start_urbs(subs, substream->runtime);
case SNDRV_PCM_TRIGGER_STOP:
- return deactivate_urbs(subs, 0, 0);
+ return deactivate_urbs_old(subs, 0, 0);
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
subs->ops.retire = retire_paused_capture_urb;
return 0;
@@ -950,8 +952,8 @@ int snd_usb_substream_prepare(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime)
{
/* clear urbs (to be sure) */
- deactivate_urbs(subs, 0, 1);
- wait_clear_urbs(subs);
+ deactivate_urbs_old(subs, 0, 1);
+ wait_clear_urbs_old(subs);
/* for playback, submit the URBs now; otherwise, the first hwptr_done
* updates for all URBs would happen at the same time when starting */
@@ -963,3 +965,797 @@ int snd_usb_substream_prepare(struct snd_usb_substream *subs,
return 0;
}
+int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep)
+{
+ return ep->sync_master &&
+ ep->sync_master->type == SND_USB_ENDPOINT_TYPE_DATA &&
+ ep->type == SND_USB_ENDPOINT_TYPE_DATA &&
+ usb_pipeout(ep->pipe);
+}
+
+/* determine the number of frames in the next packet */
+static int next_packet_size(struct snd_usb_endpoint *ep)
+{
+ if (ep->fill_max)
+ return ep->maxframesize;
+ else {
+ ep->phase = (ep->phase & 0xffff)
+ + (ep->freqm << ep->datainterval);
+ return min(ep->phase >> 16, ep->maxframesize);
+ }
+}
+
+static void retire_outbound_urb(struct snd_usb_endpoint *ep,
+ struct snd_urb_ctx *urb_ctx)
+{
+ if (ep->retire_data_urb)
+ ep->retire_data_urb(ep->data_subs, urb_ctx->urb);
+}
+
+static void retire_inbound_urb(struct snd_usb_endpoint *ep,
+ struct snd_urb_ctx *urb_ctx)
+{
+ struct urb *urb = urb_ctx->urb;
+
+ if (ep->sync_slave)
+ snd_usb_handle_sync_urb(ep->sync_slave, ep, urb);
+
+ if (ep->retire_data_urb)
+ ep->retire_data_urb(ep->data_subs, urb);
+}
+
+static void prepare_outbound_urb_sizes(struct snd_usb_endpoint *ep,
+ struct snd_urb_ctx *ctx)
+{
+ int i;
+
+ for (i = 0; i < ctx->packets; ++i)
+ ctx->packet_size[i] = next_packet_size(ep);
+}
+
+/*
+ * Prepare a PLAYBACK urb for submission to the bus.
+ */
+static void prepare_outbound_urb(struct snd_usb_endpoint *ep,
+ struct snd_urb_ctx *ctx)
+{
+ int i;
+ struct urb *urb = ctx->urb;
+ unsigned char *cp = urb->transfer_buffer;
+
+ urb->dev = ep->chip->dev; /* we need to set this at each time */
+
+ switch (ep->type) {
+ case SND_USB_ENDPOINT_TYPE_DATA:
+ if (ep->prepare_data_urb) {
+ ep->prepare_data_urb(ep->data_subs, urb);
+ } else {
+ /* no data provider, so send silence */
+ unsigned int offs = 0;
+ for (i = 0; i < ctx->packets; ++i) {
+ int counts = ctx->packet_size[i];
+ urb->iso_frame_desc[i].offset = offs * ep->stride;
+ urb->iso_frame_desc[i].length = counts * ep->stride;
+ offs += counts;
+ }
+
+ urb->number_of_packets = ctx->packets;
+ urb->transfer_buffer_length = offs * ep->stride;
+ memset(urb->transfer_buffer, ep->silence_value,
+ offs * ep->stride);
+ }
+ break;
+
+ case SND_USB_ENDPOINT_TYPE_SYNC:
+ if (snd_usb_get_speed(ep->chip->dev) >= USB_SPEED_HIGH) {
+ /*
+ * fill the length and offset of each urb descriptor.
+ * the fixed 12.13 frequency is passed as 16.16 through the pipe.
+ */
+ urb->iso_frame_desc[0].length = 4;
+ urb->iso_frame_desc[0].offset = 0;
+ cp[0] = ep->freqn;
+ cp[1] = ep->freqn >> 8;
+ cp[2] = ep->freqn >> 16;
+ cp[3] = ep->freqn >> 24;
+ } else {
+ /*
+ * fill the length and offset of each urb descriptor.
+ * the fixed 10.14 frequency is passed through the pipe.
+ */
+ urb->iso_frame_desc[0].length = 3;
+ urb->iso_frame_desc[0].offset = 0;
+ cp[0] = ep->freqn >> 2;
+ cp[1] = ep->freqn >> 10;
+ cp[2] = ep->freqn >> 18;
+ }
+
+ break;
+ }
+}
+
+/*
+ * Prepare a CAPTURE or SYNC urb for submission to the bus.
+ */
+static inline void prepare_inbound_urb(struct snd_usb_endpoint *ep,
+ struct snd_urb_ctx *urb_ctx)
+{
+ int i, offs;
+ struct urb *urb = urb_ctx->urb;
+
+ urb->dev = ep->chip->dev; /* we need to set this at each time */
+
+ switch (ep->type) {
+ case SND_USB_ENDPOINT_TYPE_DATA:
+ offs = 0;
+ for (i = 0; i < urb_ctx->packets; i++) {
+ urb->iso_frame_desc[i].offset = offs;
+ urb->iso_frame_desc[i].length = ep->curpacksize;
+ offs += ep->curpacksize;
+ }
+
+ urb->transfer_buffer_length = offs;
+ urb->number_of_packets = urb_ctx->packets;
+ break;
+
+ case SND_USB_ENDPOINT_TYPE_SYNC:
+ urb->iso_frame_desc[0].length = min(4u, ep->syncmaxsize);
+ urb->iso_frame_desc[0].offset = 0;
+ break;
+ }
+}
+
+/*
+ * complete callback for urbs
+ */
+static void snd_complete_urb(struct urb *urb)
+{
+ struct snd_urb_ctx *ctx = urb->context;
+ struct snd_usb_endpoint *ep = ctx->ep;
+ int err;
+
+ if (ep->use_count == 0)
+ goto exit_clear;
+
+ if (usb_pipeout(ep->pipe)) {
+ retire_outbound_urb(ep, ctx);
+ if (ep->use_count == 0) /* can be stopped during retire callback */
+ goto exit_clear;
+
+ if (snd_usb_endpoint_implict_feedback_sink(ep))
+ goto exit_clear;
+
+ prepare_outbound_urb_sizes(ep, ctx);
+ prepare_outbound_urb(ep, ctx);
+ } else {
+ retire_inbound_urb(ep, ctx);
+ if (ep->use_count == 0) /* can be stopped during retire callback */
+ goto exit_clear;
+
+ prepare_inbound_urb(ep, ctx);
+ }
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err == 0)
+ return;
+
+ snd_printk(KERN_ERR "cannot submit urb (err = %d)\n", err);
+ //snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+
+exit_clear:
+ clear_bit(ctx->index, &ep->active_mask);
+}
+
+struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
+ struct usb_host_interface *alts,
+ int ep_num, int direction, int type)
+{
+ struct list_head *p;
+ struct snd_usb_endpoint *ep;
+ int is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK;
+
+ list_for_each(p, &chip->ep_list) {
+ ep = list_entry(p, struct snd_usb_endpoint, list);
+ if (ep->ep_num == ep_num &&
+ ep->iface == alts->desc.bInterfaceNumber &&
+ ep->alt_idx == alts->desc.bAlternateSetting) {
+ snd_printk("Re-using EP %x in iface %d,%d @%p\n",
+ ep_num, ep->iface, ep->alt_idx, ep);
+ return ep;
+ }
+ }
+
+ snd_printk(KERN_INFO "Creating new %s %s endpoint #%x\n",
+ is_playback ? "playback" : "capture",
+ type == SND_USB_ENDPOINT_TYPE_DATA ? "data" : "sync",
+ ep_num);
+
+ ep = kzalloc(sizeof(*ep), GFP_KERNEL);
+ if (!ep)
+ return NULL;
+
+ spin_lock_init(&ep->lock);
+
+ ep->chip = chip;
+ ep->type = type;
+ ep->ep_num = ep_num;
+ ep->iface = alts->desc.bInterfaceNumber;
+ ep->alt_idx = alts->desc.bAlternateSetting;
+
+ /* select the alt setting once so the endpoints become valid */
+ snd_printk("%s() calling usb_set_interface()\n", __func__);
+ usb_set_interface(ep->chip->dev, ep->iface, ep->alt_idx);
+
+ ep_num &= USB_ENDPOINT_NUMBER_MASK;
+
+ if (is_playback)
+ ep->pipe = usb_sndisocpipe(chip->dev, ep_num);
+ else
+ ep->pipe = usb_rcvisocpipe(chip->dev, ep_num);
+
+ if (type == SND_USB_ENDPOINT_TYPE_SYNC) {
+ if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
+ get_endpoint(alts, 1)->bRefresh >= 1 &&
+ get_endpoint(alts, 1)->bRefresh <= 9)
+ ep->syncinterval = get_endpoint(alts, 1)->bRefresh;
+ else if (snd_usb_get_speed(chip->dev) == USB_SPEED_FULL)
+ ep->syncinterval = 1;
+ else if (get_endpoint(alts, 1)->bInterval >= 1 &&
+ get_endpoint(alts, 1)->bInterval <= 16)
+ ep->syncinterval = get_endpoint(alts, 1)->bInterval - 1;
+ else
+ ep->syncinterval = 3;
+
+ ep->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize);
+ }
+
+ list_add_tail(&ep->list, &chip->ep_list);
+
+ return ep;
+}
+
+/*
+ * wait until all urbs are processed.
+ */
+static int wait_clear_urbs(struct snd_usb_endpoint *ep)
+{
+ unsigned long end_time = jiffies + msecs_to_jiffies(1000);
+ unsigned int i;
+ int alive;
+
+ do {
+ alive = 0;
+ for (i = 0; i < ep->nurbs; i++)
+ if (test_bit(i, &ep->active_mask))
+ alive++;
+
+ if (! alive)
+ break;
+
+ schedule_timeout_uninterruptible(1);
+ } while (time_before(jiffies, end_time));
+
+ if (alive)
+ snd_printk(KERN_ERR "timeout: still %d active urbs on EP #%x\n",
+ alive, ep->ep_num);
+
+ return 0;
+}
+
+/*
+ * unlink active urbs.
+ */
+static int deactivate_urbs(struct snd_usb_endpoint *ep, int force, int can_sleep)
+{
+ unsigned int i;
+ int async;
+
+ if (!force && ep->chip->shutdown) /* to be sure... */
+ return -EBADFD;
+
+ async = !can_sleep && ep->chip->async_unlink;
+
+ if (!async && in_interrupt())
+ return 0;
+
+ for (i = 0; i < ep->nurbs; i++) {
+ if (test_bit(i, &ep->active_mask)) {
+ if (!test_and_set_bit(i, &ep->unlink_mask)) {
+ struct urb *u = ep->urb[i].urb;
+ if (async)
+ usb_unlink_urb(u);
+ else
+ usb_kill_urb(u);
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * release an endpoint's urbs
+ */
+static void release_urbs(struct snd_usb_endpoint *ep, int force)
+{
+ int i;
+
+ /* route incoming urbs to nirvana */
+ ep->retire_data_urb = NULL;
+ ep->prepare_data_urb = NULL;
+
+ /* stop urbs */
+ deactivate_urbs(ep, force, 1);
+ wait_clear_urbs(ep);
+
+ for (i = 0; i < ep->nurbs; i++)
+ release_urb_ctx(&ep->urb[i]);
+
+ usb_free_coherent(ep->chip->dev, SYNC_URBS * 4,
+ ep->syncbuf, ep->sync_dma);
+
+ ep->syncbuf = NULL;
+ ep->nurbs = 0;
+}
+
+static int data_ep_set_params(struct snd_usb_endpoint *ep,
+ struct snd_pcm_hw_params *hw_params,
+ struct audioformat *fmt,
+ struct snd_usb_endpoint *sync_ep)
+{
+ unsigned int maxsize, i, urb_packs, total_packs, packs_per_ms;
+ int period_bytes = params_period_bytes(hw_params);
+ int format = params_format(hw_params);
+ int is_playback = usb_pipeout(ep->pipe);
+ int frame_bits = snd_pcm_format_physical_width(params_format(hw_params)) *
+ params_channels(hw_params);
+
+ ep->datainterval = fmt->datainterval;
+ ep->stride = frame_bits >> 3;
+ ep->silence_value = format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0;
+
+ /* calculate max. frequency */
+ if (ep->maxpacksize) {
+ /* whatever fits into a max. size packet */
+ maxsize = ep->maxpacksize;
+ ep->freqmax = (maxsize / (frame_bits >> 3))
+ << (16 - ep->datainterval);
+ } else {
+ /* no max. packet size: just take 25% higher than nominal */
+ ep->freqmax = ep->freqn + (ep->freqn >> 2);
+ maxsize = ((ep->freqmax + 0xffff) * (frame_bits >> 3))
+ >> (16 - ep->datainterval);
+ }
+
+ if (ep->fill_max)
+ ep->curpacksize = ep->maxpacksize;
+ else
+ ep->curpacksize = maxsize;
+
+ if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL)
+ packs_per_ms = 8 >> ep->datainterval;
+ else
+ packs_per_ms = 1;
+
+ if (is_playback && !snd_usb_endpoint_implict_feedback_sink(ep)) {
+ urb_packs = max(ep->chip->nrpacks, 1);
+ urb_packs = min(urb_packs, (unsigned int) MAX_PACKS);
+ } else {
+ urb_packs = 1;
+ }
+
+ urb_packs *= packs_per_ms;
+
+ if (sync_ep && !snd_usb_endpoint_implict_feedback_sink(ep))
+ urb_packs = min(urb_packs, 1U << sync_ep->syncinterval);
+
+ /* decide how many packets to be used */
+ if (is_playback && !snd_usb_endpoint_implict_feedback_sink(ep)) {
+ unsigned int minsize, maxpacks;
+ /* determine how small a packet can be */
+ minsize = (ep->freqn >> (16 - ep->datainterval))
+ * (frame_bits >> 3);
+ /* with sync from device, assume it can be 12% lower */
+ if (sync_ep)
+ minsize -= minsize >> 3;
+ minsize = max(minsize, 1u);
+ total_packs = (period_bytes + minsize - 1) / minsize;
+ /* we need at least two URBs for queueing */
+ if (total_packs < 2) {
+ total_packs = 2;
+ } else {
+ /* and we don't want too long a queue either */
+ maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2);
+ total_packs = min(total_packs, maxpacks);
+ }
+ } else {
+ while (urb_packs > 1 && urb_packs * maxsize >= period_bytes)
+ urb_packs >>= 1;
+ total_packs = MAX_URBS * urb_packs;
+ }
+
+ snd_printk("is_playback? %d impf %d, total_packs %d urb_packs %d\n",
+ is_playback, snd_usb_endpoint_implict_feedback_sink(ep), total_packs, urb_packs);
+
+ ep->nurbs = (total_packs + urb_packs - 1) / urb_packs;
+ if (ep->nurbs > MAX_URBS) {
+ /* too much... */
+ ep->nurbs = MAX_URBS;
+ total_packs = MAX_URBS * urb_packs;
+ } else if (ep->nurbs < 2) {
+ /* too little - we need at least two packets
+ * to ensure contiguous playback/capture
+ */
+ ep->nurbs = 2;
+ }
+
+ /* allocate and initialize data urbs */
+ for (i = 0; i < ep->nurbs; i++) {
+ struct snd_urb_ctx *u = &ep->urb[i];
+ u->index = i;
+ u->ep = ep;
+ u->packets = (i + 1) * total_packs / ep->nurbs
+ - i * total_packs / ep->nurbs;
+ u->buffer_size = maxsize * u->packets;
+ snd_printk(" ep %p:: buffer_size %d maxsize %d packets %d\n", ep, u->buffer_size, maxsize, u->packets);
+ if (fmt->fmt_type == UAC_FORMAT_TYPE_II)
+ u->packets++; /* for transfer delimiter */
+ u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
+ if (!u->urb)
+ goto out_of_memory;
+
+ u->urb->transfer_buffer =
+ usb_alloc_coherent(ep->chip->dev, u->buffer_size,
+ GFP_KERNEL, &u->urb->transfer_dma);
+ if (!u->urb->transfer_buffer)
+ goto out_of_memory;
+ u->urb->pipe = ep->pipe;
+ u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+ u->urb->interval = 1 << ep->datainterval;
+ u->urb->context = u;
+ u->urb->complete = snd_complete_urb;
+ }
+
+ return 0;
+
+out_of_memory:
+ release_urbs(ep, 0);
+ return -ENOMEM;
+}
+
+static int sync_ep_set_params(struct snd_usb_endpoint *ep,
+ struct snd_pcm_hw_params *hw_params,
+ struct audioformat *fmt)
+{
+ int i;
+
+ ep->syncbuf = usb_alloc_coherent(ep->chip->dev, SYNC_URBS * 4,
+ GFP_KERNEL, &ep->sync_dma);
+ if (!ep->syncbuf)
+ goto out_of_memory;
+
+ for (i = 0; i < SYNC_URBS; i++) {
+ struct snd_urb_ctx *u = &ep->urb[i];
+ u->index = i;
+ u->ep = ep;
+ u->packets = 1;
+ u->urb = usb_alloc_urb(1, GFP_KERNEL);
+ if (!u->urb)
+ goto out_of_memory;
+ u->urb->transfer_buffer = ep->syncbuf + i * 4;
+ u->urb->transfer_dma = ep->sync_dma + i * 4;
+ u->urb->transfer_buffer_length = 4;
+ u->urb->pipe = ep->pipe;
+ u->urb->transfer_flags = URB_ISO_ASAP |
+ URB_NO_TRANSFER_DMA_MAP;
+ u->urb->number_of_packets = 1;
+ u->urb->interval = 1 << ep->syncinterval;
+ u->urb->context = u;
+ u->urb->complete = snd_complete_urb;
+ }
+
+ ep->nurbs = SYNC_URBS;
+
+ return 0;
+
+out_of_memory:
+ release_urbs(ep, 0);
+ return -ENOMEM;
+}
+
+int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
+ struct snd_pcm_hw_params *hw_params,
+ struct audioformat *fmt,
+ struct snd_usb_endpoint *sync_ep)
+{
+ int err;
+
+ if (ep->use_count > 0) {
+ snd_printk(KERN_WARNING "Unable to change format on ep #%x: already in use\n",
+ ep->ep_num);
+ return -EBUSY;
+ }
+
+ ep->datainterval = fmt->datainterval;
+ ep->maxpacksize = fmt->maxpacksize;
+ ep->fill_max = fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX;
+
+ if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL)
+ ep->freqn = get_usb_full_speed_rate(params_rate(hw_params));
+ else
+ ep->freqn = get_usb_high_speed_rate(params_rate(hw_params));
+
+ /* calculate the frequency in 16.16 format */
+ ep->freqm = ep->freqn;
+ ep->freqshift = INT_MIN;
+
+ ep->phase = 0;
+
+ switch (ep->type) {
+ case SND_USB_ENDPOINT_TYPE_DATA:
+ err = data_ep_set_params(ep, hw_params, fmt, sync_ep);
+ break;
+ case SND_USB_ENDPOINT_TYPE_SYNC:
+ err = sync_ep_set_params(ep, hw_params, fmt);
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ snd_printk("Setting params for ep #%x (type %d, %d urbs) -> %d\n",
+ ep->ep_num, ep->type, ep->nurbs, err);
+
+ return err;
+}
+
+int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
+{
+ int err;
+ unsigned int i;
+
+ if (ep->chip->shutdown)
+ return -EBADFD;
+
+ /* already running? */
+ if (++ep->use_count != 1)
+ return 0;
+
+ ep->phase = 0;
+ ep->active_mask = 0;
+ ep->unlink_mask = 0;
+
+ /*
+ * If this endpoint has a data endpoint as implicit feedback source,
+ * don't start the urbs here. Instead, wait for the record urbs to
+ * arrive and queue from that context.
+ */
+ if (snd_usb_endpoint_implict_feedback_sink(ep))
+ return 0;
+
+ for (i = 0; i < ep->nurbs; i++) {
+ struct urb *urb = ep->urb[i].urb;
+
+ if (snd_BUG_ON(!urb))
+ return -EINVAL;
+
+ if (usb_pipeout(ep->pipe)) {
+ prepare_outbound_urb_sizes(ep, urb->context);
+ prepare_outbound_urb(ep, urb->context);
+ } else {
+ prepare_inbound_urb(ep, urb->context);
+ }
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ snd_printk(KERN_ERR "Submmiting urb %d/%d (in? %d buf %p len %d) ret (%d)\n",
+ i, ep->nurbs, usb_pipein(ep->pipe),
+ ep->urb[i].urb->transfer_buffer,
+ ep->urb[i].urb->transfer_buffer_length,
+ err);
+ if (err < 0) {
+ snd_printk(KERN_ERR "cannot submit urb %d, error %d: %s\n",
+ i, err, usb_error_string(err));
+ goto __error;
+ }
+ set_bit(i, &ep->active_mask);
+ }
+
+ return 0;
+
+__error:
+ ep->use_count--;
+ deactivate_urbs(ep, 0, 0);
+ return -EPIPE;
+}
+
+void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, int force, int can_sleep)
+{
+ if (!ep)
+ return;
+
+ if (snd_BUG_ON(ep->use_count == 0))
+ return;
+
+ if (--ep->use_count == 0) {
+ ep->sync_slave = NULL;
+ ep->retire_data_urb = NULL;
+ ep->prepare_data_urb = NULL;
+ ep->sync_master = NULL;
+ deactivate_urbs(ep, force, can_sleep);
+ }
+}
+
+void snd_usb_endpoint_activate(struct snd_usb_endpoint *ep)
+{
+ if (ep && ep->use_count == 0 && !ep->chip->shutdown && !ep->activated) {
+ snd_printk("%s() calling usb_set_interface(%d,%d)\n", __func__, ep->iface, ep->alt_idx);
+ usb_set_interface(ep->chip->dev, ep->iface, ep->alt_idx);
+ ep->activated = 1;
+ }
+}
+
+void snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep)
+{
+ if (ep && ep->use_count == 0 && !ep->chip->shutdown && ep->activated) {
+ snd_printk("%s() calling usb_set_interface(%d,0)\n", __func__, ep->iface);
+ usb_set_interface(ep->chip->dev, ep->iface, 0);
+ ep->activated = 0;
+ }
+}
+
+void snd_usb_endpoint_free(struct list_head *head)
+{
+ struct snd_usb_endpoint *ep;
+
+ ep = list_entry(head, struct snd_usb_endpoint, list);
+ deactivate_urbs(ep, 1, 1);
+ release_urbs(ep, 1);
+}
+
+/*
+ * process after playback sync complete
+ *
+ * Full speed devices report feedback values in 10.14 format as samples per
+ * frame, high speed devices in 16.16 format as samples per microframe.
+ * Because the Audio Class 1 spec was written before USB 2.0, many high speed
+ * devices use a wrong interpretation, some others use an entirely different
+ * format. Therefore, we cannot predict what format any particular device uses
+ * and must detect it automatically.
+ */
+void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
+ struct snd_usb_endpoint *sender,
+ const struct urb *urb)
+{
+ int shift;
+ unsigned int f;
+ unsigned long flags;
+
+ snd_BUG_ON(ep == sender);
+
+ if (snd_usb_endpoint_implict_feedback_sink(ep) && ep->use_count > 0) {
+ /* implicit feedback case */
+ int i, err, bytes = 0;
+ struct urb *out_urb = NULL;
+ struct snd_urb_ctx *in_ctx, *out_ctx;
+
+ in_ctx = urb->context;
+
+ /* Count overall packet size */
+ for (i = 0; i < in_ctx->packets; i++)
+ if (urb->iso_frame_desc[i].status == 0)
+ bytes += urb->iso_frame_desc[i].actual_length;
+
+ /*
+ * skip empty packets. At least M-Audio's Fast Track Ultra stops
+ * streaming once it received a 0-byte OUT URB
+ */
+ if (bytes == 0)
+ return;
+
+ for (i = 0; i < ep->nurbs; i++)
+ if (!test_and_set_bit(i, &ep->active_mask)) {
+ out_urb = ep->urb[i].urb;
+ break;
+ }
+
+ if (!out_urb) {
+ snd_printk(KERN_ERR "Unable to find an urb for playback (nurbs %d)\n",
+ ep->nurbs);
+ return;
+ }
+
+ out_ctx = out_urb->context;
+ out_ctx->packets = in_ctx->packets;
+
+ /*
+ * Iterate through the inbound packet and prepare the lengths
+ * for the output packet. The OUT packet we are about to send
+ * will have the same amount of payload than the IN packet we
+ * just received.
+ */
+
+ for (i = 0; i < in_ctx->packets; i++) {
+ if (urb->iso_frame_desc[i].status == 0)
+ out_ctx->packet_size[i] =
+ urb->iso_frame_desc[i].actual_length / ep->stride;
+ else
+ out_ctx->packet_size[i] = 0;
+ }
+
+ prepare_outbound_urb(ep, out_ctx);
+
+ for (i = 0; i < in_ctx->packets; i++) {
+ if (urb->iso_frame_desc[i].status != 0)
+ continue;
+
+ if (urb->iso_frame_desc[i].actual_length !=
+ out_urb->iso_frame_desc[i].length)
+ snd_printk(" index %d: in %d, out %d (%d) stride %d\n", i,
+ urb->iso_frame_desc[i].actual_length,
+ out_urb->iso_frame_desc[i].length,
+ out_ctx->packet_size[i], ep->stride);
+ }
+
+
+ err = usb_submit_urb(out_urb, GFP_ATOMIC);
+ if (err < 0) {
+ snd_printk(KERN_ERR "Unable to submit urb #%d: %d (urb %p)\n",
+ out_ctx->index, err, out_urb);
+ clear_bit(out_ctx->index, &ep->active_mask);
+ }
+
+ return;
+ }
+
+ if (urb->iso_frame_desc[0].status != 0 ||
+ urb->iso_frame_desc[0].actual_length < 3)
+ return;
+
+ f = le32_to_cpup(urb->transfer_buffer);
+ if (urb->iso_frame_desc[0].actual_length == 3)
+ f &= 0x00ffffff;
+ else
+ f &= 0x0fffffff;
+
+ if (f == 0)
+ return;
+
+ if (unlikely(ep->freqshift == INT_MIN)) {
+ /*
+ * The first time we see a feedback value, determine its format
+ * by shifting it left or right until it matches the nominal
+ * frequency value. This assumes that the feedback does not
+ * differ from the nominal value more than +50% or -25%.
+ */
+ shift = 0;
+ while (f < ep->freqn - ep->freqn / 4) {
+ f <<= 1;
+ shift++;
+ }
+ while (f > ep->freqn + ep->freqn / 2) {
+ f >>= 1;
+ shift--;
+ }
+ ep->freqshift = shift;
+ }
+ else if (ep->freqshift >= 0)
+ f <<= ep->freqshift;
+ else
+ f >>= -ep->freqshift;
+
+ if (likely(f >= ep->freqn - ep->freqn / 8 && f <= ep->freqmax)) {
+ /*
+ * If the frequency looks valid, set it.
+ * This value is referred to in prepare_playback_urb().
+ */
+ spin_lock_irqsave(&ep->lock, flags);
+ ep->freqm = f;
+ spin_unlock_irqrestore(&ep->lock, flags);
+ } else {
+ /*
+ * Out of range; maybe the shift value is wrong.
+ * Reset it so that we autodetect again the next time.
+ */
+ ep->freqshift = INT_MIN;
+ }
+}
+
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h
index 88eb63a..6819b83 100644
--- a/sound/usb/endpoint.h
+++ b/sound/usb/endpoint.h
@@ -18,4 +18,29 @@ int snd_usb_substream_prepare(struct snd_usb_substream *subs,
int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd);
int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd);
+
+#define SND_USB_ENDPOINT_TYPE_DATA 0
+#define SND_USB_ENDPOINT_TYPE_SYNC 1
+
+struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
+ struct usb_host_interface *alts,
+ int ep_num, int direction, int type);
+
+int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
+ struct snd_pcm_hw_params *hw_params,
+ struct audioformat *fmt,
+ struct snd_usb_endpoint *sync_ep);
+
+int snd_usb_endpoint_start(struct snd_usb_endpoint *ep);
+void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, int force, int can_sleep);
+void snd_usb_endpoint_activate(struct snd_usb_endpoint *ep);
+void snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep);
+void snd_usb_endpoint_free(struct list_head *head);
+
+int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep);
+
+void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
+ struct snd_usb_endpoint *sender,
+ const struct urb *urb);
+
#endif /* __USBAUDIO_ENDPOINT_H */
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 3e2b035..f1f4b6f 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -46,6 +46,7 @@ struct snd_usb_audio {
int num_suspended_intf;
struct list_head pcm_list; /* list of pcm streams */
+ struct list_head ep_list; /* list of audio-related endpoints */
int pcm_devs;
struct list_head midi_list; /* list of midi interfaces */
--
1.7.5.4
^ permalink raw reply related
* [PATCH 2/5] ALSA: snd-usb: switch over to new endpoint streaming logic
From: Daniel Mack @ 2011-10-31 12:10 UTC (permalink / raw)
To: alsa-devel; +Cc: gdiffey, tiwai, clemens, linuxaudio, Daniel Mack, blablack
In-Reply-To: <1320063030-3502-1-git-send-email-zonque@gmail.com>
---
sound/usb/card.c | 6 +-
sound/usb/card.h | 5 +
sound/usb/endpoint.c | 40 -----
sound/usb/endpoint.h | 3 -
sound/usb/pcm.c | 402 +++++++++++++++++++++++++++++++++++++++++---------
sound/usb/stream.c | 31 ++++-
6 files changed, 369 insertions(+), 118 deletions(-)
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 05c1aae..21f6359 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -130,7 +130,6 @@ static void snd_usb_stream_disconnect(struct list_head *head)
subs = &as->substream[idx];
if (!subs->num_formats)
continue;
- snd_usb_release_substream_urbs(subs, 1);
subs->interface = -1;
}
}
@@ -347,6 +346,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
INIT_LIST_HEAD(&chip->pcm_list);
+ INIT_LIST_HEAD(&chip->ep_list);
INIT_LIST_HEAD(&chip->midi_list);
INIT_LIST_HEAD(&chip->mixer_list);
@@ -564,6 +564,10 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
list_for_each(p, &chip->pcm_list) {
snd_usb_stream_disconnect(p);
}
+ /* release the endpoint resources */
+ list_for_each(p, &chip->ep_list) {
+ snd_usb_endpoint_free(p);
+ }
/* release the midi resources */
list_for_each(p, &chip->midi_list) {
snd_usbmidi_disconnect(p);
diff --git a/sound/usb/card.h b/sound/usb/card.h
index 8662702..7fb8778 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -135,6 +135,11 @@ struct snd_usb_substream {
struct snd_urb_ctx syncurb[SYNC_URBS]; /* sync urb table */
char *syncbuf; /* sync buffer for all sync URBs */
dma_addr_t sync_dma; /* DMA address of syncbuf */
+ /* data and sync endpoints for this stream */
+ struct snd_usb_endpoint *data_endpoint;
+ struct snd_usb_endpoint *sync_endpoint;
+ unsigned int data_endpoint_started:1;
+ unsigned int sync_endpoint_started:1;
u64 formats; /* format bitmasks (all or'ed) */
unsigned int num_formats; /* number of supported audio formats (list) */
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 03a67f2..e0872a0 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -908,46 +908,6 @@ void snd_usb_init_substream(struct snd_usb_stream *as,
subs->fmt_type = fp->fmt_type;
}
-int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct snd_usb_substream *subs = substream->runtime->private_data;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- subs->ops.prepare = prepare_playback_urb;
- return 0;
- case SNDRV_PCM_TRIGGER_STOP:
- return deactivate_urbs_old(subs, 0, 0);
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- subs->ops.prepare = prepare_nodata_playback_urb;
- return 0;
- }
-
- return -EINVAL;
-}
-
-int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct snd_usb_substream *subs = substream->runtime->private_data;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- subs->ops.retire = retire_capture_urb;
- return start_urbs(subs, substream->runtime);
- case SNDRV_PCM_TRIGGER_STOP:
- return deactivate_urbs_old(subs, 0, 0);
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- subs->ops.retire = retire_paused_capture_urb;
- return 0;
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- subs->ops.retire = retire_capture_urb;
- return 0;
- }
-
- return -EINVAL;
-}
-
int snd_usb_substream_prepare(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime)
{
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h
index 6819b83..f9d3843 100644
--- a/sound/usb/endpoint.h
+++ b/sound/usb/endpoint.h
@@ -15,9 +15,6 @@ void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force);
int snd_usb_substream_prepare(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime);
-int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd);
-int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd);
-
#define SND_USB_ENDPOINT_TYPE_DATA 0
#define SND_USB_ENDPOINT_TYPE_SYNC 1
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 0220b0f..af21d38 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -208,6 +208,71 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
}
}
+static int start_endpoints(struct snd_usb_substream *subs)
+{
+ int err;
+
+ if (!subs->data_endpoint)
+ return -EINVAL;
+
+ if (!subs->data_endpoint_started) {
+ struct snd_usb_endpoint *ep = subs->data_endpoint;
+
+ snd_printk("Starting data EP @%p\n", ep);
+
+ ep->data_subs = subs;
+
+ err = snd_usb_endpoint_start(ep);
+ if (err < 0)
+ return err;
+
+ subs->data_endpoint_started = 1;
+ }
+
+ if (!subs->sync_endpoint_started && subs->sync_endpoint) {
+ struct snd_usb_endpoint *ep = subs->sync_endpoint;
+
+ snd_printk("Starting sync EP @%p\n", ep);
+
+ ep->sync_slave = subs->data_endpoint;
+ err = snd_usb_endpoint_start(ep);
+ if (err < 0)
+ return err;
+
+ subs->sync_endpoint_started = 1;
+ }
+
+ return 0;
+}
+
+static void stop_endpoints(struct snd_usb_substream *subs, int force, int can_sleep)
+{
+ snd_printk("%s(%p,%d,%d)\n", __func__, subs, force, can_sleep);
+
+ if (subs->sync_endpoint_started)
+ snd_usb_endpoint_stop(subs->sync_endpoint, force, can_sleep);
+
+ if (subs->data_endpoint_started)
+ snd_usb_endpoint_stop(subs->data_endpoint, force, can_sleep);
+
+ subs->sync_endpoint_started = 0;
+ subs->data_endpoint_started = 0;
+}
+
+static void activate_endpoints(struct snd_usb_substream *subs)
+{
+ snd_printk("%s(%p)\n", __func__, subs);
+ snd_usb_endpoint_activate(subs->sync_endpoint);
+ snd_usb_endpoint_activate(subs->data_endpoint);
+}
+
+static void deactivate_endpoints(struct snd_usb_substream *subs)
+{
+ snd_printk("%s(%p)\n", __func__, subs);
+ snd_usb_endpoint_deactivate(subs->sync_endpoint);
+ snd_usb_endpoint_deactivate(subs->data_endpoint);
+}
+
/*
* find a matching format and set up the interface
*/
@@ -232,40 +297,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
if (fmt == subs->cur_audiofmt)
return 0;
- /* close the old interface */
- if (subs->interface >= 0 && subs->interface != fmt->iface) {
- if (usb_set_interface(subs->dev, subs->interface, 0) < 0) {
- snd_printk(KERN_ERR "%d:%d:%d: return to setting 0 failed\n",
- dev->devnum, fmt->iface, fmt->altsetting);
- return -EIO;
- }
- subs->interface = -1;
- subs->altset_idx = 0;
- }
-
- /* set interface */
- if (subs->interface != fmt->iface || subs->altset_idx != fmt->altset_idx) {
- if (usb_set_interface(dev, fmt->iface, fmt->altsetting) < 0) {
- snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed\n",
- dev->devnum, fmt->iface, fmt->altsetting);
- return -EIO;
- }
- snd_printdd(KERN_INFO "setting usb interface %d:%d\n", fmt->iface, fmt->altsetting);
- subs->interface = fmt->iface;
- subs->altset_idx = fmt->altset_idx;
- }
-
- /* create a data pipe */
- ep = fmt->endpoint & USB_ENDPOINT_NUMBER_MASK;
- if (is_playback)
- subs->datapipe = usb_sndisocpipe(dev, ep);
- else
- subs->datapipe = usb_rcvisocpipe(dev, ep);
- subs->datainterval = fmt->datainterval;
- subs->syncpipe = subs->syncinterval = 0;
- subs->maxpacksize = fmt->maxpacksize;
- subs->syncmaxsize = 0;
- subs->fill_max = 0;
+ subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip,
+ alts, fmt->endpoint, subs->direction,
+ SND_USB_ENDPOINT_TYPE_DATA);
+ if (!subs->data_endpoint)
+ return -EINVAL;
/* we need a sync pipe in async OUT or adaptive IN mode */
/* check the number of EP, since some devices have broken
@@ -276,6 +312,15 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) ||
(! is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) &&
altsd->bNumEndpoints >= 2) {
+ switch (subs->stream->chip->usb_id) {
+ case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */
+ case USB_ID(0x0763, 0x2081):
+ ep = 0x81;
+ iface = usb_ifnum_to_if(dev, 2);
+ alts = &iface->altsetting[1];
+ goto add_sync_ep;
+ }
+
/* check sync-pipe endpoint */
/* ... and check descriptor size before accessing bSynchAddress
because there is a version of the SB Audigy 2 NX firmware lacking
@@ -295,28 +340,16 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
dev->devnum, fmt->iface, fmt->altsetting);
return -EINVAL;
}
- ep &= USB_ENDPOINT_NUMBER_MASK;
- if (is_playback)
- subs->syncpipe = usb_rcvisocpipe(dev, ep);
- else
- subs->syncpipe = usb_sndisocpipe(dev, ep);
- if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
- get_endpoint(alts, 1)->bRefresh >= 1 &&
- get_endpoint(alts, 1)->bRefresh <= 9)
- subs->syncinterval = get_endpoint(alts, 1)->bRefresh;
- else if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
- subs->syncinterval = 1;
- else if (get_endpoint(alts, 1)->bInterval >= 1 &&
- get_endpoint(alts, 1)->bInterval <= 16)
- subs->syncinterval = get_endpoint(alts, 1)->bInterval - 1;
- else
- subs->syncinterval = 3;
- subs->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize);
- }
-
- /* always fill max packet size */
- if (fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX)
- subs->fill_max = 1;
+add_sync_ep:
+ subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip,
+ alts, ep, !subs->direction,
+ SND_USB_ENDPOINT_TYPE_SYNC);
+
+ if (!subs->sync_endpoint)
+ return -EINVAL;
+
+ subs->data_endpoint->sync_master = subs->sync_endpoint;
+ }
if ((err = snd_usb_init_pitch(subs->stream->chip, subs->interface, alts, fmt)) < 0)
return err;
@@ -390,15 +423,22 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
if (changed) {
mutex_lock(&subs->stream->chip->shutdown_mutex);
/* format changed */
- snd_usb_release_substream_urbs(subs, 0);
- /* influenced: period_bytes, channels, rate, format, */
- ret = snd_usb_init_substream_urbs(subs, params_period_bytes(hw_params),
- params_rate(hw_params),
- snd_pcm_format_physical_width(params_format(hw_params)) *
- params_channels(hw_params));
+ snd_printk("%s(): format changed\n", __func__);
+ stop_endpoints(subs, 0, 1);
+
+ snd_printk(" -- data %p\n", subs->data_endpoint);
+ snd_printk(" -- sync %p\n", subs->sync_endpoint);
+
+ ret = snd_usb_endpoint_set_params(subs->data_endpoint, hw_params, fmt,
+ subs->sync_endpoint);
+ if (ret == 0 && subs->sync_endpoint)
+ snd_usb_endpoint_set_params(subs->sync_endpoint,
+ hw_params, fmt, NULL);
mutex_unlock(&subs->stream->chip->shutdown_mutex);
}
+ snd_printk(KERN_ERR "Returning from %s() with %d\n", __func__, ret);
+
return ret;
}
@@ -415,7 +455,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
subs->cur_rate = 0;
subs->period_bytes = 0;
mutex_lock(&subs->stream->chip->shutdown_mutex);
- snd_usb_release_substream_urbs(subs, 0);
+ stop_endpoints(subs, 0, 1);
mutex_unlock(&subs->stream->chip->shutdown_mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
}
@@ -435,19 +475,30 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
return -ENXIO;
}
+ if (snd_BUG_ON(!subs->data_endpoint))
+ return -EIO;
+
/* some unit conversions in runtime */
- subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize);
- subs->curframesize = bytes_to_frames(runtime, subs->curpacksize);
+ subs->data_endpoint->maxframesize =
+ bytes_to_frames(runtime, subs->data_endpoint->maxpacksize);
+ subs->data_endpoint->curframesize =
+ bytes_to_frames(runtime, subs->data_endpoint->curpacksize);
/* reset the pointer */
subs->hwptr_done = 0;
subs->transfer_done = 0;
- subs->phase = 0;
subs->last_delay = 0;
subs->last_frame_number = 0;
runtime->delay = 0;
- return snd_usb_substream_prepare(subs, runtime);
+ activate_endpoints(subs);
+
+ /* for playback, submit the URBs now; otherwise, the first hwptr_done
+ * updates for all URBs would happen at the same time when starting */
+ if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK)
+ return start_endpoints(subs);
+
+ return 0;
}
static struct snd_pcm_hardware snd_usb_hardware =
@@ -843,15 +894,168 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction)
struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
struct snd_usb_substream *subs = &as->substream[direction];
- if (!as->chip->shutdown && subs->interface >= 0) {
- usb_set_interface(subs->dev, subs->interface, 0);
- subs->interface = -1;
- }
+ stop_endpoints(subs, 1, 1);
+ deactivate_endpoints(subs);
subs->pcm_substream = NULL;
snd_usb_autosuspend(subs->stream->chip);
return 0;
}
+/* Since a URB can handle only a single linear buffer, we must use double
+ * buffering when the data to be transferred overflows the buffer boundary.
+ * To avoid inconsistencies when updating hwptr_done, we use double buffering
+ * for all URBs.
+ */
+static void retire_capture_urb(struct snd_usb_substream *subs,
+ struct urb *urb)
+{
+ struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
+ unsigned int stride, frames, bytes, oldptr;
+ int i, period_elapsed = 0;
+ unsigned long flags;
+ unsigned char *cp;
+
+ stride = runtime->frame_bits >> 3;
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+ if (urb->iso_frame_desc[i].status) {
+ snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
+ // continue;
+ }
+ bytes = urb->iso_frame_desc[i].actual_length;
+ frames = bytes / stride;
+ if (!subs->txfr_quirk)
+ bytes = frames * stride;
+ if (bytes % (runtime->sample_bits >> 3) != 0) {
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+ int oldbytes = bytes;
+#endif
+ bytes = frames * stride;
+ snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n",
+ oldbytes, bytes);
+ }
+ /* update the current pointer */
+ spin_lock_irqsave(&subs->lock, flags);
+ oldptr = subs->hwptr_done;
+ subs->hwptr_done += bytes;
+ if (subs->hwptr_done >= runtime->buffer_size * stride)
+ subs->hwptr_done -= runtime->buffer_size * stride;
+ frames = (bytes + (oldptr % stride)) / stride;
+ subs->transfer_done += frames;
+ if (subs->transfer_done >= runtime->period_size) {
+ subs->transfer_done -= runtime->period_size;
+ period_elapsed = 1;
+ }
+ spin_unlock_irqrestore(&subs->lock, flags);
+ /* copy a data chunk */
+ if (oldptr + bytes > runtime->buffer_size * stride) {
+ unsigned int bytes1 =
+ runtime->buffer_size * stride - oldptr;
+ memcpy(runtime->dma_area + oldptr, cp, bytes1);
+ memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1);
+ } else {
+ memcpy(runtime->dma_area + oldptr, cp, bytes);
+ }
+ }
+
+ if (period_elapsed)
+ snd_pcm_period_elapsed(subs->pcm_substream);
+}
+
+static void prepare_playback_urb(struct snd_usb_substream *subs,
+ struct urb *urb)
+{
+ struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
+ struct snd_urb_ctx *ctx = urb->context;
+ unsigned int counts, frames, bytes;
+ int i, stride, period_elapsed = 0;
+ unsigned long flags;
+
+ stride = runtime->frame_bits >> 3;
+
+ frames = 0;
+ urb->number_of_packets = 0;
+ spin_lock_irqsave(&subs->lock, flags);
+ for (i = 0; i < ctx->packets; i++) {
+ counts = ctx->packet_size[i];
+ /* set up descriptor */
+ urb->iso_frame_desc[i].offset = frames * stride;
+ urb->iso_frame_desc[i].length = counts * stride;
+ frames += counts;
+ urb->number_of_packets++;
+ subs->transfer_done += counts;
+ if (subs->transfer_done >= runtime->period_size) {
+ subs->transfer_done -= runtime->period_size;
+ period_elapsed = 1;
+ if (subs->fmt_type == UAC_FORMAT_TYPE_II) {
+ if (subs->transfer_done > 0) {
+ /* FIXME: fill-max mode is not
+ * supported yet */
+ frames -= subs->transfer_done;
+ counts -= subs->transfer_done;
+ urb->iso_frame_desc[i].length =
+ counts * stride;
+ subs->transfer_done = 0;
+ }
+ i++;
+ if (i < ctx->packets) {
+ /* add a transfer delimiter */
+ urb->iso_frame_desc[i].offset =
+ frames * stride;
+ urb->iso_frame_desc[i].length = 0;
+ urb->number_of_packets++;
+ }
+ break;
+ }
+ }
+ if (period_elapsed &&
+ !snd_usb_endpoint_implict_feedback_sink(subs->data_endpoint)) /* finish at the period boundary */
+ break;
+ }
+ bytes = frames * stride;
+ if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
+ /* err, the transferred area goes over buffer boundary. */
+ unsigned int bytes1 =
+ runtime->buffer_size * stride - subs->hwptr_done;
+ memcpy(urb->transfer_buffer,
+ runtime->dma_area + subs->hwptr_done, bytes1);
+ memcpy(urb->transfer_buffer + bytes1,
+ runtime->dma_area, bytes - bytes1);
+ } else {
+ memcpy(urb->transfer_buffer,
+ runtime->dma_area + subs->hwptr_done, bytes);
+ }
+ subs->hwptr_done += bytes;
+ if (subs->hwptr_done >= runtime->buffer_size * stride)
+ subs->hwptr_done -= runtime->buffer_size * stride;
+ runtime->delay += frames;
+ spin_unlock_irqrestore(&subs->lock, flags);
+ urb->transfer_buffer_length = bytes;
+ if (period_elapsed)
+ snd_pcm_period_elapsed(subs->pcm_substream);
+}
+
+/*
+ * process after playback data complete
+ * - decrease the delay count again
+ */
+static void retire_playback_urb(struct snd_usb_substream *subs,
+ struct urb *urb)
+{
+ unsigned long flags;
+ struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
+ int stride = runtime->frame_bits >> 3;
+ int processed = urb->transfer_buffer_length / stride;
+
+ spin_lock_irqsave(&subs->lock, flags);
+ if (processed > runtime->delay)
+ runtime->delay = 0;
+ else
+ runtime->delay -= processed;
+ spin_unlock_irqrestore(&subs->lock, flags);
+}
+
static int snd_usb_playback_open(struct snd_pcm_substream *substream)
{
return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK);
@@ -872,6 +1076,62 @@ static int snd_usb_capture_close(struct snd_pcm_substream *substream)
return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_CAPTURE);
}
+static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct snd_usb_substream *subs = substream->runtime->private_data;
+
+ snd_printk("%s(): cmd %d\n", __func__, cmd);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ snd_printk("START!\n");
+ subs->data_endpoint->prepare_data_urb = prepare_playback_urb;
+ subs->data_endpoint->retire_data_urb = retire_playback_urb;
+ return 0;
+ case SNDRV_PCM_TRIGGER_STOP:
+ stop_endpoints(subs, 0, 0);
+ return 0;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ snd_printk("PAUSE!\n");
+ subs->data_endpoint->prepare_data_urb = NULL;
+ subs->data_endpoint->retire_data_urb = NULL;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int err;
+ struct snd_usb_substream *subs = substream->runtime->private_data;
+
+ snd_printk("%s(): cmd %d\n", __func__, cmd);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ err = start_endpoints(subs);
+ if (err < 0)
+ return err;
+
+ subs->data_endpoint->retire_data_urb = retire_capture_urb;
+ return 0;
+ case SNDRV_PCM_TRIGGER_STOP:
+ stop_endpoints(subs, 0, 0);
+ return 0;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ subs->data_endpoint->retire_data_urb = NULL;
+ return 0;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ subs->data_endpoint->retire_data_urb = retire_capture_urb;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
static struct snd_pcm_ops snd_usb_playback_ops = {
.open = snd_usb_playback_open,
.close = snd_usb_playback_close,
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 5ff8010..6b7d7a2 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -73,6 +73,31 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)
}
}
+/*
+ * initialize the substream instance.
+ */
+
+static void snd_usb_init_substream(struct snd_usb_stream *as,
+ int stream,
+ struct audioformat *fp)
+{
+ struct snd_usb_substream *subs = &as->substream[stream];
+
+ INIT_LIST_HEAD(&subs->fmt_list);
+ spin_lock_init(&subs->lock);
+
+ subs->stream = as;
+ subs->direction = stream;
+ subs->dev = as->chip->dev;
+ subs->txfr_quirk = as->chip->txfr_quirk;
+
+ snd_usb_set_pcm_ops(as->pcm, stream);
+
+ list_add_tail(&fp->list, &subs->fmt_list);
+ subs->formats |= fp->formats;
+ subs->num_formats++;
+ subs->fmt_type = fp->fmt_type;
+}
/*
* add this endpoint to the chip instance.
@@ -94,9 +119,9 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
if (as->fmt_type != fp->fmt_type)
continue;
subs = &as->substream[stream];
- if (!subs->endpoint)
+ if (!subs->data_endpoint)
continue;
- if (subs->endpoint == fp->endpoint) {
+ if (subs->data_endpoint->ep_num == fp->endpoint) {
list_add_tail(&fp->list, &subs->fmt_list);
subs->num_formats++;
subs->formats |= fp->formats;
@@ -109,7 +134,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
if (as->fmt_type != fp->fmt_type)
continue;
subs = &as->substream[stream];
- if (subs->endpoint)
+ if (subs->data_endpoint)
continue;
err = snd_pcm_new_stream(as->pcm, stream, 1);
if (err < 0)
--
1.7.5.4
^ permalink raw reply related
* [PATCH 3/5] ALSA: snd-usb: remove old streaming logic
From: Daniel Mack @ 2011-10-31 12:10 UTC (permalink / raw)
To: alsa-devel; +Cc: gdiffey, tiwai, clemens, linuxaudio, Daniel Mack, blablack
In-Reply-To: <1320063030-3502-1-git-send-email-zonque@gmail.com>
---
sound/usb/endpoint.c | 917 +++-----------------------------------------------
sound/usb/endpoint.h | 15 -
2 files changed, 41 insertions(+), 891 deletions(-)
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index e0872a0..cceb2ff 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -49,882 +49,6 @@ static inline unsigned get_usb_high_speed_rate(unsigned int rate)
return ((rate << 10) + 62) / 125;
}
-/*
- * unlink active urbs.
- */
-static int deactivate_urbs_old(struct snd_usb_substream *subs, int force, int can_sleep)
-{
- struct snd_usb_audio *chip = subs->stream->chip;
- unsigned int i;
- int async;
-
- subs->running = 0;
-
- if (!force && subs->stream->chip->shutdown) /* to be sure... */
- return -EBADFD;
-
- async = !can_sleep && chip->async_unlink;
-
- if (!async && in_interrupt())
- return 0;
-
- for (i = 0; i < subs->nurbs; i++) {
- if (test_bit(i, &subs->active_mask)) {
- if (!test_and_set_bit(i, &subs->unlink_mask)) {
- struct urb *u = subs->dataurb[i].urb;
- if (async)
- usb_unlink_urb(u);
- else
- usb_kill_urb(u);
- }
- }
- }
- if (subs->syncpipe) {
- for (i = 0; i < SYNC_URBS; i++) {
- if (test_bit(i+16, &subs->active_mask)) {
- if (!test_and_set_bit(i+16, &subs->unlink_mask)) {
- struct urb *u = subs->syncurb[i].urb;
- if (async)
- usb_unlink_urb(u);
- else
- usb_kill_urb(u);
- }
- }
- }
- }
- return 0;
-}
-
-
-/*
- * release a urb data
- */
-static void release_urb_ctx(struct snd_urb_ctx *u)
-{
- if (u->urb) {
- if (u->buffer_size)
- usb_free_coherent(u->subs->dev, u->buffer_size,
- u->urb->transfer_buffer,
- u->urb->transfer_dma);
- usb_free_urb(u->urb);
- u->urb = NULL;
- }
-}
-
-/*
- * wait until all urbs are processed.
- */
-static int wait_clear_urbs_old(struct snd_usb_substream *subs)
-{
- unsigned long end_time = jiffies + msecs_to_jiffies(1000);
- unsigned int i;
- int alive;
-
- do {
- alive = 0;
- for (i = 0; i < subs->nurbs; i++) {
- if (test_bit(i, &subs->active_mask))
- alive++;
- }
- if (subs->syncpipe) {
- for (i = 0; i < SYNC_URBS; i++) {
- if (test_bit(i + 16, &subs->active_mask))
- alive++;
- }
- }
- if (! alive)
- break;
- schedule_timeout_uninterruptible(1);
- } while (time_before(jiffies, end_time));
- if (alive)
- snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
- return 0;
-}
-
-/*
- * release a substream
- */
-void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force)
-{
- int i;
-
- /* stop urbs (to be sure) */
- deactivate_urbs_old(subs, force, 1);
- wait_clear_urbs_old(subs);
-
- for (i = 0; i < MAX_URBS; i++)
- release_urb_ctx(&subs->dataurb[i]);
- for (i = 0; i < SYNC_URBS; i++)
- release_urb_ctx(&subs->syncurb[i]);
- usb_free_coherent(subs->dev, SYNC_URBS * 4,
- subs->syncbuf, subs->sync_dma);
- subs->syncbuf = NULL;
- subs->nurbs = 0;
-}
-
-/*
- * complete callback from data urb
- */
-static void snd_complete_urb_old(struct urb *urb)
-{
- struct snd_urb_ctx *ctx = urb->context;
- struct snd_usb_substream *subs = ctx->subs;
- struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
- int err = 0;
-
- if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) ||
- !subs->running || /* can be stopped during retire callback */
- (err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 ||
- (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
- clear_bit(ctx->index, &subs->active_mask);
- if (err < 0) {
- snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err);
- snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
- }
- }
-}
-
-
-/*
- * complete callback from sync urb
- */
-static void snd_complete_sync_urb(struct urb *urb)
-{
- struct snd_urb_ctx *ctx = urb->context;
- struct snd_usb_substream *subs = ctx->subs;
- struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
- int err = 0;
-
- if ((subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) ||
- !subs->running || /* can be stopped during retire callback */
- (err = subs->ops.prepare_sync(subs, substream->runtime, urb)) < 0 ||
- (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
- clear_bit(ctx->index + 16, &subs->active_mask);
- if (err < 0) {
- snd_printd(KERN_ERR "cannot submit sync urb (err = %d)\n", err);
- snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
- }
- }
-}
-
-
-/*
- * initialize a substream for plaback/capture
- */
-int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
- unsigned int period_bytes,
- unsigned int rate,
- unsigned int frame_bits)
-{
- unsigned int maxsize, i;
- int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
- unsigned int urb_packs, total_packs, packs_per_ms;
- struct snd_usb_audio *chip = subs->stream->chip;
-
- /* calculate the frequency in 16.16 format */
- if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
- subs->freqn = get_usb_full_speed_rate(rate);
- else
- subs->freqn = get_usb_high_speed_rate(rate);
- subs->freqm = subs->freqn;
- subs->freqshift = INT_MIN;
- /* calculate max. frequency */
- if (subs->maxpacksize) {
- /* whatever fits into a max. size packet */
- maxsize = subs->maxpacksize;
- subs->freqmax = (maxsize / (frame_bits >> 3))
- << (16 - subs->datainterval);
- } else {
- /* no max. packet size: just take 25% higher than nominal */
- subs->freqmax = subs->freqn + (subs->freqn >> 2);
- maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3))
- >> (16 - subs->datainterval);
- }
- subs->phase = 0;
-
- if (subs->fill_max)
- subs->curpacksize = subs->maxpacksize;
- else
- subs->curpacksize = maxsize;
-
- if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL)
- packs_per_ms = 8 >> subs->datainterval;
- else
- packs_per_ms = 1;
-
- if (is_playback) {
- urb_packs = max(chip->nrpacks, 1);
- urb_packs = min(urb_packs, (unsigned int)MAX_PACKS);
- } else
- urb_packs = 1;
- urb_packs *= packs_per_ms;
- if (subs->syncpipe)
- urb_packs = min(urb_packs, 1U << subs->syncinterval);
-
- /* decide how many packets to be used */
- if (is_playback) {
- unsigned int minsize, maxpacks;
- /* determine how small a packet can be */
- minsize = (subs->freqn >> (16 - subs->datainterval))
- * (frame_bits >> 3);
- /* with sync from device, assume it can be 12% lower */
- if (subs->syncpipe)
- minsize -= minsize >> 3;
- minsize = max(minsize, 1u);
- total_packs = (period_bytes + minsize - 1) / minsize;
- /* we need at least two URBs for queueing */
- if (total_packs < 2) {
- total_packs = 2;
- } else {
- /* and we don't want too long a queue either */
- maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2);
- total_packs = min(total_packs, maxpacks);
- }
- } else {
- while (urb_packs > 1 && urb_packs * maxsize >= period_bytes)
- urb_packs >>= 1;
- total_packs = MAX_URBS * urb_packs;
- }
- subs->nurbs = (total_packs + urb_packs - 1) / urb_packs;
- if (subs->nurbs > MAX_URBS) {
- /* too much... */
- subs->nurbs = MAX_URBS;
- total_packs = MAX_URBS * urb_packs;
- } else if (subs->nurbs < 2) {
- /* too little - we need at least two packets
- * to ensure contiguous playback/capture
- */
- subs->nurbs = 2;
- }
-
- /* allocate and initialize data urbs */
- for (i = 0; i < subs->nurbs; i++) {
- struct snd_urb_ctx *u = &subs->dataurb[i];
- u->index = i;
- u->subs = subs;
- u->packets = (i + 1) * total_packs / subs->nurbs
- - i * total_packs / subs->nurbs;
- u->buffer_size = maxsize * u->packets;
- if (subs->fmt_type == UAC_FORMAT_TYPE_II)
- u->packets++; /* for transfer delimiter */
- u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
- if (!u->urb)
- goto out_of_memory;
- u->urb->transfer_buffer =
- usb_alloc_coherent(subs->dev, u->buffer_size,
- GFP_KERNEL, &u->urb->transfer_dma);
- if (!u->urb->transfer_buffer)
- goto out_of_memory;
- u->urb->pipe = subs->datapipe;
- u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
- u->urb->interval = 1 << subs->datainterval;
- u->urb->context = u;
- u->urb->complete = snd_complete_urb_old;
- }
-
- if (subs->syncpipe) {
- /* allocate and initialize sync urbs */
- subs->syncbuf = usb_alloc_coherent(subs->dev, SYNC_URBS * 4,
- GFP_KERNEL, &subs->sync_dma);
- if (!subs->syncbuf)
- goto out_of_memory;
- for (i = 0; i < SYNC_URBS; i++) {
- struct snd_urb_ctx *u = &subs->syncurb[i];
- u->index = i;
- u->subs = subs;
- u->packets = 1;
- u->urb = usb_alloc_urb(1, GFP_KERNEL);
- if (!u->urb)
- goto out_of_memory;
- u->urb->transfer_buffer = subs->syncbuf + i * 4;
- u->urb->transfer_dma = subs->sync_dma + i * 4;
- u->urb->transfer_buffer_length = 4;
- u->urb->pipe = subs->syncpipe;
- u->urb->transfer_flags = URB_ISO_ASAP |
- URB_NO_TRANSFER_DMA_MAP;
- u->urb->number_of_packets = 1;
- u->urb->interval = 1 << subs->syncinterval;
- u->urb->context = u;
- u->urb->complete = snd_complete_sync_urb;
- }
- }
- return 0;
-
-out_of_memory:
- snd_usb_release_substream_urbs(subs, 0);
- return -ENOMEM;
-}
-
-/*
- * prepare urb for full speed capture sync pipe
- *
- * fill the length and offset of each urb descriptor.
- * the fixed 10.14 frequency is passed through the pipe.
- */
-static int prepare_capture_sync_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
-{
- unsigned char *cp = urb->transfer_buffer;
- struct snd_urb_ctx *ctx = urb->context;
-
- urb->dev = ctx->subs->dev; /* we need to set this at each time */
- urb->iso_frame_desc[0].length = 3;
- urb->iso_frame_desc[0].offset = 0;
- cp[0] = subs->freqn >> 2;
- cp[1] = subs->freqn >> 10;
- cp[2] = subs->freqn >> 18;
- return 0;
-}
-
-/*
- * prepare urb for high speed capture sync pipe
- *
- * fill the length and offset of each urb descriptor.
- * the fixed 12.13 frequency is passed as 16.16 through the pipe.
- */
-static int prepare_capture_sync_urb_hs(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
-{
- unsigned char *cp = urb->transfer_buffer;
- struct snd_urb_ctx *ctx = urb->context;
-
- urb->dev = ctx->subs->dev; /* we need to set this at each time */
- urb->iso_frame_desc[0].length = 4;
- urb->iso_frame_desc[0].offset = 0;
- cp[0] = subs->freqn;
- cp[1] = subs->freqn >> 8;
- cp[2] = subs->freqn >> 16;
- cp[3] = subs->freqn >> 24;
- return 0;
-}
-
-/*
- * process after capture sync complete
- * - nothing to do
- */
-static int retire_capture_sync_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
-{
- return 0;
-}
-
-/*
- * prepare urb for capture data pipe
- *
- * fill the offset and length of each descriptor.
- *
- * we use a temporary buffer to write the captured data.
- * since the length of written data is determined by host, we cannot
- * write onto the pcm buffer directly... the data is thus copied
- * later at complete callback to the global buffer.
- */
-static int prepare_capture_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
-{
- int i, offs;
- struct snd_urb_ctx *ctx = urb->context;
-
- offs = 0;
- urb->dev = ctx->subs->dev; /* we need to set this at each time */
- for (i = 0; i < ctx->packets; i++) {
- urb->iso_frame_desc[i].offset = offs;
- urb->iso_frame_desc[i].length = subs->curpacksize;
- offs += subs->curpacksize;
- }
- urb->transfer_buffer_length = offs;
- urb->number_of_packets = ctx->packets;
- return 0;
-}
-
-/*
- * process after capture complete
- *
- * copy the data from each desctiptor to the pcm buffer, and
- * update the current position.
- */
-static int retire_capture_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
-{
- unsigned long flags;
- unsigned char *cp;
- int i;
- unsigned int stride, frames, bytes, oldptr;
- int period_elapsed = 0;
-
- stride = runtime->frame_bits >> 3;
-
- for (i = 0; i < urb->number_of_packets; i++) {
- cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
- if (urb->iso_frame_desc[i].status) {
- snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
- // continue;
- }
- bytes = urb->iso_frame_desc[i].actual_length;
- frames = bytes / stride;
- if (!subs->txfr_quirk)
- bytes = frames * stride;
- if (bytes % (runtime->sample_bits >> 3) != 0) {
-#ifdef CONFIG_SND_DEBUG_VERBOSE
- int oldbytes = bytes;
-#endif
- bytes = frames * stride;
- snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n",
- oldbytes, bytes);
- }
- /* update the current pointer */
- spin_lock_irqsave(&subs->lock, flags);
- oldptr = subs->hwptr_done;
- subs->hwptr_done += bytes;
- if (subs->hwptr_done >= runtime->buffer_size * stride)
- subs->hwptr_done -= runtime->buffer_size * stride;
- frames = (bytes + (oldptr % stride)) / stride;
- subs->transfer_done += frames;
- if (subs->transfer_done >= runtime->period_size) {
- subs->transfer_done -= runtime->period_size;
- period_elapsed = 1;
- }
- spin_unlock_irqrestore(&subs->lock, flags);
- /* copy a data chunk */
- if (oldptr + bytes > runtime->buffer_size * stride) {
- unsigned int bytes1 =
- runtime->buffer_size * stride - oldptr;
- memcpy(runtime->dma_area + oldptr, cp, bytes1);
- memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1);
- } else {
- memcpy(runtime->dma_area + oldptr, cp, bytes);
- }
- }
- if (period_elapsed)
- snd_pcm_period_elapsed(subs->pcm_substream);
- return 0;
-}
-
-/*
- * Process after capture complete when paused. Nothing to do.
- */
-static int retire_paused_capture_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
-{
- return 0;
-}
-
-
-/*
- * prepare urb for playback sync pipe
- *
- * set up the offset and length to receive the current frequency.
- */
-static int prepare_playback_sync_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
-{
- struct snd_urb_ctx *ctx = urb->context;
-
- urb->dev = ctx->subs->dev; /* we need to set this at each time */
- urb->iso_frame_desc[0].length = min(4u, ctx->subs->syncmaxsize);
- urb->iso_frame_desc[0].offset = 0;
- return 0;
-}
-
-/*
- * process after playback sync complete
- *
- * Full speed devices report feedback values in 10.14 format as samples per
- * frame, high speed devices in 16.16 format as samples per microframe.
- * Because the Audio Class 1 spec was written before USB 2.0, many high speed
- * devices use a wrong interpretation, some others use an entirely different
- * format. Therefore, we cannot predict what format any particular device uses
- * and must detect it automatically.
- */
-static int retire_playback_sync_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
-{
- unsigned int f;
- int shift;
- unsigned long flags;
-
- if (urb->iso_frame_desc[0].status != 0 ||
- urb->iso_frame_desc[0].actual_length < 3)
- return 0;
-
- f = le32_to_cpup(urb->transfer_buffer);
- if (urb->iso_frame_desc[0].actual_length == 3)
- f &= 0x00ffffff;
- else
- f &= 0x0fffffff;
- if (f == 0)
- return 0;
-
- if (unlikely(subs->freqshift == INT_MIN)) {
- /*
- * The first time we see a feedback value, determine its format
- * by shifting it left or right until it matches the nominal
- * frequency value. This assumes that the feedback does not
- * differ from the nominal value more than +50% or -25%.
- */
- shift = 0;
- while (f < subs->freqn - subs->freqn / 4) {
- f <<= 1;
- shift++;
- }
- while (f > subs->freqn + subs->freqn / 2) {
- f >>= 1;
- shift--;
- }
- subs->freqshift = shift;
- }
- else if (subs->freqshift >= 0)
- f <<= subs->freqshift;
- else
- f >>= -subs->freqshift;
-
- if (likely(f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax)) {
- /*
- * If the frequency looks valid, set it.
- * This value is referred to in prepare_playback_urb().
- */
- spin_lock_irqsave(&subs->lock, flags);
- subs->freqm = f;
- spin_unlock_irqrestore(&subs->lock, flags);
- } else {
- /*
- * Out of range; maybe the shift value is wrong.
- * Reset it so that we autodetect again the next time.
- */
- subs->freqshift = INT_MIN;
- }
-
- return 0;
-}
-
-/* determine the number of frames in the next packet */
-static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs)
-{
- if (subs->fill_max)
- return subs->maxframesize;
- else {
- subs->phase = (subs->phase & 0xffff)
- + (subs->freqm << subs->datainterval);
- return min(subs->phase >> 16, subs->maxframesize);
- }
-}
-
-/*
- * Prepare urb for streaming before playback starts or when paused.
- *
- * We don't have any data, so we send silence.
- */
-static int prepare_nodata_playback_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
-{
- unsigned int i, offs, counts;
- struct snd_urb_ctx *ctx = urb->context;
- int stride = runtime->frame_bits >> 3;
-
- offs = 0;
- urb->dev = ctx->subs->dev;
- for (i = 0; i < ctx->packets; ++i) {
- counts = snd_usb_audio_next_packet_size(subs);
- urb->iso_frame_desc[i].offset = offs * stride;
- urb->iso_frame_desc[i].length = counts * stride;
- offs += counts;
- }
- urb->number_of_packets = ctx->packets;
- urb->transfer_buffer_length = offs * stride;
- memset(urb->transfer_buffer,
- runtime->format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0,
- offs * stride);
- return 0;
-}
-
-/*
- * prepare urb for playback data pipe
- *
- * Since a URB can handle only a single linear buffer, we must use double
- * buffering when the data to be transferred overflows the buffer boundary.
- * To avoid inconsistencies when updating hwptr_done, we use double buffering
- * for all URBs.
- */
-static int prepare_playback_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
-{
- int i, stride;
- unsigned int counts, frames, bytes;
- unsigned long flags;
- int period_elapsed = 0;
- struct snd_urb_ctx *ctx = urb->context;
-
- stride = runtime->frame_bits >> 3;
-
- frames = 0;
- urb->dev = ctx->subs->dev; /* we need to set this at each time */
- urb->number_of_packets = 0;
- spin_lock_irqsave(&subs->lock, flags);
- for (i = 0; i < ctx->packets; i++) {
- counts = snd_usb_audio_next_packet_size(subs);
- /* set up descriptor */
- urb->iso_frame_desc[i].offset = frames * stride;
- urb->iso_frame_desc[i].length = counts * stride;
- frames += counts;
- urb->number_of_packets++;
- subs->transfer_done += counts;
- if (subs->transfer_done >= runtime->period_size) {
- subs->transfer_done -= runtime->period_size;
- period_elapsed = 1;
- if (subs->fmt_type == UAC_FORMAT_TYPE_II) {
- if (subs->transfer_done > 0) {
- /* FIXME: fill-max mode is not
- * supported yet */
- frames -= subs->transfer_done;
- counts -= subs->transfer_done;
- urb->iso_frame_desc[i].length =
- counts * stride;
- subs->transfer_done = 0;
- }
- i++;
- if (i < ctx->packets) {
- /* add a transfer delimiter */
- urb->iso_frame_desc[i].offset =
- frames * stride;
- urb->iso_frame_desc[i].length = 0;
- urb->number_of_packets++;
- }
- break;
- }
- }
- if (period_elapsed) /* finish at the period boundary */
- break;
- }
- bytes = frames * stride;
- if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
- /* err, the transferred area goes over buffer boundary. */
- unsigned int bytes1 =
- runtime->buffer_size * stride - subs->hwptr_done;
- memcpy(urb->transfer_buffer,
- runtime->dma_area + subs->hwptr_done, bytes1);
- memcpy(urb->transfer_buffer + bytes1,
- runtime->dma_area, bytes - bytes1);
- } else {
- memcpy(urb->transfer_buffer,
- runtime->dma_area + subs->hwptr_done, bytes);
- }
- subs->hwptr_done += bytes;
- if (subs->hwptr_done >= runtime->buffer_size * stride)
- subs->hwptr_done -= runtime->buffer_size * stride;
-
- /* update delay with exact number of samples queued */
- runtime->delay = subs->last_delay;
- runtime->delay += frames;
- subs->last_delay = runtime->delay;
-
- /* realign last_frame_number */
- subs->last_frame_number = usb_get_current_frame_number(subs->dev);
- subs->last_frame_number &= 0xFF; /* keep 8 LSBs */
-
- spin_unlock_irqrestore(&subs->lock, flags);
- urb->transfer_buffer_length = bytes;
- if (period_elapsed)
- snd_pcm_period_elapsed(subs->pcm_substream);
- return 0;
-}
-
-/*
- * process after playback data complete
- * - decrease the delay count again
- */
-static int retire_playback_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
-{
- unsigned long flags;
- int stride = runtime->frame_bits >> 3;
- int processed = urb->transfer_buffer_length / stride;
- int est_delay;
-
- spin_lock_irqsave(&subs->lock, flags);
-
- est_delay = snd_usb_pcm_delay(subs, runtime->rate);
- /* update delay with exact number of samples played */
- if (processed > subs->last_delay)
- subs->last_delay = 0;
- else
- subs->last_delay -= processed;
- runtime->delay = subs->last_delay;
-
- /*
- * Report when delay estimate is off by more than 2ms.
- * The error should be lower than 2ms since the estimate relies
- * on two reads of a counter updated every ms.
- */
- if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2)
- snd_printk(KERN_DEBUG "delay: estimated %d, actual %d\n",
- est_delay, subs->last_delay);
-
- spin_unlock_irqrestore(&subs->lock, flags);
- return 0;
-}
-
-static const char *usb_error_string(int err)
-{
- switch (err) {
- case -ENODEV:
- return "no device";
- case -ENOENT:
- return "endpoint not enabled";
- case -EPIPE:
- return "endpoint stalled";
- case -ENOSPC:
- return "not enough bandwidth";
- case -ESHUTDOWN:
- return "device disabled";
- case -EHOSTUNREACH:
- return "device suspended";
- case -EINVAL:
- case -EAGAIN:
- case -EFBIG:
- case -EMSGSIZE:
- return "internal error";
- default:
- return "unknown error";
- }
-}
-
-/*
- * set up and start data/sync urbs
- */
-static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime)
-{
- unsigned int i;
- int err;
-
- if (subs->stream->chip->shutdown)
- return -EBADFD;
-
- for (i = 0; i < subs->nurbs; i++) {
- if (snd_BUG_ON(!subs->dataurb[i].urb))
- return -EINVAL;
- if (subs->ops.prepare(subs, runtime, subs->dataurb[i].urb) < 0) {
- snd_printk(KERN_ERR "cannot prepare datapipe for urb %d\n", i);
- goto __error;
- }
- }
- if (subs->syncpipe) {
- for (i = 0; i < SYNC_URBS; i++) {
- if (snd_BUG_ON(!subs->syncurb[i].urb))
- return -EINVAL;
- if (subs->ops.prepare_sync(subs, runtime, subs->syncurb[i].urb) < 0) {
- snd_printk(KERN_ERR "cannot prepare syncpipe for urb %d\n", i);
- goto __error;
- }
- }
- }
-
- subs->active_mask = 0;
- subs->unlink_mask = 0;
- subs->running = 1;
- for (i = 0; i < subs->nurbs; i++) {
- err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC);
- if (err < 0) {
- snd_printk(KERN_ERR "cannot submit datapipe "
- "for urb %d, error %d: %s\n",
- i, err, usb_error_string(err));
- goto __error;
- }
- set_bit(i, &subs->active_mask);
- }
- if (subs->syncpipe) {
- for (i = 0; i < SYNC_URBS; i++) {
- err = usb_submit_urb(subs->syncurb[i].urb, GFP_ATOMIC);
- if (err < 0) {
- snd_printk(KERN_ERR "cannot submit syncpipe "
- "for urb %d, error %d: %s\n",
- i, err, usb_error_string(err));
- goto __error;
- }
- set_bit(i + 16, &subs->active_mask);
- }
- }
- return 0;
-
- __error:
- // snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
- deactivate_urbs_old(subs, 0, 0);
- return -EPIPE;
-}
-
-
-/*
- */
-static struct snd_urb_ops audio_urb_ops[2] = {
- {
- .prepare = prepare_nodata_playback_urb,
- .retire = retire_playback_urb,
- .prepare_sync = prepare_playback_sync_urb,
- .retire_sync = retire_playback_sync_urb,
- },
- {
- .prepare = prepare_capture_urb,
- .retire = retire_capture_urb,
- .prepare_sync = prepare_capture_sync_urb,
- .retire_sync = retire_capture_sync_urb,
- },
-};
-
-/*
- * initialize the substream instance.
- */
-
-void snd_usb_init_substream(struct snd_usb_stream *as,
- int stream, struct audioformat *fp)
-{
- struct snd_usb_substream *subs = &as->substream[stream];
-
- INIT_LIST_HEAD(&subs->fmt_list);
- spin_lock_init(&subs->lock);
-
- subs->stream = as;
- subs->direction = stream;
- subs->dev = as->chip->dev;
- subs->txfr_quirk = as->chip->txfr_quirk;
- subs->ops = audio_urb_ops[stream];
- if (snd_usb_get_speed(subs->dev) >= USB_SPEED_HIGH)
- subs->ops.prepare_sync = prepare_capture_sync_urb_hs;
-
- snd_usb_set_pcm_ops(as->pcm, stream);
-
- list_add_tail(&fp->list, &subs->fmt_list);
- subs->formats |= fp->formats;
- subs->endpoint = fp->endpoint;
- subs->num_formats++;
- subs->fmt_type = fp->fmt_type;
-}
-
-int snd_usb_substream_prepare(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime)
-{
- /* clear urbs (to be sure) */
- deactivate_urbs_old(subs, 0, 1);
- wait_clear_urbs_old(subs);
-
- /* for playback, submit the URBs now; otherwise, the first hwptr_done
- * updates for all URBs would happen at the same time when starting */
- if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) {
- subs->ops.prepare = prepare_nodata_playback_urb;
- return start_urbs(subs, runtime);
- }
-
- return 0;
-}
-
int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep)
{
return ep->sync_master &&
@@ -1174,6 +298,47 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
return ep;
}
+static const char *usb_error_string(int err)
+{
+ switch (err) {
+ case -ENODEV:
+ return "no device";
+ case -ENOENT:
+ return "endpoint not enabled";
+ case -EPIPE:
+ return "endpoint stalled";
+ case -ENOSPC:
+ return "not enough bandwidth";
+ case -ESHUTDOWN:
+ return "device disabled";
+ case -EHOSTUNREACH:
+ return "device suspended";
+ case -EINVAL:
+ case -EAGAIN:
+ case -EFBIG:
+ case -EMSGSIZE:
+ return "internal error";
+ default:
+ return "unknown error";
+ }
+}
+
+/*
+ * release a urb data
+ */
+static void release_urb_ctx(struct snd_urb_ctx *u)
+{
+ if (!u->urb)
+ return;
+
+ if (u->buffer_size)
+ usb_free_coherent(u->ep->chip->dev, u->buffer_size,
+ u->urb->transfer_buffer,
+ u->urb->transfer_dma);
+ usb_free_urb(u->urb);
+ u->urb = NULL;
+}
+
/*
* wait until all urbs are processed.
*/
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h
index f9d3843..e499050 100644
--- a/sound/usb/endpoint.h
+++ b/sound/usb/endpoint.h
@@ -1,21 +1,6 @@
#ifndef __USBAUDIO_ENDPOINT_H
#define __USBAUDIO_ENDPOINT_H
-void snd_usb_init_substream(struct snd_usb_stream *as,
- int stream,
- struct audioformat *fp);
-
-int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
- unsigned int period_bytes,
- unsigned int rate,
- unsigned int frame_bits);
-
-void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force);
-
-int snd_usb_substream_prepare(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime);
-
-
#define SND_USB_ENDPOINT_TYPE_DATA 0
#define SND_USB_ENDPOINT_TYPE_SYNC 1
--
1.7.5.4
^ permalink raw reply related
* [PATCH 4/5] ALSA: snd-usb: set MAX_URBS to 16
From: Daniel Mack @ 2011-10-31 12:10 UTC (permalink / raw)
To: alsa-devel; +Cc: gdiffey, tiwai, clemens, linuxaudio, Daniel Mack, blablack
In-Reply-To: <1320063030-3502-1-git-send-email-zonque@gmail.com>
This is needed for implicity feedback data streams.
---
sound/usb/card.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/sound/usb/card.h b/sound/usb/card.h
index 7fb8778..0a5515a 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -3,7 +3,7 @@
#define MAX_PACKS 20
#define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */
-#define MAX_URBS 8
+#define MAX_URBS 16
#define SYNC_URBS 4 /* always four urbs for sync */
#define MAX_QUEUE 24 /* try not to exceed this queue length, in ms */
--
1.7.5.4
^ permalink raw reply related
* [PATCH 5/5] ALSA: snd-usb: add support for implicit feedback
From: Daniel Mack @ 2011-10-31 12:10 UTC (permalink / raw)
To: alsa-devel; +Cc: gdiffey, tiwai, clemens, linuxaudio, Daniel Mack, blablack
In-Reply-To: <1320063030-3502-1-git-send-email-zonque@gmail.com>
---
sound/usb/pcm.c | 14 ++++++++++----
1 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index af21d38..e88abfa 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -312,9 +312,12 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) ||
(! is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) &&
altsd->bNumEndpoints >= 2) {
+ int implicit_fb = (get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_USAGE_MASK)
+ == USB_ENDPOINT_USAGE_IMPLICIT_FB;
switch (subs->stream->chip->usb_id) {
case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */
case USB_ID(0x0763, 0x2081):
+ implicit_fb = 1;
ep = 0x81;
iface = usb_ifnum_to_if(dev, 2);
alts = &iface->altsetting[1];
@@ -327,7 +330,8 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
the audio fields in the endpoint descriptors */
if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != 0x01 ||
(get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
- get_endpoint(alts, 1)->bSynchAddress != 0)) {
+ get_endpoint(alts, 1)->bSynchAddress != 0 &&
+ !implicit_fb)) {
snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n",
dev->devnum, fmt->iface, fmt->altsetting);
return -EINVAL;
@@ -335,7 +339,8 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
ep = get_endpoint(alts, 1)->bEndpointAddress;
if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
(( is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) ||
- (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) {
+ (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)) ||
+ ( is_playback && !implicit_fb))) {
snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n",
dev->devnum, fmt->iface, fmt->altsetting);
return -EINVAL;
@@ -343,8 +348,9 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
add_sync_ep:
subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip,
alts, ep, !subs->direction,
- SND_USB_ENDPOINT_TYPE_SYNC);
-
+ implicit_fb ?
+ SND_USB_ENDPOINT_TYPE_DATA :
+ SND_USB_ENDPOINT_TYPE_SYNC);
if (!subs->sync_endpoint)
return -EINVAL;
--
1.7.5.4
^ permalink raw reply related
* [Xenomai-help] configuring user-space xenomai 2.6
From: Łukasz Sacha @ 2011-10-31 12:14 UTC (permalink / raw)
To: xenomai
Hey,
I'm following README_INSTALL from the xenoami 2.6 tree. I successfully
patched and built the kernel 2.6.38.8 and modules. Now I'm trying to
configure the user-space.
I'm running the configure command as given in the example:
./configure CFLAGS="-march=armv4t" LDFLAGS="-march=armv4t"
--host=arm-none-linux-gnueabi- --build=i686-pc-linux-gnu
I get the following error:
checking build system type... i686-pc-linux-gnu
checking host system type... Invalid configuration
`arm-none-linux-gnueabi-': machine `arm-none-linux-gnueabi' not
recognized
configure: error: /bin/bash config/config.sub arm-none-linux-gnueabi- failed
This is how my environment is setup:
luke@domain.hid$ which
arm-none-linux-gnueabi-gcc
/home/luke/Desktop/moje/mini2440/arm-2008q3/bin/arm-none-linux-gnueabi-gcc
luke@domain.hid$ echo $PATH
/home/luke/Desktop/moje/mini2440/arm-2008q3/bin:/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
No adequate info in the TROUBLESHOOTING.
Am doing something wrong? Help me out please.
regards,
--
Łukasz Dragilla Sacha
^ permalink raw reply
* [Bug 41592] [Radeon] The display often freezes with gnome-shell 3.2
From: bugzilla-daemon @ 2011-10-31 12:14 UTC (permalink / raw)
To: dri-devel
In-Reply-To: <bug-41592-502@http.bugs.freedesktop.org/>
https://bugs.freedesktop.org/show_bug.cgi?id=41592
--- Comment #13 from peterle@hottemptation.org 2011-10-31 05:14:25 PDT ---
Forgot something important!
Are you using the last official xf86-video-radeon driver or the one from git?
--
Configure bugmail: https://bugs.freedesktop.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug.
^ permalink raw reply
* Re: [PATCH] xfsdump: fix metadata restore on split files
From: Bill Kendall @ 2011-10-31 12:14 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: xfs
In-Reply-To: <20111028093716.GA23069@infradead.org>
On 10/28/2011 04:37 AM, Christoph Hellwig wrote:
> On Wed, Oct 26, 2011 at 06:24:43PM -0500, Bill Kendall wrote:
>> xfsrestore does not apply certain metadata until all of the file's
>> data has been restored. This allows, for example, files with the
>> immutable flag set to be restored properly.
>>
>> While testing multi-stream restores, I noticed that files split
>> across multiple streams did not have their metadata restored.
>> Looking into this further, it also applies to the single-stream
>> case where files are split across media files, such as when a
>> backup spans multiple tapes.
>>
>> The fix is to check to see if a file is completely restored
>> whenever we hit the end of a media file. The current code
>> is broken because it relies on all media files being applied
>> during the same restore session.
>>
>> This also moves the S_ISREG() check into restore_complete_reg()
>> rather than relying on callers to make the check.
>
> Uhh, that's a nasty bug for people storing large files over multiple
> tapes. Any chance we could get an xfstests test case for this?
I mischaracterized the existing bug, files split across tapes
are okay. The bug occurs when:
- a file ends right at the end of a tape in a multi-tape dump, and
- the next tape is not loaded during the same restore session
(i.e., the restore is interrupted and resumed later)
> Can we somehow simulate multiple tapes using small files?
We can simulate multiple tapes on a single tape by asking for a
small media file size. I've got a couple of tests which do this
which I'll post later today.
I don't have a test for the exact scenario above. That would
require using 2 tapes (or 2 files on small loopback filesystems)
and knowing the exact number of bytes that will fit in the dump
file, then working backwards to find a file size that will end
at the right spot on media. Sounds like a very fragile test. It
would break if, for example, a file in the filesystem being
dumped was written as 2 extents instead of 1.
I'll repost this patch with correct commit message.
Bill
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply
* Re: [PATCH v2 3/3] staging:iio:dac: Add AD5421 driver
From: Lars-Peter Clausen @ 2011-10-31 12:14 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Lars-Peter Clausen, Hennerich, Michael, linux-iio@vger.kernel.org,
device-drivers-devel@blackfin.uclinux.org, Drivers
In-Reply-To: <4EAE8660.2020604@cam.ac.uk>
On 10/31/2011 12:28 PM, Jonathan Cameron wrote:
> On 10/27/11 09:44, Lars-Peter Clausen wrote:
>> This patch adds support for the Analog Devices AD5421 Loop-Powered, 4mA to 20mA
>> DAC.
>>
>> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
> Acked-by: Jonathan Cameron <jic23@cam.ac.uk>
>
> Feel free to send on to Greg as you've nailed everything I cared about.
>
> I do wonder if we might be better with an explicit 'no_read' flag in the
> chan_spec for channels like this. That way we could assign more meaningful
> channel numbers? Afterall, sooner of later we are going to have something
> with two temperature sensors that only generate events.
>
> What do you think?
Makes sense, but I think we can add this when we have to add support for
such a device.
An alternative would be to make devices explicitly request raw attributes
through info_mask. But that would require touching all existing drivers again.
Could you also Ack "staging:iio: IIO_EVENT_CODE: Clamp channel numbers"?
I'll replace the s16 with __s16 before sending it on to Greg.
Thanks
- Lars
^ permalink raw reply
* Re: read 2
From: Stefan Puiu @ 2011-10-31 12:15 UTC (permalink / raw)
To: Jon Grant
Cc: mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w,
linux-man-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <CAGc9EveAKHV4--YZZWX6XMWuMDRh3C346eBBZwuKYQ1MBDBmcQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Hi,
read() is a system call. If you check 'man man', system calls are
documented in section 2, while library functions like fread are in
section 3.
Thanks,
Stefan.
On Sat, Oct 29, 2011 at 1:41 AM, Jon Grant <jg-hus3n9K41k0@public.gmane.org> wrote:
> Hello
>
> I saw fread is on section 3, but should read really be 3? It's not a
> kernel function directly I think. Perhaps the numbering is just
> historical?
>
> http://man7.org/linux/man-pages/online/pages/man2/read.2.html
>
> Best regards, Jon
> --
> To unsubscribe from this list: send the line "unsubscribe linux-man" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-man" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH RFC v2 12/13] libxl: New API for providing OS events to libxl
From: Ian Campbell @ 2011-10-31 12:15 UTC (permalink / raw)
To: Ian Jackson, Jon Ludlam, Dave Scott, Jim Fehlig
Cc: xen-devel@lists.xensource.com
In-Reply-To: <1319827031-15395-13-git-send-email-ian.jackson@eu.citrix.com>
Jon/Dave/Jim,
I CC'd you the API bits from 13/13 (as potential users of it) without
realising that there was some here too. Once again I've trimmed this to
just the public headers, see the archives if you want the underlying
bits.
Comments on the suitability for your usecases etc gratefully received.
Ian.
On Fri, 2011-10-28 at 19:37 +0100, Ian Jackson wrote:
> We provide a new set of functions and related structures
> libxl_osevent_*
> which are to be used by event-driven applications to receive
> information from libxl about which fds libxl is interested in, and
> what timeouts libxl is waiting for, and to pass back to libxl
> information about which fds are readable/writeable etc., and which
> timeouts have occurred. Ie, low-level events.
>
> In this patch, this new machinery is still all unused. Callers will
> appear in the next patch in the series, which introduces a new API for
> applications to receive high-level events about actual domains etc.
>
> Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
> ---
> tools/libxl/Makefile | 2 +-
> tools/libxl/libxl.c | 25 ++
> tools/libxl/libxl.h | 6 +
> tools/libxl/libxl_event.c | 704 ++++++++++++++++++++++++++++++++++++++++++
> tools/libxl/libxl_event.h | 185 +++++++++++
> tools/libxl/libxl_internal.h | 212 +++++++++++++-
> 6 files changed, 1131 insertions(+), 3 deletions(-)
> create mode 100644 tools/libxl/libxl_event.c
> create mode 100644 tools/libxl/libxl_event.h
[...]
> diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
> index 5d28ff9..da06ed2 100644
> --- a/tools/libxl/libxl.h
> +++ b/tools/libxl/libxl.h
> @@ -137,6 +137,7 @@
> #include <xen/sysctl.h>
>
> #include <libxl_uuid.h>
> +#include <_libxl_list.h>
>
> typedef uint8_t libxl_mac[6];
> #define LIBXL_MAC_FMT "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx"
> @@ -221,6 +222,9 @@ enum {
> ERROR_INVAL = -6,
> ERROR_BADFAIL = -7,
> ERROR_GUEST_TIMEDOUT = -8,
> + ERROR_NOT_READY = -9,
> + ERROR_OSEVENT_REG_FAIL = -10,
> + ERROR_BUFFERFULL = -11,
> };
>
> #define LIBXL_VERSION 0
> @@ -539,6 +543,8 @@ const char *libxl_xen_script_dir_path(void);
> const char *libxl_lock_dir_path(void);
> const char *libxl_run_dir_path(void);
>
> +#include <libxl_event.h>
> +
> #endif /* LIBXL_H */
>
> /*
> [...]
> diff --git a/tools/libxl/libxl_event.h b/tools/libxl/libxl_event.h
> new file mode 100644
> index 0000000..48c6277
> --- /dev/null
> +++ b/tools/libxl/libxl_event.h
> @@ -0,0 +1,185 @@
> +/*
> + * Copyright (C) 2011 Citrix Ltd.
> + * Author Ian Jackson <ian.jackson@eu.citrix.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU Lesser General Public License as published
> + * by the Free Software Foundation; version 2.1 only. with the special
> + * exception on linking described in file LICENSE.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU Lesser General Public License for more details.
> + */
> +
> +#ifndef LIBXL_EVENT_H
> +#define LIBXL_EVENT_H
> +
> +#include <libxl.h>
> +
> +
> +/*======================================================================*/
> +
> +/*
> + * OS event handling - passing low-level OS events to libxl
> + *
> + * Event-driven programs must use these facilities to allow libxl
> + * to become aware of readability/writeability of file descriptors
> + * and the occurrence of timeouts.
> + *
> + * There are two approaches available. The first is appropriate for
> + * simple programs handling reasonably small numbers of domains:
> + *
> + * for (;;) {
> + * libxl_osevent_beforepoll(...)
> + * poll();
> + * libxl_osevent_afterpoll(...);
> + * for (;;) {
> + * r=libxl_event_check(...);
> + * if (r==LIBXL_NOT_READY) break;
> + * if (r) handle failure;
> + * do something with the event;
> + * }
> + * }
> + *
> + * The second approach uses libxl_osevent_register_hooks and is
> + * suitable for programs which are already using a callback-based
> + * event library.
> + *
> + * An application may freely mix the two styles of interaction.
> + */
> +
> +struct pollfd;
> +
> +int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io,
> + struct pollfd *fds, int *timeout_upd,
> + struct timeval now);
> + /* The caller should provide beforepoll with some space for libxl's
> + * fds, and tell libxl how much space is available by setting *nfds_io.
> + * fds points to the start of this space (and fds may be a pointer into
> + * a larger array, for example, if the application has some fds of
> + * its own that it is interested in).
> + *
> + * On return *nfds_io will in any case have been updated by libxl
> + * according to how many fds libxl wants to poll on.
> + *
> + * If the space was sufficient, libxl fills in fds[0..<new
> + * *nfds_io>] suitably for poll(2), updates *timeout_upd if needed,
> + * and returns ok.
> + *
> + * If space was insufficient, fds[0..<old *nfds_io>] is undefined on
> + * return; *nfds_io on return will be greater than the value on
> + * entry; *timeout_upd may or may not have been updated; and
> + * libxl_osevent_beforepoll returns ERROR_BUFERFULL. In this case
> + * the application needs to make more space (enough space for
> + * *nfds_io struct pollfd) and then call beforepoll again, before
> + * entering poll(2). Typically this will involve calling realloc.
> + *
> + * The application may call beforepoll with fds==NULL and
> + * *nfds_io==0 in order to find out how much space is needed.
> + *
> + * *timeout_upd is as for poll(2): it's in milliseconds, and
> + * negative values mean no timeout (infinity).
> + * libxl_osevent_beforepoll will only reduce the timeout, naturally.
> + */
> +void libxl_osevent_afterpoll(libxl_ctx *ctx, int nfds, const struct pollfd *fds,
> + struct timeval now);
> + /* nfds and fds[0..nfds] must be from the most recent call to
> + * _beforepoll, as modified by poll.
> + *
> + * This function actually performs all of the IO and other actions,
> + * and generates events (libxl_event), which are implied by either
> + * (a) the time of day or (b) both (i) the returned information from
> + * _beforepoll, and (ii) the results from poll specified in
> + * fds[0..nfds-1]. Generated events can then be retrieved by
> + * libxl_event_check.
> + */
> +
> +
> +typedef struct libxl_osevent_hooks {
> + int (*fd_register)(void *user, int fd, void **for_app_registration_out,
> + short events, void *for_libxl);
> + int (*fd_modify)(void *user, int fd, void **for_app_registration_update,
> + short events);
> + void (*fd_deregister)(void *user, int fd, void *for_app_registration);
> + int (*timeout_register)(void *user, void **for_app_registration_out,
> + struct timeval abs, void *for_libxl);
> + int (*timeout_modify)(void *user, void **for_app_registration_update,
> + struct timeval abs);
> + void (*timeout_deregister)(void *user, void *for_app_registration_io);
> +} libxl_osevent_hooks;
> +
> +void libxl_osevent_register_hooks(libxl_ctx *ctx,
> + const libxl_osevent_hooks *hooks,
> + void *user);
> + /* The application which calls register_fd_hooks promises to
> + * maintain a register of fds and timeouts that libxl is interested
> + * in, and make calls into libxl (libxl_osevent_occurred_*)
> + * when those fd events and timeouts occur. This is more efficient
> + * than _beforepoll/_afterpoll if there are many fds (which can
> + * happen if the same libxl application is managing many domains).
> + *
> + * For an fd event, events is as for poll(). register or modify may
> + * be called with events==0, in which case it must still work
> + * normally, just not generate any events.
> + *
> + * For a timeout event, milliseconds is as for poll().
> + * Specifically, negative values of milliseconds mean NO TIMEOUT.
> + * This is used by libxl to temporarily disable a timeout.
> + *
> + * If the register or modify hook succeeds it may update
> + * *for_app_registration_out/_update and must then return 0.
> + * On entry to register, *for_app_registration_out is always NULL.
> + *
> + * A registration or modification hook may fail, in which case it
> + * must leave the registration state of the fd or timeout unchanged.
> + * It may then either return ERROR_OSEVENT_REG_FAIL or any positive
> + * int. The value returned will be passed up through libxl and
> + * eventually returned back to the application. When register
> + * fails, any value stored into *for_registration_out is ignored by
> + * libxl; when modify fails, any changed value stored into
> + * *for_registration_update is honoured by libxl and will be passed
> + * to future modify or deregister calls.
> + *
> + * libxl will only attempt to register one callback for any one fd.
> + * libxl will remember the value stored in *for_app_registration_io
> + * by a successful call to register or modify and pass it into
> + * subsequent calls to modify or deregister.
> + *
> + * register_fd_hooks may be called only once for each libxl_ctx.
> + * libxl may make calls to register/modify/deregister from within
> + * any libxl function (indeed, it will usually call register from
> + * register_event_hooks). Conversely, the application MUST NOT make
> + * the event occurrence calls (libxl_osevent_occurred_*) into libxl
> + * reentrantly from within libxl (for example, from within the
> + * register/modify functions).
> + *
> + * The value *hooks is not copied and must outlast the libxl_ctx.
> + */
> +
> +/* It is NOT legal to call _occurred_ reentrantly within any libxl
> + * function. Specifically it is NOT legal to call it from within
> + * a register callback. Conversely, libxl MAY call register/deregister
> + * from within libxl_event_registered_call_*.
> + */
> +
> +void libxl_osevent_occurred_fd(libxl_ctx *ctx, void *for_libxl,
> + int fd, short events, short revents);
> +
> +void libxl_osevent_occurred_timeout(libxl_ctx *ctx, void *for_libxl);
> + /* Implicitly, on entry to this function the timeout has been
> + * deregistered. If _occurred_timeout is called, libxl will not
> + * call timeout_deregister; if it wants to requeue the timeout it
> + * will call timeout_register again.
> + */
> +
> +#endif
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
^ permalink raw reply
* Re: [Qemu-devel] [PATCH 0/3] Xen related patches
From: Kevin Wolf @ 2011-10-31 12:20 UTC (permalink / raw)
To: John Baboval; +Cc: qemu-devel
In-Reply-To: <4EAB04A0.9010602@virtualcomputer.com>
Am 28.10.2011 21:38, schrieb John Baboval:
> These are some xen related patches that have been sitting around in are
> queue waiting for us to re-base onto a modern qemu. Now that we're
> up-to-date, they're ready to share with the list.
>
> They are all things that enable successfully running windows in xen HVM
> guests.
>
> Support guest reboots when in Xen HVM mode
> Xen conditionals
> piix4 acpi xen support
>
> -John
Your patches are corrupted by line wraps, and they don't use proper
email threading. Please consider using git send-email, which
automatically does both of this right.
Kevin
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.