From 4842a62062cd5567fd2edeb6099d71c2e92a2412 Mon Sep 17 00:00:00 2001 From: Giovanni Maruzzelli Date: Wed, 20 Apr 2011 03:38:45 -0500 Subject: [PATCH] skypopen: deleted osscuse subdir --- .../mod_skypopen/osscuse/98-osscuse.rules | 7 - .../endpoints/mod_skypopen/osscuse/LICENSE | 339 --- .../endpoints/mod_skypopen/osscuse/Makefile | 69 - src/mod/endpoints/mod_skypopen/osscuse/README | 119 - .../mod_skypopen/osscuse/ossp-alsap.c | 613 ----- .../mod_skypopen/osscuse/ossp-slave.c | 250 -- .../mod_skypopen/osscuse/ossp-slave.h | 28 - .../mod_skypopen/osscuse/ossp-util.c | 369 --- .../mod_skypopen/osscuse/ossp-util.h | 609 ----- src/mod/endpoints/mod_skypopen/osscuse/ossp.c | 83 - src/mod/endpoints/mod_skypopen/osscuse/ossp.h | 117 - .../endpoints/mod_skypopen/osscuse/osspd.c | 2374 ----------------- 12 files changed, 4977 deletions(-) delete mode 100644 src/mod/endpoints/mod_skypopen/osscuse/98-osscuse.rules delete mode 100644 src/mod/endpoints/mod_skypopen/osscuse/LICENSE delete mode 100644 src/mod/endpoints/mod_skypopen/osscuse/Makefile delete mode 100644 src/mod/endpoints/mod_skypopen/osscuse/README delete mode 100644 src/mod/endpoints/mod_skypopen/osscuse/ossp-alsap.c delete mode 100644 src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.c delete mode 100644 src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.h delete mode 100644 src/mod/endpoints/mod_skypopen/osscuse/ossp-util.c delete mode 100644 src/mod/endpoints/mod_skypopen/osscuse/ossp-util.h delete mode 100644 src/mod/endpoints/mod_skypopen/osscuse/ossp.c delete mode 100644 src/mod/endpoints/mod_skypopen/osscuse/ossp.h delete mode 100644 src/mod/endpoints/mod_skypopen/osscuse/osspd.c diff --git a/src/mod/endpoints/mod_skypopen/osscuse/98-osscuse.rules b/src/mod/endpoints/mod_skypopen/osscuse/98-osscuse.rules deleted file mode 100644 index c1430fd5c0..0000000000 --- a/src/mod/endpoints/mod_skypopen/osscuse/98-osscuse.rules +++ /dev/null @@ -1,7 +0,0 @@ -# Since these devices are not part of 'sound' subsystem the group is forced -# to audio by name -# /dev/cuse can stay mode 0660 root:root since osspd is run as root -# and drops privileges to user level when opened by user -KERNEL=="dsp", GROUP="audio" -KERNEL=="mixer", GROUP="audio" -KERNEL=="adsp", GROUP="audio" diff --git a/src/mod/endpoints/mod_skypopen/osscuse/LICENSE b/src/mod/endpoints/mod_skypopen/osscuse/LICENSE deleted file mode 100644 index d511905c16..0000000000 --- a/src/mod/endpoints/mod_skypopen/osscuse/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/src/mod/endpoints/mod_skypopen/osscuse/Makefile b/src/mod/endpoints/mod_skypopen/osscuse/Makefile deleted file mode 100644 index a42d37a8a3..0000000000 --- a/src/mod/endpoints/mod_skypopen/osscuse/Makefile +++ /dev/null @@ -1,69 +0,0 @@ -# These can be overridden if needed -# DESTDIR is completely respected -CC := gcc -AR := ar -CFLAGS := -Wall $(CFLAGS) -XLDFLAGS := $(LDFLAGS) -LDFLAGS := -L. -lossp $(LDFLAGS) -prefix := /usr/local -DESTDIR := -UDEVDIR := /etc/udev/rules.d - -ifeq "$(origin OSSPD_CFLAGS)" "undefined" -OSSPD_CFLAGS := $(shell pkg-config --cflags fuse) -endif - -ifeq "$(origin OSSPD_LDFLAGS)" "undefined" -OSSPD_LDFLAGS := $(shell pkg-config --libs fuse) -endif - -ifeq "$(origin OSSP_PADSP_CFLAGS)" "undefined" -OSSP_PADSP_CFLAGS := $(shell pkg-config --cflags libpulse) -endif - -ifeq "$(origin OSSP_PADSP_LDFLAGS)" "undefined" -OSSP_PADSP_LDFLAGS := $(shell pkg-config --libs libpulse) -endif - -ifeq "$(origin OSSP_ALSAP_CFLAGS)" "undefined" -OSSP_ALSAP_CFLAGS := $(shell pkg-config --libs alsa) -endif - -ifeq "$(origin OSSP_ALSAP_LDFLAGS)" "undefined" -OSSP_ALSAP_LDFLAGS := $(shell pkg-config --libs alsa) -endif - -headers := ossp.h ossp-util.h ossp-slave.h - -#all: osspd ossp-padsp ossp-alsap -all: osspd ossp-alsap - -install: - mkdir -p $(DESTDIR)$(prefix)/sbin - install -m755 osspd ossp-padsp ossp-alsap $(DESTDIR)$(prefix)/sbin - mkdir -p $(DESTDIR)$(UDEVDIR) - install -m644 98-osscuse.rules $(DESTDIR)$(UDEVDIR) - -libossp.a: ossp.c ossp.h ossp-util.c ossp-util.h ossp-slave.c ossp-slave.h - $(CC) $(CFLAGS) -c -o ossp.o ossp.c - $(CC) $(CFLAGS) -c -o ossp-util.o ossp-util.c - $(CC) $(CFLAGS) -c -o ossp-slave.o ossp-slave.c - $(AR) rc $@ ossp.o ossp-util.o ossp-slave.o - -osspd: osspd.c libossp.a $(headers) - $(CC) $(CFLAGS) $(OSSPD_CFLAGS) -o $@ $< $(OSSPD_LDFLAGS) $(LDFLAGS) - -ossp-padsp: ossp-padsp.c libossp.a $(headers) - $(CC) $(CFLAGS) $(OSSP_PADSP_CFLAGS) -o $@ $< $(OSSP_PADSP_LDFLAGS) $(LDFLAGS) - -ossp-alsap: ossp-alsap.c libossp.a $(headers) - $(CC) $(CFLAGS) $(OSSP_ALSAP_CFLAGS) -o $@ $< $(OSSP_ALSAP_LDFLAGS) $(LDFLAGS) - -osstest: osstest.c - $(CC) $(CFLAGS) -o $@ $< $(XLDFLAGS) - -test: osstest - @./osstest - -clean: - rm -f *.o *.a osspd ossp-padsp ossp-alsap osstest diff --git a/src/mod/endpoints/mod_skypopen/osscuse/README b/src/mod/endpoints/mod_skypopen/osscuse/README deleted file mode 100644 index 6b716c76e4..0000000000 --- a/src/mod/endpoints/mod_skypopen/osscuse/README +++ /dev/null @@ -1,119 +0,0 @@ - - OSS Proxy - emulate OSS device using CUSE - - Copyright (C) 2008-2009 SUSE Linux Products GmbH - Copyright (C) 2008-2009 Tejun Heo - -1. What is it? --------------- - -Well, first, OSS refers to Open Sound System. If it still doesn't -ring a bell, think /dev/dsp, /dev/adsp and /dev/mixer. - -Currently, Linux supports two audio programming interface - ALSA and -OSS. The latter one is deprecated and has been that way for a long -time but there still are applications which still use them including -UML (usermode Linux) host sound support. - -ALSA contains OSS emulation but sadly the emulation is behind -multiplexing layer (which is in userland) which means that if your -sound card doesn't support multiple audio streams, only either one of -ALSA or OSS interface would be usable at any given moment. - -There have been also attempts to emulate OSS in userland using dynamic -library preloading - aoss and more recently padsp. This works for -many applications but it's just not easy to emulate everything using -the technique. Things like polling, signals, forking, privilege -changes make it very difficult to emulate things reliably. - -OSS Proxy uses CUSE (extension of FUSE allowing character devices to -be implemented in userspace) to implement OSS interface - /dev/dsp, -/dev/adsp and /dev/mixer. From the POV of the applications, these -devices are proper character devices and behave exactly the same way -so it can be made quite versatile. - - -2. Hmmm... So, how does the whole thing work? ---------------------------------------------- - -The OSS Proxy daemon - osspd - should be started first. Note that -osspd will fail to start if sound device number regions are already -occupied. You'll need to turn off OSS or its emulation[1]. - -On startup, osspd creates /dev/dsp, /dev/adsp and /dev/mixer using -CUSE. When an application access one of the devices, all IOs are -redirected to osspd via CUSE. Upon receiving a new DSP open request, -osspd creates a slave process which drops the root privilege and -assumes the opening process's credentials. After handshaking, osspd -forwards all relevant IOs to the slave which is responsible for -actually playing the sound. - -Currently there's only one slave implemented - ossp-padsp, which as -the name suggests forwards (again) the sound to pulseaudio. To sum -up, the whole pipe looks like the following. - - App <-> /dev/dsp <-> CUSE <-> osspd <-> ossp-padsp <-> pulseaudio - -Which is a lot of forwarding, but on modern machines, it won't be too -noticeable. - - -3. What works? --------------- - -Well, MIDI part isn't implemented and I doubt it will be in any near -future but except that everything should work. Playing, recording, -5.1ch, A-V syncing, all should work. If not, it's a bug, so please -report. - -The mixer behaves a bit differently tho. In the original OSS, -/dev/mixer is the hardware mixer, so adjusting volumes there affects -all audio streams. When using ossp, each process group gets its own -mixer and the mixer always contains only two knobs - PCM and IGAIN. -Combined with per-stream volume control of pulseaudio, this scheme -works quite well for applications with embedded volume control -although it makes standalone OSS mixer programs virtually useless[2]. - - -4. How do I use it? -------------------- - -First you need CUSE support in kernel which might land on 2.6.28 with -sufficient luck[3] and then you also need libfuse which supports -CUSE[4]. Once you have both, it should be easy. First build it by -running `make'. You can set OSSPD_CFLAGS, OSSPD_LDFLAGS, -OSSP_PADSP_CFLAGS and OSSP_PADSP_LDFLAGS if you have stuff at -non-default locations. - -After build completes, there will be two executables - `osspd' and -`ossp-padsp'. Just copy them to where other system executables live. -Specific location doesn't matter as long as both files end up in the -same directory. - -Execute `osspd'. It will create the device files and you're all set. -`osspd' uses syslog with LOG_DAEMON facility, so if something doesn't -work take a look at what osspd complains about. - - -[1] As of this writing, turning on any sound support makes the - soundcore module claim OSS device regions. Patch to make it claim - OSS device regions only when OSS support or emulation is enabled - is scheduled for 2.6.28. Even with the patch, soundcore will - claim OSS device regions if OSS support or ALSA OSS emulation is - enabled. Make sure they're turned off. - -[2] If you have a strong reason to use standalone OSS mixer program, - you can play some shell tricks to put it into the same process - group as the target audio application. e.g. To use aumix with - mpg123 - `(mpg123 asdf.mp3 > /dev/null 2>&1 & aumix)', but - seriously, just use PA or ALSA one. - -[3] For the time being, here's the git tree with all the necessary - changes. This tree is base on top of 2.6.27-rc3. - - http://git.kernel.org/?p=linux/kernel/git/tj/misc.git;a=shortlog;h=cuse - git://git.kernel.org/pub/scm/linux/kernel/git/tj/misc.git cuse - -[4] And libfuse with the modifications can be found at... - - http://userweb.kernel.org/~tj/ossp/fuse-cuse.tar.gz diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp-alsap.c b/src/mod/endpoints/mod_skypopen/osscuse/ossp-alsap.c deleted file mode 100644 index 607e05ca84..0000000000 --- a/src/mod/endpoints/mod_skypopen/osscuse/ossp-alsap.c +++ /dev/null @@ -1,613 +0,0 @@ -/* - * ossp-alsap - ossp DSP slave which forwards to alsa - * - * Copyright (C) 2009 Maarten Lankhorst - * - * This file is released under the GPLv2. - * - * Why an alsa plugin as well? Just to show how much - * the alsa userspace api sucks ;-) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "ossp-slave.h" - -enum { - AFMT_FLOAT = 0x00004000, - AFMT_S32_LE = 0x00001000, - AFMT_S32_BE = 0x00002000, -}; - -static size_t page_size; - -/* alsa structures */ -static snd_pcm_t *pcm[2]; -static snd_pcm_hw_params_t *hw_params; -static snd_pcm_sw_params_t *sw_params; -static int block; - -static unsigned int byte_counter[2]; -static snd_pcm_uframes_t mmap_pos[2]; -static int stream_corked[2]; -static int stream_notify; - -static struct format { - snd_pcm_format_t format; - snd_pcm_sframes_t rate; - int channels; -} hw_format = { SND_PCM_FORMAT_U8, 8000, 1 }; - -#if 0 -/* future mmap stuff */ -static size_t mmap_raw_size, mmap_size; -static int mmap_fd[2] = { -1, -1 }; -static void *mmap_map[2]; -static uint64_t mmap_idx[2]; /* mmap pointer */ -static uint64_t mmap_last_idx[2]; /* last idx for get_ptr */ -static struct ring_buf mmap_stg[2]; /* staging ring buffer */ -static size_t mmap_lead[2]; /* lead bytes */ -static int mmap_sync[2]; /* sync with backend stream */ -#endif - -static snd_pcm_format_t fmt_oss_to_alsa(int fmt) -{ - switch (fmt) { - case AFMT_U8: return SND_PCM_FORMAT_U8; - case AFMT_A_LAW: return SND_PCM_FORMAT_A_LAW; - case AFMT_MU_LAW: return SND_PCM_FORMAT_MU_LAW; - case AFMT_S16_LE: return SND_PCM_FORMAT_S16_LE; - case AFMT_S16_BE: return SND_PCM_FORMAT_S16_BE; - case AFMT_FLOAT: return SND_PCM_FORMAT_FLOAT; - case AFMT_S32_LE: return SND_PCM_FORMAT_S32_LE; - case AFMT_S32_BE: return SND_PCM_FORMAT_S32_BE; - default: return SND_PCM_FORMAT_U8; - } -} - -static int fmt_alsa_to_oss(snd_pcm_format_t fmt) -{ - switch (fmt) { - case SND_PCM_FORMAT_U8: return AFMT_U8; - case SND_PCM_FORMAT_A_LAW: return AFMT_A_LAW; - case SND_PCM_FORMAT_MU_LAW: return AFMT_MU_LAW; - case SND_PCM_FORMAT_S16_LE: return AFMT_S16_LE; - case SND_PCM_FORMAT_S16_BE: return AFMT_S16_BE; - case SND_PCM_FORMAT_FLOAT: return AFMT_FLOAT; - case SND_PCM_FORMAT_S32_LE: return AFMT_S32_LE; - case SND_PCM_FORMAT_S32_BE: return AFMT_S32_BE; - default: return AFMT_U8; - } -} - -static void flush_streams(int drain) -{ - /* FIXME: snd_pcm_drain appears to be able to deadlock, - * always drop or check state? */ - if (drain) { - if (pcm[PLAY]) - snd_pcm_drain(pcm[PLAY]); - if (pcm[REC]) - snd_pcm_drain(pcm[REC]); - } else { - if (pcm[PLAY]) - snd_pcm_drop(pcm[PLAY]); - if (pcm[REC]) - snd_pcm_drop(pcm[REC]); - } - - /* XXX: Really needed? */ -#if 0 - if (pcm[PLAY]) { - snd_pcm_close(pcm[PLAY]); - snd_pcm_open(&pcm[PLAY], "default", - SND_PCM_STREAM_PLAYBACK, block); - } - if (pcm[REC]) { - snd_pcm_close(pcm[REC]); - snd_pcm_open(&pcm[REC], "default", - SND_PCM_STREAM_CAPTURE, block); - } -#endif -} - -static void kill_streams(void) -{ - flush_streams(0); -} - -static int trigger_streams(int play, int rec) -{ - int ret = 0; - - if (pcm[PLAY] && play >= 0) { - ret = snd_pcm_sw_params_set_start_threshold(pcm[PLAY], sw_params, - play ? 1 : -1); - if (ret >= 0) - snd_pcm_sw_params(pcm[PLAY], sw_params); - } - if (ret >= 0 && pcm[REC] && rec >= 0) { - ret = snd_pcm_sw_params_set_start_threshold(pcm[REC], sw_params, - rec ? 1 : -1); - if (ret >= 0) - snd_pcm_sw_params(pcm[REC], sw_params); - } - - return ret; -} - -static ssize_t alsap_mixer(enum ossp_opcode opcode, - void *carg, void *din, size_t din_sz, - void *rarg, void *dout, size_t *dout_szp, int tfd) -{ -return -EBUSY; -} - -static int set_hw_params(snd_pcm_t *pcm) -{ - int ret; - unsigned rate; - - ret = snd_pcm_hw_params_any(pcm, hw_params); - if (ret >= 0) - ret = snd_pcm_hw_params_set_access(pcm, hw_params, - SND_PCM_ACCESS_RW_INTERLEAVED); - rate = hw_format.rate; - if (ret >= 0) - ret = snd_pcm_hw_params_set_rate_minmax(pcm, hw_params, - &rate, NULL, - &rate, NULL); - if (ret >= 0) - ret = snd_pcm_hw_params_set_format(pcm, hw_params, hw_format.format); - if (ret >= 0) - ret = snd_pcm_hw_params_set_channels(pcm, hw_params, - hw_format.channels); - if (ret >= 0) - ret = snd_pcm_hw_params(pcm, hw_params); - if (ret >= 0) - ret = snd_pcm_sw_params_current(pcm, sw_params); - if (ret >= 0) - ret = snd_pcm_sw_params(pcm, sw_params); - return ret; -} - -static ssize_t alsap_open(enum ossp_opcode opcode, - void *carg, void *din, size_t din_sz, - void *rarg, void *dout, size_t *dout_szp, int tfd) -{ - struct ossp_dsp_open_arg *arg = carg; - int ret; - block = arg->flags & O_NONBLOCK ? SND_PCM_NONBLOCK : 0; - int access; -// block |= SND_PCM_ASYNC; - /* Woop dee dooo.. I love handling things in SIGIO (PAIN!!) - * Probably needed for MMAP - */ - - if (!hw_params) - ret = snd_pcm_hw_params_malloc(&hw_params); - if (ret < 0) - return ret; - - if (!sw_params) - ret = snd_pcm_sw_params_malloc(&sw_params); - if (ret < 0) - return ret; - - if (pcm[PLAY]) - snd_pcm_close(pcm[PLAY]); - if (pcm[REC]) - snd_pcm_close(pcm[REC]); - pcm[REC] = pcm[PLAY] = NULL; - - access = arg->flags & O_ACCMODE; - if (access == O_WRONLY || access == O_RDWR) { - ret = snd_pcm_open(&pcm[PLAY], "default", - SND_PCM_STREAM_PLAYBACK, block); - if (ret >= 0) - ret = set_hw_params(pcm[PLAY]); - } - - if (ret >= 0 && (access == O_RDONLY || access == O_RDWR)) { - ret = snd_pcm_open(&pcm[REC], "default", - SND_PCM_STREAM_CAPTURE, block); - if (ret >= 0) - ret = set_hw_params(pcm[REC]); - } - - if (ret < 0) { - if (pcm[PLAY]) - snd_pcm_close(pcm[PLAY]); - if (pcm[REC]) - snd_pcm_close(pcm[REC]); - pcm[REC] = pcm[PLAY] = NULL; - return ret; - } - return 0; -} - -#define GIOVANNI -#ifdef GIOVANNI - -#define GIOVA_SLEEP 40000 -#define GIOVA_BLK 3840 -static ssize_t alsap_write(enum ossp_opcode opcode, - void *carg, void *din, size_t din_sz, - void *rarg, void *dout, size_t *dout_szp, int tfd) -{ - usleep((GIOVA_SLEEP/GIOVA_BLK)* din_sz); - return din_sz; -} -static ssize_t alsap_read(enum ossp_opcode opcode, - void *carg, void *din, size_t din_sz, - void *rarg, void *dout, size_t *dout_szp, int tfd) -{ - usleep((GIOVA_SLEEP/GIOVA_BLK)* *dout_szp); - return *dout_szp; -} -#else// GIOVANNI -static ssize_t alsap_write(enum ossp_opcode opcode, - void *carg, void *din, size_t din_sz, - void *rarg, void *dout, size_t *dout_szp, int tfd) -{ -// struct ossp_dsp_rw_arg *arg = carg; - int ret, insize; - - insize = snd_pcm_bytes_to_frames(pcm[PLAY], din_sz); - - if (snd_pcm_state(pcm[PLAY]) == SND_PCM_STATE_SETUP) - snd_pcm_prepare(pcm[PLAY]); - -// snd_pcm_start(pcm[PLAY]); - ret = snd_pcm_writei(pcm[PLAY], din, insize); - if (ret < 0) - ret = snd_pcm_recover(pcm[PLAY], ret, 1); - - if (ret >= 0) - return snd_pcm_frames_to_bytes(pcm[PLAY], ret); - else - return ret; -} - -static ssize_t alsap_read(enum ossp_opcode opcode, - void *carg, void *din, size_t din_sz, - void *rarg, void *dout, size_t *dout_szp, int tfd) -{ -// struct ossp_dsp_rw_arg *arg = carg; - int ret, outsize; - - outsize = snd_pcm_bytes_to_frames(pcm[REC], *dout_szp); - - if (snd_pcm_state(pcm[REC]) == SND_PCM_STATE_SETUP) - snd_pcm_prepare(pcm[REC]); - - ret = snd_pcm_readi(pcm[REC], dout, outsize); - if (ret < 0) - ret = snd_pcm_recover(pcm[REC], ret, 1); - if (ret >= 0) - *dout_szp = ret = snd_pcm_frames_to_bytes(pcm[REC], ret); - else - *dout_szp = 0; - - return ret; -} -#endif// GIOVANNI - -static ssize_t alsap_poll(enum ossp_opcode opcode, - void *carg, void *din, size_t din_sz, - void *rarg, void *dout, size_t *dout_szp, int tfd) -{ - unsigned revents = 0; - - stream_notify |= *(int *)carg; - - if (pcm[PLAY]) - revents |= POLLOUT; - if (pcm[REC]) - revents |= POLLIN; - - *(unsigned *)rarg = revents; - return 0; -} - - -static ssize_t alsap_flush(enum ossp_opcode opcode, - void *carg, void *din, size_t din_sz, - void *rarg, void *dout, size_t *dout_szp, int tfd) -{ - flush_streams(opcode == OSSP_DSP_SYNC); - return 0; -} - -static ssize_t alsap_post(enum ossp_opcode opcode, - void *carg, void *din, size_t din_sz, - void *rarg, void *dout, size_t *dout_szp, int tfd) -{ - int ret; - - ret = trigger_streams(1, 1); - if (ret >= 0 && pcm[PLAY]) - ret = snd_pcm_start(pcm[PLAY]); - if (pcm[REC]) - ret = snd_pcm_start(pcm[REC]); - return ret; -} - -static ssize_t alsap_get_param(enum ossp_opcode opcode, - void *carg, void *din, size_t din_sz, - void *rarg, void *dout, size_t *dout_szp, - int tfd) -{ - int v = 0; - - switch (opcode) { - case OSSP_DSP_GET_RATE: - return hw_format.rate; - - case OSSP_DSP_GET_CHANNELS: - return hw_format.channels; - - case OSSP_DSP_GET_FORMAT: { - v = fmt_alsa_to_oss(hw_format.format); - break; - } - - case OSSP_DSP_GET_BLKSIZE: { - snd_pcm_uframes_t psize; - snd_pcm_hw_params_get_period_size(hw_params, &psize, NULL); - v = psize; - break; - } - - case OSSP_DSP_GET_FORMATS: - v = AFMT_U8 | AFMT_A_LAW | AFMT_MU_LAW | AFMT_S16_LE | - AFMT_S16_BE | AFMT_FLOAT | AFMT_S32_LE | AFMT_S32_BE; - break; - - case OSSP_DSP_GET_TRIGGER: - if (!stream_corked[PLAY]) - v |= PCM_ENABLE_OUTPUT; - if (!stream_corked[REC]) - v |= PCM_ENABLE_INPUT; - break; - - default: - assert(0); - } - - *(int *)rarg = v; - - return 0; -} - -static ssize_t alsap_set_param(enum ossp_opcode opcode, - void *carg, void *din, size_t din_sz, - void *rarg, void *dout, size_t *dout_szp, - int tfd) -{ - int v = *(int *)carg; - int ret = 0; - - /* kill the streams before changing parameters */ - kill_streams(); - - switch (opcode) { - case OSSP_DSP_SET_RATE: { - hw_format.rate = v; - break; - } - - case OSSP_DSP_SET_CHANNELS: { - hw_format.channels = v; - break; - } - - case OSSP_DSP_SET_FORMAT: { - snd_pcm_format_t format = fmt_oss_to_alsa(v); - hw_format.format = format; - break; - } - - case OSSP_DSP_SET_SUBDIVISION: - if (!v) - v = 1; -#if 0 - if (!v) { - v = user_subdivision ?: 1; - break; - } - user_frag_size = 0; - user_subdivision = v; - break; - - case OSSP_DSP_SET_FRAGMENT: - user_subdivision = 0; - user_frag_size = 1 << (v & 0xffff); - user_max_frags = (v >> 16) & 0xffff; - if (user_frag_size < 4) - user_frag_size = 4; - if (user_max_frags < 2) - user_max_frags = 2; -#else - case OSSP_DSP_SET_FRAGMENT: -#endif - break; - default: - assert(0); - } - - if (pcm[PLAY]) - ret = set_hw_params(pcm[PLAY]); - if (ret >= 0 && pcm[REC]) - ret = set_hw_params(pcm[REC]); - - if (rarg) - *(int *)rarg = v; - return 0; -} - -static ssize_t alsap_set_trigger(enum ossp_opcode opcode, - void *carg, void *din, size_t din_sz, - void *rarg, void *dout, size_t *dout_szp, - int fd) -{ - int enable = *(int *)carg; - - stream_corked[PLAY] = !!(enable & PCM_ENABLE_OUTPUT); - stream_corked[REC] = !!(enable & PCM_ENABLE_INPUT); - - return trigger_streams(enable & PCM_ENABLE_OUTPUT, - enable & PCM_ENABLE_INPUT); -} - -static ssize_t alsap_get_space(enum ossp_opcode opcode, - void *carg, void *din, size_t din_sz, - void *rarg, void *dout, size_t *dout_szp, int tfd) -{ - int dir = (opcode == OSSP_DSP_GET_OSPACE) ? PLAY : REC; - int underrun = 0; - struct audio_buf_info info = { }; - unsigned long bufsize; - snd_pcm_uframes_t avail, fragsize; - snd_pcm_state_t state; - - if (!pcm[dir]) - return -EINVAL; - - state = snd_pcm_state(pcm[dir]); - if (state == SND_PCM_STATE_XRUN) { - snd_pcm_recover(pcm[dir], -EPIPE, 0); - underrun = 1; - } else if (state == SND_PCM_STATE_SUSPENDED) { - snd_pcm_recover(pcm[dir], -ESTRPIPE, 0); - underrun = 1; - } - - snd_pcm_hw_params_current(pcm[dir], hw_params); - snd_pcm_hw_params_get_period_size(hw_params, &fragsize, NULL); - snd_pcm_hw_params_get_buffer_size(hw_params, &bufsize); - info.fragsize = snd_pcm_frames_to_bytes(pcm[dir], fragsize); - info.fragstotal = bufsize / fragsize; - if (!underrun) { - avail = snd_pcm_avail_update(pcm[dir]); - info.fragments = avail / fragsize; - } else - info.fragments = info.fragstotal; - - info.bytes = info.fragsize * info.fragments; - - *(struct audio_buf_info *)rarg = info; - return 0; -} - -static ssize_t alsap_get_ptr(enum ossp_opcode opcode, - void *carg, void *din, size_t din_sz, - void *rarg, void *dout, size_t *dout_szp, int tfd) -{ - int dir = (opcode == OSSP_DSP_GET_OPTR) ? PLAY : REC; - struct count_info info = { }; - - if (!pcm[dir]) - return -EIO; - - snd_pcm_hw_params_current(pcm[dir], hw_params); - info.bytes = byte_counter[dir]; - snd_pcm_hw_params_get_periods(hw_params, (unsigned int *)&info.blocks, NULL); - info.ptr = mmap_pos[dir]; - - *(struct count_info *)rarg = info; - return 0; -} - -static ssize_t alsap_get_odelay(enum ossp_opcode opcode, - void *carg, void *din, size_t din_sz, - void *rarg, void *dout, size_t *dout_szp, - int fd) -{ - snd_pcm_sframes_t delay; - - if (!pcm[PLAY]) - return -EIO; - - if (snd_pcm_delay(pcm[PLAY], &delay) < 0) - return -EIO; - - *(int *)rarg = snd_pcm_frames_to_bytes(pcm[PLAY], delay); - return 0; -} - -static ossp_action_fn_t action_fn_tbl[OSSP_NR_OPCODES] = { - [OSSP_MIXER] = alsap_mixer, - [OSSP_DSP_OPEN] = alsap_open, - [OSSP_DSP_READ] = alsap_read, - [OSSP_DSP_WRITE] = alsap_write, - [OSSP_DSP_POLL] = alsap_poll, -#if 0 - [OSSP_DSP_MMAP] = alsap_mmap, - [OSSP_DSP_MUNMAP] = alsap_munmap, -#endif - [OSSP_DSP_RESET] = alsap_flush, - [OSSP_DSP_SYNC] = alsap_flush, - [OSSP_DSP_POST] = alsap_post, - [OSSP_DSP_GET_RATE] = alsap_get_param, - [OSSP_DSP_GET_CHANNELS] = alsap_get_param, - [OSSP_DSP_GET_FORMAT] = alsap_get_param, - [OSSP_DSP_GET_BLKSIZE] = alsap_get_param, - [OSSP_DSP_GET_FORMATS] = alsap_get_param, - [OSSP_DSP_SET_RATE] = alsap_set_param, - [OSSP_DSP_SET_CHANNELS] = alsap_set_param, - [OSSP_DSP_SET_FORMAT] = alsap_set_param, - [OSSP_DSP_SET_SUBDIVISION] = alsap_set_param, - [OSSP_DSP_SET_FRAGMENT] = alsap_set_param, - [OSSP_DSP_GET_TRIGGER] = alsap_get_param, - [OSSP_DSP_SET_TRIGGER] = alsap_set_trigger, - [OSSP_DSP_GET_OSPACE] = alsap_get_space, - [OSSP_DSP_GET_ISPACE] = alsap_get_space, - [OSSP_DSP_GET_OPTR] = alsap_get_ptr, - [OSSP_DSP_GET_IPTR] = alsap_get_ptr, - [OSSP_DSP_GET_ODELAY] = alsap_get_odelay, -}; - -static int action_pre(void) -{ - return 0; -} - -static void action_post(void) -{ -} - -int main(int argc, char **argv) -{ - int rc; - - ossp_slave_init(argc, argv); - - page_size = sysconf(_SC_PAGE_SIZE); - - /* Okay, now we're open for business */ - rc = 0; - do { - rc = ossp_slave_process_command(ossp_cmd_fd, action_fn_tbl, - action_pre, action_post); - } while (rc > 0); - - return rc ? 1 : 0; -} diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.c b/src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.c deleted file mode 100644 index 4c5cb2d129..0000000000 --- a/src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * ossp-slave - OSS Proxy: Common codes for slaves - * - * Copyright (C) 2008-2010 SUSE Linux Products GmbH - * Copyright (C) 2008-2010 Tejun Heo - * - * This file is released under the GPLv2. - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ossp-slave.h" - -static const char *usage = -"usage: ossp-SLAVE [options]\n" -"\n" -"proxies commands from osspd to pulseaudio\n" -"\n" -"options:\n" -" -u UID uid to use\n" -" -g GID gid to use\n" -" -c CMD_FD fd to receive commands from osspd\n" -" -n NOTIFY_FD fd to send async notifications to osspd\n" -" -m MMAP_FD fd to use for mmap\n" -" -o MMAP_OFFSET mmap offset\n" -" -s MMAP_SIZE mmap size\n" -" -l LOG_LEVEL set log level\n" -" -t enable log timestamps\n"; - -char ossp_user_name[OSSP_USER_NAME_LEN]; -int ossp_cmd_fd = -1, ossp_notify_fd = -1; -void *ossp_mmap_addr[2]; - -void ossp_slave_init(int argc, char **argv) -{ - int have_uid = 0, have_gid = 0; - uid_t uid; - gid_t gid; - int mmap_fd = -1; - off_t mmap_off = 0; - size_t mmap_size = 0; - int opt; - struct passwd *pw, pw_buf; - struct sigaction sa; - char pw_sbuf[sysconf(_SC_GETPW_R_SIZE_MAX)]; - - while ((opt = getopt(argc, argv, "u:g:c:n:m:o:s:l:t")) != -1) { - switch (opt) { - case 'u': - have_uid = 1; - uid = strtol(optarg, NULL, 0); - break; - case 'g': - have_gid = 1; - gid = strtol(optarg, NULL, 0); - break; - case 'c': - ossp_cmd_fd = strtol(optarg, NULL, 0); - break; - case 'n': - ossp_notify_fd = strtol(optarg, NULL, 0); - break; - case 'm': - mmap_fd = strtol(optarg, NULL, 0); - break; - case 'o': - mmap_off = strtoull(optarg, NULL, 0); - break; - case 's': - mmap_size = strtoul(optarg, NULL, 0); - break; - case 'l': - ossp_log_level = strtol(optarg, NULL, 0); - break; - case 't': - ossp_log_timestamp = 1; - break; - } - } - - if (!have_uid || !have_gid || ossp_cmd_fd < 0 || ossp_notify_fd < 0) { - fprintf(stderr, usage); - _exit(1); - } - - snprintf(ossp_user_name, sizeof(ossp_user_name), "uid%d", uid); - if (getpwuid_r(uid, &pw_buf, pw_sbuf, sizeof(pw_sbuf), &pw) == 0) - snprintf(ossp_user_name, sizeof(ossp_user_name), "%s", - pw->pw_name); - - snprintf(ossp_log_name, sizeof(ossp_log_name), "ossp-padsp[%s:%d]", - ossp_user_name, getpid()); - - if (mmap_fd >= 0) { - void *p; - - if (!mmap_off || !mmap_size) { - fprintf(stderr, usage); - _exit(1); - } - - p = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, - mmap_fd, mmap_off); - if (p == MAP_FAILED) - fatal_e(-errno, "mmap failed"); - - ossp_mmap_addr[PLAY] = p; - ossp_mmap_addr[REC] = p + mmap_size / 2; - close(mmap_fd); - } - - /* mmap done, drop privileges */ - if (setresgid(gid, gid, gid) || setresuid(uid, uid, uid)) - fatal_e(-errno, "failed to drop privileges"); - - /* block SIGPIPE */ - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = SIG_IGN; - if (sigaction(SIGPIPE, &sa, NULL)) - fatal_e(-errno, "failed to ignore SIGPIPE"); -} - -int ossp_slave_process_command(int cmd_fd, - ossp_action_fn_t const *action_fn_tbl, - int (*action_pre_fn)(void), - void (*action_post_fn)(void)) -{ - static struct sized_buf carg_sbuf = { }, rarg_sbuf = { }; - static struct sized_buf din_sbuf = { }, dout_sbuf = { }; - struct ossp_cmd cmd; - int fd = -1; - char cmsg_buf[CMSG_SPACE(sizeof(fd))]; - struct iovec iov = { &cmd, sizeof(cmd) }; - struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1, - .msg_control = cmsg_buf, - .msg_controllen = sizeof(cmsg_buf) }; - struct cmsghdr *cmsg; - size_t carg_size, din_size, rarg_size, dout_size; - char *carg = NULL, *din = NULL, *rarg = NULL, *dout = NULL; - struct ossp_reply reply = { .magic = OSSP_REPLY_MAGIC }; - ssize_t ret; - - ret = recvmsg(cmd_fd, &msg, 0); - if (ret == 0) - return 0; - if (ret < 0) { - ret = -errno; - err_e(ret, "failed to read command channel"); - return ret; - } - - if (ret != sizeof(cmd)) { - err("command struct size mismatch (%zu, should be %zu)", - ret, sizeof(cmd)); - return -EINVAL; - } - - if (cmd.magic != OSSP_CMD_MAGIC) { - err("illegal command magic 0x%x", cmd.magic); - return -EINVAL; - } - - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; - cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_RIGHTS) - fd = *(int *)CMSG_DATA(cmsg); - else { - err("unknown cmsg %d:%d received (opcode %d)", - cmsg->cmsg_level, cmsg->cmsg_type, cmd.opcode); - return -EINVAL; - } - } - - if (cmd.opcode >= OSSP_NR_OPCODES) { - err("unknown opcode %d", cmd.opcode); - return -EINVAL; - } - - carg_size = ossp_arg_sizes[cmd.opcode].carg_size; - din_size = cmd.din_size; - rarg_size = ossp_arg_sizes[cmd.opcode].rarg_size; - dout_size = cmd.dout_size; - - if ((fd >= 0) != ossp_arg_sizes[cmd.opcode].has_fd) { - err("fd=%d unexpected for opcode %d", fd, cmd.opcode); - return -EINVAL; - } - - if (ensure_sbuf_size(&carg_sbuf, carg_size) || - ensure_sbuf_size(&din_sbuf, din_size) || - ensure_sbuf_size(&rarg_sbuf, rarg_size) || - ensure_sbuf_size(&dout_sbuf, dout_size)) { - err("failed to allocate command buffers"); - return -ENOMEM; - } - - if (carg_size) { - carg = carg_sbuf.buf; - ret = read_fill(cmd_fd, carg, carg_size); - if (ret < 0) - return ret; - } - if (din_size) { - din = din_sbuf.buf; - ret = read_fill(cmd_fd, din, din_size); - if (ret < 0) - return ret; - } - if (rarg_size) - rarg = rarg_sbuf.buf; - if (dout_size) - dout = dout_sbuf.buf; - - ret = -EINVAL; - if (action_fn_tbl[cmd.opcode]) { - ret = action_pre_fn(); - if (ret == 0) { - ret = action_fn_tbl[cmd.opcode](cmd.opcode, carg, - din, din_size, rarg, - dout, &dout_size, fd); - action_post_fn(); - } - } - - reply.result = ret; - if (ret >= 0) - reply.dout_size = dout_size; - else { - rarg_size = 0; - dout_size = 0; - } - - if (write_fill(cmd_fd, &reply, sizeof(reply)) < 0 || - write_fill(cmd_fd, rarg, rarg_size) < 0 || - write_fill(cmd_fd, dout, dout_size) < 0) - return -EIO; - - return 1; -} diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.h b/src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.h deleted file mode 100644 index 10c22cdb02..0000000000 --- a/src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * ossp-slave - OSS Proxy: Common codes for slaves - * - * Copyright (C) 2008-2010 SUSE Linux Products GmbH - * Copyright (C) 2008-2010 Tejun Heo - * - * This file is released under the GPLv2. - */ - -#ifndef _OSSP_SLAVE_H -#define _OSSP_SLAVE_H - -#include "ossp.h" -#include "ossp-util.h" - -#define OSSP_USER_NAME_LEN 128 - -extern char ossp_user_name[OSSP_USER_NAME_LEN]; -extern int ossp_cmd_fd, ossp_notify_fd; -extern void *ossp_mmap_addr[2]; - -void ossp_slave_init(int argc, char **argv); -int ossp_slave_process_command(int cmd_fd, - ossp_action_fn_t const *action_fn_tbl, - int (*action_pre_fn)(void), - void (*action_post_fn)(void)); - -#endif /* _OSSP_SLAVE_H */ diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp-util.c b/src/mod/endpoints/mod_skypopen/osscuse/ossp-util.c deleted file mode 100644 index 325cefd5fd..0000000000 --- a/src/mod/endpoints/mod_skypopen/osscuse/ossp-util.c +++ /dev/null @@ -1,369 +0,0 @@ -/* - * ossp-util - OSS Proxy: Common utilities - * - * Copyright (C) 2008-2010 SUSE Linux Products GmbH - * Copyright (C) 2008-2010 Tejun Heo - * - * This file is released under the GPLv2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ossp-util.h" - -#define BIT(nr) (1UL << (nr)) -#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) -#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) -#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) -#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) - -char ossp_log_name[OSSP_LOG_NAME_LEN]; -int ossp_log_level = OSSP_LOG_DFL; -int ossp_log_timestamp; - -static const char *severity_strs[] = { - [OSSP_LOG_CRIT] = "CRIT", - [OSSP_LOG_ERR] = " ERR", - [OSSP_LOG_WARN] = "WARN", - [OSSP_LOG_INFO] = NULL, - [OSSP_LOG_DBG0] = "DBG0", - [OSSP_LOG_DBG1] = "DBG1", -}; - -static int severity_map[] = { - [OSSP_LOG_CRIT] = LOG_ERR, - [OSSP_LOG_ERR] = LOG_ERR, - [OSSP_LOG_WARN] = LOG_WARNING, - [OSSP_LOG_INFO] = LOG_INFO, - [OSSP_LOG_DBG0] = LOG_DEBUG, - [OSSP_LOG_DBG1] = LOG_DEBUG, -}; - -void log_msg(int severity, const char *fmt, ...) -{ - static int syslog_opened = 0; - char buf[1024]; - size_t len = sizeof(buf), off = 0; - va_list ap; - - if (severity > abs(ossp_log_level)) - return; - - if (ossp_log_level < 0 && !syslog_opened) - openlog(ossp_log_name, 0, LOG_DAEMON); - - assert(severity >= 0 && severity < ARRAY_SIZE(severity_strs)); - - if (ossp_log_timestamp) { - static uint64_t start; - uint64_t now; - struct timeval tv; - gettimeofday(&tv, NULL); - now = tv.tv_sec * 1000 + tv.tv_usec / 1000; - if (!start) - start = now; - - off += snprintf(buf + off, len - off, "<%08"PRIu64"> ", - now - start); - } - - if (ossp_log_level > 0) { - char sev_buf[16] = ""; - if (severity_strs[severity]) - snprintf(sev_buf, sizeof(sev_buf), " %s", - severity_strs[severity]); - off += snprintf(buf + off, len - off, "%s%s: ", - ossp_log_name, sev_buf); - } else if (severity_strs[severity]) - off += snprintf(buf + off, len - off, "%s ", - severity_strs[severity]); - - va_start(ap, fmt); - off += vsnprintf(buf + off, len - off, fmt, ap); - va_end(ap); - - off += snprintf(buf + off, len - off, "\n"); - - if (ossp_log_level > 0) - fputs(buf, stderr); - else - syslog(severity_map[severity], "%s", buf); -} - -int read_fill(int fd, void *buf, size_t size) -{ - while (size) { - ssize_t ret; - int rc; - - ret = read(fd, buf, size); - if (ret <= 0) { - if (ret == 0) - rc = -EIO; - else - rc = -errno; - err_e(rc, "failed to read_fill %zu bytes from fd %d", - size, fd); - return rc; - } - buf += ret; - size -= ret; - } - return 0; -} - -int write_fill(int fd, const void *buf, size_t size) -{ - while (size) { - ssize_t ret; - int rc; - - ret = write(fd, buf, size); - if (ret <= 0) { - if (ret == 0) - rc = -EIO; - else - rc = -errno; - err_e(rc, "failed to write_fill %zu bytes to fd %d", - size, fd); - return rc; - } - buf += ret; - size -= ret; - } - return 0; -} - -void ring_fill(struct ring_buf *ring, const void *buf, size_t size) -{ - size_t tail; - - assert(ring_space(ring) >= size); - - tail = (ring->head + ring->size - ring->bytes) % ring->size; - - if (ring->head >= tail) { - size_t todo = min(size, ring->size - ring->head); - - memcpy(ring->buf + ring->head, buf, todo); - ring->head = (ring->head + todo) % ring->size; - ring->bytes += todo; - buf += todo; - size -= todo; - } - - assert(ring->size - ring->head >= size); - memcpy(ring->buf + ring->head, buf, size); - ring->head += size; - ring->bytes += size; -} - -void *ring_data(struct ring_buf *ring, size_t *sizep) -{ - size_t tail; - - if (!ring->bytes) - return NULL; - - tail = (ring->head + ring->size - ring->bytes) % ring->size; - - *sizep = min(ring->bytes, ring->size - tail); - return ring->buf + tail; -} - -int ring_resize(struct ring_buf *ring, size_t new_size) -{ - struct ring_buf new_ring = { .size = new_size }; - void *p; - size_t size; - - if (ring_bytes(ring) > new_size) - return -ENOSPC; - - new_ring.buf = calloc(1, new_size); - if (new_size && !new_ring.buf) - return -ENOMEM; - - while ((p = ring_data(ring, &size))) { - ring_fill(&new_ring, p, size); - ring_consume(ring, size); - } - - free(ring->buf); - *ring = new_ring; - return 0; -} - -int ensure_sbuf_size(struct sized_buf *sbuf, size_t size) -{ - char *new_buf; - - if (sbuf->size >= size) - return 0; - - new_buf = realloc(sbuf->buf, size); - if (size && !new_buf) - return -ENOMEM; - - sbuf->buf = new_buf; - sbuf->size = size; - return 0; -} - -static unsigned long __ffs(unsigned long word) -{ - int num = 0; - - if (BITS_PER_LONG == 64) { - if ((word & 0xffffffff) == 0) { - num += 32; - word >>= 32; - } - } - - if ((word & 0xffff) == 0) { - num += 16; - word >>= 16; - } - if ((word & 0xff) == 0) { - num += 8; - word >>= 8; - } - if ((word & 0xf) == 0) { - num += 4; - word >>= 4; - } - if ((word & 0x3) == 0) { - num += 2; - word >>= 2; - } - if ((word & 0x1) == 0) - num += 1; - return num; -} - -#define ffz(x) __ffs(~(x)) - -unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, - unsigned long offset) -{ - const unsigned long *p = addr + BITOP_WORD(offset); - unsigned long result = offset & ~(BITS_PER_LONG-1); - unsigned long tmp; - - if (offset >= size) - return size; - size -= result; - offset %= BITS_PER_LONG; - if (offset) { - tmp = *(p++); - tmp |= ~0UL >> (BITS_PER_LONG - offset); - if (size < BITS_PER_LONG) - goto found_first; - if (~tmp) - goto found_middle; - size -= BITS_PER_LONG; - result += BITS_PER_LONG; - } - while (size & ~(BITS_PER_LONG-1)) { - if (~(tmp = *(p++))) - goto found_middle; - result += BITS_PER_LONG; - size -= BITS_PER_LONG; - } - if (!size) - return result; - tmp = *p; - -found_first: - tmp |= ~0UL << size; - if (tmp == ~0UL) /* Are any bits zero? */ - return result + size; /* Nope. */ -found_middle: - return result + ffz(tmp); -} - -void __set_bit(int nr, volatile unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - - *p |= mask; -} - -void __clear_bit(int nr, volatile unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - - *p &= ~mask; -} - -int get_proc_self_info(pid_t pid, pid_t *ppid_r, - char *cmd_buf, size_t cmd_buf_sz) - -{ - char path[64], buf[4096]; - int fd = -1; - char *cmd_start, *cmd_end, *ppid_start, *end; - ssize_t ret; - pid_t ppid; - int i, rc; - - snprintf(path, sizeof(path), "/proc/%ld/stat", (long)pid); - fd = open(path, O_RDONLY); - if (fd < 0) { - rc = -errno; - goto out; - } - - ret = read(fd, buf, sizeof(buf)); - if (ret < 0) - goto out; - if (ret == sizeof(buf)) { - rc = -EOVERFLOW; - goto out; - } - buf[ret] = '\0'; - - rc = -EINVAL; - cmd_start = strchr(buf, '('); - cmd_end = strrchr(buf, ')'); - if (!cmd_start || !cmd_end) - goto out; - cmd_start++; - - ppid_start = cmd_end; - for (i = 0; i < 3; i++) { - ppid_start = strchr(ppid_start, ' '); - if (!ppid_start) - goto out; - ppid_start++; - } - - ppid = strtoul(ppid_start, &end, 10); - if (end == ppid_start || *end != ' ') - goto out; - - if (ppid_r) - *ppid_r = ppid; - if (cmd_buf) { - size_t len = min_t(size_t, cmd_end - cmd_start, cmd_buf_sz - 1); - memcpy(cmd_buf, cmd_start, len); - cmd_buf[len] = '\0'; - } - - rc = 0; - out: - close(fd); - - return rc; -} diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp-util.h b/src/mod/endpoints/mod_skypopen/osscuse/ossp-util.h deleted file mode 100644 index f48d02257a..0000000000 --- a/src/mod/endpoints/mod_skypopen/osscuse/ossp-util.h +++ /dev/null @@ -1,609 +0,0 @@ -/* - * ossp-util - OSS Proxy: Common utilities - * - * Copyright (C) 2008-2010 SUSE Linux Products GmbH - * Copyright (C) 2008-2010 Tejun Heo - * - * This file is released under the GPLv2. - */ - -#ifndef _OSSP_UTIL_H -#define _OSSP_UTIL_H - -#include -#include -#include -#include -#include -#include -#include "ossp.h" - -#define OSSP_LOG_NAME_LEN 128 - -enum { - OSSP_LOG_CRIT = 1, - OSSP_LOG_ERR, - OSSP_LOG_WARN, - OSSP_LOG_INFO, - OSSP_LOG_DFL = OSSP_LOG_INFO, /* default log level */ - OSSP_LOG_DBG0, - OSSP_LOG_DBG1, - OSSP_LOG_MAX = OSSP_LOG_DBG1, -}; - -extern char ossp_log_name[OSSP_LOG_NAME_LEN]; -extern int ossp_log_level; -extern int ossp_log_timestamp; - -#define BITS_PER_BYTE 8 -#define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long)) -#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) -#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) - -/* ARRAY_SIZE and min/max macros stolen from linux/kernel.h */ -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) - -#define min(x, y) ({ \ - typeof(x) _min1 = (x); \ - typeof(y) _min2 = (y); \ - (void) (&_min1 == &_min2); \ - _min1 < _min2 ? _min1 : _min2; }) - -#define max(x, y) ({ \ - typeof(x) _max1 = (x); \ - typeof(y) _max2 = (y); \ - (void) (&_max1 == &_max2); \ - _max1 > _max2 ? _max1 : _max2; }) - -#define min_t(type, x, y) ({ \ - type __min1 = (x); \ - type __min2 = (y); \ - __min1 < __min2 ? __min1: __min2; }) - -#define max_t(type, x, y) ({ \ - type __max1 = (x); \ - type __max2 = (y); \ - __max1 > __max2 ? __max1: __max2; }) - -void log_msg(int severity, const char *fmt, ...) - __attribute__ ((format (printf, 2, 3))); - -#define fatal(fmt, args...) do { \ - log_msg(OSSP_LOG_CRIT, fmt , ##args); \ - _exit(1); \ -} while (0) -#define err(fmt, args...) log_msg(OSSP_LOG_ERR, fmt , ##args) -#define warn(fmt, args...) log_msg(OSSP_LOG_WARN, fmt , ##args) -#define info(fmt, args...) log_msg(OSSP_LOG_INFO, fmt , ##args) -#define dbg0(fmt, args...) log_msg(OSSP_LOG_DBG0, fmt , ##args) -#define dbg1(fmt, args...) log_msg(OSSP_LOG_DBG1, fmt , ##args) - -#define fatal_e(e, fmt, args...) \ - fatal(fmt" (%s)" , ##args, strerror(-(e))) -#define err_e(e, fmt, args...) \ - err(fmt" (%s)" , ##args, strerror(-(e))) -#define warn_e(e, fmt, args...) \ - warn(fmt" (%s)" , ##args, strerror(-(e))) -#define info_e(e, fmt, args...) \ - info(fmt" (%s)" , ##args, strerror(-(e))) -#define dbg0_e(e, fmt, args...) \ - dbg0(fmt" (%s)" , ##args, strerror(-(e))) -#define dbg1_e(e, fmt, args...) \ - dbg1(fmt" (%s)" , ##args, strerror(-(e))) - -struct ring_buf { - char *buf; - size_t size; - size_t head; - size_t bytes; -}; - -static inline size_t ring_size(struct ring_buf *ring) -{ - return ring->size; -} - -static inline size_t ring_bytes(struct ring_buf *ring) -{ - return ring->bytes; -} - -static inline size_t ring_space(struct ring_buf *ring) -{ - return ring->size - ring->bytes; -} - -static inline void ring_consume(struct ring_buf *ring, size_t size) -{ - assert(ring->bytes >= size); - ring->bytes -= size; -} - -static inline void ring_manual_init(struct ring_buf *ring, void *buf, - size_t size, size_t head, size_t bytes) -{ - ring->buf = buf; - ring->size = size; - ring->head = head; - ring->bytes = bytes; -} - -void ring_fill(struct ring_buf *ring, const void *buf, size_t size); -void *ring_data(struct ring_buf *ring, size_t *sizep); -int ring_resize(struct ring_buf *ring, size_t new_size); - -struct sized_buf { - char *buf; - size_t size; -}; - -int ensure_sbuf_size(struct sized_buf *sbuf, size_t size); - -int read_fill(int fd, void *buf, size_t size); -int write_fill(int fd, const void *buf, size_t size); - -/* - * Bitops lifted from linux asm-generic implementation. - */ -unsigned long find_next_zero_bit(const unsigned long *addr, unsigned - long size, unsigned long offset); -#define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0) -extern void __set_bit(int nr, volatile unsigned long *addr); -extern void __clear_bit(int nr, volatile unsigned long *addr); - -typedef ssize_t (*ossp_action_fn_t)(enum ossp_opcode opcode, - void *carg, void *din, size_t din_sz, - void *rarg, void *dout, size_t *dout_szp, - int fd); - -int get_proc_self_info(pid_t tid, pid_t *pgrp, - char *cmd_buf, size_t cmd_buf_sz); - -/* - * Doubly linked list handling code shamelessly stolen from the Linux - * kernel 2.6.26 include/linux/list.h. - */ - -/** - * container_of - cast a member of a structure out to the containing structure - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - * - */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -#define LIST_POISON1 ((void *) 0x00100100) -#define LIST_POISON2 ((void *) 0x00200200) - -/* - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. - */ - -struct list_head { - struct list_head *next, *prev; -}; - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -static inline void INIT_LIST_HEAD(struct list_head *list) -{ - list->next = list; - list->prev = list; -} - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} - -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head * prev, struct list_head * next) -{ - next->prev = prev; - prev->next = next; -} - -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty() on entry does not return true after this, the entry is - * in an undefined state. - */ -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; -} - -/** - * list_replace - replace old entry by new one - * @old : the element to be replaced - * @new : the new element to insert - * - * If @old was empty, it will be overwritten. - */ -static inline void list_replace(struct list_head *old, - struct list_head *new) -{ - new->next = old->next; - new->next->prev = new; - new->prev = old->prev; - new->prev->next = new; -} - -static inline void list_replace_init(struct list_head *old, - struct list_head *new) -{ - list_replace(old, new); - INIT_LIST_HEAD(old); -} - -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); -} - -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add(list, head); -} - -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add_tail(list, head); -} - -/** - * list_is_last - tests whether @list is the last entry in list @head - * @list: the entry to test - * @head: the head of the list - */ -static inline int list_is_last(const struct list_head *list, - const struct list_head *head) -{ - return list->next == head; -} - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(const struct list_head *head) -{ - return head->next == head; -} - -/** - * list_empty_careful - tests whether a list is empty and not being modified - * @head: the list to test - * - * Description: - * tests whether a list is empty _and_ checks that no other CPU might be - * in the process of modifying either member (next or prev) - * - * NOTE: using list_empty_careful() without synchronization - * can only be safe if the only activity that can happen - * to the list entry is list_del_init(). Eg. it cannot be used - * if another CPU could re-list_add() it. - */ -static inline int list_empty_careful(const struct list_head *head) -{ - struct list_head *next = head->next; - return (next == head) && (next == head->prev); -} - -/** - * list_is_singular - tests whether a list has just one entry. - * @head: the list to test. - */ -static inline int list_is_singular(const struct list_head *head) -{ - return !list_empty(head) && (head->next == head->prev); -} - -static inline void __list_splice(const struct list_head *list, - struct list_head *head) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - struct list_head *at = head->next; - - first->prev = head; - head->next = first; - - last->next = at; - at->prev = last; -} - -/** - * list_splice - join two lists - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice(const struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head); -} - -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head); - INIT_LIST_HEAD(list); - } -} - -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_first_entry - get the first element from a list - * @ptr: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - * - * Note, that list is expected to be not empty. - */ -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -/** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev; pos != (head); pos = pos->prev) - -/** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_prev_safe(pos, n, head) \ - for (pos = (head)->prev, n = pos->prev; \ - pos != (head); pos = n, n = pos->prev) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_reverse - iterate backwards over list of given type. - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() - * @pos: the type * to use as a start point - * @head: the head of the list - * @member: the name of the list_struct within the struct. - * - * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). - */ -#define list_prepare_entry(pos, head, member) \ - ((pos) ? : list_entry(head, typeof(*pos), member)) - -/** - * list_for_each_entry_continue - continue iteration over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Continue to iterate over list of given type, continuing after - * the current position. - */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_continue_reverse - iterate backwards from the given point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Start to iterate over list of given type backwards, continuing after - * the current position. - */ -#define list_for_each_entry_continue_reverse(pos, head, member) \ - for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_for_each_entry_from - iterate over list of given type from the current point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing from current position. - */ -#define list_for_each_entry_from(pos, head, member) \ - for (; &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_continue - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing after current point, - * safe against removal of list entry. - */ -#define list_for_each_entry_safe_continue(pos, n, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_from - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type from current point, safe against - * removal of list entry. - */ -#define list_for_each_entry_safe_from(pos, n, head, member) \ - for (n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_reverse - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate backwards over list of given type, safe against removal - * of list entry. - */ -#define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - n = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.prev, typeof(*n), member)) - -#endif /*_OSSP_UTIL_H*/ diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp.c b/src/mod/endpoints/mod_skypopen/osscuse/ossp.c deleted file mode 100644 index 96f98fa37a..0000000000 --- a/src/mod/endpoints/mod_skypopen/osscuse/ossp.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * ossp - OSS Proxy: emulate OSS device using CUSE - * - * Copyright (C) 2008-2010 SUSE Linux Products GmbH - * Copyright (C) 2008-2010 Tejun Heo - * - * This file is released under the GPLv2. - */ - -#include "ossp.h" - -const struct ossp_arg_size ossp_arg_sizes[OSSP_NR_OPCODES] = { - [OSSP_MIXER] = { sizeof(struct ossp_mixer_arg), - sizeof(struct ossp_mixer_arg), 0 }, - - [OSSP_DSP_OPEN] = { sizeof(struct ossp_dsp_open_arg), 0, 0 }, - [OSSP_DSP_READ] = { sizeof(struct ossp_dsp_rw_arg), 0, 0 }, - [OSSP_DSP_WRITE] = { sizeof(struct ossp_dsp_rw_arg), 0, 0 }, - [OSSP_DSP_POLL] = { sizeof(int), sizeof(unsigned), 0 }, - [OSSP_DSP_MMAP] = { sizeof(struct ossp_dsp_mmap_arg), 0, 0 }, - [OSSP_DSP_MUNMAP] = { sizeof(int), 0, 0 }, - - [OSSP_DSP_RESET] = { 0, 0, 0 }, - [OSSP_DSP_SYNC] = { 0, 0, 0 }, - [OSSP_DSP_POST] = { 0, 0, 0 }, - [OSSP_DSP_GET_RATE] = { 0, sizeof(int), 0 }, - [OSSP_DSP_GET_CHANNELS] = { 0, sizeof(int), 0 }, - [OSSP_DSP_GET_FORMAT] = { 0, sizeof(int), 0 }, - [OSSP_DSP_GET_BLKSIZE] = { 0, sizeof(int), 0 }, - [OSSP_DSP_GET_FORMATS] = { 0, sizeof(int), 0 }, - [OSSP_DSP_SET_RATE] = { sizeof(int), sizeof(int), 0 }, - [OSSP_DSP_SET_CHANNELS] = { sizeof(int), sizeof(int), 0 }, - [OSSP_DSP_SET_FORMAT] = { sizeof(int), sizeof(int), 0 }, - [OSSP_DSP_SET_SUBDIVISION] = { sizeof(int), sizeof(int), 0 }, - [OSSP_DSP_SET_FRAGMENT] = { sizeof(int), 0, 0 }, - [OSSP_DSP_GET_TRIGGER] = { 0, sizeof(int), 0 }, - [OSSP_DSP_SET_TRIGGER] = { sizeof(int), 0, 0 }, - [OSSP_DSP_GET_OSPACE] = { 0, sizeof(struct audio_buf_info), 0 }, - [OSSP_DSP_GET_ISPACE] = { 0, sizeof(struct audio_buf_info), 0 }, - [OSSP_DSP_GET_OPTR] = { 0, sizeof(struct count_info), 0 }, - [OSSP_DSP_GET_IPTR] = { 0, sizeof(struct count_info), 0 }, - [OSSP_DSP_GET_ODELAY] = { 0, sizeof(int), 0 }, -}; - -const char *ossp_cmd_str[OSSP_NR_OPCODES] = { - [OSSP_MIXER] = "MIXER", - - [OSSP_DSP_OPEN] = "OPEN", - [OSSP_DSP_READ] = "READ", - [OSSP_DSP_WRITE] = "WRITE", - [OSSP_DSP_POLL] = "POLL", - [OSSP_DSP_MMAP] = "MMAP", - [OSSP_DSP_MUNMAP] = "MUNMAP", - - [OSSP_DSP_RESET] = "RESET", - [OSSP_DSP_SYNC] = "SYNC", - [OSSP_DSP_POST] = "POST", - - [OSSP_DSP_GET_RATE] = "GET_RATE", - [OSSP_DSP_GET_CHANNELS] = "GET_CHANNELS", - [OSSP_DSP_GET_FORMAT] = "GET_FORMAT", - [OSSP_DSP_GET_BLKSIZE] = "GET_BLKSIZE", - [OSSP_DSP_GET_FORMATS] = "GET_FORMATS", - [OSSP_DSP_SET_RATE] = "SET_RATE", - [OSSP_DSP_SET_CHANNELS] = "SET_CHANNELS", - [OSSP_DSP_SET_FORMAT] = "SET_FORMAT", - [OSSP_DSP_SET_SUBDIVISION] = "SET_BUSDIVISION", - - [OSSP_DSP_SET_FRAGMENT] = "SET_FRAGMENT", - [OSSP_DSP_GET_TRIGGER] = "GET_TRIGGER", - [OSSP_DSP_SET_TRIGGER] = "SET_TRIGGER", - [OSSP_DSP_GET_OSPACE] = "GET_OSPACE", - [OSSP_DSP_GET_ISPACE] = "GET_ISPACE", - [OSSP_DSP_GET_OPTR] = "GET_OPTR", - [OSSP_DSP_GET_IPTR] = "GET_IPTR", - [OSSP_DSP_GET_ODELAY] = "GET_ODELAY", -}; - -const char *ossp_notify_str[OSSP_NR_NOTIFY_OPCODES] = { - [OSSP_NOTIFY_POLL] = "POLL", - [OSSP_NOTIFY_OBITUARY] = "OBITUARY", - [OSSP_NOTIFY_VOLCHG] = "VOLCHG", -}; diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp.h b/src/mod/endpoints/mod_skypopen/osscuse/ossp.h deleted file mode 100644 index 9d03e63adf..0000000000 --- a/src/mod/endpoints/mod_skypopen/osscuse/ossp.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * ossp - OSS Proxy: emulate OSS device using CUSE - * - * Copyright (C) 2008-2010 SUSE Linux Products GmbH - * Copyright (C) 2008-2010 Tejun Heo - * - * This file is released under the GPLv2. - */ - -#ifndef _OSSP_H -#define _OSSP_H - -#include -#include -#include - -#define OSSP_VERSION "1.3.2" -#define OSSP_CMD_MAGIC 0xdeadbeef -#define OSSP_REPLY_MAGIC 0xbeefdead -#define OSSP_NOTIFY_MAGIC 0xbebebebe - -#define PLAY 0 -#define REC 1 -#define LEFT 0 -#define RIGHT 1 - -enum ossp_opcode { - OSSP_MIXER, - - OSSP_DSP_OPEN, - OSSP_DSP_READ, - OSSP_DSP_WRITE, - OSSP_DSP_POLL, - OSSP_DSP_MMAP, - OSSP_DSP_MUNMAP, - - OSSP_DSP_RESET, - OSSP_DSP_SYNC, - OSSP_DSP_POST, - - OSSP_DSP_GET_RATE, - OSSP_DSP_GET_CHANNELS, - OSSP_DSP_GET_FORMAT, - OSSP_DSP_GET_BLKSIZE, - OSSP_DSP_GET_FORMATS, - OSSP_DSP_SET_RATE, - OSSP_DSP_SET_CHANNELS, - OSSP_DSP_SET_FORMAT, - OSSP_DSP_SET_SUBDIVISION, - - OSSP_DSP_SET_FRAGMENT, - OSSP_DSP_GET_TRIGGER, - OSSP_DSP_SET_TRIGGER, - OSSP_DSP_GET_OSPACE, - OSSP_DSP_GET_ISPACE, - OSSP_DSP_GET_OPTR, - OSSP_DSP_GET_IPTR, - OSSP_DSP_GET_ODELAY, - - OSSP_NR_OPCODES, -}; - -enum ossp_notify_opcode { - OSSP_NOTIFY_POLL, - OSSP_NOTIFY_OBITUARY, - OSSP_NOTIFY_VOLCHG, - - OSSP_NR_NOTIFY_OPCODES, -}; - -struct ossp_mixer_arg { - int vol[2][2]; -}; - -struct ossp_dsp_open_arg { - int flags; - pid_t opener_pid; -}; - -struct ossp_dsp_rw_arg { - unsigned nonblock:1; -}; - -struct ossp_dsp_mmap_arg { - int dir; - size_t size; -}; - -struct ossp_cmd { - unsigned magic; - enum ossp_opcode opcode; - size_t din_size; - size_t dout_size; -}; - -struct ossp_reply { - unsigned magic; - int result; - size_t dout_size; /* <= cmd.data_in_size */ -}; - -struct ossp_notify { - unsigned magic; - enum ossp_notify_opcode opcode; -}; - -struct ossp_arg_size { - ssize_t carg_size; - ssize_t rarg_size; - unsigned has_fd:1; -}; - -extern const struct ossp_arg_size ossp_arg_sizes[OSSP_NR_OPCODES]; -extern const char *ossp_cmd_str[OSSP_NR_OPCODES]; -extern const char *ossp_notify_str[OSSP_NR_NOTIFY_OPCODES]; - -#endif /* _OSSP_H */ diff --git a/src/mod/endpoints/mod_skypopen/osscuse/osspd.c b/src/mod/endpoints/mod_skypopen/osscuse/osspd.c deleted file mode 100644 index dc9f36a09b..0000000000 --- a/src/mod/endpoints/mod_skypopen/osscuse/osspd.c +++ /dev/null @@ -1,2374 +0,0 @@ -/* - * osspd - OSS Proxy Daemon: emulate OSS device using CUSE - * - * Copyright (C) 2008-2010 SUSE Linux Products GmbH - * Copyright (C) 2008-2010 Tejun Heo - * - * This file is released under the GPLv2. - */ -#undef GIOVANNI - -#define FUSE_USE_VERSION 28 -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ossp.h" -#include "ossp-util.h" - -/* - * MMAP support needs to be updated to the new fuse MMAP API. Disable - * it for the time being. - */ -#warning mmap support disabled for now -/* #define OSSP_MMAP */ - -#define DFL_MIXER_NAME "mixer" -#define DFL_DSP_NAME "dsp" -#define DFL_ADSP_NAME "adsp" -#define STRFMT "S[%u/%d]" -#define STRID(os) os->id, os->pid - -#define dbg1_os(os, fmt, args...) dbg1(STRFMT" "fmt, STRID(os) , ##args) -#define dbg0_os(os, fmt, args...) dbg0(STRFMT" "fmt, STRID(os) , ##args) -#define warn_os(os, fmt, args...) warn(STRFMT" "fmt, STRID(os) , ##args) -#define err_os(os, fmt, args...) err(STRFMT" "fmt, STRID(os) , ##args) -#define warn_ose(os, err, fmt, args...) \ - warn_e(err, STRFMT" "fmt, STRID(os) , ##args) -#define err_ose(os, err, fmt, args...) \ - err_e(err, STRFMT" "fmt, STRID(os) , ##args) - -enum { - SNDRV_OSS_VERSION = ((3<<16)|(8<<8)|(1<<4)|(0)), /* 3.8.1a */ - DFL_MIXER_MAJOR = 14, - DFL_MIXER_MINOR = 0, - DFL_DSP_MAJOR = 14, - DFL_DSP_MINOR = 3, - DFL_ADSP_MAJOR = 14, - DFL_ADSP_MINOR = 12, - DFL_MAX_STREAMS = 128, - MIXER_PUT_DELAY = 600, /* 10 mins */ - /* DSPS_MMAP_SIZE / 2 must be multiple of SHMLBA */ - DSPS_MMAP_SIZE = 2 * (512 << 10), /* 512k for each dir */ -}; - -struct ossp_uid_cnt { - struct list_head link; - uid_t uid; - unsigned nr_os; -}; - -struct ossp_mixer { - pid_t pgrp; - struct list_head link; - struct list_head delayed_put_link; - unsigned refcnt; - /* the following two fields are protected by mixer_mutex */ - int vol[2][2]; - int modify_counter; - time_t put_expires; -}; - -struct ossp_mixer_cmd { - struct ossp_mixer *mixer; - struct ossp_mixer_arg set; - int out_dir; - int rvol; -}; - -#define for_each_vol(i, j) \ - for (i = 0, j = 0; i < 2; j += i << 1, j++, i = j >> 1, j &= 1) - -struct ossp_stream { - unsigned id; /* stream ID */ - struct list_head link; - struct list_head pgrp_link; - struct list_head notify_link; - unsigned refcnt; - pthread_mutex_t cmd_mutex; - pthread_mutex_t mmap_mutex; - struct fuse_pollhandle *ph; - - /* stream owner info */ - pid_t pid; - pid_t pgrp; - uid_t uid; - gid_t gid; - - /* slave info */ - pid_t slave_pid; - int cmd_fd; - int notify_tx; - int notify_rx; - - /* the following dead flag is set asynchronously, keep it separate. */ - int dead; - - /* stream mixer state, protected by mixer_mutex */ - int mixer_pending; - int vol[2][2]; - int vol_set[2][2]; - - off_t mmap_off; - size_t mmap_size; - - struct ossp_uid_cnt *ucnt; - struct fuse_session *se; /* associated fuse session */ - struct ossp_mixer *mixer; -}; - -struct ossp_dsp_stream { - struct ossp_stream os; - unsigned rw; - unsigned mmapped; - int nonblock; -}; - -#define os_to_dsps(_os) container_of(_os, struct ossp_dsp_stream, os) - -static unsigned max_streams; -static unsigned umax_streams; -static unsigned hashtbl_size; -static char dsp_slave_path[PATH_MAX]; - -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t mixer_mutex = PTHREAD_MUTEX_INITIALIZER; -static unsigned long *os_id_bitmap; -static unsigned nr_mixers; -static struct list_head *mixer_tbl; /* indexed by PGRP */ -static struct list_head *os_tbl; /* indexed by ID */ -static struct list_head *os_pgrp_tbl; /* indexed by PGRP */ -static struct list_head *os_notify_tbl; /* indexed by notify fd */ -static LIST_HEAD(uid_cnt_list); -static int notify_epfd; /* epoll used to monitor notify fds */ -static pthread_t notify_poller_thread; -static pthread_t slave_reaper_thread; -static pthread_t mixer_delayed_put_thread; -static pthread_t cuse_mixer_thread; -static pthread_t cuse_adsp_thread; -static pthread_cond_t notify_poller_kill_wait = PTHREAD_COND_INITIALIZER; -static pthread_cond_t slave_reaper_wait = PTHREAD_COND_INITIALIZER; -static LIST_HEAD(slave_corpse_list); -static LIST_HEAD(mixer_delayed_put_head); /* delayed reference */ -static pthread_cond_t mixer_delayed_put_cond = PTHREAD_COND_INITIALIZER; - -static int init_wait_fd = -1; -static int exit_on_idle; -static struct fuse_session *mixer_se; -static struct fuse_session *dsp_se; -static struct fuse_session *adsp_se; - -static void put_os(struct ossp_stream *os); - - -/*************************************************************************** - * Accessors - */ - -static struct list_head *mixer_tbl_head(pid_t pid) -{ - return &mixer_tbl[pid % hashtbl_size]; -} - -static struct list_head *os_tbl_head(uint64_t id) -{ - return &os_tbl[id % hashtbl_size]; -} - -static struct list_head *os_pgrp_tbl_head(pid_t pgrp) -{ - return &os_pgrp_tbl[pgrp % hashtbl_size]; -} - -static struct list_head *os_notify_tbl_head(int notify_rx) -{ - return &os_notify_tbl[notify_rx % hashtbl_size]; -} - -static struct ossp_mixer *find_mixer_locked(pid_t pgrp) -{ - struct ossp_mixer *mixer; - - list_for_each_entry(mixer, mixer_tbl_head(pgrp), link) - if (mixer->pgrp == pgrp) - return mixer; - return NULL; -} - -static struct ossp_mixer *find_mixer(pid_t pgrp) -{ - struct ossp_mixer *mixer; - - pthread_mutex_lock(&mutex); - mixer = find_mixer_locked(pgrp); - pthread_mutex_unlock(&mutex); - return mixer; -} - -static struct ossp_stream *find_os(unsigned id) -{ - struct ossp_stream *os, *found = NULL; - - pthread_mutex_lock(&mutex); - list_for_each_entry(os, os_tbl_head(id), link) - if (os->id == id) { - found = os; - break; - } - pthread_mutex_unlock(&mutex); - return found; -} - -static struct ossp_stream *find_os_by_notify_rx(int notify_rx) -{ - struct ossp_stream *os, *found = NULL; - - pthread_mutex_lock(&mutex); - list_for_each_entry(os, os_notify_tbl_head(notify_rx), notify_link) - if (os->notify_rx == notify_rx) { - found = os; - break; - } - pthread_mutex_unlock(&mutex); - return found; -} - - -/*************************************************************************** - * Command and ioctl helpers - */ - -static ssize_t exec_cmd_intern(struct ossp_stream *os, enum ossp_opcode opcode, - const void *carg, size_t carg_size, const void *din, size_t din_size, - void *rarg, size_t rarg_size, void *dout, size_t *dout_sizep, int fd) -{ - size_t dout_size = dout_sizep ? *dout_sizep : 0; - struct ossp_cmd cmd = { .magic = OSSP_CMD_MAGIC, .opcode = opcode, - .din_size = din_size, - .dout_size = dout_size }; - struct iovec iov = { &cmd, sizeof(cmd) }; - struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 }; - struct ossp_reply reply = { }; - char cmsg_buf[CMSG_SPACE(sizeof(fd))]; - char reason[512]; - int rc; - - if (os->dead) - return -EIO; - - //dbg1_os(os, "opcode %s=%d carg=%zu din=%zu rarg=%zu dout=%zu", - //ossp_cmd_str[opcode], opcode, carg_size, din_size, rarg_size, - //dout_size); -#ifndef GIOVANNI -memset(dout, 255, dout_size); -memset(din, 255, din_size); - -#define GIOVA_BLK 3840 -#define GIOVA_SLEEP 40000 -switch(opcode){ - - case 1: //OPEN - reply.result = 0; - break; - case 2: //READ - usleep((GIOVA_SLEEP/GIOVA_BLK)* *dout_sizep); - reply.result = *dout_sizep; - break; - case 3: //WRITE - usleep((GIOVA_SLEEP/GIOVA_BLK)* din_size); - reply.result = din_size; - break; - case 9: //POST - reply.result = -32; - break; - case 13: //GET_BLKSIZE - reply.result = 0; - *(int *)rarg = GIOVA_BLK; - break; - case 14: //GET_FORMATS - reply.result = 0; - *(int *)rarg = 28731; - break; - case 15: //SET_RATE - reply.result = 0; - *(int *)rarg = *(int *) carg; - break; - case 16: //SET_CHANNELS - reply.result = 0; - *(int *)rarg = *(int *) carg; - break; - case 17: //SET_FORMAT - reply.result = 0; - *(int *)rarg = *(int *) carg; - break; - case 19: //SET_FRAGMENT - reply.result = 0; - break; - default: - reply.result = 0; - break; -} -#endif // GIOVANNI - -#ifdef GIOVANNI - if (fd >= 0) { - struct cmsghdr *cmsg; - - msg.msg_control = cmsg_buf; - msg.msg_controllen = sizeof(cmsg_buf); - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); - *(int *)CMSG_DATA(cmsg) = fd; - msg.msg_controllen = cmsg->cmsg_len; - } - - if (sendmsg(os->cmd_fd, &msg, 0) <= 0) { - rc = -errno; - snprintf(reason, sizeof(reason), "command sendmsg failed: %s", - strerror(-rc)); - goto fail; - } - - if ((rc = write_fill(os->cmd_fd, carg, carg_size)) < 0 || - (rc = write_fill(os->cmd_fd, din, din_size)) < 0) { - snprintf(reason, sizeof(reason), - "can't tranfer command argument and/or data: %s", - strerror(-rc)); - goto fail; - } - if ((rc = read_fill(os->cmd_fd, &reply, sizeof(reply))) < 0) { - snprintf(reason, sizeof(reason), "can't read reply: %s", - strerror(-rc)); - goto fail; - } - - if (reply.magic != OSSP_REPLY_MAGIC) { - snprintf(reason, sizeof(reason), - "reply magic mismatch %x != %x", - reply.magic, OSSP_REPLY_MAGIC); - rc = -EINVAL; - goto fail; - } - - if (reply.result < 0) - goto out_unlock; - - if (reply.dout_size > dout_size) { - snprintf(reason, sizeof(reason), - "data out size overflow %zu > %zu", - reply.dout_size, dout_size); - rc = -EINVAL; - goto fail; - } - - dout_size = reply.dout_size; - if (dout_sizep) - *dout_sizep = dout_size; - - if ((rc = read_fill(os->cmd_fd, rarg, rarg_size)) < 0 || - (rc = read_fill(os->cmd_fd, dout, dout_size)) < 0) { - snprintf(reason, sizeof(reason), "can't read data out: %s", - strerror(-rc)); - goto fail; - } - -#endif // GIOVANNI - -out_unlock: - //dbg1_os(os, " completed, result=%d dout=%zu", - //reply.result, dout_size); - -//if(rarg) - //dbg1_os(os, " 2 %s=%d completed, result=%d dout=%zu carg=%d rarg=%d", ossp_cmd_str[opcode], opcode, - //reply.result, dout_size, carg ? *(int *) carg : 666, *(int *)rarg); - return reply.result; - -fail: - warn_os(os, "communication with slave failed (%s)", reason); - os->dead = 1; - return rc; -} - -static ssize_t exec_cmd(struct ossp_stream *os, enum ossp_opcode opcode, - const void *carg, size_t carg_size, const void *din, size_t din_size, - void *rarg, size_t rarg_size, void *dout, size_t *dout_sizep, int fd) -{ - int is_mixer; - int i, j; - ssize_t ret, mret; - - /* mixer command is handled exlicitly below */ - is_mixer = opcode == OSSP_MIXER; - if (is_mixer) { - ret = -pthread_mutex_trylock(&os->cmd_mutex); - if (ret) - return ret; - } else { - pthread_mutex_lock(&os->cmd_mutex); - - ret = exec_cmd_intern(os, opcode, carg, carg_size, - din, din_size, rarg, rarg_size, - dout, dout_sizep, fd); - } - - /* lazy mixer handling */ - pthread_mutex_lock(&mixer_mutex); - - if (os->mixer_pending) { - struct ossp_mixer_arg marg; - repeat_mixer: - /* we have mixer command pending */ - memcpy(marg.vol, os->vol_set, sizeof(os->vol_set)); - memset(os->vol_set, -1, sizeof(os->vol_set)); - - pthread_mutex_unlock(&mixer_mutex); - mret = exec_cmd_intern(os, OSSP_MIXER, &marg, sizeof(marg), - NULL, 0, &marg, sizeof(marg), NULL, NULL, - -1); - pthread_mutex_lock(&mixer_mutex); - - /* was there mixer set request while executing mixer command? */ - for_each_vol(i, j) - if (os->vol_set[i][j] >= 0) - goto repeat_mixer; - - /* update internal mixer state */ - if (mret == 0) { - for_each_vol(i, j) { - if (marg.vol[i][j] >= 0) { - if (os->vol[i][j] != marg.vol[i][j]) - os->mixer->modify_counter++; - os->vol[i][j] = marg.vol[i][j]; - } - } - } - os->mixer_pending = 0; - } - - pthread_mutex_unlock(&os->cmd_mutex); - - /* - * mixer mutex must be released after cmd_mutex so that - * exec_mixer_cmd() can guarantee that mixer_pending flags - * will be handled immediately or when the currently - * in-progress command completes. - */ - pthread_mutex_unlock(&mixer_mutex); - - return is_mixer ? mret : ret; -} - -static ssize_t exec_simple_cmd(struct ossp_stream *os, - enum ossp_opcode opcode, void *carg, void *rarg) -{ - return exec_cmd(os, opcode, - carg, ossp_arg_sizes[opcode].carg_size, NULL, 0, - rarg, ossp_arg_sizes[opcode].rarg_size, NULL, NULL, -1); -} - -static int ioctl_prep_uarg(fuse_req_t req, void *in, size_t in_sz, void *out, - size_t out_sz, void *uarg, const void *in_buf, - size_t in_bufsz, size_t out_bufsz) -{ - struct iovec in_iov = { }, out_iov = { }; - int retry = 0; - - if (in) { - if (!in_bufsz) { - in_iov.iov_base = uarg; - in_iov.iov_len = in_sz; - retry = 1; - } else { - assert(in_bufsz == in_sz); - memcpy(in, in_buf, in_sz); - } - } - - if (out) { - if (!out_bufsz) { - out_iov.iov_base = uarg; - out_iov.iov_len = out_sz; - retry = 1; - } else - assert(out_bufsz == out_sz); - } - - if (retry) - fuse_reply_ioctl_retry(req, &in_iov, 1, &out_iov, 1); - - return retry; -} - -#define PREP_UARG(inp, outp) do { \ - if (ioctl_prep_uarg(req, (inp), sizeof(*(inp)), \ - (outp), sizeof(*(outp)), uarg, \ - in_buf, in_bufsz, out_bufsz)) \ - return; \ -} while (0) - -#define IOCTL_RETURN(result, outp) do { \ - if ((outp) != NULL) \ - fuse_reply_ioctl(req, result, (outp), sizeof(*(outp))); \ - else \ - fuse_reply_ioctl(req, result, NULL, 0); \ - return; \ -} while (0) - - -/*************************************************************************** - * Mixer implementation - */ - -static void put_mixer_real(struct ossp_mixer *mixer) -{ - if (!--mixer->refcnt) { - dbg0("DESTROY mixer(%d)", mixer->pgrp); - list_del_init(&mixer->link); - list_del_init(&mixer->delayed_put_link); - free(mixer); - nr_mixers--; - - /* - * If exit_on_idle, mixer for pgrp0 is touched during - * init and each stream has mixer attached. As mixers - * are destroyed after they have been idle for - * MIXER_PUT_DELAY seconds, we can use it for idle - * detection. Note that this might race with - * concurrent open. The race is inherent. - */ - if (exit_on_idle && !nr_mixers) { - info("idle, exiting"); - exit(0); - } - } -} - -static struct ossp_mixer *get_mixer(pid_t pgrp) -{ - struct ossp_mixer *mixer; - - pthread_mutex_lock(&mutex); - - /* is there a matching one? */ - mixer = find_mixer_locked(pgrp); - if (mixer) { - if (list_empty(&mixer->delayed_put_link)) - mixer->refcnt++; - else - list_del_init(&mixer->delayed_put_link); - goto out_unlock; - } - - /* reap delayed put list if there are too many mixers */ - while (nr_mixers > 2 * max_streams && - !list_empty(&mixer_delayed_put_head)) { - struct ossp_mixer *mixer = - list_first_entry(&mixer_delayed_put_head, - struct ossp_mixer, delayed_put_link); - - assert(mixer->refcnt == 1); - put_mixer_real(mixer); - } - - /* create a new one */ - mixer = calloc(1, sizeof(*mixer)); - if (!mixer) { - warn("failed to allocate mixer for %d", pgrp); - mixer = NULL; - goto out_unlock; - } - - mixer->pgrp = pgrp; - INIT_LIST_HEAD(&mixer->link); - INIT_LIST_HEAD(&mixer->delayed_put_link); - mixer->refcnt = 1; - memset(mixer->vol, -1, sizeof(mixer->vol)); - - list_add(&mixer->link, mixer_tbl_head(pgrp)); - nr_mixers++; - dbg0("CREATE mixer(%d)", pgrp); - -out_unlock: - pthread_mutex_unlock(&mutex); - return mixer; -} - -static void put_mixer(struct ossp_mixer *mixer) -{ - pthread_mutex_lock(&mutex); - - if (mixer) { - if (mixer->refcnt == 1) { - struct timespec ts; - - clock_gettime(CLOCK_REALTIME, &ts); - mixer->put_expires = ts.tv_sec + MIXER_PUT_DELAY; - list_add_tail(&mixer->delayed_put_link, - &mixer_delayed_put_head); - pthread_cond_signal(&mixer_delayed_put_cond); - } else - put_mixer_real(mixer); - } - - pthread_mutex_unlock(&mutex); -} - -static void *mixer_delayed_put_worker(void *arg) -{ - struct ossp_mixer *mixer; - struct timespec ts; - time_t now; - - pthread_mutex_lock(&mutex); -again: - clock_gettime(CLOCK_REALTIME, &ts); - now = ts.tv_sec; - - mixer = NULL; - while (!list_empty(&mixer_delayed_put_head)) { - mixer = list_first_entry(&mixer_delayed_put_head, - struct ossp_mixer, delayed_put_link); - - if (now <= mixer->put_expires) - break; - - assert(mixer->refcnt == 1); - put_mixer_real(mixer); - mixer = NULL; - } - - if (mixer) { - ts.tv_sec = mixer->put_expires + 1; - pthread_cond_timedwait(&mixer_delayed_put_cond, &mutex, &ts); - } else - pthread_cond_wait(&mixer_delayed_put_cond, &mutex); - - goto again; -} - -static void init_mixer_cmd(struct ossp_mixer_cmd *mxcmd, - struct ossp_mixer *mixer) -{ - memset(mxcmd, 0, sizeof(*mxcmd)); - memset(&mxcmd->set.vol, -1, sizeof(mxcmd->set.vol)); - mxcmd->mixer = mixer; - mxcmd->out_dir = -1; -} - -static int exec_mixer_cmd(struct ossp_mixer_cmd *mxcmd, struct ossp_stream *os) -{ - int i, j, rc; - - /* - * Set pending flags before trying to execute mixer command. - * Combined with lock release order in exec_cmd(), this - * guarantees that the mixer command will be executed - * immediately or when the current command completes. - */ - pthread_mutex_lock(&mixer_mutex); - os->mixer_pending = 1; - for_each_vol(i, j) - if (mxcmd->set.vol[i][j] >= 0) - os->vol_set[i][j] = mxcmd->set.vol[i][j]; - pthread_mutex_unlock(&mixer_mutex); - - rc = exec_simple_cmd(os, OSSP_MIXER, NULL, NULL); - if (rc >= 0) { - dbg0_os(os, "volume set=%d/%d:%d/%d get=%d/%d:%d/%d", - mxcmd->set.vol[PLAY][LEFT], mxcmd->set.vol[PLAY][RIGHT], - mxcmd->set.vol[REC][LEFT], mxcmd->set.vol[REC][RIGHT], - os->vol[PLAY][LEFT], os->vol[PLAY][RIGHT], - os->vol[REC][LEFT], os->vol[REC][RIGHT]); - } else if (rc != -EBUSY) - warn_ose(os, rc, "mixer command failed"); - - return rc; -} - -static void finish_mixer_cmd(struct ossp_mixer_cmd *mxcmd) -{ - struct ossp_mixer *mixer = mxcmd->mixer; - struct ossp_stream *os; - int dir = mxcmd->out_dir; - int vol[2][2] = { }; - int cnt[2][2] = { }; - int i, j; - - pthread_mutex_lock(&mixer_mutex); - - /* get volume of all streams attached to this mixer */ - pthread_mutex_lock(&mutex); - list_for_each_entry(os, os_pgrp_tbl_head(mixer->pgrp), pgrp_link) { - if (os->pgrp != mixer->pgrp) - continue; - for_each_vol(i, j) { - if (os->vol[i][j] < 0) - continue; - vol[i][j] += os->vol[i][j]; - cnt[i][j]++; - } - } - pthread_mutex_unlock(&mutex); - - /* calculate the summary volume values */ - for_each_vol(i, j) { - if (mxcmd->set.vol[i][j] >= 0) - vol[i][j] = mxcmd->set.vol[i][j]; - else if (cnt[i][j]) - vol[i][j] = vol[i][j] / cnt[i][j]; - else if (mixer->vol[i][j] >= 0) - vol[i][j] = mixer->vol[i][j]; - else - vol[i][j] = 100; - - vol[i][j] = min(max(0, vol[i][j]), 100); - } - - if (dir >= 0) - mxcmd->rvol = vol[dir][LEFT] | (vol[dir][RIGHT] << 8); - - pthread_mutex_unlock(&mixer_mutex); -} - -static void mixer_simple_ioctl(fuse_req_t req, struct ossp_mixer *mixer, - unsigned cmd, void *uarg, const void *in_buf, - size_t in_bufsz, size_t out_bufsz, - int *not_minep) -{ - const char *id = "OSS Proxy", *name = "Mixer"; - int i; - - switch (cmd) { - case SOUND_MIXER_INFO: { - struct mixer_info info = { }; - - PREP_UARG(NULL, &info); - strncpy(info.id, id, sizeof(info.id) - 1); - strncpy(info.name, name, sizeof(info.name) - 1); - info.modify_counter = mixer->modify_counter; - IOCTL_RETURN(0, &info); - } - - case SOUND_OLD_MIXER_INFO: { - struct _old_mixer_info info = { }; - - PREP_UARG(NULL, &info); - strncpy(info.id, id, sizeof(info.id) - 1); - strncpy(info.name, name, sizeof(info.name) - 1); - IOCTL_RETURN(0, &info); - } - - case OSS_GETVERSION: - i = SNDRV_OSS_VERSION; - goto puti; - case SOUND_MIXER_READ_DEVMASK: - case SOUND_MIXER_READ_STEREODEVS: - i = SOUND_MASK_PCM | SOUND_MASK_IGAIN; - goto puti; - case SOUND_MIXER_READ_CAPS: - i = SOUND_CAP_EXCL_INPUT; - goto puti; - case SOUND_MIXER_READ_RECMASK: - case SOUND_MIXER_READ_RECSRC: - i = SOUND_MASK_IGAIN; - goto puti; - puti: - PREP_UARG(NULL, &i); - IOCTL_RETURN(0, &i); - - case SOUND_MIXER_WRITE_RECSRC: - IOCTL_RETURN(0, NULL); - - default: - *not_minep = 1; - return; - } - assert(0); -} - -static void mixer_do_ioctl(fuse_req_t req, struct ossp_mixer *mixer, - unsigned cmd, void *uarg, const void *in_buf, - size_t in_bufsz, size_t out_bufsz) -{ - struct ossp_mixer_cmd mxcmd; - struct ossp_stream *os, **osa; - int not_mine = 0; - int slot = cmd & 0xff, dir; - int nr_os; - int i, rc; - - mixer_simple_ioctl(req, mixer, cmd, uarg, in_buf, in_bufsz, out_bufsz, - ¬_mine); - if (!not_mine) - return; - - rc = -ENXIO; - if (!(cmd & (SIOC_IN | SIOC_OUT))) - goto err; - - /* - * Okay, it's not one of the easy ones. Build mxcmd for - * actual volume control. - */ - if (cmd & SIOC_IN) - PREP_UARG(&i, &i); - else - PREP_UARG(NULL, &i); - - switch (slot) { - case SOUND_MIXER_PCM: - dir = PLAY; - break; - case SOUND_MIXER_IGAIN: - dir = REC; - break; - default: - i = 0; - IOCTL_RETURN(0, &i); - } - - init_mixer_cmd(&mxcmd, mixer); - - if (cmd & SIOC_IN) { - unsigned l, r; - - rc = -EINVAL; - l = i & 0xff; - r = (i >> 8) & 0xff; - if (l > 100 || r > 100) - goto err; - - mixer->vol[dir][LEFT] = mxcmd.set.vol[dir][LEFT] = l; - mixer->vol[dir][RIGHT] = mxcmd.set.vol[dir][RIGHT] = r; - } - mxcmd.out_dir = dir; - - /* - * Apply volume conrol - */ - /* acquire target streams */ - pthread_mutex_lock(&mutex); - osa = calloc(max_streams, sizeof(osa[0])); - if (!osa) { - pthread_mutex_unlock(&mutex); - rc = -ENOMEM; - goto err; - } - - nr_os = 0; - list_for_each_entry(os, os_pgrp_tbl_head(mixer->pgrp), pgrp_link) { - if (os->pgrp == mixer->pgrp) { - osa[nr_os++] = os; - os->refcnt++; - } - } - - pthread_mutex_unlock(&mutex); - - /* execute mxcmd for each stream and put it */ - for (i = 0; i < nr_os; i++) { - exec_mixer_cmd(&mxcmd, osa[i]); - put_os(osa[i]); - } - - finish_mixer_cmd(&mxcmd); - free(osa); - - IOCTL_RETURN(0, out_bufsz ? &mxcmd.rvol : NULL); - -err: - fuse_reply_err(req, -rc); -} - -static void mixer_open(fuse_req_t req, struct fuse_file_info *fi) -{ - pid_t pid = fuse_req_ctx(req)->pid, pgrp; - struct ossp_mixer *mixer; - int rc; - - rc = get_proc_self_info(pid, &pgrp, NULL, 0); - if (rc) { - err_e(rc, "get_proc_self_info(%d) failed", pid); - fuse_reply_err(req, -rc); - return; - } - - mixer = get_mixer(pgrp); - fi->fh = pgrp; - - if (mixer) - fuse_reply_open(req, fi); - else - fuse_reply_err(req, ENOMEM); -} - -static void mixer_ioctl(fuse_req_t req, int signed_cmd, void *uarg, - struct fuse_file_info *fi, unsigned int flags, - const void *in_buf, size_t in_bufsz, size_t out_bufsz) -{ - struct ossp_mixer *mixer; - - mixer = find_mixer(fi->fh); - if (!mixer) { - fuse_reply_err(req, EBADF); - return; - } - - mixer_do_ioctl(req, mixer, signed_cmd, uarg, in_buf, in_bufsz, - out_bufsz); -} - -static void mixer_release(fuse_req_t req, struct fuse_file_info *fi) -{ - struct ossp_mixer *mixer; - - mixer = find_mixer(fi->fh); - if (mixer) { - put_mixer(mixer); - fuse_reply_err(req, 0); - } else - fuse_reply_err(req, EBADF); -} - - -/*************************************************************************** - * Stream implementation - */ - -static int alloc_os(size_t stream_size, size_t mmap_size, pid_t pid, uid_t pgrp, - uid_t uid, gid_t gid, int cmd_sock, - const int *notify, struct fuse_session *se, - struct ossp_stream **osp) -{ - struct ossp_uid_cnt *tmp_ucnt, *ucnt = NULL; - struct ossp_stream *os; - int rc; - - assert(stream_size >= sizeof(struct ossp_stream)); - os = calloc(1, stream_size); - if (!os) - return -ENOMEM; - - INIT_LIST_HEAD(&os->link); - INIT_LIST_HEAD(&os->pgrp_link); - INIT_LIST_HEAD(&os->notify_link); - os->refcnt = 1; - - rc = -pthread_mutex_init(&os->cmd_mutex, NULL); - if (rc) - goto err_free; - - rc = -pthread_mutex_init(&os->mmap_mutex, NULL); - if (rc) - goto err_destroy_cmd_mutex; - - pthread_mutex_lock(&mutex); - - list_for_each_entry(tmp_ucnt, &uid_cnt_list, link) - if (tmp_ucnt->uid == uid) { - ucnt = tmp_ucnt; - break; - } - if (!ucnt) { - rc = -ENOMEM; - ucnt = calloc(1, sizeof(*ucnt)); - if (!ucnt) - goto err_unlock; - ucnt->uid = uid; - list_add(&ucnt->link, &uid_cnt_list); - } - - rc = -EBUSY; - if (ucnt->nr_os + 1 > umax_streams) - goto err_unlock; - - /* everything looks fine, allocate id and init stream */ - rc = -EBUSY; - os->id = find_next_zero_bit(os_id_bitmap, max_streams, 0); - if (os->id >= max_streams) - goto err_unlock; - __set_bit(os->id, os_id_bitmap); - - os->cmd_fd = cmd_sock; - os->notify_tx = notify[1]; - os->notify_rx = notify[0]; - os->pid = pid; - os->pgrp = pgrp; - os->uid = uid; - os->gid = gid; - if (mmap_size) { - os->mmap_off = os->id * mmap_size; - os->mmap_size = mmap_size; - } - os->ucnt = ucnt; - os->se = se; - - memset(os->vol, -1, sizeof(os->vol)); - memset(os->vol_set, -1, sizeof(os->vol)); - - list_add(&os->link, os_tbl_head(os->id)); - list_add(&os->pgrp_link, os_pgrp_tbl_head(os->pgrp)); - - ucnt->nr_os++; - *osp = os; - pthread_mutex_unlock(&mutex); - return 0; - -err_unlock: - pthread_mutex_unlock(&mutex); - pthread_mutex_destroy(&os->mmap_mutex); -err_destroy_cmd_mutex: - pthread_mutex_destroy(&os->cmd_mutex); -err_free: - free(os); - return rc; -} - -static void shutdown_notification(struct ossp_stream *os) -{ - struct ossp_notify obituary = { .magic = OSSP_NOTIFY_MAGIC, - .opcode = OSSP_NOTIFY_OBITUARY }; - ssize_t ret; - - /* - * Shutdown notification for this stream. We politely ask - * notify_poller to shut the receive side down to avoid racing - * with it. - */ - while (os->notify_rx >= 0) { - ret = write(os->notify_tx, &obituary, sizeof(obituary)); - if (ret <= 0) { - if (ret == 0) - warn_os(os, "unexpected EOF on notify_tx"); - else if (errno != EPIPE) - warn_ose(os, -errno, - "unexpected error on notify_tx"); - close(os->notify_rx); - os->notify_rx = -1; - break; - } - - if (ret != sizeof(obituary)) - warn_os(os, "short transfer on notify_tx"); - pthread_cond_wait(¬ify_poller_kill_wait, &mutex); - } -} - -static void put_os(struct ossp_stream *os) -{ - if (!os) - return; - - pthread_mutex_lock(&mutex); - - assert(os->refcnt); - if (--os->refcnt) { - pthread_mutex_unlock(&mutex); - return; - } - - os->dead = 1; - shutdown_notification(os); - - dbg0_os(os, "DESTROY"); - - list_del_init(&os->link); - list_del_init(&os->pgrp_link); - list_del_init(&os->notify_link); - os->ucnt->nr_os--; - - pthread_mutex_unlock(&mutex); - - close(os->cmd_fd); - close(os->notify_tx); - put_mixer(os->mixer); - pthread_mutex_destroy(&os->cmd_mutex); - pthread_mutex_destroy(&os->mmap_mutex); - - pthread_mutex_lock(&mutex); - dbg1_os(os, "stream dead, requesting reaping"); - list_add_tail(&os->link, &slave_corpse_list); - pthread_cond_signal(&slave_reaper_wait); - pthread_mutex_unlock(&mutex); -} - -static void set_extra_env(pid_t pid) -{ - char procenviron[32]; - const int step = 1024; - char *data = malloc(step + 1); - int ofs = 0; - int fd; - int ret; - - if (!data) - return; - - sprintf(procenviron, "/proc/%d/environ", pid); - fd = open(procenviron, O_RDONLY); - if (fd < 0) - return; - - /* - * There should really be a 'read whole file to a newly allocated - * buffer' function. - */ - while ((ret = read(fd, data + ofs, step)) > 0) { - char *newdata; - ofs += ret; - newdata = realloc(data, ofs + step + 1); - if (!newdata) { - ret = -1; - break; - } - data = newdata; - } - if (ret == 0) { - char *ptr = data; - /* Append the extra 0 for end condition */ - data[ofs] = 0; - - while ((ret = strlen(ptr)) > 0) { - /* - * Copy all PULSE variables and DISPLAY so that - * ssh -X remotehost 'mplayer -ao oss' will work - */ - if (!strncmp(ptr, "DISPLAY=", 8) || - !strncmp(ptr, "PULSE_", 6)) - putenv(ptr); - ptr += ret + 1; - } - } - - free(data); - close(fd); -} - -#ifndef GIOVANNI -int contapid = 13000; -#endif// GIOVANNI - -static int create_os(const char *slave_path, - size_t stream_size, size_t mmap_size, - pid_t pid, pid_t pgrp, uid_t uid, gid_t gid, - struct fuse_session *se, struct ossp_stream **osp) -{ - static pthread_mutex_t create_mutex = PTHREAD_MUTEX_INITIALIZER; - int cmd_sock[2] = { -1, -1 }; - int notify_sock[2] = { -1, -1 }; - struct ossp_stream *os = NULL; - struct epoll_event ev = { }; - int i, rc; - - /* - * Only one thread can be creating a stream. This is to avoid - * leaking unwanted fds into slaves. - */ - pthread_mutex_lock(&create_mutex); - - /* prepare communication channels */ - if (socketpair(AF_UNIX, SOCK_STREAM, 0, cmd_sock) || - socketpair(AF_UNIX, SOCK_STREAM, 0, notify_sock)) { - rc = -errno; - warn_e(rc, "failed to create slave command channel"); - goto close_all; - } - - if (fcntl(notify_sock[0], F_SETFL, O_NONBLOCK) < 0) { - rc = -errno; - warn_e(rc, "failed to set NONBLOCK on notify sock"); - goto close_all; - } - - /* - * Alloc stream which will be responsible for all server side - * resources from now on. - */ - rc = alloc_os(stream_size, mmap_size, pid, pgrp, uid, gid, cmd_sock[0], - notify_sock, se, &os); - if (rc) { - warn_e(rc, "failed to allocate stream for %d", pid); - goto close_all; - } - - rc = -ENOMEM; - os->mixer = get_mixer(pgrp); - if (!os->mixer) - goto put_os; - - /* - * Register notification. If successful, notify_poller has - * custody of notify_rx fd. - */ - pthread_mutex_lock(&mutex); - list_add(&os->notify_link, os_notify_tbl_head(os->notify_rx)); - pthread_mutex_unlock(&mutex); - -#ifndef GIOVANNI - os->slave_pid = contapid; - contapid++; - if(contapid > 30000) - contapid=13000; -#endif //GIOVANNI - -//#ifdef GIOVANNI - ev.events = EPOLLIN; - ev.data.fd = notify_sock[0]; - if (epoll_ctl(notify_epfd, EPOLL_CTL_ADD, notify_sock[0], &ev)) { - /* - * Without poller watching this notify sock, poller - * shutdown sequence in shutdown_notification() can't - * be used. Kill notification rx manually. - */ - rc = -errno; - warn_ose(os, rc, "failed to add notify epoll"); - close(os->notify_rx); - os->notify_rx = -1; - goto put_os; - } - - /* start slave */ - os->slave_pid = fork(); - if (os->slave_pid < 0) { - rc = -errno; - warn_ose(os, rc, "failed to fork slave"); - goto put_os; - } - - if (os->slave_pid == 0) { - /* child */ - char id_str[2][16], fd_str[3][16]; - char mmap_off_str[32], mmap_size_str[32]; - char log_str[16], slave_path_copy[PATH_MAX]; - char *argv[] = { slave_path_copy, "-u", id_str[0], - "-g", id_str[1], "-c", fd_str[0], - "-n", fd_str[1], "-m", fd_str[2], - "-o", mmap_off_str, "-s", mmap_size_str, - "-l", log_str, NULL, NULL }; - struct passwd *pwd; - - /* drop stuff we don't need */ - if (close(cmd_sock[0]) || close(notify_sock[0])) - fatal_e(-errno, "failed to close server pipe fds"); - -#ifdef OSSP_MMAP - if (!mmap_size) - close(fuse_mmap_fd(se)); -#endif - - clearenv(); - pwd = getpwuid(os->uid); - if (pwd) { - setenv("LOGNAME", pwd->pw_name, 1); - setenv("USER", pwd->pw_name, 1); - setenv("HOME", pwd->pw_dir, 1); - } - /* Set extra environment variables from the caller */ - set_extra_env(pid); - - /* prep and exec */ - slave_path_copy[sizeof(slave_path_copy) - 1] = '\0'; - strncpy(slave_path_copy, slave_path, sizeof(slave_path_copy) - 1); - if (slave_path_copy[sizeof(slave_path_copy) - 1] != '\0') { - rc = -errno; - err_ose(os, rc, "slave path too long"); - goto child_fail; - } - - snprintf(id_str[0], sizeof(id_str[0]), "%d", os->uid); - snprintf(id_str[1], sizeof(id_str[0]), "%d", os->gid); - snprintf(fd_str[0], sizeof(fd_str[0]), "%d", cmd_sock[1]); - snprintf(fd_str[1], sizeof(fd_str[1]), "%d", notify_sock[1]); - snprintf(fd_str[2], sizeof(fd_str[2]), "%d", -#ifdef OSSP_MMAP - mmap_size ? fuse_mmap_fd(se) : -#endif - -1); - snprintf(mmap_off_str, sizeof(mmap_off_str), "0x%llx", - (unsigned long long)os->mmap_off); - snprintf(mmap_size_str, sizeof(mmap_size_str), "0x%zx", - mmap_size); - snprintf(log_str, sizeof(log_str), "%d", ossp_log_level); - if (ossp_log_timestamp) - argv[ARRAY_SIZE(argv) - 2] = "-t"; - - execv(slave_path, argv); - rc = -errno; - err_ose(os, rc, "execv failed for <%d>", pid); - child_fail: - _exit(1); - } -//#endif //GIOVANNI - - /* turn on CLOEXEC on all server side fds */ - if (fcntl(os->cmd_fd, F_SETFD, FD_CLOEXEC) < 0 || - fcntl(os->notify_tx, F_SETFD, FD_CLOEXEC) < 0 || - fcntl(os->notify_rx, F_SETFD, FD_CLOEXEC) < 0) { - rc = -errno; - err_ose(os, rc, "failed to set CLOEXEC on server side fds"); - goto put_os; - } - - dbg0_os(os, "CREATE slave=%d %s", os->slave_pid, slave_path); - dbg0_os(os, " client=%d cmd=%d:%d notify=%d:%d mmap=%d:0x%llx:%zu", - pid, cmd_sock[0], cmd_sock[1], notify_sock[0], notify_sock[1], -#ifdef OSSP_MMAP - os->mmap_size ? fuse_mmap_fd(se) : -#endif - -1, - (unsigned long long)os->mmap_off, os->mmap_size); - - *osp = os; - rc = 0; - goto close_client_fds; - -put_os: - put_os(os); -close_client_fds: - close(cmd_sock[1]); - pthread_mutex_unlock(&create_mutex); - return rc; - -close_all: - for (i = 0; i < 2; i++) { - close(cmd_sock[i]); - close(notify_sock[i]); - } - pthread_mutex_unlock(&create_mutex); - return rc; -} - -static void dsp_open_common(fuse_req_t req, struct fuse_file_info *fi, - struct fuse_session *se) -{ - const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req); - struct ossp_dsp_open_arg arg = { }; - struct ossp_stream *os = NULL; - struct ossp_mixer *mixer; - struct ossp_dsp_stream *dsps; - struct ossp_mixer_cmd mxcmd; - pid_t pgrp; - ssize_t ret; - - ret = get_proc_self_info(fuse_ctx->pid, &pgrp, NULL, 0); - if (ret) { - err_e(ret, "get_proc_self_info(%d) failed", fuse_ctx->pid); - goto err; - } - - ret = create_os(dsp_slave_path, sizeof(*dsps), DSPS_MMAP_SIZE, - fuse_ctx->pid, pgrp, fuse_ctx->uid, fuse_ctx->gid, - se, &os); - if (ret) - goto err; - dsps = os_to_dsps(os); - mixer = os->mixer; - - switch (fi->flags & O_ACCMODE) { - case O_WRONLY: - dsps->rw |= 1 << PLAY; - break; - case O_RDONLY: - dsps->rw |= 1 << REC; - break; - case O_RDWR: - dsps->rw |= (1 << PLAY) | (1 << REC); - break; - default: - assert(0); - } - - arg.flags = fi->flags; - arg.opener_pid = os->pid; - ret = exec_simple_cmd(&dsps->os, OSSP_DSP_OPEN, &arg, NULL); - if (ret < 0) { - put_os(os); - goto err; - } - - memcpy(os->vol, mixer->vol, sizeof(os->vol)); - if (os->vol[PLAY][0] >= 0 || os->vol[REC][0] >= 0) { - init_mixer_cmd(&mxcmd, mixer); - memcpy(mxcmd.set.vol, os->vol, sizeof(os->vol)); - exec_mixer_cmd(&mxcmd, os); - finish_mixer_cmd(&mxcmd); - } - - fi->direct_io = 1; - fi->nonseekable = 1; - fi->fh = os->id; - - fuse_reply_open(req, fi); - return; - -err: - fuse_reply_err(req, -ret); -} - -static void dsp_open(fuse_req_t req, struct fuse_file_info *fi) -{ - dsp_open_common(req, fi, dsp_se); -} - -static void adsp_open(fuse_req_t req, struct fuse_file_info *fi) -{ - dsp_open_common(req, fi, adsp_se); -} - -static void dsp_release(fuse_req_t req, struct fuse_file_info *fi) -{ - struct ossp_stream *os; - - os = find_os(fi->fh); - if (os) { - put_os(os); - fuse_reply_err(req, 0); - } else - fuse_reply_err(req, EBADF); -} - -static void dsp_read(fuse_req_t req, size_t size, off_t off, - struct fuse_file_info *fi) -{ - struct ossp_dsp_rw_arg arg = { }; - struct ossp_stream *os; - struct ossp_dsp_stream *dsps; - void *buf = NULL; - ssize_t ret; - - ret = -EBADF; - os = find_os(fi->fh); - if (!os) - goto out; - dsps = os_to_dsps(os); - - ret = -EINVAL; - if (!(dsps->rw & (1 << REC))) - goto out; - - ret = -ENXIO; - if (dsps->mmapped) - goto out; - - ret = -ENOMEM; - buf = malloc(size); - if (!buf) - goto out; - - arg.nonblock = (fi->flags & O_NONBLOCK) || dsps->nonblock; - - ret = exec_cmd(os, OSSP_DSP_READ, &arg, sizeof(arg), - NULL, 0, NULL, 0, buf, &size, -1); -out: - if (ret >= 0) - fuse_reply_buf(req, buf, size); - else - fuse_reply_err(req, -ret); - - free(buf); -} - -static void dsp_write(fuse_req_t req, const char *buf, size_t size, off_t off, - struct fuse_file_info *fi) -{ - struct ossp_dsp_rw_arg arg = { }; - struct ossp_stream *os; - struct ossp_dsp_stream *dsps; - ssize_t ret; - - ret = -EBADF; - os = find_os(fi->fh); - if (!os) - goto out; - dsps = os_to_dsps(os); - - ret = -EINVAL; - if (!(dsps->rw & (1 << PLAY))) - goto out; - - ret = -ENXIO; - if (dsps->mmapped) - goto out; - - arg.nonblock = (fi->flags & O_NONBLOCK) || dsps->nonblock; - - ret = exec_cmd(os, OSSP_DSP_WRITE, &arg, sizeof(arg), - buf, size, NULL, 0, NULL, NULL, -1); -out: - if (ret >= 0) - fuse_reply_write(req, ret); - else - fuse_reply_err(req, -ret); -} - -static void dsp_poll(fuse_req_t req, struct fuse_file_info *fi, - struct fuse_pollhandle *ph) -{ - int notify = ph != NULL; - unsigned revents = 0; - struct ossp_stream *os; - ssize_t ret; - - ret = -EBADF; - os = find_os(fi->fh); - if (!os) - goto out; - - if (ph) { - pthread_mutex_lock(&mutex); - if (os->ph) - fuse_pollhandle_destroy(os->ph); - os->ph = ph; - pthread_mutex_unlock(&mutex); - } - - ret = exec_simple_cmd(os, OSSP_DSP_POLL, ¬ify, &revents); -out: - if (ret >= 0) - fuse_reply_poll(req, revents); - else - fuse_reply_err(req, -ret); -} - -static void dsp_ioctl(fuse_req_t req, int signed_cmd, void *uarg, - struct fuse_file_info *fi, unsigned int flags, - const void *in_buf, size_t in_bufsz, size_t out_bufsz) -{ - /* some ioctl constants are long and has the highest bit set */ - unsigned cmd = signed_cmd; - struct ossp_stream *os; - struct ossp_dsp_stream *dsps; - enum ossp_opcode op; - ssize_t ret; - int i; - - ret = -EBADF; - os = find_os(fi->fh); - if (!os) - goto err; - dsps = os_to_dsps(os); - - /* mixer commands are allowed on DSP devices */ - if (((cmd >> 8) & 0xff) == 'M') { - mixer_do_ioctl(req, os->mixer, cmd, uarg, in_buf, in_bufsz, - out_bufsz); - return; - } - - /* and the rest */ - switch (cmd) { - case OSS_GETVERSION: - i = SNDRV_OSS_VERSION; - PREP_UARG(NULL, &i); - IOCTL_RETURN(0, &i); - - case SNDCTL_DSP_GETCAPS: - i = DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | -#ifdef OSSP_MMAP - DSP_CAP_MMAP | -#endif - DSP_CAP_MULTI; - PREP_UARG(NULL, &i); - IOCTL_RETURN(0, &i); - - case SNDCTL_DSP_NONBLOCK: - dsps->nonblock = 1; - ret = 0; - IOCTL_RETURN(0, NULL); - - case SNDCTL_DSP_RESET: op = OSSP_DSP_RESET; goto nd; - case SNDCTL_DSP_SYNC: op = OSSP_DSP_SYNC; goto nd; - case SNDCTL_DSP_POST: op = OSSP_DSP_POST; goto nd; - nd: - ret = exec_simple_cmd(&dsps->os, op, NULL, NULL); - if (ret) - goto err; - IOCTL_RETURN(0, NULL); - - case SOUND_PCM_READ_RATE: op = OSSP_DSP_GET_RATE; goto ri; - case SOUND_PCM_READ_BITS: op = OSSP_DSP_GET_FORMAT; goto ri; - case SOUND_PCM_READ_CHANNELS: op = OSSP_DSP_GET_CHANNELS; goto ri; - case SNDCTL_DSP_GETBLKSIZE: op = OSSP_DSP_GET_BLKSIZE; goto ri; - case SNDCTL_DSP_GETFMTS: op = OSSP_DSP_GET_FORMATS; goto ri; - case SNDCTL_DSP_GETTRIGGER: op = OSSP_DSP_GET_TRIGGER; goto ri; - ri: - PREP_UARG(NULL, &i); - ret = exec_simple_cmd(&dsps->os, op, NULL, &i); - if (ret) - goto err; - IOCTL_RETURN(0, &i); - - case SNDCTL_DSP_SPEED: op = OSSP_DSP_SET_RATE; goto wi; - case SNDCTL_DSP_SETFMT: op = OSSP_DSP_SET_FORMAT; goto wi; - case SNDCTL_DSP_CHANNELS: op = OSSP_DSP_SET_CHANNELS; goto wi; - case SNDCTL_DSP_SUBDIVIDE: op = OSSP_DSP_SET_SUBDIVISION; goto wi; - wi: - PREP_UARG(&i, &i); - ret = exec_simple_cmd(&dsps->os, op, &i, &i); - if (ret) - goto err; - IOCTL_RETURN(0, &i); - - case SNDCTL_DSP_STEREO: - PREP_UARG(NULL, &i); - i = 2; - ret = exec_simple_cmd(&dsps->os, OSSP_DSP_SET_CHANNELS, &i, &i); - i--; - if (ret) - goto err; - IOCTL_RETURN(0, &i); - - case SNDCTL_DSP_SETFRAGMENT: - PREP_UARG(&i, NULL); - ret = exec_simple_cmd(&dsps->os, - OSSP_DSP_SET_FRAGMENT, &i, NULL); - if (ret) - goto err; - IOCTL_RETURN(0, NULL); - - case SNDCTL_DSP_SETTRIGGER: - PREP_UARG(&i, NULL); - ret = exec_simple_cmd(&dsps->os, - OSSP_DSP_SET_TRIGGER, &i, NULL); - if (ret) - goto err; - IOCTL_RETURN(0, NULL); - - case SNDCTL_DSP_GETOSPACE: - case SNDCTL_DSP_GETISPACE: { - struct audio_buf_info info; - - ret = -EINVAL; - if (cmd == SNDCTL_DSP_GETOSPACE) { - if (!(dsps->rw & (1 << PLAY))) - goto err; - op = OSSP_DSP_GET_OSPACE; - } else { - if (!(dsps->rw & (1 << REC))) - goto err; - op = OSSP_DSP_GET_ISPACE; - } - - PREP_UARG(NULL, &info); - ret = exec_simple_cmd(&dsps->os, op, NULL, &info); - if (ret) - goto err; - IOCTL_RETURN(0, &info); - } - - case SNDCTL_DSP_GETOPTR: - case SNDCTL_DSP_GETIPTR: { - struct count_info info; - - op = cmd == SNDCTL_DSP_GETOPTR ? OSSP_DSP_GET_OPTR - : OSSP_DSP_GET_IPTR; - PREP_UARG(NULL, &info); - ret = exec_simple_cmd(&dsps->os, op, NULL, &info); - if (ret) - goto err; - IOCTL_RETURN(0, &info); - } - - case SNDCTL_DSP_GETODELAY: - PREP_UARG(NULL, &i); - i = 0; - ret = exec_simple_cmd(&dsps->os, OSSP_DSP_GET_ODELAY, NULL, &i); - IOCTL_RETURN(ret, &i); /* always copy out result, 0 on err */ - - case SOUND_PCM_WRITE_FILTER: - case SOUND_PCM_READ_FILTER: - ret = -EIO; - goto err; - - case SNDCTL_DSP_MAPINBUF: - case SNDCTL_DSP_MAPOUTBUF: - ret = -EINVAL; - goto err; - - case SNDCTL_DSP_SETSYNCRO: - case SNDCTL_DSP_SETDUPLEX: - case SNDCTL_DSP_PROFILE: - IOCTL_RETURN(0, NULL); - - default: - warn_os(os, "unknown ioctl 0x%x", cmd); - ret = -EINVAL; - goto err; - } - assert(0); /* control shouldn't reach here */ -err: - fuse_reply_err(req, -ret); -} - -#ifdef OSSP_MMAP -static int dsp_mmap_dir(int prot) -{ - if (!(prot & PROT_WRITE)) - return REC; - return PLAY; -} - -static void dsp_mmap(fuse_req_t req, void *addr, size_t len, int prot, - int flags, off_t offset, struct fuse_file_info *fi, - uint64_t mh) -{ - int dir = dsp_mmap_dir(prot); - struct ossp_dsp_mmap_arg arg = { }; - struct ossp_stream *os; - struct ossp_dsp_stream *dsps; - ssize_t ret; - - os = find_os(fi->fh); - if (!os) { - fuse_reply_err(req, EBADF); - return; - } - dsps = os_to_dsps(os); - - if (!os->mmap_off || len > os->mmap_size / 2) { - fuse_reply_err(req, EINVAL); - return; - } - - pthread_mutex_lock(&os->mmap_mutex); - - ret = -EBUSY; - if (dsps->mmapped & (1 << dir)) - goto out_unlock; - - arg.dir = dir; - arg.size = len; - - ret = exec_simple_cmd(os, OSSP_DSP_MMAP, &arg, NULL); - if (ret == 0) - dsps->mmapped |= 1 << dir; - -out_unlock: - pthread_mutex_unlock(&os->mmap_mutex); - - if (ret == 0) - fuse_reply_mmap(req, os->mmap_off + dir * os->mmap_size / 2, 0); - else - fuse_reply_err(req, -ret); -} - -static void dsp_munmap(fuse_req_t req, size_t len, struct fuse_file_info *fi, - off_t offset, uint64_t mh) -{ - struct ossp_stream *os; - struct ossp_dsp_stream *dsps; - int dir, rc; - - os = find_os(fi->fh); - if (!os) - goto out; - dsps = os_to_dsps(os); - - pthread_mutex_lock(&os->mmap_mutex); - - for (dir = 0; dir < 2; dir++) - if (offset == os->mmap_off + dir * os->mmap_size / 2) - break; - if (dir == 2 || len > os->mmap_size / 2) { - warn_os(os, "invalid munmap request " - "offset=%llu len=%zu mmapped=0x%x", - (unsigned long long)offset, len, dsps->mmapped); - goto out_unlock; - } - - rc = exec_simple_cmd(os, OSSP_DSP_MUNMAP, &dir, NULL); - if (rc) - warn_ose(os, rc, "MUNMAP failed for dir=%d", dir); - - dsps->mmapped &= ~(1 << dir); - -out_unlock: - pthread_mutex_unlock(&os->mmap_mutex); -out: - fuse_reply_none(req); -} -#endif - - -/*************************************************************************** - * Notify poller - */ - -static void *notify_poller(void *arg) -{ - struct epoll_event events[1024]; - int i, nfds; - -repeat: - nfds = epoll_wait(notify_epfd, events, ARRAY_SIZE(events), -1); - for (i = 0; i < nfds; i++) { - int do_notify = 0; - struct ossp_stream *os; - struct ossp_notify notify; - ssize_t ret; - - os = find_os_by_notify_rx(events[i].data.fd); - if (!os) { - err("can't find stream for notify_rx fd %d", - events[i].data.fd); - epoll_ctl(notify_epfd, EPOLL_CTL_DEL, events[i].data.fd, - NULL); - /* we don't know what's going on, don't close the fd */ - continue; - } - - while ((ret = read(os->notify_rx, - ¬ify, sizeof(notify))) > 0) { - if (os->dead) - continue; - if (ret != sizeof(notify)) { - warn_os(os, "short read on notify_rx (%zu, " - "expected %zu), killing the stream", - ret, sizeof(notify)); - os->dead = 1; - break; - } - if (notify.magic != OSSP_NOTIFY_MAGIC) { - warn_os(os, "invalid magic on notification, " - "killing the stream"); - os->dead = 1; - break; - } - - if (notify.opcode >= OSSP_NR_NOTIFY_OPCODES) - goto unknown; - - dbg1_os(os, "NOTIFY %s", ossp_notify_str[notify.opcode]); - - switch (notify.opcode) { - case OSSP_NOTIFY_POLL: - do_notify = 1; - break; - case OSSP_NOTIFY_OBITUARY: - os->dead = 1; - break; - case OSSP_NOTIFY_VOLCHG: - pthread_mutex_lock(&mixer_mutex); - os->mixer->modify_counter++; - pthread_mutex_unlock(&mixer_mutex); - break; - default: - unknown: - warn_os(os, "unknown notification %d", - notify.opcode); - } - } - if (ret == 0) - os->dead = 1; - else if (ret < 0 && errno != EAGAIN) { - warn_ose(os, -errno, "read fail on notify fd"); - os->dead = 1; - } - - if (!do_notify && !os->dead) - continue; - - pthread_mutex_lock(&mutex); - - if (os->ph) { - fuse_lowlevel_notify_poll(os->ph); - fuse_pollhandle_destroy(os->ph); - os->ph = NULL; - } - - if (os->dead) { - dbg0_os(os, "removing %d from notify poll list", - os->notify_rx); - epoll_ctl(notify_epfd, EPOLL_CTL_DEL, os->notify_rx, - NULL); - close(os->notify_rx); - os->notify_rx = -1; - pthread_cond_broadcast(¬ify_poller_kill_wait); - } - - pthread_mutex_unlock(&mutex); - } - goto repeat; -} - - -/*************************************************************************** - * Slave corpse reaper - */ - -static void *slave_reaper(void *arg) -{ - struct ossp_stream *os; - int status; - pid_t pid; - - pthread_mutex_lock(&mutex); -repeat: - while (list_empty(&slave_corpse_list)) - pthread_cond_wait(&slave_reaper_wait, &mutex); - - os = list_first_entry(&slave_corpse_list, struct ossp_stream, link); - list_del_init(&os->link); - - pthread_mutex_unlock(&mutex); - - do { - pid = waitpid(os->slave_pid, &status, 0); - } while (pid < 0 && errno == EINTR); - - if (pid < 0) { - if (errno == ECHILD) - warn_ose(os, -errno, "slave %d already gone?", - os->slave_pid); - else - fatal_e(-errno, "waitpid(%d) failed", os->slave_pid); - } - - pthread_mutex_lock(&mutex); - - dbg1_os(os, "slave %d reaped", os->slave_pid); - __clear_bit(os->id, os_id_bitmap); - free(os); - - goto repeat; -} - - -/*************************************************************************** - * Stuff to bind and start everything - */ - -static void ossp_daemonize(void) -{ - int fd, pfd[2]; - pid_t pid; - ssize_t ret; - int err; - - fd = open("/dev/null", O_RDWR); - if (fd >= 0) { - dup2(fd, 0); - dup2(fd, 1); - dup2(fd, 2); - if (fd > 2) - close(fd); - } - - if (pipe(pfd)) - fatal_e(-errno, "failed to create pipe for init wait"); - - if (fcntl(pfd[0], F_SETFD, FD_CLOEXEC) < 0 || - fcntl(pfd[1], F_SETFD, FD_CLOEXEC) < 0) - fatal_e(-errno, "failed to set CLOEXEC on init wait pipe"); - - pid = fork(); - if (pid < 0) - fatal_e(-errno, "failed to fork for daemon"); - - if (pid == 0) { - close(pfd[0]); - init_wait_fd = pfd[1]; - - /* be evil, my child */ - chdir("/"); - setsid(); - return; - } - - /* wait for init completion and pass over success indication */ - close(pfd[1]); - - do { - ret = read(pfd[0], &err, sizeof(err)); - } while (ret < 0 && errno == EINTR); - - if (ret == sizeof(err) && err == 0) - exit(0); - - fatal("daemon init failed ret=%zd err=%d", ret, err); - exit(1); -} - -static void ossp_init_done(void *userdata) -{ - /* init complete, notify parent if it's waiting */ - if (init_wait_fd >= 0) { - ssize_t ret; - int err = 0; - - ret = write(init_wait_fd, &err, sizeof(err)); - if (ret != sizeof(err)) - fatal_e(-errno, "failed to notify init completion, " - "ret=%zd", ret); - close(init_wait_fd); - init_wait_fd = -1; - } -} - -static const struct cuse_lowlevel_ops mixer_ops = { - .open = mixer_open, - .release = mixer_release, - .ioctl = mixer_ioctl, -}; - -static const struct cuse_lowlevel_ops dsp_ops = { - .init_done = ossp_init_done, - .open = dsp_open, - .release = dsp_release, - .read = dsp_read, - .write = dsp_write, - .poll = dsp_poll, - .ioctl = dsp_ioctl, -#ifdef OSSP_MMAP - .mmap = dsp_mmap, - .munmap = dsp_munmap, -#endif -}; - -static const struct cuse_lowlevel_ops adsp_ops = { - .open = adsp_open, - .release = dsp_release, - .read = dsp_read, - .write = dsp_write, - .poll = dsp_poll, - .ioctl = dsp_ioctl, -#ifdef OSSP_MMAP - .mmap = dsp_mmap, - .munmap = dsp_munmap, -#endif -}; - -static const char *usage = -"usage: osspd [options]\n" -"\n" -"options:\n" -" --help print this help message\n" -" --dsp=NAME DSP device name (default dsp)\n" -" --dsp-maj=MAJ DSP device major number (default 14)\n" -" --dsp-min=MIN DSP device minor number (default 3)\n" -" --adsp=NAME Aux DSP device name (default adsp, blank to disable)\n" -" --adsp-maj=MAJ Aux DSP device major number (default 14)\n" -" --adsp-min=MIN Aux DSP device minor number (default 12)\n" -" --mixer=NAME mixer device name (default mixer, blank to disable)\n" -" --mixer-maj=MAJ mixer device major number (default 14)\n" -" --mixer-min=MIN mixer device minor number (default 0)\n" -" --max=MAX maximum number of open streams (default 256)\n" -" --umax=MAX maximum number of open streams per UID (default --max)\n" -" --exit-on-idle exit if idle\n" -" --dsp-slave=PATH DSP slave (default ossp-padsp in the same dir)\n" -" --log=LEVEL log level (0..6)\n" -" --timestamp timestamp log messages\n" -" -v increase verbosity, can be specified multiple times\n" -" -f Run in foreground (don't daemonize)\n" -"\n"; - -struct ossp_param { - char *dsp_name; - unsigned dsp_major; - unsigned dsp_minor; - char *adsp_name; - unsigned adsp_major; - unsigned adsp_minor; - char *mixer_name; - unsigned mixer_major; - unsigned mixer_minor; - unsigned max_streams; - unsigned umax_streams; - char *dsp_slave_path; - unsigned log_level; - int exit_on_idle; - int timestamp; - int fg; - int help; -}; - -#define OSSP_OPT(t, p) { t, offsetof(struct ossp_param, p), 1 } - -static const struct fuse_opt ossp_opts[] = { - OSSP_OPT("--dsp=%s", dsp_name), - OSSP_OPT("--dsp-maj=%u", dsp_major), - OSSP_OPT("--dsp-min=%u", dsp_minor), - OSSP_OPT("--adsp=%s", adsp_name), - OSSP_OPT("--adsp-maj=%u", adsp_major), - OSSP_OPT("--adsp-min=%u", adsp_minor), - OSSP_OPT("--mixer=%s", mixer_name), - OSSP_OPT("--mixer-maj=%u", mixer_major), - OSSP_OPT("--mixer-min=%u", mixer_minor), - OSSP_OPT("--max=%u", max_streams), - OSSP_OPT("--umax=%u", umax_streams), - OSSP_OPT("--exit-on-idle", exit_on_idle), - OSSP_OPT("--dsp-slave=%s", dsp_slave_path), - OSSP_OPT("--timestamp", timestamp), - OSSP_OPT("--log=%u", log_level), - OSSP_OPT("-f", fg), - FUSE_OPT_KEY("-h", 0), - FUSE_OPT_KEY("--help", 0), - FUSE_OPT_KEY("-v", 1), - FUSE_OPT_END -}; - -static struct fuse_session *setup_ossp_cuse(const struct cuse_lowlevel_ops *ops, - const char *name, int major, - int minor, int argc, char **argv) -{ - char name_buf[128]; - const char *bufp = name_buf; - struct cuse_info ci = { .dev_major = major, .dev_minor = minor, - .dev_info_argc = 1, .dev_info_argv = &bufp, - .flags = CUSE_UNRESTRICTED_IOCTL }; - struct fuse_session *se; - int fd; - - snprintf(name_buf, sizeof(name_buf), "DEVNAME=%s", name); - - se = cuse_lowlevel_setup(argc, argv, &ci, ops, NULL, NULL); - if (!se) { - err("failed to setup %s CUSE", name); - return NULL; - } - - fd = fuse_chan_fd(fuse_session_next_chan(se, NULL)); - if ( -#ifdef OSSP_MMAP - fd != fuse_mmap_fd(se) && -#endif - fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { - err_e(-errno, "failed to set CLOEXEC on %s CUSE fd", name); - cuse_lowlevel_teardown(se); - return NULL; - } - - return se; -} - -static void *cuse_worker(void *arg) -{ - struct fuse_session *se = arg; - int rc; - - rc = fuse_session_loop_mt(se); - cuse_lowlevel_teardown(se); - - return (void *)(unsigned long)rc; -} - -static int process_arg(void *data, const char *arg, int key, - struct fuse_args *outargs) -{ - struct ossp_param *param = data; - - switch (key) { - case 0: - fprintf(stderr, usage); - param->help = 1; - return 0; - case 1: - param->log_level++; - return 0; - } - return 1; -} - -int main(int argc, char **argv) -{ - static struct ossp_param param = { - .dsp_name = DFL_DSP_NAME, - .dsp_major = DFL_DSP_MAJOR, .dsp_minor = DFL_DSP_MINOR, - .adsp_name = DFL_ADSP_NAME, - .adsp_major = DFL_ADSP_MAJOR, .adsp_minor = DFL_ADSP_MINOR, - .mixer_name = DFL_MIXER_NAME, - .mixer_major = DFL_MIXER_MAJOR, .mixer_minor = DFL_MIXER_MINOR, - .max_streams = DFL_MAX_STREAMS, - }; - struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - char path_buf[PATH_MAX], *dir; - char adsp_buf[64] = "", mixer_buf[64] = ""; - struct sigaction sa; - struct stat stat_buf; - ssize_t ret; - unsigned u; - - snprintf(ossp_log_name, sizeof(ossp_log_name), "osspd"); - param.log_level = ossp_log_level; - - if (fuse_opt_parse(&args, ¶m, ossp_opts, process_arg)) - fatal("failed to parse arguments"); - - if (param.help) - return 0; - - max_streams = param.max_streams; - hashtbl_size = max_streams / 2 + 13; - - umax_streams = max_streams; - if (param.umax_streams) - umax_streams = param.umax_streams; - if (param.log_level > OSSP_LOG_MAX) - param.log_level = OSSP_LOG_MAX; - if (!param.fg) - param.log_level = -param.log_level; - ossp_log_level = param.log_level; - ossp_log_timestamp = param.timestamp; - - if (!param.fg) - ossp_daemonize(); - - /* daemonization already handled, prevent forking inside FUSE */ - fuse_opt_add_arg(&args, "-f"); - - info("OSS Proxy v%s (C) 2008-2010 by Tejun Heo ", - OSSP_VERSION); - - /* ignore stupid SIGPIPEs */ - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = SIG_IGN; - if (sigaction(SIGPIPE, &sa, NULL)) - fatal_e(-errno, "failed to ignore SIGPIPE"); - -//#ifdef GIOVANNI - /* determine slave path and check for availability */ - ret = readlink("/proc/self/exe", path_buf, PATH_MAX - 1); - if (ret < 0) - fatal_e(-errno, "failed to determine executable path"); - path_buf[ret] = '\0'; - dir = dirname(path_buf); - - if (param.dsp_slave_path) { - strncpy(dsp_slave_path, param.dsp_slave_path, PATH_MAX - 1); - dsp_slave_path[PATH_MAX - 1] = '\0'; - } else { - ret = snprintf(dsp_slave_path, PATH_MAX, "%s/%s", - dir, "ossp-padsp"); - if (ret >= PATH_MAX) - fatal("dsp slave pathname too long"); - } - - if (stat(dsp_slave_path, &stat_buf)) - fatal_e(-errno, "failed to stat %s", dsp_slave_path); - if (!S_ISREG(stat_buf.st_mode) || !(stat_buf.st_mode & 0444)) - fatal("%s is not executable", dsp_slave_path); - -//#endif// GIOVANNI - /* allocate tables */ - os_id_bitmap = calloc(BITS_TO_LONGS(max_streams), sizeof(long)); - mixer_tbl = calloc(hashtbl_size, sizeof(mixer_tbl[0])); - os_tbl = calloc(hashtbl_size, sizeof(os_tbl[0])); - os_pgrp_tbl = calloc(hashtbl_size, sizeof(os_pgrp_tbl[0])); - os_notify_tbl = calloc(hashtbl_size, sizeof(os_notify_tbl[0])); - if (!os_id_bitmap || !mixer_tbl || !os_tbl || !os_pgrp_tbl || - !os_notify_tbl) - fatal("failed to allocate stream hash tables"); - for (u = 0; u < hashtbl_size; u++) { - INIT_LIST_HEAD(&mixer_tbl[u]); - INIT_LIST_HEAD(&os_tbl[u]); - INIT_LIST_HEAD(&os_pgrp_tbl[u]); - INIT_LIST_HEAD(&os_notify_tbl[u]); - } - __set_bit(0, os_id_bitmap); /* don't use id 0 */ - - /* create mixer delayed reference worker */ - ret = -pthread_create(&mixer_delayed_put_thread, NULL, - mixer_delayed_put_worker, NULL); - if (ret) - fatal_e(ret, "failed to create mixer delayed put worker"); - - /* if exit_on_idle, touch mixer for pgrp0 */ - exit_on_idle = param.exit_on_idle; - if (exit_on_idle) { - struct ossp_mixer *mixer; - - mixer = get_mixer(0); - if (!mixer) - fatal("failed to touch idle mixer"); - put_mixer(mixer); - } - - /* create notify epoll and kick off watcher thread */ - notify_epfd = epoll_create(max_streams); - if (notify_epfd < 0) - fatal_e(-errno, "failed to create notify epoll"); - if (fcntl(notify_epfd, F_SETFD, FD_CLOEXEC) < 0) - fatal_e(-errno, "failed to set CLOEXEC on notify epfd"); - - ret = -pthread_create(¬ify_poller_thread, NULL, notify_poller, NULL); - if (ret) - fatal_e(ret, "failed to create notify poller thread"); - - /* create reaper for slave corpses */ - ret = -pthread_create(&slave_reaper_thread, NULL, slave_reaper, NULL); - if (ret) - fatal_e(ret, "failed to create slave reaper thread"); - -#ifdef GIOVANNI - /* we're set, let's setup fuse structures */ - if (strlen(param.mixer_name)) - mixer_se = setup_ossp_cuse(&mixer_ops, param.mixer_name, - param.mixer_major, param.mixer_minor, - args.argc, args.argv); - if (strlen(param.adsp_name)) - adsp_se = setup_ossp_cuse(&dsp_ops, param.adsp_name, - param.adsp_major, param.adsp_minor, - args.argc, args.argv); - -#endif// GIOVANNI - dsp_se = setup_ossp_cuse(&dsp_ops, param.dsp_name, - param.dsp_major, param.dsp_minor, - args.argc, args.argv); - if (!dsp_se) - fatal("can't create dsp, giving up"); - -#ifdef GIOVANNI - if (mixer_se) - snprintf(mixer_buf, sizeof(mixer_buf), ", %s (%d:%d)", - param.mixer_name, param.mixer_major, param.mixer_minor); - if (adsp_se) - snprintf(adsp_buf, sizeof(adsp_buf), ", %s (%d:%d)", - param.adsp_name, param.adsp_major, param.adsp_minor); - -#endif// GIOVANNI - info("Creating %s (%d:%d)%s%s", param.dsp_name, param.dsp_major, - param.dsp_minor, adsp_buf, mixer_buf); - -#ifdef GIOVANNI - /* start threads for mixer and adsp */ - if (mixer_se) { - ret = -pthread_create(&cuse_mixer_thread, NULL, - cuse_worker, mixer_se); - if (ret) - err_e(ret, "failed to create mixer worker"); - } - if (adsp_se) { - ret = -pthread_create(&cuse_adsp_thread, NULL, - cuse_worker, adsp_se); - if (ret) - err_e(ret, "failed to create adsp worker"); - } -#endif// GIOVANNI - - /* run CUSE for /dev/dsp in the main thread */ - ret = (ssize_t)cuse_worker(dsp_se); - if (ret < 0) - fatal("dsp worker failed"); - return 0; -}